Skip to content

Instantly share code, notes, and snippets.

@paaloeye
Last active December 15, 2015 19:18
Show Gist options
  • Save paaloeye/5309999 to your computer and use it in GitHub Desktop.
Save paaloeye/5309999 to your computer and use it in GitHub Desktop.
Puppet: Get file content for File resource with content attribute
#
# Purpose: Get content of file from Puppet catalog
#
# Usage: ruby file.rb args
# Args:
# | Name | Desc | Default
# ------------------------------------------
# | node | |
# | path | \
# | environment | production \
#
# Environment variables:
# -----------------------------------------------------------
# | NO_SSL=1 | Don't use SSL | 0
# | MASTER | FQDN of master | puppet
# -----------------------------------------------------------
#
require 'rubygems'
require 'json'
require 'pp'
require 'net/http'
require 'openssl'
require 'uri'
require 'pry'
require 'fileutils'
require 'pathname'
def define_func(name, &body)
$context ||= context_default
define_method(name) do |*args|
body.call($context, *args)
end
end
def context_default
{
:no_ssl => ENV['NO_SSL'].nil? ? false : true,
:environment => 'production',
:master => ENV['MASTER'].nil? ? 'puppet' : ENV['MASTER'],
:key => '/Users/paulche/tmp/var/puppet/ssl/private_keys/host.vagrant.local.pem',
:cert => '/Users/paulche/tmp/var/puppet/ssl/certs/host.vagrant.local.pem',
:cacert => '/Users/paulche/tmp/var/puppet/ssl/certs/ca.pem',
:tmpdir => '/Users/paulche/tmp/concat-puppet'
}
end
define_func(:retrieve_catalog) do |context|
rest = "catalog/#{context[:node]}"
res = get_https_content(rest,{'accept' => 'pson'})
JSON.load(res)["data"]["resources"]
end
define_func(:context) do |context|
context
end
define_func(:get_https_content) do |context, rest, headers|
uri = URI.parse("https://#{context[:master]}:8140/#{context[:environment]}/#{rest}")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
if context[:no_ssl]
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
else
http.cert = OpenSSL::X509::Certificate.new(File.read(context[:cert]))
http.ca_file = context[:cacert]
http.key = OpenSSL::PKey::RSA.new(File.read(context[:key]))
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
end
request = Net::HTTP::Get.new(uri.request_uri)
headers.each do |k,v|
request[k] = v
end
response = http.request(request)
response.body
end
define_func(:setup) do |context,args|
usage_proc = proc { $stderr.puts "Usage: ruby file.rb node path [environment]"; exit(0) }
fail_proc = proc { $stderr.puts "ERROR: Try --help"; exit(2) }
case args.count
when 0
usage_proc.call
when 1
if args.first == '--help'
usage_proc.call
else
fail_proc.call
end
when 2
context[:node] = args[0]
context[:path] = args[1]
when 3
context[:node] = args[0]
context[:path] = args[1]
context[:environment] = args[2]
else
fail_proc.call
end
end
define_func(:setup_concat) do |context, catalog|
FileUtils.mkdir(context[:tmpdir]) unless File.exists?(context[:tmpdir])
end
define_func(:concat_wrap) do |context, catalog|
FileUtils.mkdir_p("#{context[:tmpdir]}/concat/fragments") unless File.exists?("#{context[:tmpdir]}/concat/fragments")
context[:safe_path] = context[:path].gsub(%r{[/\n]},"_")
find = Regexp.new("#{context[:safe_path]}/fragments/.+")
fragments = catalog.select { |el| el['type'] == 'File' and el['title'] =~ find }
res = concat_exec(catalog, fragments)
FileUtils.rm_rf context[:tmpdir]
res
end
define_func(:concat_exec) do |context, catalog, fragments|
fragments.each do |el|
title = el['title']
basename = Pathname.new(title).basename
tmpdir = "#{context[:tmpdir]}/concat/fragments"
to_write = if content = el['parameters']['content']
content
elsif src = el['parameters']['source']
get_https_content("file_content#{URI(src).path}", {'accept' => '*/*'})
else
end
File.open("#{tmpdir}/#{basename}", :mode => 'w' ) { |f| f.write(to_write) }
end
# Retreive concatfragments.sh
exec_title = "concat_#{context[:path]}"
exec_resource = catalog.detect { |el| el['type'] == 'Exec' and el['title'] == exec_title }
exec_resource['parameters']['command'] =~ /^([^ ]+) -o/
resource = catalog.detect { |el| el['type'] == 'File' and el['title'] == $1 }
concat = get_https_content("file_content#{URI(resource['parameters']['source']).path}", {'accept' => '*/*'})
File.open("#{context[:tmpdir]}/concat.sh", :mode => 'w' ) { |f| f.write(concat) }
FileUtils.chmod 0777, "#{context[:tmpdir]}/concat.sh"
# Reduce fragments to signle file
exec_resource['parameters']['command'] =~ /^([^ ]+) -o ([^ ]+) -d ([^ ]+)(.*)$/
exec = "#{context[:tmpdir]}/concat.sh -o #{context[:tmpdir]}/concat.out -d #{context[:tmpdir]}/concat #{$4}"
Kernel.system(exec)
File.read("#{context[:tmpdir]}/concat.out")
end
#
# Main part
#
#
# Plot
# 1. Get catalog
# 2. Determine type of file:
# * template
# Print content of file
# * source
# Retrive content of file via second request
# Print content of file
# * concat
# Get all fragment
# Find out type of fragment
# source
# Retrive content of file via second request
# template
# Return content param
#
def main
setup ARGV
path = context[:path]
catalog = retrieve_catalog
# 2. Find out type of file
file_resource = catalog.detect do |el|
el['type'] == 'File' and \
(el['parameters'] \
and (!el['parameters']['alias'] or (el['parameters']['alias'] !~ /^concat/)) \
and (!el['parameters']['path'] and el['title'] == path) \
or (el['parameters']['path'] and el['parameters']['path'] == path))
end
if file_resource
# source, template types
if src = file_resource['parameters']['source']
puts get_https_content("file_content#{URI(src).path}", {'accept' => '*/*'})
exit(0)
elsif content = file_resource['parameters']['content']
puts content
exit(0)
end
else
# either concat or not_found
if catalog.detect { |el| el['type'] == 'Concat' and el['parameters']['path'] == path }
# Concat type
# _etc_motd/fragments
# /var/lib/puppet/concat/_etc_motd/fragments/02_motd_header2
setup_concat
puts concat_wrap(catalog)
exit(0)
else
$stderr.puts "File wasn't found in the catalog"
exit(41)
end
end
end
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment