diff --git a/lib/puppet/application/configurer.rb b/lib/puppet/application/configurer.rb new file mode 100644 index 0000000..70d2481 --- /dev/null +++ b/lib/puppet/application/configurer.rb @@ -0,0 +1,23 @@ +require 'puppet/application' +require 'puppet/interface' + +class Puppet::Application::Configurer < Puppet::Application + should_parse_config + run_mode :agent + + option("--debug","-d") + option("--verbose","-v") + + def setup + if options[:debug] or options[:verbose] + Puppet::Util::Log.level = options[:debug] ? :debug : :info + end + + Puppet::Util::Log.newdestination(:console) + end + + def run_command + report = Puppet::Interface::Configurer.synchronize(Puppet[:certname]) + Puppet::Interface::Report.submit(report) + end +end diff --git a/lib/puppet/interface.rb b/lib/puppet/interface.rb index d169067..13b1a81 100644 --- a/lib/puppet/interface.rb +++ b/lib/puppet/interface.rb @@ -7,6 +7,8 @@ class Puppet::Interface include Puppet::Interface::ActionManager extend Puppet::Interface::ActionManager + include Puppet::Util + # This is just so we can search for actions. We only use its # list of directories to search. # Can't we utilize an external autoloader, or simply use the $LOAD_PATH? -pvb diff --git a/lib/puppet/interface/catalog.rb b/lib/puppet/interface/catalog.rb index b2ed08f..f99d088 100644 --- a/lib/puppet/interface/catalog.rb +++ b/lib/puppet/interface/catalog.rb @@ -1,4 +1,36 @@ require 'puppet/interface/indirector' Puppet::Interface::Indirector.new(:catalog) do + action(:apply) do |catalog| + report = Puppet::Transaction::Report.new("apply") + report.configuration_version = catalog.version + + Puppet::Util::Log.newdestination(report) + + begin + benchmark(:notice, "Finished catalog run") do + catalog.apply(:report => report) + end + rescue => detail + puts detail.backtrace if Puppet[:trace] + Puppet.err "Failed to apply catalog: #{detail}" + end + + report.finalize_report + report + end + + action(:download) do |certname,facts| + Puppet::Resource::Catalog.terminus_class = :rest + facts_to_upload = {:facts_format => :b64_zlib_yaml, :facts => CGI.escape(facts.render(:b64_zlib_yaml))} + catalog = nil + retrieval_duration = thinmark do + catalog = Puppet::Interface::Catalog.find(certname, facts_to_upload) + end + catalog = catalog.to_ral + catalog.finalize + catalog.retrieval_duration = retrieval_duration + catalog.write_class_file + catalog + end end diff --git a/lib/puppet/interface/configurer.rb b/lib/puppet/interface/configurer.rb new file mode 100644 index 0000000..42e950f --- /dev/null +++ b/lib/puppet/interface/configurer.rb @@ -0,0 +1,13 @@ +require 'puppet/interface' + +Puppet::Interface.new(:configurer) do + action(:synchronize) do |certname| + facts = Puppet::Interface::Facts.find(certname) + + catalog = Puppet::Interface::Catalog.download(certname, facts) + + report = Puppet::Interface::Catalog.apply(catalog) + + report + end +end diff --git a/lib/puppet/interface/report.rb b/lib/puppet/interface/report.rb index e7b9165..4923a4b 100644 --- a/lib/puppet/interface/report.rb +++ b/lib/puppet/interface/report.rb @@ -1,4 +1,13 @@ require 'puppet/interface/indirector' Puppet::Interface::Indirector.new(:report) do + action(:submit) do |report| + begin + Puppet::Transaction::Report.terminus_class = :rest + report.save + rescue => detail + puts detail.backtrace if Puppet[:trace] + Puppet.err "Could not send report: #{detail}" + end + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 242ef0a..db4eeee 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -8,6 +8,26 @@ RSpec.configure do |config| config.mock_with :mocha + + config.before :each do + # Set the confdir and vardir to gibberish so that tests + # have to be correctly mocked. + Puppet[:confdir] = "/dev/null" + Puppet[:vardir] = "/dev/null" + + # Avoid opening ports to the outside world + Puppet.settings[:bindaddress] = "127.0.0.1" + + @logs = [] + Puppet::Util::Log.newdestination(@logs) + end + + config.after :each do + Puppet.settings.clear + + @logs.clear + Puppet::Util::Log.close_all + end end # We need this because the RAL uses 'should' as a method. This diff --git a/spec/unit/application/configurer_spec.rb b/spec/unit/application/configurer_spec.rb new file mode 100644 index 0000000..621039b --- /dev/null +++ b/spec/unit/application/configurer_spec.rb @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby + +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') +require 'puppet/application/configurer' +require 'puppet/indirector/catalog/rest' +require 'puppet/indirector/report/rest' +require 'tempfile' + +describe "Puppet::Application::Configurer" do + it "should retrieve and apply a catalog and submit a report" do + dirname = Dir.mktmpdir("puppetdir") + Puppet[:vardir] = dirname + Puppet[:confdir] = dirname + Puppet[:certname] = "foo" + @catalog = Puppet::Resource::Catalog.new + @file = Puppet::Resource.new(:file, File.join(dirname, "tmp_dir_resource"), :parameters => {:ensure => :present}) + @catalog.add_resource(@file) + + @report = Puppet::Transaction::Report.new("apply") + Puppet::Transaction::Report.stubs(:new).returns(@report) + + Puppet::Resource::Catalog::Rest.any_instance.stubs(:find).returns(@catalog) + @report.expects(:save) + + Puppet::Util::Log.stubs(:newdestination) + + Puppet::Application::Configurer.new.run + + @report.status.should == "changed" + end +end diff --git a/spec/unit/interface/configurer_spec.rb b/spec/unit/interface/configurer_spec.rb new file mode 100644 index 0000000..99f5f7a --- /dev/null +++ b/spec/unit/interface/configurer_spec.rb @@ -0,0 +1,25 @@ +#!/usr/bin/env ruby + +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb') +require 'puppet/interface/configurer' +require 'puppet/indirector/catalog/rest' +require 'tempfile' + +describe Puppet::Interface::Configurer do + describe "#synchronize" do + it "should retrieve and apply a catalog and return a report" do + dirname = Dir.mktmpdir("puppetdir") + Puppet[:vardir] = dirname + Puppet[:confdir] = dirname + @catalog = Puppet::Resource::Catalog.new + @file = Puppet::Resource.new(:file, File.join(dirname, "tmp_dir_resource"), :parameters => {:ensure => :present}) + @catalog.add_resource(@file) + Puppet::Resource::Catalog::Rest.any_instance.stubs(:find).returns(@catalog) + + report = Puppet::Interface::Configurer.synchronize("foo") + + report.kind.should == "apply" + report.status.should == "changed" + end + end +end