Skip to content
Permalink
Browse files

Fixes needed for running tests against puppet's master branch

Specifically this commit

 - Adds specific checks for puppet 3 when loading storeconfig code
   storeconfig does not work against current master and will be removed
   as part of Puppet 4.0.0. We want to maintain backward compatibility,
   so the code supports both

 - Removes references to Puppet[:trusted_node_data] when on Puppet
   4 (essentially assuming it is always true on 4). Like above we will
   look for it when on Puppet 3.y.z and ignore it (assuming true) when
   on Puppet 4.y.z
  • Loading branch information...
Ryan Senior
Ryan Senior committed Nov 25, 2014
1 parent 2fd9719 commit 9ef68b635d1bb1f5338b3e40034a2ed787f2e107
@@ -1,177 +1,192 @@
require 'puppet/util/puppetdb'
require 'puppet/face'
require 'tmpdir'

Puppet::Face.define(:storeconfigs, '0.0.1') do
copyright "Puppet Labs", 2011
license "Apache 2 license"
if Puppet::Util::Puppetdb.puppet3compat?
require 'tmpdir'

summary "Interact with the storeconfigs database"
description <<-DESC
Puppet::Face.define(:storeconfigs, '0.0.1') do
copyright "Puppet Labs", 2011
license "Apache 2 license"

summary "Interact with the storeconfigs database"
description <<-DESC
This subcommand interacts with the ActiveRecord storeconfigs database, and
can be used to export a dump of that data which is suitable for import by
PuppetDB.
DESC

action :export do
summary "Export the storeconfigs database"
description <<-DESC
action :export do
summary "Export the storeconfigs database"
description <<-DESC
Generate a dump of all catalogs from the storeconfigs database, as a
tarball which can be imported by PuppetDB. Only exported resources are
included; non-exported resources, edges, facts, or other data are
omitted. Returns the location of the output.
DESC

when_invoked do |options|
when_invoked do |options|

require 'puppet/rails'
require 'puppet/rails'

tmpdir = Dir.mktmpdir
workdir = File.join(tmpdir, 'puppetdb-bak')
Dir.mkdir(workdir)
tmpdir = Dir.mktmpdir
workdir = File.join(tmpdir, 'puppetdb-bak')
Dir.mkdir(workdir)

begin
Puppet::Rails.connect
begin
Puppet::Rails.connect

# Fetch all nodes, including exported resources and their params
nodes = Puppet::Rails::Host.all(:include => {:resources => [:param_values, :puppet_tags]},
:conditions => {:resources => {:exported => true}})
# Fetch all nodes, including exported resources and their params
nodes = Puppet::Rails::Host.all(:include => {:resources => [:param_values, :puppet_tags]},
:conditions => {:resources => {:exported => true}})

catalogs = nodes.map { |node| node_to_catalog_hash(node) }
catalogs = nodes.map { |node| node_to_catalog_hash(node) }

catalog_dir = File.join(workdir, 'catalogs')
FileUtils.mkdir(catalog_dir)
catalog_dir = File.join(workdir, 'catalogs')
FileUtils.mkdir(catalog_dir)

catalogs.each do |catalog|
filename = File.join(catalog_dir, "#{catalog[:data][:name]}.json")
catalogs.each do |catalog|
filename = File.join(catalog_dir, "#{catalog[:data][:name]}.json")

File.open(filename, 'w') do |file|
file.puts catalog.to_pson
File.open(filename, 'w') do |file|
file.puts catalog.to_pson
end
end
end

node_names = nodes.map(&:name).sort
node_names = nodes.map(&:name).sort

timestamp = Time.now
timestamp = Time.now

