Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(PUP-7260) Only remove inspect command, not audit metaparameter #5983

Merged
merged 3 commits into from
Jun 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions api/schemas/report.json
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@
"enum": [
"success",
"failure",
"audit",
"noop",
"total"
]
Expand All @@ -371,6 +372,7 @@
"enum": [
"Success",
"Failure",
"Audit",
"Noop",
"Total"
]
Expand Down Expand Up @@ -553,6 +555,11 @@
"type": "object",
"properties": {

"audited": {
"description": "True if this property is being audited, otherwise false. True in report of `inspect` kind.",
"type": "boolean"
},

"property": {
"description": "The property for which the event occurred.",
"oneOf": [
Expand Down Expand Up @@ -581,6 +588,16 @@
]
},

"historical_value": {
"description": "The audited value from a previous run of Puppet, if known. Absent in reports of `inspect` kind.",
"oneOf": [
{ "type": "string" },
{ "type": "array" },
{ "type": "object" },
{ "type": "null" }
]
},

"message": {
"description": "The log message generated by this event.",
"type": "string"
Expand All @@ -597,11 +614,12 @@
},

"status": {
"description": "One of the following strings:\n\n* `success` - property was out of sync, and was successfully changed to be in sync.\n* `failure`- property was out of sync, and couldn't be changed to be in sync due to an error.\n* `noop` - property was out of sync, and wasn't changed due to noop mode.\n\ndepending on the type of the event.\n",
"description": "One of the following strings:\n\n* `success` - property was out of sync, and was successfully changed to be in sync.\n* `failure`- property was out of sync, and couldn't be changed to be in sync due to an error.\n* `noop` - property was out of sync, and wasn't changed due to noop mode.\n* `audit` - property was in sync, and was being audited.\n\ndepending on the type of the event. Always `audit` in reports of `inspect` kind.\n",
"enum": [
"success",
"failure",
"noop"
"noop",
"audit"
]
},
"time": {
Expand All @@ -615,6 +633,7 @@
}
},
"required": [
"audited",
"property",
"message",
"name",
Expand Down
8 changes: 1 addition & 7 deletions lib/puppet/indirector/resource/ral.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,7 @@ def allow_remote_requests?
def find( request )
# find by name
res = type(request).instances.find { |o| o.name == resource_name(request) }
if !res
res = type(request).new(:name => resource_name(request))
# Register all of the properties for data collection
type(request).properties.collect do |s|
res.newattr(s.name.to_sym)
end
end
res ||= type(request).new(:name => resource_name(request), :audit => type(request).properties.collect { |s| s.name })

res.to_resource
end
Expand Down
1 change: 1 addition & 0 deletions lib/puppet/pops/resource/resource_type_impl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def <=>(other)
METAPARAMS = [
:noop,
:schedule,
:audit,
:loglevel,
:alias,
:tag,
Expand Down
8 changes: 5 additions & 3 deletions lib/puppet/resource/status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Status
attr_reader :change_count

# @!attribute [r] out_of_sync_count
# @return [Integer] A count of the changes made while
# @return [Integer] A count of the audited changes made while
# evaluating `@real_resource`.
attr_reader :out_of_sync_count

Expand Down Expand Up @@ -122,8 +122,10 @@ def add_event(event)
@change_count += 1
@changed = true
end
@out_of_sync_count += 1
@out_of_sync = true
if event.status != 'audit'
@out_of_sync_count += 1
@out_of_sync = true
end
if event.corrective_change
@corrective_change = true
end
Expand Down
4 changes: 2 additions & 2 deletions lib/puppet/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,7 @@ def service_user_available?
return @service_user_available if defined?(@service_user_available)

if self[:user]
user = Puppet::Type.type(:user).new :name => self[:user]
user = Puppet::Type.type(:user).new :name => self[:user], :audit => :ensure

@service_user_available = user.exists?
else
Expand All @@ -799,7 +799,7 @@ def service_group_available?
return @service_group_available if defined?(@service_group_available)

if self[:group]
group = Puppet::Type.type(:group).new :name => self[:group]
group = Puppet::Type.type(:group).new :name => self[:group], :audit => :ensure

@service_group_available = group.exists?
else
Expand Down
9 changes: 7 additions & 2 deletions lib/puppet/transaction/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ class Puppet::Transaction::Event
include Puppet::Util::Logging
include Puppet::Network::FormatSupport

ATTRIBUTES = [:name, :resource, :property, :previous_value, :desired_value, :status, :message, :file, :line, :source_description, :invalidate_refreshes, :redacted, :corrective_change]
ATTRIBUTES = [:name, :resource, :property, :previous_value, :desired_value, :historical_value, :status, :message, :file, :line, :source_description, :audited, :invalidate_refreshes, :redacted, :corrective_change]
attr_accessor *ATTRIBUTES
attr_accessor :time
attr_reader :default_log_level

EVENT_STATUSES = %w{noop success failure }
EVENT_STATUSES = %w{noop success failure audit}

def self.from_data_hash(data)
obj = self.allocate
Expand All @@ -25,6 +25,7 @@ def self.from_data_hash(data)
end

def initialize(options = {})
@audited = false
@redacted = false
@corrective_change = false

Expand All @@ -42,9 +43,11 @@ def initialize_from_hash(data)
:allow_unresolved => true,
:loader => Puppet::Pops::Loaders.static_loader
})
@audited = data['audited']
@property = data['property']
@previous_value = data['previous_value']
@desired_value = data['desired_value']
@historical_value = data['historical_value']
@message = data['message']
@name = data['name'].intern if data['name']
@status = data['status']
Expand All @@ -56,9 +59,11 @@ def initialize_from_hash(data)

