summaryrefslogtreecommitdiff
path: root/lib/chef/resource_reporter.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chef/resource_reporter.rb')
-rw-r--r--lib/chef/resource_reporter.rb183
1 files changed, 46 insertions, 137 deletions
diff --git a/lib/chef/resource_reporter.rb b/lib/chef/resource_reporter.rb
index 3198f84d12..01e4073549 100644
--- a/lib/chef/resource_reporter.rb
+++ b/lib/chef/resource_reporter.rb
@@ -3,7 +3,7 @@
# Author:: Prajakta Purohit (prajakta@chef.io>)
# Auther:: Tyler Cloke (<tyler@opscode.com>)
#
-# Copyright:: Copyright 2012-2018, Chef Software Inc.
+# Copyright:: Copyright 2012-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,88 +25,40 @@ require "chef/event_dispatch/base"
class Chef
class ResourceReporter < EventDispatch::Base
+ def for_json(action_record)
+ new_resource = action_record.new_resource
+ current_resource = action_record.current_resource
- ResourceReport = Struct.new(:new_resource,
- :current_resource,
- :action,
- :exception,
- :elapsed_time) do
-
- def self.new_with_current_state(new_resource, action, current_resource)
- report = new
- report.new_resource = new_resource
- report.action = action
- report.current_resource = current_resource
- report
- end
+ as_hash = {}
+ as_hash["type"] = new_resource.resource_name.to_sym
+ as_hash["name"] = new_resource.name.to_s
+ as_hash["id"] = new_resource.identity.to_s
+ as_hash["after"] = new_resource.state_for_resource_reporter
+ as_hash["before"] = current_resource ? current_resource.state_for_resource_reporter : {}
+ as_hash["duration"] = ( action_record.elapsed_time * 1000 ).to_i
+ as_hash["delta"] = new_resource.diff if new_resource.respond_to?("diff")
+ as_hash["delta"] = "" if as_hash["delta"].nil?
- def self.new_for_exception(new_resource, action)
- report = new
- report.new_resource = new_resource
- report.action = action
- report
+ # TODO: rename as "action"
+ as_hash["result"] = action_record.action.to_s
+ if new_resource.cookbook_name
+ as_hash["cookbook_name"] = new_resource.cookbook_name
+ as_hash["cookbook_version"] = new_resource.cookbook_version.version
end
- # Future: Some resources store state information that does not convert nicely
- # to json. We can't call a resource's state method here, since there are conflicts
- # with some LWRPs, so we can't override a resource's state method to return
- # json-friendly state data.
- #
- # The registry key resource returns json-friendly state data through its state
- # attribute, and uses a read-only variable for fetching true state data. If
- # we have conflicts with other resources reporting json incompatible state, we
- # may want to extend the state_attrs API with the ability to rename POST'd
- # attrs.
- def for_json
- as_hash = {}
- as_hash["type"] = new_resource.resource_name.to_sym
- as_hash["name"] = new_resource.name.to_s
- as_hash["id"] = new_resource.identity.to_s
- as_hash["after"] = new_resource.state_for_resource_reporter
- as_hash["before"] = current_resource ? current_resource.state_for_resource_reporter : {}
- as_hash["duration"] = (elapsed_time * 1000).to_i.to_s
- as_hash["delta"] = new_resource.diff if new_resource.respond_to?("diff")
- as_hash["delta"] = "" if as_hash["delta"].nil?
-
- # TODO: rename as "action"
- as_hash["result"] = action.to_s
- if success?
- else
- # as_hash["result"] = "failed"
- end
- if new_resource.cookbook_name
- as_hash["cookbook_name"] = new_resource.cookbook_name
- as_hash["cookbook_version"] = new_resource.cookbook_version.version
- end
-
- as_hash
- end
-
- def finish
- self.elapsed_time = new_resource.elapsed_time
- end
-
- def success?
- !exception
- end
- end # End class ResouceReport
+ as_hash
+ end
- attr_reader :updated_resources
attr_reader :status
attr_reader :exception
attr_reader :error_descriptions
+ attr_reader :action_collection
+ attr_reader :rest_client
PROTOCOL_VERSION = "0.1.0".freeze
def initialize(rest_client)
- if Chef::Config[:enable_reporting] && !Chef::Config[:why_run]
- @reporting_enabled = true
- else
- @reporting_enabled = false
- end
- @updated_resources = []
- @total_res_count = 0
- @pending_update = nil
+ @pending_update = nil
@status = "success"
@exception = nil
@rest_client = rest_client
@@ -120,8 +72,8 @@ class Chef
if reporting_enabled?
begin
resource_history_url = "reports/nodes/#{node_name}/runs"
- server_response = @rest_client.post(resource_history_url, { action: :start, run_id: run_id,
- start_time: start_time.to_s }, headers)
+ server_response = rest_client.post(resource_history_url, { action: :start, run_id: run_id,
+ start_time: start_time.to_s }, headers)
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
handle_error_starting_run(e, resource_history_url)
end
@@ -157,62 +109,13 @@ class Chef
end
end
- @reporting_enabled = false
+ @runs_endpoint_failed = true
end
def run_id
@run_status.run_id
end
- def resource_current_state_loaded(new_resource, action, current_resource)
- unless nested_resource?(new_resource)
- @pending_update = ResourceReport.new_with_current_state(new_resource, action, current_resource)
- end
- end
-
- def resource_up_to_date(new_resource, action)
- @total_res_count += 1
- @pending_update = nil unless nested_resource?(new_resource)
- end
-
- def resource_skipped(resource, action, conditional)
- @total_res_count += 1
- @pending_update = nil unless nested_resource?(resource)
- end
-
- def resource_updated(new_resource, action)
- @total_res_count += 1
- end
-
- def resource_failed(new_resource, action, exception)
- @total_res_count += 1
- unless nested_resource?(new_resource)
- @pending_update ||= ResourceReport.new_for_exception(new_resource, action)
- @pending_update.exception = exception
- end
- description = Formatters::ErrorMapper.resource_failed(new_resource, action, exception)
- @error_descriptions = description.for_json
- end
-
- def resource_completed(new_resource)
- if @pending_update && !nested_resource?(new_resource)
- @pending_update.finish
-
- # Verify if the resource has sensitive data
- # and create a new blank resource with only
- # the name so we can report it back without
- # sensitive data
- if @pending_update.new_resource.sensitive
- klass = @pending_update.new_resource.class
- resource_name = @pending_update.new_resource.name
- @pending_update.new_resource = klass.new(resource_name)
- end
-
- @updated_resources << @pending_update
- @pending_update = nil
- end
- end
-
def run_completed(node)
@status = "success"
post_reporting_data
@@ -232,6 +135,11 @@ class Chef
@expanded_run_list = run_list_expansion
end
+ def action_collection_registration(action_collection)
+ @action_collection = action_collection
+ action_collection.register(self) if reporting_enabled?
+ end
+
def post_reporting_data
if reporting_enabled?
run_data = prepare_run_data
@@ -242,7 +150,7 @@ class Chef
Chef::Log.trace("Sending compressed run data...")
# Since we're posting compressed data we can not directly call post which expects JSON
begin
- @rest_client.raw_request(:POST, resource_history_url, headers({ "Content-Encoding" => "gzip" }), compressed_data)
+ rest_client.raw_request(:POST, resource_history_url, headers({ "Content-Encoding" => "gzip" }), compressed_data)
rescue StandardError => e
if e.respond_to? :response
Chef::FileCache.store("failed-reporting-data.json", Chef::JSONCompat.to_json_pretty(run_data), 0640)
@@ -273,15 +181,24 @@ class Chef
@run_status.end_time
end
+ # get only the top level resources and strip out the subcollections
+ def updated_resources
+ @updated_resources ||= action_collection.filtered_collection(max_nesting: 0, up_to_date: false, skipped: false, unprocessed: false)
+ end
+
+ def total_res_count
+ updated_resources.count
+ end
+
def prepare_run_data
run_data = {}
run_data["action"] = "end"
- run_data["resources"] = updated_resources.map do |resource_record|
- resource_record.for_json
+ run_data["resources"] = updated_resources.map do |action_record|
+ for_json(action_record)
end
run_data["status"] = @status
run_data["run_list"] = Chef::JSONCompat.to_json(@run_status.node.run_list)
- run_data["total_res_count"] = @total_res_count.to_s
+ run_data["total_res_count"] = total_res_count.to_s
run_data["data"] = {}
run_data["start_time"] = start_time.to_s
run_data["end_time"] = end_time.to_s
@@ -313,18 +230,10 @@ class Chef
@error_descriptions = description.for_json
end
- def reporting_enabled?
- @reporting_enabled
- end
-
private
- # If we are getting messages about a resource while we are in the middle of
- # another resource's update, we assume that the nested resource is just the
- # implementation of a provider, and we want to hide it from the reporting
- # output.
- def nested_resource?(new_resource)
- @pending_update && @pending_update.new_resource != new_resource
+ def reporting_enabled?
+ Chef::Config[:enable_reporting] && !Chef::Config[:why_run] && !@runs_endpoint_failed
end
def encode_gzip(data)