[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, experimental, updated. debian/2.6.8-1-844-g7ec39d5
Nick Lewis
nick at puppetlabs.com
Tue May 10 08:06:52 UTC 2011
The following commit has been merged in the experimental branch:
commit e3d24865c89bccd0221f3d6d475d350f577ed3fb
Author: Nick Lewis <nick at puppetlabs.com>
Date: Tue Mar 22 12:54:52 2011 -0700
(#6814) Create a dedicated Action class
This class will represents an action, and allows us to store metadata for an
action, and programmatically introspect and invoke them. A helper class
ActionBuilder represents the DSL for defining an action.
Also defined an "invoke" DSL method to handle the functionality of defining the
method for an action.
Reviewed-By: Daniel Pittman
diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb
new file mode 100644
index 0000000..e4c2a46
--- /dev/null
+++ b/lib/puppet/interface/action.rb
@@ -0,0 +1,16 @@
+require 'puppet/interface'
+
+class Puppet::Interface::Action
+ attr_reader :name
+
+ def initialize(interface, name)
+ name = name.to_s
+ raise "'#{name}' is an invalid action name" unless name =~ /^[a-z]\w*$/
+ @interface = interface
+ @name = name
+ end
+
+ def invoke(*args, &block)
+ @interface.method(name).call(*args,&block)
+ end
+end
diff --git a/lib/puppet/interface/action_builder.rb b/lib/puppet/interface/action_builder.rb
new file mode 100644
index 0000000..777fcaf
--- /dev/null
+++ b/lib/puppet/interface/action_builder.rb
@@ -0,0 +1,29 @@
+require 'puppet/interface'
+
+class Puppet::Interface::ActionBuilder
+ attr_reader :action
+
+ def self.build(interface, name, &block)
+ name = name.to_s
+ raise "Action '#{name}' must specify a block" unless block
+ builder = new(interface, name, &block)
+ builder.action
+ end
+
+ def initialize(interface, name, &block)
+ @interface = interface
+ @action = Puppet::Interface::Action.new(interface, name)
+ instance_eval(&block)
+ end
+
+ # Ideally the method we're defining here would be added to the action, and a
+ # method on the interface would defer to it
+ def invoke(&block)
+ raise "Invoke called on an ActionBuilder with no corresponding Action" unless @action
+ if @interface.is_a?(Class)
+ @interface.define_method(@action.name, &block)
+ else
+ @interface.meta_def(@action.name, &block)
+ end
+ end
+end
diff --git a/lib/puppet/interface/action_manager.rb b/lib/puppet/interface/action_manager.rb
index 27a9829..8629b4c 100644
--- a/lib/puppet/interface/action_manager.rb
+++ b/lib/puppet/interface/action_manager.rb
@@ -1,32 +1,36 @@
+require 'puppet/interface/action_builder'
+
module Puppet::Interface::ActionManager
# Declare that this app can take a specific action, and provide
# the code to do so.
def action(name, &block)
- @actions ||= []
+ @actions ||= {}
name = name.to_s.downcase.to_sym
+
raise "Action #{name} already defined for #{self}" if action?(name)
- @actions << name
- if self.is_a?(Class)
- define_method(name, &block)
- else
- meta_def(name, &block)
- end
+ action = Puppet::Interface::ActionBuilder.build(self, name, &block)
+
+ @actions[name] = action
end
def actions
- @actions ||= []
- result = @actions.dup
+ @actions ||= {}
+ result = @actions.keys
if self.is_a?(Class) and superclass.respond_to?(:actions)
result += superclass.actions
elsif self.class.respond_to?(:actions)
result += self.class.actions
end
- result.sort { |a,b| a.to_s <=> b.to_s }
+ result.sort
+ end
+
+ def get_action(name)
+ @actions[name].dup
end
def action?(name)
- actions.include?(name.to_sym)
+ actions.include?(name)
end
end
diff --git a/lib/puppet/interface/catalog.rb b/lib/puppet/interface/catalog.rb
index f99d088..6c235e2 100644
--- a/lib/puppet/interface/catalog.rb
+++ b/lib/puppet/interface/catalog.rb
@@ -1,36 +1,40 @@
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
+ action(:apply) do
+ invoke do |catalog|
+ report = Puppet::Transaction::Report.new("apply")
+ report.configuration_version = catalog.version
- Puppet::Util::Log.newdestination(report)
+ Puppet::Util::Log.newdestination(report)
- begin
- benchmark(:notice, "Finished catalog run") do
- catalog.apply(:report => 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
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Failed to apply catalog: #{detail}"
- end
- report.finalize_report
- report
+ report.finalize_report
+ report
+ end
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)
+ action(:download) do
+ invoke 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
- catalog = catalog.to_ral
- catalog.finalize
- catalog.retrieval_duration = retrieval_duration
- catalog.write_class_file
- catalog
end
end
diff --git a/lib/puppet/interface/catalog/select.rb b/lib/puppet/interface/catalog/select.rb
index 4bb4931..349d9c5 100644
--- a/lib/puppet/interface/catalog/select.rb
+++ b/lib/puppet/interface/catalog/select.rb
@@ -1,8 +1,10 @@
# Select and show a list of resources of a given type.
-Puppet::Interface::Catalog.action :select do |*args|
- host = args.shift
- type = args.shift
- catalog = Puppet::Resource::Catalog.indirection.find(host)
+Puppet::Interface::Catalog.action :select do
+ invoke do |*args|
+ host = args.shift
+ type = args.shift
+ catalog = Puppet::Resource::Catalog.indirection.find(host)
- catalog.resources.reject { |res| res.type != type }.each { |res| puts res }
+ catalog.resources.reject { |res| res.type != type }.each { |res| puts res }
+ end
end
diff --git a/lib/puppet/interface/config.rb b/lib/puppet/interface/config.rb
index 501099a..0aecc26 100644
--- a/lib/puppet/interface/config.rb
+++ b/lib/puppet/interface/config.rb
@@ -1,10 +1,10 @@
require 'puppet/interface'
Puppet::Interface.new(:config) do
- action(:print) do |*args|
- if name
+ action(:print) do
+ invoke do |*args|
Puppet.settings[:configprint] = args.join(",")
+ Puppet.settings.print_config_options
end
- Puppet.settings.print_config_options
end
end
diff --git a/lib/puppet/interface/configurer.rb b/lib/puppet/interface/configurer.rb
index 42e950f..36953ba 100644
--- a/lib/puppet/interface/configurer.rb
+++ b/lib/puppet/interface/configurer.rb
@@ -1,13 +1,15 @@
require 'puppet/interface'
Puppet::Interface.new(:configurer) do
- action(:synchronize) do |certname|
- facts = Puppet::Interface::Facts.find(certname)
+ action(:synchronize) do
+ invoke do |certname|
+ facts = Puppet::Interface::Facts.find(certname)
- catalog = Puppet::Interface::Catalog.download(certname, facts)
+ catalog = Puppet::Interface::Catalog.download(certname, facts)
- report = Puppet::Interface::Catalog.apply(catalog)
+ report = Puppet::Interface::Catalog.apply(catalog)
- report
+ report
+ end
end
end
diff --git a/lib/puppet/interface/facts.rb b/lib/puppet/interface/facts.rb
index 3262745..8843d29 100644
--- a/lib/puppet/interface/facts.rb
+++ b/lib/puppet/interface/facts.rb
@@ -5,12 +5,14 @@ Puppet::Interface::Indirector.new(:facts) do
set_default_format :yaml
# Upload our facts to the server
- action(:upload) do |*args|
- Puppet::Node::Facts.indirection.terminus_class = :facter
- facts = Puppet::Node::Facts.indirection.find(Puppet[:certname])
- Puppet::Node::Facts.indirection.terminus_class = :rest
- Puppet::Node::Facts.indirection.save(facts)
- Puppet.notice "Uploaded facts for '#{Puppet[:certname]}'"
- nil
+ action(:upload) do
+ invoke do |*args|
+ Puppet::Node::Facts.indirection.terminus_class = :facter
+ facts = Puppet::Node::Facts.indirection.find(Puppet[:certname])
+ Puppet::Node::Facts.indirection.terminus_class = :rest
+ Puppet::Node::Facts.indirection.save(facts)
+ Puppet.notice "Uploaded facts for '#{Puppet[:certname]}'"
+ nil
+ end
end
end
diff --git a/lib/puppet/interface/indirector.rb b/lib/puppet/interface/indirector.rb
index 9c26cc3..485af47 100644
--- a/lib/puppet/interface/indirector.rb
+++ b/lib/puppet/interface/indirector.rb
@@ -10,28 +10,30 @@ class Puppet::Interface::Indirector < Puppet::Interface
Puppet::Indirector::Terminus.terminus_classes(indirection.to_sym).collect { |t| t.to_s }.sort
end
- action :destroy do |*args|
- call_indirection_method(:destroy, *args)
+ action :destroy do
+ invoke { |*args| call_indirection_method(:destroy, *args) }
end
- action :find do |*args|
- call_indirection_method(:find, *args)
+ action :find do
+ invoke { |*args| call_indirection_method(:find, *args) }
end
- action :save do |*args|
- call_indirection_method(:save, *args)
+ action :save do
+ invoke { |*args| call_indirection_method(:save, *args) }
end
- action :search do |*args|
- call_indirection_method(:search, *args)
+ action :search do
+ invoke { |*args| call_indirection_method(:search, *args) }
end
# Print the configuration for the current terminus class
- action :info do |*args|
- if t = indirection.terminus_class
- puts "Run mode '#{Puppet.run_mode.name}': #{t}"
- else
- $stderr.puts "No default terminus class for run mode '#{Puppet.run_mode.name}'"
+ action :info do
+ invoke do |*args|
+ if t = indirection.terminus_class
+ puts "Run mode '#{Puppet.run_mode.name}': #{t}"
+ else
+ $stderr.puts "No default terminus class for run mode '#{Puppet.run_mode.name}'"
+ end
end
end
diff --git a/lib/puppet/interface/report.rb b/lib/puppet/interface/report.rb
index 4923a4b..e785ae2 100644
--- a/lib/puppet/interface/report.rb
+++ b/lib/puppet/interface/report.rb
@@ -1,13 +1,15 @@
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}"
+ action(:submit) do
+ invoke 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
end
diff --git a/spec/unit/interface/action_builder_spec.rb b/spec/unit/interface/action_builder_spec.rb
new file mode 100644
index 0000000..39b2386
--- /dev/null
+++ b/spec/unit/interface/action_builder_spec.rb
@@ -0,0 +1,30 @@
+#!/usr/bin/env ruby
+
+require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb')
+require 'puppet/interface/action_builder'
+
+describe Puppet::Interface::ActionBuilder do
+ describe "::build" do
+ it "should build an action" do
+ action = Puppet::Interface::ActionBuilder.build(nil,:foo) do
+ end
+ action.should be_a(Puppet::Interface::Action)
+ action.name.should == "foo"
+ end
+
+ it "should define a method on the interface which invokes the action" do
+ interface = Puppet::Interface.new(:action_builder_test_interface)
+ action = Puppet::Interface::ActionBuilder.build(interface, :foo) do
+ invoke do
+ "invoked the method"
+ end
+ end
+
+ interface.foo.should == "invoked the method"
+ end
+
+ it "should require a block" do
+ lambda { Puppet::Interface::ActionBuilder.build(nil,:foo) }.should raise_error("Action 'foo' must specify a block")
+ end
+ end
+end
diff --git a/spec/unit/interface/action_manager_spec.rb b/spec/unit/interface/action_manager_spec.rb
index b71aeca..0b12db3 100644
--- a/spec/unit/interface/action_manager_spec.rb
+++ b/spec/unit/interface/action_manager_spec.rb
@@ -16,19 +16,28 @@ describe Puppet::Interface::ActionManager do
describe "when included in a class" do
it "should be able to define an action" do
- @tester.action(:foo) { "something "}
+ @tester.action(:foo) do
+ invoke { "something "}
+ end
end
it "should be able to list defined actions" do
- @tester.action(:foo) { "something" }
- @tester.action(:bar) { "something" }
+ @tester.action(:foo) do
+ invoke { "something" }
+ end
+ @tester.action(:bar) do
+ invoke { "something" }
+ end
- @tester.actions.should be_include(:bar)
- @tester.actions.should be_include(:foo)
+ @tester.actions.should include(:bar)
+ @tester.actions.should include(:foo)
end
it "should be able to indicate when an action is defined" do
- @tester.action(:foo) { "something" }
+ @tester.action(:foo) do
+ invoke { "something" }
+ end
+
@tester.should be_action(:foo)
end
end
@@ -40,15 +49,21 @@ describe Puppet::Interface::ActionManager do
end
it "should be able to define an action" do
- @tester.action(:foo) { "something "}
+ @tester.action(:foo) do
+ invoke { "something "}
+ end
end
it "should be able to list defined actions" do
- @tester.action(:foo) { "something" }
- @tester.action(:bar) { "something" }
+ @tester.action(:foo) do
+ invoke { "something" }
+ end
+ @tester.action(:bar) do
+ invoke { "something" }
+ end
- @tester.actions.should be_include(:bar)
- @tester.actions.should be_include(:foo)
+ @tester.actions.should include(:bar)
+ @tester.actions.should include(:foo)
end
it "should be able to indicate when an action is defined" do
@@ -67,54 +82,78 @@ describe Puppet::Interface::ActionManager do
end
it "should be able to define an action at the class level" do
- @klass.action(:foo) { "something "}
+ @klass.action(:foo) do
+ invoke { "something "}
+ end
end
it "should create an instance method when an action is defined at the class level" do
- @klass.action(:foo) { "something" }
+ @klass.action(:foo) do
+ invoke { "something" }
+ end
@instance.foo.should == "something"
end
it "should be able to define an action at the instance level" do
- @instance.action(:foo) { "something "}
+ @instance.action(:foo) do
+ invoke { "something "}
+ end
end
it "should create an instance method when an action is defined at the instance level" do
- @instance.action(:foo) { "something" }
+ @instance.action(:foo) do
+ invoke { "something" }
+ end
@instance.foo.should == "something"
end
it "should be able to list actions defined at the class level" do
- @klass.action(:foo) { "something" }
- @klass.action(:bar) { "something" }
+ @klass.action(:foo) do
+ invoke { "something" }
+ end
+ @klass.action(:bar) do
+ invoke { "something" }
+ end
- @klass.actions.should be_include(:bar)
- @klass.actions.should be_include(:foo)
+ @klass.actions.should include(:bar)
+ @klass.actions.should include(:foo)
end
it "should be able to list actions defined at the instance level" do
- @instance.action(:foo) { "something" }
- @instance.action(:bar) { "something" }
+ @instance.action(:foo) do
+ invoke { "something" }
+ end
+ @instance.action(:bar) do
+ invoke { "something" }
+ end
- @instance.actions.should be_include(:bar)
- @instance.actions.should be_include(:foo)
+ @instance.actions.should include(:bar)
+ @instance.actions.should include(:foo)
end
it "should be able to list actions defined at both instance and class level" do
- @klass.action(:foo) { "something" }
- @instance.action(:bar) { "something" }
+ @klass.action(:foo) do
+ invoke { "something" }
+ end
+ @instance.action(:bar) do
+ invoke { "something" }
+ end
- @instance.actions.should be_include(:bar)
- @instance.actions.should be_include(:foo)
+ @instance.actions.should include(:bar)
+ @instance.actions.should include(:foo)
end
it "should be able to indicate when an action is defined at the class level" do
- @klass.action(:foo) { "something" }
+ @klass.action(:foo) do
+ invoke { "something" }
+ end
@instance.should be_action(:foo)
end
it "should be able to indicate when an action is defined at the instance level" do
- @klass.action(:foo) { "something" }
+ @klass.action(:foo) do
+ invoke { "something" }
+ end
@instance.should be_action(:foo)
end
@@ -122,9 +161,15 @@ describe Puppet::Interface::ActionManager do
@subclass = Class.new(@klass)
@instance = @subclass.new
- @klass.action(:parent) { "a" }
- @subclass.action(:sub) { "a" }
- @instance.action(:instance) { "a" }
+ @klass.action(:parent) do
+ invoke { "a" }
+ end
+ @subclass.action(:sub) do
+ invoke { "a" }
+ end
+ @instance.action(:instance) do
+ invoke { "a" }
+ end
@instance.should be_action(:parent)
@instance.should be_action(:sub)
@@ -135,7 +180,9 @@ describe Puppet::Interface::ActionManager do
@subclass = Class.new(@klass)
@instance = @subclass.new
- @klass.action(:foo) { "something" }
+ @klass.action(:foo) do
+ invoke { "something" }
+ end
@instance.foo.should == "something"
end
end
diff --git a/spec/unit/interface/action_spec.rb b/spec/unit/interface/action_spec.rb
new file mode 100644
index 0000000..e74fa9f
--- /dev/null
+++ b/spec/unit/interface/action_spec.rb
@@ -0,0 +1,75 @@
+#!/usr/bin/env ruby
+
+require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper.rb')
+require 'puppet/interface/action'
+
+describe Puppet::Interface::Action do
+ describe "when validating the action name" do
+ it "should require a name" do
+ lambda { Puppet::Interface::Action.new(nil,nil) }.should raise_error("'' is an invalid action name")
+ end
+
+ it "should not allow empty names" do
+ lambda { Puppet::Interface::Action.new(nil,'') }.should raise_error("'' is an invalid action name")
+ end
+
+ it "should not allow names with whitespace" do
+ lambda { Puppet::Interface::Action.new(nil,'foo bar') }.should raise_error("'foo bar' is an invalid action name")
+ end
+
+ it "should not allow names beginning with dashes" do
+ lambda { Puppet::Interface::Action.new(nil,'-foobar') }.should raise_error("'-foobar' is an invalid action name")
+ end
+ end
+
+ describe "when invoking" do
+ it "should be able to call other actions on the same object" do
+ interface = Puppet::Interface.new(:my_interface) do
+ action(:foo) do
+ invoke { 25 }
+ end
+
+ action(:bar) do
+ invoke { "the value of foo is '#{foo}'" }
+ end
+ end
+ interface.foo.should == 25
+ interface.bar.should == "the value of foo is '25'"
+ end
+
+ # bar is a class action calling a class action
+ # quux is a class action calling an instance action
+ # baz is an instance action calling a class action
+ # qux is an instance action calling an instance action
+ it "should be able to call other actions on the same object when defined on a class" do
+ class Puppet::Interface::MyInterfaceBaseClass < Puppet::Interface
+ action(:foo) do
+ invoke { 25 }
+ end
+
+ action(:bar) do
+ invoke { "the value of foo is '#{foo}'" }
+ end
+
+ action(:quux) do
+ invoke { "qux told me #{qux}" }
+ end
+ end
+
+ interface = Puppet::Interface::MyInterfaceBaseClass.new(:my_inherited_interface) do
+ action(:baz) do
+ invoke { "the value of foo in baz is '#{foo}'" }
+ end
+
+ action(:qux) do
+ invoke { baz }
+ end
+ end
+ interface.foo.should == 25
+ interface.bar.should == "the value of foo is '25'"
+ interface.quux.should == "qux told me the value of foo in baz is '25'"
+ interface.baz.should == "the value of foo in baz is '25'"
+ interface.qux.should == "the value of foo in baz is '25'"
+ end
+ end
+end
--
Puppet packaging for Debian
More information about the Pkg-puppet-devel
mailing list