[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, upstream, updated. 0.25.5-639-g8f94f35
test branch
puppet-dev at googlegroups.com
Wed Jul 14 10:34:40 UTC 2010
The following commit has been merged in the upstream branch:
commit be7112aff784cec1490af9d809c4950b940287cb
Author: Luke Kanies <luke at puppetlabs.com>
Date: Fri Jun 11 11:14:29 2010 -0700
Fixing #3139 - all properties can now be audited
This provides a full audit trail for any parameter on any
resource Puppet can manage. Just use:
file { "/my/file": audit => [content, owner] }
And Puppet will generate an event any time either of
those properties change.
This commit also deprecates the 'check' parameter in favor of
a new 'audit' parameter.
Signed-off-by: Luke Kanies <luke at puppetlabs.com>
diff --git a/lib/puppet/transaction/change.rb b/lib/puppet/transaction/change.rb
index 6ecb93c..605457a 100644
--- a/lib/puppet/transaction/change.rb
+++ b/lib/puppet/transaction/change.rb
@@ -4,7 +4,11 @@ require 'puppet/transaction/event'
# Handle all of the work around performing an actual change,
# including calling 'sync' on the properties and producing events.
class Puppet::Transaction::Change
- attr_accessor :is, :should, :property, :proxy
+ attr_accessor :is, :should, :property, :proxy, :auditing
+
+ def auditing?
+ auditing
+ end
# Create our event object.
def event
@@ -24,6 +28,7 @@ class Puppet::Transaction::Change
end
def apply
+ return audit_event if auditing?
return noop_event if noop?
property.sync
@@ -63,6 +68,15 @@ class Puppet::Transaction::Change
private
+ def audit_event
+ # This needs to store the appropriate value, and then produce a new event
+ result = event
+ result.message = "audit change: previously recorded value #{property.should_to_s(should)} has been changed to #{property.is_to_s(is)}"
+ result.status = "audit"
+ result.send_log
+ return result
+ end
+
def noop_event
result = event
result.message = "is #{property.is_to_s(is)}, should be #{property.should_to_s(should)} (noop)"
diff --git a/lib/puppet/transaction/event.rb b/lib/puppet/transaction/event.rb
index b962149..bc589fe 100644
--- a/lib/puppet/transaction/event.rb
+++ b/lib/puppet/transaction/event.rb
@@ -13,7 +13,7 @@ class Puppet::Transaction::Event
attr_accessor :time
attr_reader :default_log_level
- EVENT_STATUSES = %w{noop success failure}
+ EVENT_STATUSES = %w{noop success failure audit}
def initialize(*args)
options = args.last.is_a?(Hash) ? args.pop : ATTRIBUTES.inject({}) { |hash, attr| hash[attr] = args.pop; hash }
diff --git a/lib/puppet/transaction/resource_harness.rb b/lib/puppet/transaction/resource_harness.rb
index 17e8dfa..ae38bcb 100644
--- a/lib/puppet/transaction/resource_harness.rb
+++ b/lib/puppet/transaction/resource_harness.rb
@@ -19,6 +19,10 @@ class Puppet::Transaction::ResourceHarness
def apply_changes(status, changes)
changes.each do |change|
status << change.apply
+
+ if change.auditing?
+ cache(change.property.resource, change.property.name, change.is)
+ end
end
status.changed = true
end
@@ -40,6 +44,8 @@ class Puppet::Transaction::ResourceHarness
return [] if ! allow_changes?(resource)
+ audited = copy_audited_parameters(resource, current)
+
if param = resource.parameter(:ensure)
return [] if absent_and_not_being_created?(current, param)
return [Puppet::Transaction::Change.new(param, current[:ensure])] unless ensure_is_insync?(current, param)
@@ -47,12 +53,33 @@ class Puppet::Transaction::ResourceHarness
end
resource.properties.reject { |p| p.name == :ensure }.reject do |param|
- param.should.nil?
+ param.should.nil?
end.reject do |param|
param_is_insync?(current, param)
end.collect do |param|
- Puppet::Transaction::Change.new(param, current[param.name])
+ change = Puppet::Transaction::Change.new(param, current[param.name])
+ change.auditing = true if audited.include?(param.name)
+ change
+ end
+ end
+
+ def copy_audited_parameters(resource, current)
+ return [] unless audit = resource[:audit]
+ audit = Array(audit).collect { |p| p.to_sym }
+ audited = []
+ audit.find_all do |param|
+ next if resource[param]
+
+ if value = cached(resource, param)
+ resource[param] = value
+ audited << param
+ else
+ resource.notice "Storing newly-audited value #{current[param]} for #{param}"
+ cache(resource, param, current[param])
+ end
end
+
+ audited
end
def evaluate(resource)
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index fc61617..17d6b2a 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -1020,55 +1020,55 @@ class Type
configuration before objects that use it."
end
- newmetaparam(:check) do
- desc "Properties which should have their values retrieved
- but which should not actually be modified. This is currently used
- internally, but will eventually be used for querying, so that you
- could specify that you wanted to check the install state of all
- packages, and then query the Puppet client daemon to get reports
- on all packages."
-
- munge do |args|
- # If they've specified all, collect all known properties
- if args == :all
- args = @resource.class.properties.find_all do |property|
- # Only get properties supported by our provider
- if @resource.provider
- @resource.provider.class.supports_parameter?(property)
- else
- true
- end
- end.collect do |property|
- property.name
+ newmetaparam(:audit) do
+ desc "Audit specified attributes of resources over time, and report if any have changed.
+ This attribute can be used to track changes to any resource over time, and can
+ provide an audit trail of every change that happens on any given machine.
+
+ Note that you cannot both audit and manage an attribute - managing it guarantees
+ the value, and any changes already get logged."
+
+ validate do |list|
+ list = Array(list)
+ unless list == [:all]
+ list.each do |param|
+ next if @resource.class.validattr?(param)
+ fail "Cannot audit #{param}: not a valid attribute for #{resource}"
end
end
+ end
- unless args.is_a?(Array)
- args = [args]
+ munge do |args|
+ properties_to_audit(args).each do |param|
+ next unless resource.class.validproperty?(param)
+ resource.newattr(param)
end
+ end
- unless defined? @resource
- self.devfail "No parent for %s, %s?" %
- [self.class, self.name]
+ def all_properties
+ resource.class.properties.find_all do |property|
+ resource.provider.nil? or resource.provider.class.supports_parameter?(property)
+ end.collect do |property|
+ property.name
+ end
+ end
+
+ def properties_to_audit(list)
+ if list == :all
+ list = all_properties() if list == :all
+ else
+ list = Array(list).collect { |p| p.to_sym }
end
+ end
+ end
- args.each { |property|
- unless property.is_a?(Symbol)
- property = property.intern
- end
- next if @resource.propertydefined?(property)
+ newmetaparam(:check) do
+ desc "Audit specified attributes of resources over time, and report if any have changed.
+ This parameter has been deprecated in favor of 'audit'."
- unless propertyklass = @resource.class.validproperty?(property)
- if @resource.class.validattr?(property)
- next
- else
- raise Puppet::Error, "%s is not a valid attribute for %s" %
- [property, self.class.name]
- end
- end
- next unless propertyklass.checkable?
- @resource.newattr(property)
- }
+ munge do |args|
+ resource.warning "'check' attribute is deprecated; use 'audit' instead"
+ resource[:audit] = args
end
end
diff --git a/spec/unit/transaction/change.rb b/spec/unit/transaction/change.rb
index 1834147..9419bba 100755
--- a/spec/unit/transaction/change.rb
+++ b/spec/unit/transaction/change.rb
@@ -41,6 +41,11 @@ describe Puppet::Transaction::Change do
@change.noop?.should be_true
end
+ it "should be auditing if set so" do
+ @change.auditing = true
+ @change.must be_auditing
+ end
+
it "should set its resource to the proxy if it has one" do
@change.proxy = :myresource
@change.resource.should == :myresource
@@ -107,6 +112,27 @@ describe Puppet::Transaction::Change do
end
end
+ describe "in audit mode" do
+ before { @change.auditing = true }
+
+ it "should log that it is in audit mode" do
+ @property.expects(:is_to_s)
+ @property.expects(:should_to_s)
+
+ @event.expects(:message=).with { |msg| msg.include?("audit") }
+
+ @change.apply
+ end
+
+ it "should produce a :audit event and return" do
+ @property.stub_everything
+
+ @event.expects(:status=).with("audit")
+
+ @change.apply.should == @event
+ end
+ end
+
it "should sync the property" do
@property.expects(:sync)
diff --git a/spec/unit/transaction/event.rb b/spec/unit/transaction/event.rb
index 6a837b5..85811c1 100755
--- a/spec/unit/transaction/event.rb
+++ b/spec/unit/transaction/event.rb
@@ -33,7 +33,7 @@ describe Puppet::Transaction::Event do
event.status.should == "success"
end
- it "should fail if the status is not to 'noop', 'success', or 'failure" do
+ it "should fail if the status is not to 'audit', 'noop', 'success', or 'failure" do
event = Puppet::Transaction::Event.new
lambda { event.status = "foo" }.should raise_error(ArgumentError)
end
diff --git a/spec/unit/transaction/resource_harness.rb b/spec/unit/transaction/resource_harness.rb
index ee2726d..cbb796c 100755
--- a/spec/unit/transaction/resource_harness.rb
+++ b/spec/unit/transaction/resource_harness.rb
@@ -25,6 +25,38 @@ describe Puppet::Transaction::ResourceHarness do
Puppet::Transaction::ResourceHarness.new(@transaction).relationship_graph.should == "relgraph"
end
+ describe "when copying audited parameters" do
+ before do
+ @resource = Puppet::Type.type(:file).new :path => "/foo/bar", :audit => :mode
+ end
+
+ it "should do nothing if no parameters are being audited" do
+ @resource[:audit] = []
+ @harness.expects(:cached).never
+ @harness.copy_audited_parameters(@resource, {}).should == []
+ end
+
+ it "should do nothing if an audited parameter already has a desired value set" do
+ @resource[:mode] = "755"
+ @harness.expects(:cached).never
+ @harness.copy_audited_parameters(@resource, {}).should == []
+ end
+
+ it "should copy any cached values to the 'should' values" do
+ @harness.cache(@resource, :mode, "755")
+ @harness.copy_audited_parameters(@resource, {}).should == [:mode]
+
+ @resource[:mode].should == 0755
+ end
+
+ it "should cache and log the current value if no cached values are present" do
+ @resource.expects(:notice)
+ @harness.copy_audited_parameters(@resource, {:mode => "755"}).should == []
+
+ @harness.cached(@resource, :mode).should == "755"
+ end
+ end
+
describe "when evaluating a resource" do
it "should create and return a resource status instance for the resource" do
@harness.evaluate(@resource).should be_instance_of(Puppet::Resource::Status)
@@ -133,6 +165,20 @@ describe Puppet::Transaction::ResourceHarness do
@harness.changes_to_perform(@status, @resource)
end
+ it "should copy audited parameters" do
+ @resource[:audit] = :mode
+ @harness.cache(@resource, :mode, "755")
+ @harness.changes_to_perform(@status, @resource)
+ @resource[:mode].should == 0755
+ end
+
+ it "should mark changes created as a result of auditing as auditing changes" do
+ @current_state[:mode] = 0644
+ @resource[:audit] = :mode
+ @harness.cache(@resource, :mode, "755")
+ @harness.changes_to_perform(@status, @resource)[0].must be_auditing
+ end
+
describe "and the 'ensure' parameter is present but not in sync" do
it "should return a single change for the 'ensure' parameter" do
@resource[:ensure] = :present
@@ -204,8 +250,8 @@ describe Puppet::Transaction::ResourceHarness do
describe "when applying changes" do
before do
- @change1 = stub 'change1', :apply => stub("event", :status => "success")
- @change2 = stub 'change2', :apply => stub("event", :status => "success")
+ @change1 = stub 'change1', :apply => stub("event", :status => "success"), :auditing? => false
+ @change2 = stub 'change2', :apply => stub("event", :status => "success"), :auditing? => false
@changes = [@change1, @change2]
end
@@ -228,6 +274,17 @@ describe Puppet::Transaction::ResourceHarness do
@status.events.should be_include(@change1.apply)
@status.events.should be_include(@change2.apply)
end
+
+ it "should cache the new value if it is an auditing change" do
+ @change1.expects(:auditing?).returns true
+ property = stub 'property', :name => "foo", :resource => "myres"
+ @change1.stubs(:property).returns property
+ @change1.stubs(:is).returns "myval"
+
+ @harness.apply_changes(@status, @changes)
+
+ @harness.cached("myres", "foo").should == "myval"
+ end
end
describe "when determining whether the resource can be changed" do
diff --git a/spec/unit/type.rb b/spec/unit/type.rb
index e7888a3..e3ae5e6 100755
--- a/spec/unit/type.rb
+++ b/spec/unit/type.rb
@@ -482,3 +482,48 @@ describe Puppet::Type::RelationshipMetaparam do
param.validate_relationship
end
end
+
+describe Puppet::Type.metaparamclass(:check) do
+ it "should warn and create an instance of ':audit'" do
+ file = Puppet::Type.type(:file).new :path => "/foo"
+ file.expects(:warning)
+ file[:check] = :mode
+ file[:audit].should == [:mode]
+ end
+end
+
+describe Puppet::Type.metaparamclass(:audit) do
+ before do
+ @resource = Puppet::Type.type(:file).new :path => "/foo"
+ end
+
+ it "should default to being nil" do
+ @resource[:audit].should be_nil
+ end
+
+ it "should specify all possible properties when asked to audit all properties" do
+ @resource[:audit] = :all
+
+ list = @resource.class.properties.collect { |p| p.name }
+ @resource[:audit].should == list
+ end
+
+ it "should fail if asked to audit an invalid property" do
+ lambda { @resource[:audit] = :foobar }.should raise_error(Puppet::Error)
+ end
+
+ it "should create an attribute instance for each auditable property" do
+ @resource[:audit] = :mode
+ @resource.parameter(:mode).should_not be_nil
+ end
+
+ it "should accept properties specified as a string" do
+ @resource[:audit] = "mode"
+ @resource.parameter(:mode).should_not be_nil
+ end
+
+ it "should not create attribute instances for parameters, only properties" do
+ @resource[:audit] = :noop
+ @resource.parameter(:noop).should be_nil
+ end
+end
--
Puppet packaging for Debian
More information about the Pkg-puppet-devel
mailing list