chef-handler-datadog 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +8 -8
  2. data/.gitignore +3 -0
  3. data/.rubocop.yml +4 -0
  4. data/.travis.yml +2 -1
  5. data/Appraisals +2 -1
  6. data/CHANGELOG.md +13 -1
  7. data/CONTRIBUTING.md +23 -0
  8. data/Gemfile +4 -0
  9. data/Guardfile +37 -0
  10. data/README.md +12 -20
  11. data/Rakefile +1 -1
  12. data/chef-handler-datadog.gemspec +4 -4
  13. data/gemfiles/chef_10.26.0.gemfile +4 -0
  14. data/gemfiles/chef_10.32.2.gemfile +4 -0
  15. data/gemfiles/chef_11.10.4.gemfile +4 -0
  16. data/gemfiles/{chef_11.12.2.gemfile → chef_11.12.8.gemfile} +5 -1
  17. data/gemfiles/chef_11.14.2.gemfile +16 -0
  18. data/gemfiles/chef_11.8.2.gemfile +4 -0
  19. data/lib/chef/handler/datadog.rb +47 -12
  20. data/lib/chef_handler_datadog.rb +1 -1
  21. data/spec/datadog_spec.rb +58 -8
  22. data/spec/spec_helper.rb +0 -1
  23. data/spec/support/cassettes/Chef_Handler_Datadog/failed_Chef_run/sets_alert_handles_when_specified.yml +69 -57
  24. data/spec/support/cassettes/Chef_Handler_Datadog/failed_Chef_run/sets_event_title_correctly.yml +35 -29
  25. data/spec/support/cassettes/Chef_Handler_Datadog/failed_Chef_run/sets_priority_correctly.yml +35 -29
  26. data/spec/support/cassettes/Chef_Handler_Datadog/handles_no_application_key/fails_when_no_application_key_is_provided.yml +20 -20
  27. data/spec/support/cassettes/Chef_Handler_Datadog/handles_tags_correctly/sets_the_role_and_env_and_tags.yml +23 -23
  28. data/spec/support/cassettes/Chef_Handler_Datadog/hostname/uses_the_node_name_when_no_config_specified.yml +23 -23
  29. data/spec/support/cassettes/Chef_Handler_Datadog/hostname/uses_the_specified_hostname_when_provided.yml +23 -23
  30. data/spec/support/cassettes/Chef_Handler_Datadog/reports_correct_hostname_on_an_ec2_node/does_not_use_the_instance_id_when_config_specified_to_false.yml +23 -23
  31. data/spec/support/cassettes/Chef_Handler_Datadog/reports_correct_hostname_on_an_ec2_node/uses_the_instance_id_when_config_is_specified.yml +23 -23
  32. data/spec/support/cassettes/Chef_Handler_Datadog/reports_correct_hostname_on_an_ec2_node/uses_the_instance_id_when_no_config_specified.yml +23 -23
  33. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/emits_events/posts_an_event.yml +23 -23
  34. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/emits_events/sets_priority_correctly.yml +23 -23
  35. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/emits_metrics/reports_metrics.yml +23 -23
  36. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/sets_tags/puts_the_tags_for_the_current_node.yml +23 -23
  37. data/spec/support/cassettes/Chef_Handler_Datadog/resources/failure_during_compile_phase/does_not_emit_metrics.yml +81 -0
  38. data/spec/support/cassettes/Chef_Handler_Datadog/resources/failure_during_compile_phase/posts_an_event.yml +81 -0
  39. data/spec/support/cassettes/Chef_Handler_Datadog/updated_resources/posts_an_event.yml +28 -28
  40. metadata +18 -16
  41. data/gemfiles/chef_10.26.0.gemfile.lock +0 -140
  42. data/gemfiles/chef_10.32.2.gemfile.lock +0 -140
  43. data/gemfiles/chef_11.10.4.gemfile.lock +0 -143
  44. data/gemfiles/chef_11.12.2.gemfile.lock +0 -139
  45. data/gemfiles/chef_11.8.2.gemfile.lock +0 -143
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZGY5NzgzNTc5ZDY5YjA3ZGZkNWY4OTRhM2U4NmE4ZWI0NGYyNDBhMg==
4
+ Y2VjMTZmYjcxMGU0ZTk3MTZkNWM3NzYzNWU1Y2VlMjI5ZjI4MGQ4Zg==
5
5
  data.tar.gz: !binary |-