def to_data_hash
hash = {
'audited' => @audited,
'property' => @property,
'previous_value' => @previous_value,
'desired_value' => @desired_value,
'historical_value' => @historical_value,
'message' => @message,
'name' => @name.nil? ? nil : @name.to_s,
'status' => @status,
Expand Down
106 changes: 93 additions & 13 deletions lib/puppet/transaction/resource_harness.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ def schedule(resource)
resource.catalog.resource(:schedule, name) || resource.fail(_("Could not find schedule %{name}") % { name: name })
end

# Used mostly for scheduling at this point.
# Used mostly for scheduling and auditing at this point.
def cached(resource, name)
Puppet::Util::Storage.cache(resource)[name]
end

# Used mostly for scheduling at this point.
# Used mostly for scheduling and auditing at this point.
def cache(resource, name, value)
Puppet::Util::Storage.cache(resource)[name] = value
end
Expand All @@ -70,6 +70,11 @@ def cache(resource, name, value)
def perform_changes(resource, context)
cache(resource, :checked, Time.now)

# Record the current state in state.yml.
context.audited_params.each do |param|
cache(resource, param, context.current_values[param])
end

ensure_param = resource.parameter(:ensure)
if ensure_param && ensure_param.should
ensure_event = sync_if_needed(ensure_param, context)
Expand All @@ -87,6 +92,7 @@ def perform_changes(resource, context)
end
end

capture_audit_events(resource, context)
persist_system_values(resource, context)
end

Expand All @@ -109,16 +115,23 @@ def persist_system_values(resource, context)
end

def sync_if_needed(param, context)
historical_value = context.historical_values[param.name]
current_value = context.current_values[param.name]
do_audit = context.audited_params.include?(param.name)

begin
if param.should && !param.safe_insync?(current_value)
event = create_change_event(param, current_value)
event = create_change_event(param, current_value, historical_value)
if do_audit
event = audit_event(event, param, context)
end

brief_audit_message = audit_message(param, do_audit, historical_value, current_value)

if param.noop
noop(event, param, current_value)
noop(event, param, current_value, brief_audit_message)
else
sync(event, param, current_value)
sync(event, param, current_value, brief_audit_message)
end

event
Expand All @@ -129,15 +142,15 @@ def sync_if_needed(param, context)
# Execution will continue on StandardErrors, just store the event
Puppet.log_exception(detail)

event = create_change_event(param, current_value)
event = create_change_event(param, current_value, historical_value)
event.status = "failure"
event.message = param.format(_("change from %s to %s failed: "),
param.is_to_s(current_value),
param.should_to_s(param.should)) + detail.to_s
event
rescue Exception => detail
# Execution will halt on Exceptions, they get raised to the application
event = create_change_event(param, current_value)
event = create_change_event(param, current_value, historical_value)
event.status = "failure"
event.message = param.format(_("change from %s to %s failed: "),
param.is_to_s(current_value),
Expand All @@ -153,40 +166,103 @@ def sync_if_needed(param, context)
end
end

def create_change_event(property, current_value)
def create_change_event(property, current_value, historical_value)
options = {}
should = property.should

if property.sensitive
options[:previous_value] = current_value.nil? ? nil : '[redacted]'
options[:desired_value] = should.nil? ? nil : '[redacted]'
options[:historical_value] = historical_value.nil? ? nil : '[redacted]'
else
options[:previous_value] = current_value
options[:desired_value] = should
options[:historical_value] = historical_value
end

property.event(options)
end

def noop(event, param, current_value)
# This method is an ugly hack because, given a Time object with nanosecond
# resolution, roundtripped through YAML serialization, the Time object will
# be truncated to microseconds.
# For audit purposes, this code special cases this comparison, and compares
# the two objects by their second and microsecond components. tv_sec is the
# number of seconds since the epoch, and tv_usec is only the microsecond
# portion of time.
def are_audited_values_equal(a, b)
a == b || (a.is_a?(Time) && b.is_a?(Time) && a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec)
end
private :are_audited_values_equal

# Populate an existing event with audit information.
#
# @param event [Puppet::Transaction::Event] The event to be populated.
# @param property [Puppet::Property] The property being audited.
# @param context [ResourceApplicationContext]
#
# @return [Puppet::Transaction::Event] The given event, populated with the audit information.
def audit_event(event, property, context)
event.audited = true
event.status = "audit"

# The event we've been provided might have been redacted so we need to use the state stored within
# the resource application context to see if an event was actually generated.
if !are_audited_values_equal(context.historical_values[property.name], context.current_values[property.name])
event.message = property.format(_("audit change: previously recorded value %s has been changed to %s"),
property.is_to_s(event.historical_value),
property.is_to_s(event.previous_value))
end

event
end

def audit_message(param, do_audit, historical_value, current_value)
if do_audit && historical_value && !are_audited_values_equal(historical_value, current_value)
param.format(_(" (previously recorded value was %s)"), param.is_to_s(historical_value))
else
""
end
end

def noop(event, param, current_value, audit_message)
event.message = param.format(_("current_value %s, should be %s (noop)"),
param.is_to_s(current_value),
param.should_to_s(param.should))
param.should_to_s(param.should)) + audit_message.to_s
event.status = "noop"
end

def sync(event, param, current_value)
def sync(event, param, current_value, audit_message)
param.sync
if param.sensitive
event.message = param.format(_("changed %s to %s"),
param.is_to_s(current_value),
param.should_to_s(param.should))
param.should_to_s(param.should)) + audit_message.to_s
else
event.message = "#{param.change_to_s(current_value, param.should)}"
event.message = "#{param.change_to_s(current_value, param.should)}#{audit_message}"
end
event.status = "success"
end