File.open(File.join(workdir, 'export-metadata.json'), 'w') do |file|
metadata = {
'timestamp' => timestamp,
'command-versions' => {
'replace-catalog' => 2,
File.open(File.join(workdir, 'export-metadata.json'), 'w') do |file|
metadata = {
'timestamp' => timestamp,
'command-versions' => {
'replace-catalog' => 2,
}
}
}

file.puts metadata.to_pson
end
file.puts metadata.to_pson
end

tarfile = destination_file(timestamp)
tarfile = destination_file(timestamp)

if tar = Puppet::Util.which('tar')
execute("cd #{tmpdir} && #{tar} -cf #{tarfile} puppetdb-bak")
if tar = Puppet::Util.which('tar')
execute("cd #{tmpdir} && #{tar} -cf #{tarfile} puppetdb-bak")

FileUtils.rm_rf(workdir)
FileUtils.rm_rf(workdir)

if gzip = Puppet::Util.which('gzip')
execute("#{gzip} #{tarfile}")
"#{tarfile}.gz"
if gzip = Puppet::Util.which('gzip')
execute("#{gzip} #{tarfile}")
"#{tarfile}.gz"
else
Puppet.warning "Can't find the `gzip` command to compress the tarball; output will not be compressed"
tarfile
end
else
Puppet.warning "Can't find the `gzip` command to compress the tarball; output will not be compressed"
tarfile
Puppet.warning "Can't find the `tar` command to produce a tarball; output will remain in the temporary working directory"
workdir
end
else
Puppet.warning "Can't find the `tar` command to produce a tarball; output will remain in the temporary working directory"
workdir
rescue => e
# Clean up if something goes wrong. We don't want to ensure this,
# because we want the directory to stick around in the case where they
# don't have tar.
FileUtils.rm_rf(workdir)
raise
end
rescue => e
# Clean up if something goes wrong. We don't want to ensure this,
# because we want the directory to stick around in the case where they
# don't have tar.
FileUtils.rm_rf(workdir)
raise
end
end

when_rendering :console do |filename|
"Exported storeconfigs data to #{filename}"
when_rendering :console do |filename|
"Exported storeconfigs data to #{filename}"
end
end
end

# Returns the location to leave the output. This is really only here for testing. :/
def destination_file(timestamp)
File.expand_path("storeconfigs-#{timestamp.strftime('%Y%m%d%H%M%S')}.tar")
end
# Returns the location to leave the output. This is really only here for testing. :/
def destination_file(timestamp)
File.expand_path("storeconfigs-#{timestamp.strftime('%Y%m%d%H%M%S')}.tar")
end

# Execute a command using Puppet's execution static method.
#
# @param command [Array<String>, String] the command to execute. If it is
# an Array the first element should be the executable and the rest of the
# elements should be the individual arguments to that executable.
# @return [Puppet::Util::Execution::ProcessOutput] output as specified by options
# @raise [Puppet::ExecutionFailure] if the executed chiled process did not exit with status == 0 and `failonfail` is
# `true`.
def execute(command)
Puppet::Util::Execution.execute(command)
end
# Execute a command using Puppet's execution static method.
#
# @param command [Array<String>, String] the command to execute. If it is
# an Array the first element should be the executable and the rest of the
# elements should be the individual arguments to that executable.
# @return [Puppet::Util::Execution::ProcessOutput] output as specified by options
# @raise [Puppet::ExecutionFailure] if the executed chiled process did not exit with status == 0 and `failonfail` is
# `true`.
def execute(command)
Puppet::Util::Execution.execute(command)
end

def node_to_catalog_hash(node)
resources = node.resources.map { |resource| resource_to_hash(resource) }
edges = node.resources.map { |resource| resource_to_edge_hash(resource) }

{
:metadata => {
:api_version => 1,
},
:data => {
:name => node.name,
:version => node.last_compile || Time.now,
:edges => edges,
:resources => resources + [stage_main_hash],
},
}
end
def node_to_catalog_hash(node)
resources = node.resources.map { |resource| resource_to_hash(resource) }
edges = node.resources.map { |resource| resource_to_edge_hash(resource) }

{
:metadata => {
:api_version => 1,
},
:data => {
:name => node.name,
:version => node.last_compile || Time.now,
:edges => edges,
:resources => resources + [stage_main_hash],
},
}
end

def resource_to_hash(resource)
parameters = resource.param_values.inject({}) do |params,param_value|
if params.has_key?(param_value.param_name.name)
value = [params[param_value.param_name.name],param_value.value].flatten
else
value = param_value.value
def resource_to_hash(resource)
parameters = resource.param_values.inject({}) do |params,param_value|
if params.has_key?(param_value.param_name.name)
value = [params[param_value.param_name.name],param_value.value].flatten
else
value = param_value.value
end
params.merge(param_value.param_name.name => value)
end
params.merge(param_value.param_name.name => value)
end

tags = resource.puppet_tags.map(&:name).uniq.sort
tags = resource.puppet_tags.map(&:name).uniq.sort

hash = {
:type => resource.restype,
:title => resource.title,
:exported => true,
:parameters => parameters,
:tags => tags,
}
hash = {
:type => resource.restype,
:title => resource.title,
:exported => true,
:parameters => parameters,
:tags => tags,
}

hash[:file] = resource.file if resource.file
hash[:line] = resource.line if resource.line
hash[:file] = resource.file if resource.file
hash[:line] = resource.line if resource.line

hash
end
hash
end

# The catalog *must* have edges, so everything is contained by Stage[main]!
def resource_to_edge_hash(resource)
{
'source' => {'type' => 'Stage', 'title' => 'main'},
'target' => {'type' => resource.restype, 'title' => resource.title},
'relationship' => 'contains',
}
end

# The catalog *must* have edges, so everything is contained by Stage[main]!
def resource_to_edge_hash(resource)
{
'source' => {'type' => 'Stage', 'title' => 'main'},
'target' => {'type' => resource.restype, 'title' => resource.title},
'relationship' => 'contains',
}
def stage_main_hash
{
:type => 'Stage',
:title => 'main',
:exported => false,
:parameters => {},
:tags => ['stage', 'main'],
}
end
end
else
Puppet::Face.define(:storeconfigs, '0.0.1') do
copyright "Puppet Labs", 2011
license "Apache 2 license"

def stage_main_hash
{
:type => 'Stage',
:title => 'main',
:exported => false,
:parameters => {},
:tags => ['stage', 'main'],
}
summary "storeconfigs is not supported on Puppet 4.0.0+"
description <<-DESC
Users needing this feature should migrate using Puppet 3.7.2 or a more recent
3.7 release.
DESC
end
end
@@ -21,8 +21,9 @@ def save(request)
payload = profile("Encode facts command submission payload",
[:puppetdb, :facts, :encode]) do
facts = request.instance.dup
facts.values = facts.strip_internal
if Puppet[:trusted_node_data]
facts.values = facts.strip_internal.dup

if ! Puppet::Util::Puppetdb.puppet3compat? || Puppet[:trusted_node_data]
facts.values[:trusted] = get_trusted_info(request.node)
end
{
@@ -30,6 +30,10 @@ def self.config
@config
end

def self.puppet3compat?
defined?(Puppet::Parser::AST::HashOrArrayAccess)
end

# This magical stuff is needed so that the indirector termini will make requests to
# the correct host/port, because this module gets mixed in to our indirector
# termini.

0 comments on commit 9ef68b6

Please sign in to comment.
You can’t perform that action at this time.