diff options
| author | tyler-ball <tyleraball@gmail.com> | 2014-10-31 15:05:10 -0700 |
|---|---|---|
| committer | tyler-ball <tyleraball@gmail.com> | 2014-12-17 18:51:33 -0800 |
| commit | 772232776ed10465708d1ddab7c7238a199f6199 (patch) | |
| tree | fa1eca74bf4e831d6a92498c425b18e9d1ee9020 /lib/chef/audit | |
| parent | 8efee3e8ed41dc7cd4ae0b4a1664467dd403346d (diff) | |
| download | chef-772232776ed10465708d1ddab7c7238a199f6199.tar.gz | |
Adding audit mode JSON formatter
First pass at DSL additions
Renaming DSL methods to match the spec
Creating our own example group class to simplify adding examples to the spec runner
Adding logic for exceptions from converge phase not interfering with audit phase and vice-versa
Adding error handling so saving node doesn't prevent us from running audit mode - decouples converge phase and audit phase more
Updating for github comments
Add setup phase to audit-mode.
Refactor runner into own class.
Fix typo
tie things together
Adding first round of formatter integration - STDOUT doc formatter
Preparing for demo - using rspec documentation formatter for output instead of the proxy
Add serverspec types and matchers.
add rspec/its
Add gems as core dependencies
Updating with changes from demo
Updating with @mcquin and @lamont comments
Getting rid of unused method
Wiring audit event proxy to send events correctly to the audit_reporter
removing old pry debugging statement
Removing unecessary todo
Sending to correct server URL
Fixing TODOs
Adding uncaught error information
Diffstat (limited to 'lib/chef/audit')
| -rw-r--r-- | lib/chef/audit/audit_reporter.rb | 98 | ||||
| -rw-r--r-- | lib/chef/audit/control_group_data.rb | 3 | ||||
| -rw-r--r-- | lib/chef/audit/runner.rb | 3 |
3 files changed, 70 insertions, 34 deletions
diff --git a/lib/chef/audit/audit_reporter.rb b/lib/chef/audit/audit_reporter.rb index b1c9d30bfc..5ed1f7bd52 100644 --- a/lib/chef/audit/audit_reporter.rb +++ b/lib/chef/audit/audit_reporter.rb @@ -19,22 +19,19 @@ require 'chef/event_dispatch/base' require 'chef/audit/control_group_data' +require 'time' class Chef class Audit class AuditReporter < EventDispatch::Base - attr_reader :rest_client, :audit_data, :ordered_control_groups - private :rest_client, :audit_data, :ordered_control_groups + attr_reader :rest_client, :audit_data, :ordered_control_groups, :run_status + private :rest_client, :audit_data, :ordered_control_groups, :run_status PROTOCOL_VERSION = '0.1.0' def initialize(rest_client) - if Chef::Config[:audit_mode] == false - @audit_enabled = false - else - @audit_enabled = true - end + @audit_enabled = Chef::Config[:audit_mode] @rest_client = rest_client # Ruby 1.9.3 and above "enumerate their values in the order that the corresponding keys were inserted." @ordered_control_groups = Hash.new @@ -43,25 +40,32 @@ class Chef def audit_phase_start(run_status) Chef::Log.debug("Audit Reporter starting") @audit_data = AuditData.new(run_status.node.name, run_status.run_id) + @run_status = run_status end def audit_phase_complete - Chef::Log.debug("Audit Reporter completed successfully without errors") + Chef::Log.debug("Audit Reporter completed successfully without errors.") ordered_control_groups.each do |name, control_group| audit_data.add_control_group(control_group) end - post_auditing_data end # If the audit phase failed, its because there was some kind of error in the framework # that runs tests - normal errors are interpreted as EXAMPLE failures and captured. def audit_phase_failed(error) # The stacktrace information has already been logged elsewhere - Chef::Log.error("Audit Reporter failed - sending error to server with available example information") + Chef::Log.debug("Audit Reporter failed.") ordered_control_groups.each do |name, control_group| audit_data.add_control_group(control_group) end - post_auditing_data(error) + end + + def run_completed(node) + post_auditing_data + end + + def run_failed(error) + post_reporting_data(error) end def control_group_started(name) @@ -81,41 +85,65 @@ class Chef control_group.example_failure(example_data, error.message) end + # If @audit_enabled is nil or true, we want to run audits def auditing_enabled? - @audit_enabled + @audit_enabled != false end private def post_auditing_data(error = nil) - if auditing_enabled? - audit_history_url = "controls" - Chef::Log.info("Sending audit report (run-id: #{audit_data.run_id})") - run_data = audit_data.to_hash + unless auditing_enabled? + Chef::Log.debug("Audit Reports are disabled. Skipping sending reports.") + return + end - if error - run_data[:error] = "#{error.class.to_s}: #{error.message}\n#{error.backtrace.join("\n")}" - end + unless run_status + Chef::Log.debug("Run failed before audits were initialized, not sending audit report to server") + return + end - Chef::Log.debug run_data.inspect - compressed_data = encode_gzip(Chef::JSONCompat.to_json(run_data)) - Chef::Log.debug("Sending compressed audit data...") - # Since we're posting compressed data we can not directly call post_rest which expects JSON + audit_data.start_time = iso8601ify(run_status.start_time) + audit_data.end_time = iso8601ify(run_status.end_time) + + audit_history_url = "controls" + Chef::Log.info("Sending audit report (run-id: #{audit_data.run_id})") + run_data = audit_data.to_hash + + if error + # TODO: Rather than a single string we might want to format the exception here similar to + # lib/chef/resource_reporter.rb#83 + run_data[:error] = "#{error.class.to_s}: #{error.message}\n#{error.backtrace.join("\n")}" + end + + Chef::Log.debug "Audit Report:\n#{Chef::JSONCompat.to_json_pretty(run_data)}" + # Since we're posting compressed data we can not directly call post_rest which expects JSON + begin audit_url = rest_client.create_url(audit_history_url) - begin - puts Chef::JSONCompat.to_json_pretty(run_data) - rest_client.raw_http_request(:POST, audit_url, headers({'Content-Encoding' => 'gzip'}), compressed_data) - rescue StandardError => e - if e.respond_to? :response + rest_client.post(audit_url, run_data, headers) + rescue StandardError => e + if e.respond_to? :response + code = e.response.code.nil? ? "Exception Code Empty" : e.response.code + + # 404 error code is OK. This means the version of server we're running against doesn't support + # audit reporting. Don't alarm failure in this case. + if code == "404" + Chef::Log.debug("Server doesn't support audit reporting. Skipping report.") + return + else + # Save the audit report to local disk error_file = "failed-audit-data.json" Chef::FileCache.store(error_file, Chef::JSONCompat.to_json_pretty(run_data), 0640) - Chef::Log.error("Failed to post audit report to server (HTTP #{e.response.code}), saving to #{Chef::FileCache.load(error_file, false)}") - else - Chef::Log.error("Failed to post audit report to server (#{e})") + Chef::Log.error("Failed to post audit report to server. Saving report to #{Chef::FileCache.load(error_file, false)}") end + else + Chef::Log.error("Failed to post audit report to server (#{e})") + end + + if Chef::Config[:enable_reporting_url_fatals] + Chef::Log.error("Reporting fatals enabled. Aborting run.") + raise end - else - Chef::Log.debug("Server doesn't support audit report, skipping.") end end @@ -130,6 +158,10 @@ class Chef end end + def iso8601ify(time) + time.utc.iso8601.to_s + end + end end end diff --git a/lib/chef/audit/control_group_data.rb b/lib/chef/audit/control_group_data.rb index e19a6e1a15..e221ae94cc 100644 --- a/lib/chef/audit/control_group_data.rb +++ b/lib/chef/audit/control_group_data.rb @@ -4,6 +4,7 @@ class Chef class Audit class AuditData attr_reader :node_name, :run_id, :control_groups + attr_accessor :start_time, :end_time def initialize(node_name, run_id) @node_name = node_name @@ -19,6 +20,8 @@ class Chef { :node_name => node_name, :run_id => run_id, + :start_time => start_time, + :end_time => end_time, :control_groups => control_groups.collect { |c| c.to_hash } } end diff --git a/lib/chef/audit/runner.rb b/lib/chef/audit/runner.rb index 4059741359..0758dacd6d 100644 --- a/lib/chef/audit/runner.rb +++ b/lib/chef/audit/runner.rb @@ -18,6 +18,7 @@ require 'chef/audit' require 'chef/audit/audit_event_proxy' +require 'chef/audit/rspec_formatter' require 'chef/config' class Chef @@ -79,7 +80,7 @@ class Chef end def add_formatters - configuration.add_formatter(RSpec::Core::Formatters::DocumentationFormatter) + configuration.add_formatter(Chef::Audit::RspecFormatter) configuration.add_formatter(Chef::Audit::AuditEventProxy) Chef::Audit::AuditEventProxy.events = run_context.events end |