def capture_audit_events(resource, context)
context.audited_params.each do |param_name|
if context.historical_values.include?(param_name)
if !are_audited_values_equal(context.historical_values[param_name], context.current_values[param_name]) && !context.synced_params.include?(param_name)
parameter = resource.parameter(param_name)
event = audit_event(create_change_event(parameter,
context.current_values[param_name],
context.historical_values[param_name]),
parameter, context)
event.send_log
context.record(event)
end
else
property = resource.property(param_name)
property.notice(property.format(_("audit change: newly-recorded value %s"), context.current_values[param_name]))
end
end
end

# Given an event and its property, calculate the system_value to persist
# for future calculations.
# @param [Puppet::Transaction::Event] event event to use for processing
Expand Down Expand Up @@ -216,12 +292,16 @@ def new_system_value(property, event, old_system_value)
# @api private
ResourceApplicationContext = Struct.new(:resource,
:current_values,
:historical_values,
:audited_params,
:synced_params,
:status,
:system_value_params) do
def self.from_resource(resource, status)
ResourceApplicationContext.new(resource,
resource.retrieve_resource.to_hash,
Puppet::Util::Storage.cache(resource).dup,
(resource[:audit] || []).map { |p| p.to_sym },
[],
status,
resource.parameters.select { |n,p| p.is_a?(Puppet::Property) && !p.sensitive })
Expand Down
Loading