6
- ZjkxZDg0ZDUyOGMxOWY5YWZhMjNlNmZmMTIxN2NmMjE3ZGU5Y2Y1MA==
6
+ ZGE2NGJjZjYwMGQ1MDczZjhlYjM5Yjg5N2ZmODU5NzYzN2EzMDBkYQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ODRiMjJhZTAyMDAzZDljN2M3NWRhYmI4NTRmZTQzM2U4YzQwNmY1ZWRhZjZh
10
- ZmMzNTBkOWM4ZjIyN2NjOWZmMzcyYmZiYjc5ZTEyOWIzZWVkODQ3ZTNjMzEz
11
- NmE2NTYxNTM5NWEyMGY4NTBmZjdkYTM5MDIyNGQ1YzVmMzVhODA=
9
+ Y2UwYTVkMTc3MzE0ZjFhMTM3ZDQ5YjcwMDg2NTM1MTQwMDY1YmIwMGY0OWI2
10
+ N2IxZmFhZTFiMTI2YjljYTA2ODJhOTlhZTkwZjMwN2Y5Y2Q1NmM5MGY4YmE3
11
+ ZTllNTZhZjFhODAzYjJiYTJjODY5YmM2ZWQxYjNlODhjOWZlNzc=
12
12
  data.tar.gz: !binary |-
13
- MmNjZGRmYjc1Mzg3YjJmM2E0ZjJhNzZkNDViYWVkNTZhMGFkMTg1YjhkMjI2
14
- NGIzZDkxZGQyMzZiNDYyYTVmOTI0MDk4N2M0MmZlODQyYmU5NGUzOTBmOTY2
15
- N2I4YjhlMDFiYjkxYmE1ODVkN2IwNjIwYmQ2MDdlMzA2NDNkODY=
13
+ Y2Q5MjczZDBiYmM5MTg3YzNkMzcyYTBlNzkxZWUwMTk3MGQ1NzEzM2ZiOTJi
14
+ ZTQ0MjQ2MjM0NWY3MjUzMTQzOTM2ODFhOTcyOGQ2Njg5Mjg2MDczZDA4M2Vi
15
+ YjdhYTNiMmY1Y2FiNjE4YzliNDVlYmFhOGJhNzdkMTZmMDcxYWM=
data/.gitignore CHANGED
@@ -58,3 +58,6 @@ Gemfile.lock
58
58
 
59
59
  # Any environment-specific files
60
60
  .env
61
+
62
+ # Ignore Appraisal lock files
63
+ gemfiles/*.gemfile.lock
@@ -36,3 +36,7 @@ CyclomaticComplexity:
36
36
  # be a little lofty.
37
37
  MethodLength:
38
38
  Max: 78
39
+
40
+ # TODO: select_hostname, report are both higher than the default of 7
41
+ PerceivedComplexity:
42
+ Max: 9
@@ -7,6 +7,7 @@ gemfile:
7
7
  - gemfiles/chef_10.32.2.gemfile
8
8
  - gemfiles/chef_11.8.2.gemfile
9
9
  - gemfiles/chef_11.10.4.gemfile
10
- - gemfiles/chef_11.12.2.gemfile
10
+ - gemfiles/chef_11.12.8.gemfile
11
+ - gemfiles/chef_11.14.2.gemfile
11
12
  env:
12
13
  - API_KEY=somefakeapikey APPLICATION_KEY=somefakeapplicationkey
data/Appraisals CHANGED
@@ -4,7 +4,8 @@
4
4
  %w(
5
5
  11.8.2
6
6
  11.10.4
7
- 11.12.2
7
+ 11.12.8
8
+ 11.14.2
8
9
  ).each do |tv|
9
10
  appraise "chef-#{tv}" do
10
11
  gem 'chef', tv
@@ -1,7 +1,15 @@
1
1
  Changes
2
2
  =======
3
3
 
4
- # 0.4.0 / Unreleased
4
+ # 0.5.0 / 2014-08-21
5
+
6
+ * [FEATURE] Place recent updated resources above stacktrace on failure, [#46][] [@miketheman][]
7
+ * [BUGFIX] Handle cases where Chef fails during compile phase, [#51][] [@miketheman][]
8
+ * [FEATURE] Allow credentials to be passed as string keys vs symbols, [#50][] [@dwradcliffe][]
9
+ * [MISC] Testing framework updates, [@miketheman][]
10
+ * [MISC] Doc updates
11
+
12
+ # 0.4.0 / 2014-05-08
5
13
 
6
14
  * [FEATURE] Allow specification of a `:hostname` to config to override `node.name`, [#41][] [@miketheman][]
7
15
  * [FEATURE] Allow passing an array of handles in config to alert when Chef fails, [#29][] [@miketheman][]
@@ -46,6 +54,10 @@ And all other versions were prior to this. See git history for more.
46
54
  [#37]: https://github.com/DataDog/chef-handler-datadog/issues/37
47
55
  [#39]: https://github.com/DataDog/chef-handler-datadog/issues/39
48
56
  [#41]: https://github.com/DataDog/chef-handler-datadog/issues/41
57
+ [#46]: https://github.com/DataDog/chef-handler-datadog/issues/46
58
+ [#50]: https://github.com/DataDog/chef-handler-datadog/issues/50
59
+ [#51]: https://github.com/DataDog/chef-handler-datadog/issues/51
49
60
  [@alq]: https://github.com/alq
61
+ [@dwradcliffe]: https://github.com/dwradcliffe
50
62
  [@miketheman]: https://github.com/miketheman
51
63
  [@remh]: https://github.com/remh
@@ -0,0 +1,23 @@
1
+ # Contributing
2
+
3
+ If you'd like to run the test suite, fix a bug or add a feature, please follow these steps:
4
+
5
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
6
+ * Check out the latest `master` branch to make sure the feature hasn't been implemented or the bug hasn't been fixed
7
+ * Fork the project
8
+ * Install all dependencies: `bundle install`
9
+ * Start a feature/bugfix branch: `git checkout -b my_feature_name`
10
+ * Place a `.env` file in the root of the project with `API_KEY` and `APPLICATION_KEY`:
11
+
12
+ API_KEY: myapikey
13
+ APPLICATION_KEY: chefhandlerspecificapplicationkey
14
+
15
+ This file is intentionally .gitignored to prevent security exposure.
16
+ You may use your own Datadog account keys, as the keys are filtered from the test recordings.
17
+ Running the test suite will _not_ make calls to Datadog for existing tests, see `spec/support/cassettes/` for more.
18
+
19
+ * Run `rake` to execute tests, ensure they pass
20
+ * Commit and push until you are happy with your contribution
21
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
22
+ * Please try not to mess with the `Rakefile`, version, or history.
23
+ If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
data/Gemfile CHANGED
@@ -5,6 +5,10 @@ source 'http://rubygems.org'
5
5
  gemspec
6
6
 
7
7
  group :localdev do
8
+ gem 'guard'
9
+ gem 'guard-rspec'
10
+ gem 'guard-rubocop'
8
11
  gem 'pry'
12
+ gem 'terminal-notifier-guard'
9
13
  gem 'travis-lint'
10
14
  end
@@ -0,0 +1,37 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rubocop do
5
+ watch(%r{.+\.rb$})
6
+ watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
7
+ end
8
+
9
+ # Note: The cmd option is now required due to the increasing number of ways
10
+ # rspec may be run, below are examples of the most common uses.
11
+ # * bundler: 'bundle exec rspec'
12
+ # * bundler binstubs: 'bin/rspec'
13
+ # * spring: 'bin/rsspec' (This will use spring if running and you have
14
+ # installed the spring binstubs per the docs)
15
+ # * zeus: 'zeus rspec' (requires the server to be started separetly)
16
+ # * 'just' rspec: 'rspec'
17
+ guard :rspec, cmd: 'bundle exec rspec' do
18
+ watch(%r{^spec/.+_spec\.rb$})
19
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
20
+ watch('spec/spec_helper.rb') { "spec" }
21
+
22
+ # Rails example
23
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
24
+ watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
25
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
26
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
27
+ watch('config/routes.rb') { "spec/routing" }
28
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
29
+ watch('spec/rails_helper.rb') { "spec" }
30
+
31
+ # Capybara features specs
32
+ watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
33
+
34
+ # Turnip features and steps
35
+ watch(%r{^spec/acceptance/(.+)\.feature$})
36
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
37
+ end
data/README.md CHANGED
@@ -2,35 +2,27 @@
2
2
 
3
3
  An Exception and Report Handler for Chef.
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/chef-handler-datadog.png)](http://badge.fury.io/rb/chef-handler-datadog)
6
- [![Build Status](https://secure.travis-ci.org/DataDog/chef-handler-datadog.png?branch=master)](http://travis-ci.org/DataDog/chef-handler-datadog)
7
- [![Code Climate](https://codeclimate.com/github/DataDog/chef-handler-datadog.png)](https://codeclimate.com/github/DataDog/chef-handler-datadog)
8
- [![Dependency Status](https://gemnasium.com/DataDog/chef-handler-datadog.png)](https://gemnasium.com/DataDog/chef-handler-datadog)
5
+ [![Gem Version](https://badge.fury.io/rb/chef-handler-datadog.svg)](http://badge.fury.io/rb/chef-handler-datadog)
6
+ [![Build Status](https://travis-ci.org/DataDog/chef-handler-datadog.svg?branch=master)](https://travis-ci.org/DataDog/chef-handler-datadog)
7
+ [![Code Climate](https://codeclimate.com/github/DataDog/chef-handler-datadog/badges/gpa.svg)](https://codeclimate.com/github/DataDog/chef-handler-datadog)
8
+ [![Dependency Status](https://gemnasium.com/DataDog/chef-handler-datadog.svg)](https://gemnasium.com/DataDog/chef-handler-datadog)
9
9
 
10
10
  ## Using chef-handler-datadog
11
11
 
12
- The Datadog Docs on [Chef](http://docs.datadoghq.com/guides/chef/#deployhandler) has detailed instructions.
13
-
14
- ## Contributing to chef-handler-datadog
12
+ This can be installed by using the `dd-handler` recipe from the [datadog cookbook][cookbook].
15
13
 
16
- * Check out the latest `master` to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
17
- * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
18
- * Fork the project
19
- * Start a feature/bugfix branch
20
- * Place a `.env` file in the root of the project with `API_KEY` and `APPLICATION_KEY`:
14
+ ```ruby
15
+ run_list 'foo::bar', 'datadog::dd-handler'
16
+ ```
21
17
 
22
- API_KEY: myapikey
23
- APPLICATION_KEY: chefhandlerspecificapplicationkey
18
+ The Datadog Docs on [Chef](http://docs.datadoghq.com/guides/chef/#deployhandler) has detailed instructions.
24
19
 
25
- This file is intentionally .gitignored to prevent security exposure.
20
+ ## Contributing to chef-handler-datadog
26
21
 
27
- * Run `rake` to execute tests, ensure they pass
28
- * Commit and push until you are happy with your contribution
29
- * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
30
- * Please try not to mess with the `Rakefile`, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
22
+ See [CONTRIBUTING.md](CONTRIBUTING.md)
31
23
 
32
24
  ## Copyright
33
25
 
34
26
  Copyright (c) 2012-2014 Datadog, Inc. See LICENSE.txt for further details.
35
27
 
36
- [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/DataDog/chef-handler-datadog/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
28
+ [cookbook]: https://supermarket.getchef.com/cookbooks/datadog
data/Rakefile CHANGED
@@ -14,4 +14,4 @@ CLEAN.include(['coverage/', 'doc/', 'pkg/'])
14
14
 
15
15
  RSpec::Core::RakeTask.new(:spec)
16
16
 
17
- Rubocop::RakeTask.new(:cops)
17
+ RuboCop::RakeTask.new(:cops)
@@ -3,8 +3,8 @@ require File.expand_path('../lib/chef_handler_datadog', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.name = 'chef-handler-datadog'
6
- gem.summary = %q(Chef Handler for DataDog events and metrics)
7
- gem.description = %q(This Handler will report the events and metrics for a chef-client run to DataDog.)
6
+ gem.summary = 'Chef Handler reports events and metrics to Datadog'
7
+ gem.description = 'This Handler will report the events and metrics for a chef-client run to Datadog.'
8
8
  gem.license = 'BSD'
9
9
  gem.version = ChefHandlerDatadog::VERSION
10
10
 
@@ -21,8 +21,8 @@ Gem::Specification.new do |gem|
21
21
  gem.add_development_dependency 'chef', '>= 10', '<= 12'
22
22
  gem.add_development_dependency 'dotenv'
23
23
  gem.add_development_dependency 'rake'
24
- gem.add_development_dependency 'rspec'
25
- gem.add_development_dependency 'rubocop', '~> 0.21.0'
24
+ gem.add_development_dependency 'rspec', '~> 3.0.0'
25
+ gem.add_development_dependency 'rubocop', '~> 0.25.0'
26
26
  gem.add_development_dependency 'simplecov'
27
27
  gem.add_development_dependency 'vcr'
28
28
  gem.add_development_dependency 'webmock'
@@ -6,7 +6,11 @@ gem "chef", "10.26.0"
6
6
  gem "json", "1.7.7"
7
7
 
8
8
  group :localdev do
9
+ gem "guard"
10
+ gem "guard-rspec"
11
+ gem "guard-rubocop"
9
12
  gem "pry"
13
+ gem "terminal-notifier-guard"
10
14
  gem "travis-lint"
11
15
  end
12
16
 
@@ -6,7 +6,11 @@ gem "chef", "10.32.2"
6
6
  gem "json", "1.7.7"
7
7
 
8
8
  group :localdev do
9
+ gem "guard"
10
+ gem "guard-rspec"
11
+ gem "guard-rubocop"
9
12
  gem "pry"
13
+ gem "terminal-notifier-guard"
10
14
  gem "travis-lint"
11
15
  end
12
16
 
@@ -5,7 +5,11 @@ source "http://rubygems.org"
5
5
  gem "chef", "11.10.4"
6
6
 
7
7
  group :localdev do
8
+ gem "guard"
9
+ gem "guard-rspec"
10
+ gem "guard-rubocop"
8
11
  gem "pry"
12
+ gem "terminal-notifier-guard"
9
13
  gem "travis-lint"
10
14
  end
11
15
 
@@ -2,10 +2,14 @@
2
2
 
3
3
  source "http://rubygems.org"
4
4
 
5
- gem "chef", "11.12.2"
5
+ gem "chef", "11.12.8"
6
6
 
7
7
  group :localdev do
8
+ gem "guard"
9
+ gem "guard-rspec"
10
+ gem "guard-rubocop"
8
11
  gem "pry"
12
+ gem "terminal-notifier-guard"
9
13
  gem "travis-lint"
10
14
  end
11
15
 
@@ -0,0 +1,16 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "chef", "11.14.2"
6
+
7
+ group :localdev do
8
+ gem "guard"
9
+ gem "guard-rspec"
10
+ gem "guard-rubocop"
11
+ gem "pry"
12
+ gem "terminal-notifier-guard"
13
+ gem "travis-lint"
14
+ end
15
+
16
+ gemspec :path => "../"
@@ -5,7 +5,11 @@ source "http://rubygems.org"
5
5
  gem "chef", "11.8.2"
6
6
 
7
7
  group :localdev do
8
+ gem "guard"
9
+ gem "guard-rspec"
10
+ gem "guard-rubocop"
8
11
  gem "pry"
12
+ gem "terminal-notifier-guard"
9
13
  gem "travis-lint"
10
14
  end
11
15
 
@@ -1,6 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require 'rubygems'
3
3
  require 'chef/handler'
4
+ require 'chef/mash'
4
5
  require 'dogapi'
5
6
 
6
7
  class Chef
@@ -13,9 +14,9 @@ class Chef
13
14
  # "Account Settings" page here: https://app.datadoghq.com/account/settings
14
15
  # It should be passed along from the node/role/environemnt attributes, as the default is nil.
15
16
  def initialize(config = {})
16
- @config = config
17
+ @config = Mash.new(config)
17
18
  # If *any* api_key is not provided, this will fail immediately.
18
- @dog = Dogapi::Client.new(config[:api_key], config[:application_key])
19
+ @dog = Dogapi::Client.new(@config[:api_key], @config[:application_key])
19
20
  end
20
21
 
21
22
  def report
@@ -78,11 +79,26 @@ class Chef
78
79
  # @param run_status [Chef::RunStatus] current run status
79
80
  # @return [Array] alert_type, event_priority, event_title, event_body
80
81
  def build_event_data(hostname, run_status)
82
+ # bail early in case of a compiletime failure
83
+ # OPTIMIZE: Use better inspectors to handle failure scenarios, refactor needed.
84
+ if run_status.elapsed_time.nil?
85
+
86
+ alert_type = 'error'
87
+ event_title = "Chef failed during compile phase on #{hostname} "
88
+ event_priority = 'normal'
89
+ event_body = 'Chef was unable to complete a run, an error during compilation may have occurred.'
90
+
91
+ return [alert_type, event_priority, event_title, event_body]
92
+ end
93
+
81
94
  run_time = pluralize(run_status.elapsed_time, 'second')
82
95
 
83
96
  # This is the first line of the Event body, the rest is appended here.
84
97
  event_body = "Chef updated #{run_status.updated_resources.length} resources out of #{run_status.all_resources.length} resources total."
85
98
 
99
+ # Show the updated resource list, truncated when failed to 5
100
+ event_body << updated_resource_list(run_status)
101
+
86
102
  if run_status.success?
87
103
  alert_type = 'success'
88
104
  event_priority = 'low'
@@ -98,22 +114,36 @@ class Chef
98
114
  event_body << "\nAlerting: #{handles.join(' ')}\n"
99
115
  end
100
116
 
101
- event_body << "\n@@@\n#{run_status.formatted_exception}\n@@@\n"
102
- event_body << "\n@@@\n#{run_status.backtrace.join("\n")}\n@@@\n"
103
- end
104
-
105
- if run_status.updated_resources.length.to_i > 0
106
- event_body << "\n@@@\n"
107
- run_status.updated_resources.each do |r|
108
- event_body << "- #{r} (#{r.defined_at})\n"
109
- end
110
- event_body << "\n@@@\n"
117
+ event_body << "\n$$$\n#{run_status.formatted_exception}\n$$$\n"
118
+ event_body << "\n$$$\n#{run_status.backtrace.join("\n")}\n$$$\n"
111
119
  end
112
120
 
113
121
  # Return resolved data
114
122
  [alert_type, event_priority, event_title, event_body]
115
123
  end
116
124
 
125
+ # Compose a list of resources updated during a run.
126
+ # Shorten the list when there is a failure for stacktrace debugging
127
+ #
128
+ # @param run_status [Chef::RunStatus] current run status
129
+ # @return [String] formatted list of resources updated, truncated on failure
130
+ def updated_resource_list(run_status)
131
+ # No resources updated? Go away.
132
+ return '' unless run_status.updated_resources.length.to_i > 0
133
+
134
+ if run_status.failed?
135
+ report_resources = run_status.updated_resources.last(5)
136
+ else
137
+ report_resources = run_status.updated_resources
138
+ end
139
+
140
+ event_body = "\n$$$\n"
141
+ report_resources.each do |r|
142
+ event_body << "- #{r} (#{r.defined_at})\n"
143
+ end
144
+ event_body << "\n$$$\n"
145
+ end
146
+
117
147
  # Emit Event to Datadog Event Stream
118
148
  #
119
149
  # @param hostname [String] resolved hostname to attach to Event
@@ -154,6 +184,11 @@ class Chef
154
184
  # @param hostname [String] resolved hostname to attach to series
155
185
  # @param run_status [Chef::RunStatus] current run status
156
186
  def emit_metrics_to_datadog(hostname, run_status)
187
+ # If there is a failure during compile phase, a large portion of
188
+ # run_status may be unavailable. Bail out here
189
+ warn_msg = 'Error during compile phase, no Datadog metrics available.'
190
+ return Chef::Log.warn(warn_msg) if run_status.elapsed_time.nil?
191
+
157
192
  @dog.emit_point('chef.resources.total', run_status.all_resources.length, :host => hostname)
158
193
  @dog.emit_point('chef.resources.updated', run_status.updated_resources.length, :host => hostname)
159
194
  @dog.emit_point('chef.resources.elapsed_time', run_status.elapsed_time, :host => hostname)
@@ -2,5 +2,5 @@
2
2
  # Helper module for version number only.
3
3
  # Real deal in 'chef/handler/datadog.rb'
4
4
  module ChefHandlerDatadog
5
- VERSION = '0.4.0'
5
+ VERSION = '0.5.0'
6
6
  end
@@ -23,6 +23,15 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
23
23
  )
24
24
  end
25
25
 
26
+ describe 'initialize' do
27
+ it 'should allow config hash to have string keys' do
28
+ Chef::Handler::Datadog.new(
29
+ 'api_key' => API_KEY,
30
+ 'application_key' => APPLICATION_KEY,
31
+ )
32
+ end
33
+ end
34
+
26
35
  describe 'reports metrics event and sets tags' do
27
36
  # Construct a good run_status
28
37
  before(:each) do
@@ -33,7 +42,7 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
33
42
  @run_status = Chef::RunStatus.new(@node, @events)
34
43
 
35
44
  @expected_time = Time.now
36
- Time.stub(:now).and_return(@expected_time, @expected_time + 5)
45
+ allow(Time).to receive(:now).and_return(@expected_time, @expected_time + 5)
37
46
  @run_status.start_clock
38
47
  @run_status.stop_clock
39
48
 
@@ -97,7 +106,7 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
97
106
  @run_context = Chef::RunContext.new(@node, {}, @events)
98
107
  @run_status = Chef::RunStatus.new(@node, @events)
99
108
  @expected_time = Time.now
100
- Time.stub(:now).and_return(@expected_time, @expected_time + 5)
109
+ allow(Time).to receive(:now).and_return(@expected_time, @expected_time + 5)
101
110
  @run_status.start_clock
102
111
  @run_status.stop_clock
103
112
  @run_status.run_context = @run_context
@@ -144,7 +153,7 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
144
153
  @run_context = Chef::RunContext.new(@node, {}, @events)
145
154
  @run_status = Chef::RunStatus.new(@node, @events)
146
155
  @expected_time = Time.now
147
- Time.stub(:now).and_return(@expected_time, @expected_time + 5)
156
+ allow(Time).to receive(:now).and_return(@expected_time, @expected_time + 5)
148
157
  @run_status.start_clock
149
158
  @run_status.stop_clock
150
159
  @run_status.run_context = @run_context
@@ -185,7 +194,7 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
185
194
  @run_status = Chef::RunStatus.new(@node, @events)
186
195
 
187
196
  @expected_time = Time.now
188
- Time.stub(:now).and_return(@expected_time, @expected_time + 5)
197
+ allow(Time).to receive(:now).and_return(@expected_time, @expected_time + 5)
189
198
  @run_status.start_clock
190
199
  @run_status.stop_clock
191
200
 
@@ -220,7 +229,7 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
220
229
  @run_status = Chef::RunStatus.new(@node, @events)
221
230
 
222
231
  @expected_time = Time.now
223
- Time.stub(:now).and_return(@expected_time, @expected_time + 5)
232
+ allow(Time).to receive(:now).and_return(@expected_time, @expected_time + 5)
224
233
  @run_status.start_clock
225
234
  @run_status.stop_clock
226
235
 
@@ -248,8 +257,19 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
248
257
  @run_context = Chef::RunContext.new(@node, {}, @events)
249
258
  @run_status = Chef::RunStatus.new(@node, @events)
250
259
 
260
+ all_resources = [
261
+ Chef::Resource.new('whiskers'),
262
+ Chef::Resource.new('paws'),
263
+ Chef::Resource.new('ears'),
264
+ Chef::Resource.new('nose'),
265
+ Chef::Resource.new('tail'),
266
+ Chef::Resource.new('fur')
267
+ ]
268
+ all_resources.map { |r| r.updated_by_last_action(true) }
269
+ @run_context.resource_collection.all_resources.replace(all_resources)
270
+
251
271
  @expected_time = Time.now
252
- Time.stub(:now).and_return(@expected_time, @expected_time + 2)
272
+ allow(Time).to receive(:now).and_return(@expected_time, @expected_time + 2)
253
273
  @run_status.start_clock
254
274
  @run_status.stop_clock
255
275
 
@@ -257,7 +277,7 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
257
277
 
258
278
  # Construct an exception
259
279
  exception = Chef::Exceptions::UnsupportedAction.new('Something awry.')
260
- exception.set_backtrace(['file.rb:2', 'file.rb:1'])
280
+ exception.set_backtrace(['whiskers.rb:2', 'paws.rb:1', 'file.rb:2', 'file.rb:1'])
261
281
  @run_status.exception = exception
262
282
 
263
283
  # Run the report
@@ -303,7 +323,7 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
303
323
  @run_context.resource_collection.all_resources.replace(all_resources)
304
324
 
305
325
  @expected_time = Time.now
306
- Time.stub(:now).and_return(@expected_time, @expected_time + 8)
326
+ allow(Time).to receive(:now).and_return(@expected_time, @expected_time + 8)
307
327
  @run_status.start_clock
308
328
  @run_status.stop_clock
309
329
 
@@ -322,6 +342,36 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
322
342
  end
323
343
  end
324
344
 
345
+ describe 'resources' do
346
+ before(:each) do
347
+ @node = Chef::Node.build('chef.handler.datadog.test-resources')
348
+ @node.send(:chef_environment, 'resources')
349
+ @events = Chef::EventDispatch::Dispatcher.new
350
+ @run_context = Chef::RunContext.new(@node, {}, @events)
351
+ @run_status = Chef::RunStatus.new(@node, @events)
352
+ end
353
+
354
+ context 'failure during compile phase' do
355
+ before(:each) do
356
+ @handler.run_report_unsafe(@run_status)
357
+ end
358
+
359
+ it 'does not emit metrics' do
360
+ expect(a_request(:post, METRICS_ENDPOINT).with(
361
+ :query => { 'api_key' => @handler.config[:api_key] }
362
+ )).to_not have_been_made
363
+ end
364
+
365
+ it 'posts an event' do
366
+ expect(a_request(:post, EVENTS_ENDPOINT).with(
367
+ :query => { 'api_key' => @handler.config[:api_key] },
368
+ :body => hash_including(:msg_text => 'Chef was unable to complete a run, an error during compilation may have occured.'),
369
+ :body => hash_including(:msg_title => "Chef failed during compile phase on #{@node.name} "),
370
+ )).to have_been_made.times(1)
371
+ end
372
+ end
373
+ end
374
+
325
375
  # TODO: test failures:
326
376
  # @run_status.exception = Exception.new('Boy howdy!')
327
377
  end