chef-handler-datadog 0.12.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +158 -0
  3. data/.gitignore +0 -1
  4. data/.rubocop.yml +5 -0
  5. data/CHANGELOG.md +33 -0
  6. data/CONTRIBUTING.md +14 -0
  7. data/Gemfile +1 -0
  8. data/Gemfile.lock +296 -0
  9. data/README.md +1 -3
  10. data/chef-handler-datadog.gemspec +10 -10
  11. data/lib/chef/handler/datadog.rb +18 -13
  12. data/lib/chef/handler/datadog_chef_events.rb +3 -0
  13. data/lib/chef/handler/datadog_chef_tags.rb +2 -1
  14. data/lib/chef_handler_datadog.rb +1 -1
  15. data/spec/datadog_spec.rb +216 -166
  16. data/spec/support/cassettes/Chef_Handler_Datadog/failed_Chef_run/sets_alert_handles_when_specified.yml +239 -181
  17. data/spec/support/cassettes/Chef_Handler_Datadog/failed_Chef_run/sets_event_title_correctly.yml +119 -90
  18. data/spec/support/cassettes/Chef_Handler_Datadog/failed_Chef_run/sets_priority_correctly.yml +119 -90
  19. data/spec/support/cassettes/Chef_Handler_Datadog/hostname/uses_the_node_name_when_no_config_specified.yml +119 -89
  20. data/spec/support/cassettes/Chef_Handler_Datadog/hostname/uses_the_specified_hostname_when_provided.yml +119 -89
  21. 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 +119 -89
  22. data/spec/support/cassettes/Chef_Handler_Datadog/reports_correct_hostname_on_an_ec2_node/uses_the_instance_id_when_config_is_specified.yml +119 -89
  23. data/spec/support/cassettes/Chef_Handler_Datadog/reports_correct_hostname_on_an_ec2_node/uses_the_instance_id_when_no_config_specified.yml +119 -89
  24. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/emits_events/posts_an_event.yml +119 -89
  25. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/emits_events/sets_priority_correctly.yml +119 -89
  26. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/emits_metrics/reports_metrics.yml +119 -89
  27. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/sets_tags/puts_the_tags_for_the_current_node.yml +119 -89
  28. data/spec/support/cassettes/Chef_Handler_Datadog/resources/failure_during_compile_phase/only_emits_the_run_status_metrics.yml +74 -56
  29. data/spec/support/cassettes/Chef_Handler_Datadog/resources/failure_during_compile_phase/posts_an_event.yml +74 -56
  30. data/spec/support/cassettes/Chef_Handler_Datadog/resources/failure_during_compile_phase_with_an_elapsed_time_and_incomplete_resource_collection/only_emits_the_run_status_metrics.yml +73 -55
  31. data/spec/support/cassettes/Chef_Handler_Datadog/resources/failure_during_compile_phase_with_an_elapsed_time_and_incomplete_resource_collection/posts_an_event.yml +73 -55
  32. data/spec/support/cassettes/Chef_Handler_Datadog/tags/when_policy_tags_are_enabled/sets_the_policy_name_and_policy_group_tags.yml +120 -90
  33. data/spec/support/cassettes/Chef_Handler_Datadog/tags/when_policy_tags_are_not_enabled/does_not_set_the_policy_name_and_policy_group_tags.yml +111 -81
  34. data/spec/support/cassettes/Chef_Handler_Datadog/tags/when_specified/allows_for_empty_scope_prefix.yml +119 -90
  35. data/spec/support/cassettes/Chef_Handler_Datadog/tags/when_specified/allows_for_empty_tag_prefix.yml +117 -127
  36. data/spec/support/cassettes/Chef_Handler_Datadog/tags/when_specified/allows_for_user-specified_scope_prefix.yml +119 -90
  37. data/spec/support/cassettes/Chef_Handler_Datadog/tags/when_specified/allows_for_user-specified_tag_prefix.yml +121 -92
  38. data/spec/support/cassettes/Chef_Handler_Datadog/tags/when_specified/sets_the_role_and_env_and_tags.yml +119 -90
  39. data/spec/support/cassettes/Chef_Handler_Datadog/tags/when_tag_blacklist_is_specified/does_not_include_the_tag_s_specified.yml +118 -88
  40. data/spec/support/cassettes/Chef_Handler_Datadog/tags/when_tag_blacklist_is_unspecified/should_include_all_of_the_tag_s_.yml +118 -88
  41. data/spec/support/cassettes/Chef_Handler_Datadog/tags/when_unspecified/sets_role_env_and_nothing_else.yml +119 -90
  42. data/spec/support/cassettes/Chef_Handler_Datadog/tags_submission_retries/when_not_specified/does_not_retry_after_a_failed_submission.yml +112 -124
  43. data/spec/support/cassettes/Chef_Handler_Datadog/tags_submission_retries/when_specified_as_2_retries/retries_no_more_than_twice.yml +108 -210
  44. data/spec/support/cassettes/Chef_Handler_Datadog/tags_submission_retries/when_specified_as_2_retries/stops_retrying_once_submission_is_successful.yml +110 -168
  45. data/spec/support/cassettes/Chef_Handler_Datadog/updated_resources/posts_an_event.yml +119 -89
  46. metadata +13 -24
  47. data/.travis.yml +0 -34
  48. data/gemfiles/chef_12.7.gemfile +0 -16
  49. data/gemfiles/chef_12.gemfile +0 -16
  50. data/gemfiles/chef_13.gemfile +0 -16
  51. data/gemfiles/chef_14.gemfile +0 -16
  52. data/spec/support/cassettes/Chef_Handler_Datadog/handles_no_application_key/fails_when_no_application_key_is_provided.yml +0 -143
  53. data/spec/support/cassettes/Chef_Handler_Datadog/when_reporting_to_multiple_endpoints/emits_events/posts_an_event.yml +0 -575
  54. data/spec/support/cassettes/Chef_Handler_Datadog/when_reporting_to_multiple_endpoints/emits_metrics/reports_metrics.yml +0 -575
  55. data/spec/support/cassettes/Chef_Handler_Datadog/when_reporting_to_multiple_endpoints/sets_tags/puts_the_tags_for_the_current_node.yml +0 -575
data/README.md CHANGED
@@ -3,9 +3,7 @@
3
3
  An Exception and Report Handler for Chef.
4
4
 
5
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.com/DataDog/chef-handler-datadog.svg?branch=master)](https://travis-ci.com/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)
6
+ [![Build Status](https://img.shields.io/circleci/build/gh/DataDog/chef-handler-datadog.svg)](https://circleci.com/gh/DataDog/chef-handler-datadog)
9
7
 
10
8
  ## Using chef-handler-datadog
11
9
 
@@ -3,19 +3,19 @@
3
3
  require File.expand_path('lib/chef_handler_datadog', __dir__)
4
4
 
5
5
  Gem::Specification.new do |gem|
6
- gem.name = 'chef-handler-datadog'
7
- gem.summary = 'Chef Handler reports events and metrics to Datadog'
8
- gem.description = 'This Handler will report the events and metrics for a chef-client run to Datadog.'
9
- gem.license = 'BSD'
10
- gem.version = ChefHandlerDatadog::VERSION
6
+ gem.name = 'chef-handler-datadog'
7
+ gem.summary = 'Chef Handler reports events and metrics to Datadog'
8
+ gem.description = 'This Handler will report the events and metrics for a chef-client run to Datadog.'
9
+ gem.license = 'BSD'
10
+ gem.version = ChefHandlerDatadog::VERSION
11
11
 
12
- gem.files = `git ls-files`.split($\) # rubocop:disable SpecialGlobalVars
13
- gem.executables = gem.files.grep(%r{^bin\/}).map { |f| File.basename(f) }
14
- gem.test_files = gem.files.grep(%r{^(test|spec|features)\/})
15
- gem.require_paths = ['lib']
12
+ gem.files = `git ls-files`.split($\) # rubocop:disable Style/SpecialGlobalVars
13
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.require_paths = ['lib']
16
16
  gem.extra_rdoc_files = ['README.md', 'LICENSE.txt']
17
17
 
18
- gem.add_dependency 'dogapi', '>= 1.31'
18
+ gem.add_dependency 'dogapi', '~> 1.44.0'
19
19
 
20
20
  gem.add_development_dependency 'appraisal', '~> 2.0.1'
21
21
  gem.add_development_dependency 'bundler'
@@ -78,9 +78,9 @@ class Chef
78
78
  @metrics.emit_to_datadog dog
79
79
  @event.emit_to_datadog dog
80
80
  @tags.send_update_to_datadog dog
81
- rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT => e
82
- Chef::Log.error("Could not connect to Datadog. Connection error:\n" + e)
83
- Chef::Log.error('Data to be submitted was:')
81
+ rescue => e
82
+ Chef::Log.error("Could not send/emit to Datadog:\n" + e.to_s)
83
+ Chef::Log.error('Event data to be submitted was:')
84
84
  Chef::Log.error(@event.event_title)
85
85
  Chef::Log.error(@event.event_body)
86
86
  Chef::Log.error('Tags to be set for this run:')
@@ -129,15 +129,20 @@ class Chef
129
129
  def prepare_the_pack
130
130
  dogs = []
131
131
  endpoints.each do |url, api_key, app_key|
132
- dogs.push(Dogapi::Client.new(
133
- api_key,
134
- app_key,
135
- nil, # host
136
- nil, # device
137
- true, # silent
138
- nil, # timeout
139
- url
140
- ))
132
+ begin
133
+ dogs.push(Dogapi::Client.new(
134
+ api_key,
135
+ app_key,
136
+ nil, # host
137
+ nil, # device
138
+ false, # silent
139
+ nil, # timeout
140
+ url,
141
+ config[:skip_ssl_validation]
142
+ ))
143
+ rescue => e
144
+ Chef::Log.error("Could not create API Client '#{url}'\n #{e.to_s}")
145
+ end
141
146
  end
142
147
  dogs
143
148
  end
@@ -159,7 +164,7 @@ class Chef
159
164
  # then add extra endpoints
160
165
  extra_endpoints = @config[:extra_endpoints] || []
161
166
  extra_endpoints.each do |endpoint|
162
- url = endpoint[:url] || config_url()
167
+ url = endpoint[:api_url] || endpoint[:url] || config_url()
163
168
  api_key = endpoint[:api_key]
164
169
  app_key = endpoint[:application_key]
165
170
  endpoints << [url, api_key, app_key] if validate_keys(api_key, app_key, false)
@@ -10,6 +10,9 @@ require_relative 'datadog_util'
10
10
  class DatadogChefEvents
11
11
  include DatadogUtil
12
12
 
13
+ attr_reader :event_title
14
+ attr_reader :event_body
15
+
13
16
  def initialize
14
17
  @hostname = nil
15
18
  @run_status = nil
@@ -92,6 +92,7 @@ class DatadogChefTags
92
92
  def send_update_to_datadog(dog)
93
93
  tags = combined_host_tags
94
94
  retries = @retries
95
+ rc = []
95
96
  begin
96
97
  loop do
97
98
  should_retry = false
@@ -114,7 +115,7 @@ class DatadogChefTags
114
115
  break unless should_retry
115
116
  end
116
117
  rescue StandardError => e
117
- Chef::Log.warn("Could not determine whether #{@hostname}'s tags were successfully submitted to Datadog: #{rc}. Error:\n#{e}")
118
+ Chef::Log.warn("Could not determine whether #{@hostname}'s tags were successfully submitted to Datadog: #{rc.inspect}. Error:\n#{e}")
118
119
  end
119
120
  end
120
121
 
@@ -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.12.1'
5
+ VERSION = '0.15.0'
6
6
  end
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require 'spec_helper'
3
3
 
4
- describe Chef::Handler::Datadog, :vcr => :new_episodes do
4
+ describe Chef::Handler::Datadog, vcr: :new_episodes do
5
5
  # The #report method currently long and clunky, and we need to simulate a
6
6
  # Chef run to test all aspects of this, as well as push values into the test.
7
7
  before(:all) do
@@ -18,22 +18,31 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
18
18
 
19
19
  before(:each) do
20
20
  @handler = Chef::Handler::Datadog.new(
21
- :api_key => API_KEY,
22
- :application_key => APPLICATION_KEY,
21
+ api_key: API_KEY,
22
+ application_key: APPLICATION_KEY,
23
23
  )
24
24
  end
25
25
 
26
26
  describe 'initialize' do
27
27
  it 'should allow config hash to have string keys' do
28
28
  Chef::Handler::Datadog.new(
29
- 'api_key' => API_KEY,
30
- 'application_key' => APPLICATION_KEY,
31
- 'tag_prefix' => 'tag',
32
- 'scope_prefix' => nil
29
+ api_key: API_KEY,
30
+ application_key: APPLICATION_KEY,
31
+ tag_prefix: 'tag',
32
+ scope_prefix: nil
33
33
  )
34
34
  end
35
+
36
+ it 'should create a Dogapi client for the endpoint' do
37
+ dogs = @handler.instance_variable_get(:@dogs)
38
+
39
+ # Check that we do have a Dogapi client
40
+ expect(dogs.length).to eq(1)
41
+ end
35
42
  end
36
43
 
44
+
45
+
37
46
  describe 'reports metrics event and sets tags' do
38
47
  # Construct a good run_status
39
48
  before(:each) do
@@ -57,7 +66,7 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
57
66
  context 'emits metrics' do
58
67
  it 'reports metrics' do
59
68
  expect(a_request(:post, METRICS_ENDPOINT).with(
60
- :query => { 'api_key' => @handler.config[:api_key] }
69
+ query: { api_key: @handler.config[:api_key] }
61
70
  )).to have_been_made.times(5)
62
71
  end
63
72
  end
@@ -65,17 +74,18 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
65
74
  context 'emits events' do
66
75
  it 'posts an event' do
67
76
  expect(a_request(:post, EVENTS_ENDPOINT).with(
68
- :query => { 'api_key' => @handler.config[:api_key] },
69
- :body => hash_including(:msg_text => 'Chef updated 0 resources out of 0 resources total.'),
70
- :body => hash_including(:msg_title => "Chef completed in 5 seconds on #{@node.name} "),
71
- :body => hash_including(:tags => ['env:testing']),
77
+ query: { api_key: @handler.config[:api_key] },
78
+ body: hash_including(msg_text: 'Chef updated 0 resources out of 0 resources total.',
79
+ msg_title: "Chef completed in 5 seconds on #{@node.name} ",
80
+ tags: ['env:testing']),
72
81
  )).to have_been_made.times(1)
73
82
  end
74
83
 
75
84
  it 'sets priority correctly' do
76
85
  expect(a_request(:post, EVENTS_ENDPOINT).with(
77
- :query => { 'api_key' => @handler.config[:api_key] },
78
- :body => hash_including(:priority => 'low'),
86
+ query: { api_key: @handler.config[:api_key] },
87
+ body: hash_including(alert_type: 'success',
88
+ priority: 'low'),
79
89
  )).to have_been_made.times(1)
80
90
  end
81
91
  end
@@ -85,15 +95,15 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
85
95
  # We no longer need to query the tag api for current tags,
86
96
  # rather udpate only the tags for the designated source type
87
97
  expect(a_request(:get, HOST_TAG_ENDPOINT + @node.name).with(
88
- :query => { 'api_key' => @handler.config[:api_key],
89
- 'application_key' => @handler.config[:application_key] },
98
+ headers: { 'Dd-Api-Key' => @handler.config[:api_key],
99
+ 'Dd-Application-Key' => @handler.config[:application_key] },
90
100
  )).to have_been_made.times(0)
91
101
 
92
102
  expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
93
- :query => { 'api_key' => @handler.config[:api_key],
94
- 'application_key' => @handler.config[:application_key],
95
- 'source' => 'chef' },
96
- :body => { 'tags' => ['env:testing'] },
103
+ headers: { 'Dd-Api-Key' => @handler.config[:api_key],
104
+ 'Dd-Application-Key' => @handler.config[:application_key] },
105
+ query: { source: 'chef' },
106
+ body: { tags: ['env:testing'] },
97
107
  )).to have_been_made.times(1)
98
108
  end
99
109
  end
@@ -104,7 +114,7 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
104
114
  @node = Chef::Node.build('chef.handler.datadog.test-ec2')
105
115
  @node.send(:chef_environment, 'testing')
106
116
 
107
- @node.automatic_attrs['ec2'] = { :instance_id => 'i-123456' }
117
+ @node.automatic_attrs['ec2'] = { instance_id: 'i-123456' }
108
118
 
109
119
  @run_context = Chef::RunContext.new(@node, {}, @events)
110
120
  @run_status = Chef::RunStatus.new(@node, @events)
@@ -119,9 +129,9 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
119
129
  @handler.run_report_unsafe(@run_status)
120
130
 
121
131
  expect(a_request(:post, EVENTS_ENDPOINT).with(
122
- :query => { 'api_key' => @handler.config[:api_key] },
123
- :body => hash_including(:msg_title => 'Chef completed in 5 seconds on i-123456 '),
124
- :body => hash_including(:host => 'i-123456'),
132
+ query: { api_key: @handler.config[:api_key] },
133
+ body: hash_including(msg_title: 'Chef completed in 5 seconds on i-123456 ',
134
+ host: 'i-123456'),
125
135
  )).to have_been_made.times(1)
126
136
  end
127
137
 
@@ -130,9 +140,9 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
130
140
  @handler.run_report_unsafe(@run_status)
131
141
 
132
142
  expect(a_request(:post, EVENTS_ENDPOINT).with(
133
- :query => { 'api_key' => @handler.config[:api_key] },
134
- :body => hash_including(:msg_title => 'Chef completed in 5 seconds on i-123456 '),
135
- :body => hash_including(:host => 'i-123456'),
143
+ query: { api_key: @handler.config[:api_key] },
144
+ body: hash_including(msg_title: 'Chef completed in 5 seconds on i-123456 ',
145
+ host: 'i-123456'),
136
146
  )).to have_been_made.times(1)
137
147
  end
138
148
 
@@ -141,9 +151,9 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
141
151
  @handler.run_report_unsafe(@run_status)
142
152
 
143
153
  expect(a_request(:post, EVENTS_ENDPOINT).with(
144
- :query => { 'api_key' => @handler.config[:api_key] },
145
- :body => hash_including(:msg_title => "Chef completed in 5 seconds on #{@node.name} "),
146
- :body => hash_including(:host => @node.name),
154
+ query: { api_key: @handler.config[:api_key] },
155
+ body: hash_including(msg_title: "Chef completed in 5 seconds on #{@node.name} ",
156
+ host: @node.name),
147
157
  )).to have_been_made.times(1)
148
158
  end
149
159
  end
@@ -166,9 +176,9 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
166
176
  @handler.run_report_unsafe(@run_status)
167
177
 
168
178
  expect(a_request(:post, EVENTS_ENDPOINT).with(
169
- :query => { 'api_key' => @handler.config[:api_key] },
170
- :body => hash_including(:msg_title => "Chef completed in 5 seconds on #{@node.name}"),
171
- :body => hash_including(:host => @node.name),
179
+ query: { api_key: @handler.config[:api_key] },
180
+ body: hash_including(msg_title: "Chef completed in 5 seconds on #{@node.name} ",
181
+ host: @node.name),
172
182
  )).to have_been_made.times(1)
173
183
  end
174
184
 
@@ -177,11 +187,29 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
177
187
  @handler.run_report_unsafe(@run_status)
178
188
 
179
189
  expect(a_request(:post, EVENTS_ENDPOINT).with(
180
- :query => { 'api_key' => @handler.config[:api_key] },
181
- :body => hash_including(:msg_title => 'Chef completed in 5 seconds on my-imaginary-hostname.local'),
182
- :body => hash_including(:host => 'my-imaginary-hostname.local'),
190
+ query: { api_key: @handler.config[:api_key] },
191
+ body: hash_including(msg_title: 'Chef completed in 5 seconds on my-imaginary-hostname.local ',
192
+ host: 'my-imaginary-hostname.local'),
183
193
  )).to have_been_made.times(1)
184
194
  end
195
+
196
+ describe 'when dogapi-rb fails to calculate a hostname' do
197
+ before(:each) do
198
+ allow(Dogapi::Client).to receive(:new).and_raise("getaddrinfo: Name or service not known")
199
+
200
+ @handler = Chef::Handler::Datadog.new(
201
+ api_key: API_KEY,
202
+ application_key: APPLICATION_KEY,
203
+ )
204
+ end
205
+
206
+ it 'the reporter should not fail the chef run' do
207
+ @handler.config[:hostname] = 'my-imaginary-hostname.local'
208
+ @handler.run_report_unsafe(@run_status)
209
+
210
+ expect(a_request(:post, EVENTS_ENDPOINT)).to have_been_made.times(0)
211
+ end
212
+ end
185
213
  end
186
214
 
187
215
  context 'tags' do
@@ -209,10 +237,10 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
209
237
  @handler.run_report_unsafe(@run_status)
210
238
 
211
239
  expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
212
- :query => { 'api_key' => @handler.config[:api_key],
213
- 'application_key' => @handler.config[:application_key],
214
- 'source' => 'chef' },
215
- :body => hash_including(:tags => [
240
+ headers: { 'Dd-Api-Key' => @handler.config[:api_key],
241
+ 'Dd-Application-Key' => @handler.config[:application_key] },
242
+ query: { source: 'chef' },
243
+ body: hash_including(tags: [
216
244
  'env:hostile', 'role:highlander', 'tag:the_one_and_only', 'tag:datacenter:my-cloud'
217
245
  ]),
218
246
  )).to have_been_made.times(1)
@@ -224,10 +252,10 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
224
252
  @handler.run_report_unsafe(@run_status)
225
253
 
226
254
  expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
227
- :query => { 'api_key' => @handler.config[:api_key],
228
- 'application_key' => @handler.config[:application_key],
229
- 'source' => 'chef' },
230
- :body => hash_including(:tags => [
255
+ headers: { 'Dd-Api-Key' => @handler.config[:api_key],
256
+ 'Dd-Application-Key' => @handler.config[:application_key] },
257
+ query: { source: 'chef' },
258
+ body: hash_including(tags: [
231
259
  'env:hostile', 'role:highlander', 'custom-prefix-the_one_and_only', 'custom-prefix-datacenter:my-cloud'
232
260
  ]),
233
261
  )).to have_been_made.times(1)
@@ -239,10 +267,10 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
239
267
  @handler.run_report_unsafe(@run_status)
240
268
 
241
269
  expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
242
- :query => { 'api_key' => @handler.config[:api_key],
243
- 'application_key' => @handler.config[:application_key],
244
- 'source' => 'chef' },
245
- :body => hash_including(:tags => [
270
+ headers: { 'Dd-Api-Key' => @handler.config[:api_key],
271
+ 'Dd-Application-Key' => @handler.config[:application_key] },
272
+ query: { source: 'chef' },
273
+ body: hash_including(tags: [
246
274
  'env:hostile', 'role:highlander', 'the_one_and_only', 'datacenter:my-cloud'
247
275
  ]),
248
276
  )).to have_been_made.times(1)
@@ -253,10 +281,10 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
253
281
  @handler.run_report_unsafe(@run_status)
254
282
 
255
283
  expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
256
- :query => { 'api_key' => @handler.config[:api_key],
257
- 'application_key' => @handler.config[:application_key],
258
- 'source' => 'chef' },
259
- :body => hash_including(:tags => [
284
+ headers: { 'Dd-Api-Key' => @handler.config[:api_key],
285
+ 'Dd-Application-Key' => @handler.config[:application_key] },
286
+ query: { source: 'chef' },
287
+ body: hash_including(tags: [
260
288
  'custom-prefix-env:hostile', 'custom-prefix-role:highlander'
261
289
  ]),
262
290
  )).to have_been_made.times(1)
@@ -267,10 +295,10 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
267
295
  @handler.run_report_unsafe(@run_status)
268
296
 
269
297
  expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
270
- :query => { 'api_key' => @handler.config[:api_key],
271
- 'application_key' => @handler.config[:application_key],
272
- 'source' => 'chef' },
273
- :body => hash_including(:tags => [
298
+ headers: { 'Dd-Api-Key' => @handler.config[:api_key],
299
+ 'Dd-Application-Key' => @handler.config[:application_key] },
300
+ query: { source: 'chef' },
301
+ body: hash_including(tags: [
274
302
  'env:hostile', 'role:highlander'
275
303
  ]),
276
304
  )).to have_been_made.times(1)
@@ -282,10 +310,10 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
282
310
  @handler.run_report_unsafe(@run_status)
283
311
 
284
312
  expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
285
- :query => { 'api_key' => @handler.config[:api_key],
286
- 'application_key' => @handler.config[:application_key],
287
- 'source' => 'chef' },
288
- :body => hash_including(:tags => [
313
+ headers: { 'Dd-Api-Key' => @handler.config[:api_key],
314
+ 'Dd-Application-Key' => @handler.config[:application_key] },
315
+ query: { source: 'chef' },
316
+ body: hash_including(tags: [
289
317
  'env:hostile', 'role:highlander'
290
318
  ]),
291
319
  )).to have_been_made.times(1)
@@ -299,10 +327,10 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
299
327
  @handler.run_report_unsafe(@run_status)
300
328
 
301
329
  expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
302
- :query => { 'api_key' => @handler.config[:api_key],
303
- 'application_key' => @handler.config[:application_key],
304
- 'source' => 'chef' },
305
- :body => hash_including(:tags => [
330
+ headers: { 'Dd-Api-Key' => @handler.config[:api_key],
331
+ 'Dd-Application-Key' => @handler.config[:application_key] },
332
+ query: { source: 'chef' },
333
+ body: hash_including(tags: [
306
334
  'env:hostile', 'role:highlander', 'tag:allowed_tag'
307
335
  ]),
308
336
  )).to have_been_made.times(1)
@@ -315,10 +343,10 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
315
343
  @handler.run_report_unsafe(@run_status)
316
344
 
317
345
  expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
318
- :query => { 'api_key' => @handler.config[:api_key],
319
- 'application_key' => @handler.config[:application_key],
320
- 'source' => 'chef' },
321
- :body => hash_including(:tags => [
346
+ headers: { 'Dd-Api-Key' => @handler.config[:api_key],
347
+ 'Dd-Application-Key' => @handler.config[:application_key] },
348
+ query: { source: 'chef' },
349
+ body: hash_including(tags: [
322
350
  'env:hostile', 'role:highlander', 'tag:allowed_tag', 'tag:not_allowed_tag'
323
351
  ]),
324
352
  )).to have_been_made.times(1)
@@ -336,10 +364,10 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
336
364
  @handler.run_report_unsafe(@run_status)
337
365
 
338
366
  expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
339
- :query => { 'api_key' => @handler.config[:api_key],
340
- 'application_key' => @handler.config[:application_key],
341
- 'source' => 'chef' },
342
- :body => hash_including(:tags => [
367
+ headers: { 'Dd-Api-Key' => @handler.config[:api_key],
368
+ 'Dd-Application-Key' => @handler.config[:application_key] },
369
+ query: { source: 'chef' },
370
+ body: hash_including(tags: [
343
371
  'env:hostile', 'role:highlander'
344
372
  ]),
345
373
  )).to have_been_made.times(1)
@@ -358,10 +386,10 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
358
386
  @handler.run_report_unsafe(@run_status)
359
387
 
360
388
  expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
361
- :query => { 'api_key' => @handler.config[:api_key],
362
- 'application_key' => @handler.config[:application_key],
363
- 'source' => 'chef' },
364
- :body => hash_including(:tags => [
389
+ headers: { 'Dd-Api-Key' => @handler.config[:api_key],
390
+ 'Dd-Application-Key' => @handler.config[:application_key] },
391
+ query: { source: 'chef' },
392
+ body: hash_including(tags: [
365
393
  'env:hostile', 'role:highlander', 'policy_group:the_policy_group', 'policy_name:the_policy_name'
366
394
  ]),
367
395
  )).to have_been_made.times(1)
@@ -370,6 +398,10 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
370
398
  end
371
399
 
372
400
  context 'tags submission retries' do
401
+ let(:dog) do
402
+ @handler.instance_variable_get(:@dogs)[0]
403
+ end
404
+
373
405
  before(:each) do
374
406
  @node = Chef::Node.build('chef.handler.datadog.test-tags-retries')
375
407
 
@@ -380,7 +412,6 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
380
412
  @events = Chef::EventDispatch::Dispatcher.new
381
413
  @run_context = Chef::RunContext.new(@node, {}, @events)
382
414
  @run_status = Chef::RunStatus.new(@node, @events)
383
-
384
415
  @expected_time = Time.now
385
416
  allow(Time).to receive(:now).and_return(@expected_time, @expected_time + 5)
386
417
  @run_status.start_clock
@@ -397,44 +428,30 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
397
428
  end
398
429
 
399
430
  it 'retries no more than twice' do
400
- @handler.run_report_unsafe(@run_status)
431
+ # Define mock update_tags function which returns the result of an HTTP 404 error
432
+ allow(dog).to receive(:update_tags).and_return([404, 'Not Found'])
401
433
 
402
- expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
403
- :query => { 'api_key' => @handler.config[:api_key],
404
- 'application_key' => @handler.config[:application_key],
405
- 'source' => 'chef' },
406
- :body => hash_including(:tags => [
407
- 'env:hostile', 'role:highlander', 'tag:the_one_and_only'
408
- ]),
409
- )).to have_been_made.times(3)
434
+ expect(dog).to receive(:update_tags).exactly(3).times
435
+ @handler.run_report_unsafe(@run_status)
410
436
  end
411
437
 
412
438
  it 'stops retrying once submission is successful' do
413
- @handler.run_report_unsafe(@run_status)
439
+ # Define mock update_tags function which returns the result of an HTTP 404 error once
440
+ allow(dog).to receive(:update_tags).and_return([404, 'Not Found'], [201, 'Created'])
414
441
 
415
- expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
416
- :query => { 'api_key' => @handler.config[:api_key],
417
- 'application_key' => @handler.config[:application_key],
418
- 'source' => 'chef' },
419
- :body => hash_including(:tags => [
420
- 'env:hostile', 'role:highlander', 'tag:the_one_and_only'
421
- ]),
422
- )).to have_been_made.times(2)
442
+ expect(dog).to receive(:update_tags).exactly(2).times
443
+ @handler.run_report_unsafe(@run_status)
423
444
  end
424
445
  end
425
446
 
426
447
  describe 'when not specified' do
427
- it 'does not retry after a failed submission' do
428
- @handler.run_report_unsafe(@run_status)
448
+ it 'does not retry after a failed submission' do
449
+ # Define mock update_tags function which returns the result of an HTTP 404 error
450
+ allow(dog).to receive(:update_tags).and_return([404, 'Not Found'])
429
451
 
430
- expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
431
- :query => { 'api_key' => @handler.config[:api_key],
432
- 'application_key' => @handler.config[:application_key],
433
- 'source' => 'chef' },
434
- :body => hash_including(:tags => [
435
- 'env:hostile', 'role:highlander', 'tag:the_one_and_only'
436
- ]),
437
- )).to have_been_made.times(1)
452
+
453
+ expect(dog).to receive(:update_tags).exactly(:once)
454
+ @handler.run_report_unsafe(@run_status)
438
455
  end
439
456
  end
440
457
  end
@@ -507,16 +524,16 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
507
524
 
508
525
  it 'sets event title correctly' do
509
526
  expect(a_request(:post, EVENTS_ENDPOINT).with(
510
- :query => { 'api_key' => @handler.config[:api_key] },
511
- :body => hash_including(:msg_title => "Chef failed in 2 seconds on #{@node.name} "),
527
+ query: { api_key: @handler.config[:api_key] },
528
+ body: hash_including(msg_title: "Chef failed in 2 seconds on #{@node.name} "),
512
529
  )).to have_been_made.times(1)
513
530
  end
514
531
 
515
532
  it 'sets priority correctly' do
516
533
  expect(a_request(:post, EVENTS_ENDPOINT).with(
517
- :query => { 'api_key' => @handler.config[:api_key] },
518
- :body => hash_including(:alert_type => 'success'),
519
- :body => hash_including(:priority => 'normal'),
534
+ query: { api_key: @handler.config[:api_key] },
535
+ body: hash_including(alert_type: 'error',
536
+ priority: 'normal'),
520
537
  )).to have_been_made.times(1)
521
538
  end
522
539
 
@@ -525,8 +542,8 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
525
542
  @handler.run_report_unsafe(@run_status)
526
543
 
527
544
  expect(a_request(:post, EVENTS_ENDPOINT).with(
528
- :query => { 'api_key' => @handler.config[:api_key] },
529
- :body => /Alerting: @alice @bob/
545
+ query: { api_key: @handler.config[:api_key] },
546
+ body: /Alerting: @alice @bob/
530
547
  )).to have_been_made.times(1)
531
548
  end
532
549
  end
@@ -556,9 +573,10 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
556
573
 
557
574
  it 'posts an event' do
558
575
  expect(a_request(:post, EVENTS_ENDPOINT).with(
559
- :query => { 'api_key' => @handler.config[:api_key] },
560
- :body => hash_including(:msg_text => 'Chef updated 1 resources out of 2 resources total.'),
561
- :body => hash_including(:msg_title => "Chef completed in 8 seconds on #{@node.name} "),
576
+ query: { api_key: @handler.config[:api_key] },
577
+ # FIXME: msg_text is "\n$$$\n- [whiskers] (dynamically defined)\n\n$$$\n" - is this a bug?
578
+ body: hash_including(#msg_text: 'Chef updated 1 resources out of 2 resources total.',
579
+ msg_title: "Chef completed in 8 seconds on #{@node.name} "),
562
580
  )).to have_been_made.times(1)
563
581
  end
564
582
  end
@@ -578,15 +596,15 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
578
596
 
579
597
  it 'only emits the run status metrics' do
580
598
  expect(a_request(:post, METRICS_ENDPOINT).with(
581
- :query => { 'api_key' => @handler.config[:api_key] }
599
+ query: { api_key: @handler.config[:api_key] }
582
600
  )).to have_been_made.times(2)
583
601
  end
584
602
 
585
603
  it 'posts an event' do
586
604
  expect(a_request(:post, EVENTS_ENDPOINT).with(
587
- :query => { 'api_key' => @handler.config[:api_key] },
588
- :body => hash_including(:msg_text => 'Chef was unable to complete a run, an error during compilation may have occured.'),
589
- :body => hash_including(:msg_title => "Chef failed during compile phase on #{@node.name} "),
605
+ query: { api_key: @handler.config[:api_key] },
606
+ body: hash_including(msg_text: 'Chef was unable to complete a run, an error during compilation may have occurred.',
607
+ msg_title: "Chef failed during compile phase on #{@node.name} "),
590
608
  )).to have_been_made.times(1)
591
609
  end
592
610
  end
@@ -608,15 +626,15 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
608
626
 
609
627
  it 'only emits the run status metrics' do
610
628
  expect(a_request(:post, METRICS_ENDPOINT).with(
611
- :query => { 'api_key' => @handler.config[:api_key] }
629
+ query: { api_key: @handler.config[:api_key] }
612
630
  )).to have_been_made.times(2)
613
631
  end
614
632
 
615
633
  it 'posts an event' do
616
634
  expect(a_request(:post, EVENTS_ENDPOINT).with(
617
- :query => { 'api_key' => @handler.config[:api_key] },
618
- :body => hash_including(:msg_text => 'Chef was unable to complete a run, an error during compilation may have occured.'),
619
- :body => hash_including(:msg_title => "Chef failed during compile phase on #{@node.name} "),
635
+ query: { api_key: @handler.config[:api_key] },
636
+ body: hash_including(msg_text: 'Chef was unable to complete a run, an error during compilation may have occurred.',
637
+ msg_title: "Chef failed during compile phase on #{@node.name} "),
620
638
  )).to have_been_made.times(1)
621
639
  end
622
640
  end
@@ -734,6 +752,31 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
734
752
  expect(handler.send(:endpoints)).to eq(triplets[0..1])
735
753
  end
736
754
  end
755
+
756
+ context 'when using api url instead of url' do
757
+ it 'returns available triplets' do
758
+ triplets = [
759
+ ['https://app.datadoghq.com', 'api_key_2' , 'app_key_2'],
760
+ ['https://app.example.com', 'api_key_3', 'app_key_3'],
761
+ ['https://app.example.com', 'api_key_4', 'app_key_4']
762
+ ]
763
+ handler = Chef::Handler::Datadog.new api_key: triplets[0][1],
764
+ application_key: triplets[0][2],
765
+ url: triplets[0][0],
766
+ extra_endpoints: [{
767
+ api_url: triplets[1][0],
768
+ url: triplets[0][0],
769
+ api_key: triplets[1][1],
770
+ application_key: triplets[1][2]
771
+ }, {
772
+ api_url: triplets[2][0],
773
+ url:triplets[0][0],
774
+ api_key: triplets[2][1],
775
+ application_key: triplets[2][2]
776
+ }]
777
+ expect(handler.send(:endpoints)).to eq(triplets)
778
+ end
779
+ end
737
780
  end
738
781
 
739
782
  context 'when reporting to multiple endpoints' do
@@ -744,17 +787,29 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
744
787
  let(:host_tag_endpoint2) { base_url2 + '/api/v1/tags/hosts/' }
745
788
  let(:metrics_endpoint2) { base_url2 + '/api/v1/series' }
746
789
  let(:handler) do
747
- Chef::Handler::Datadog.new api_key: API_KEY,
748
- application_key: APPLICATION_KEY,
749
- url: BASE_URL,
750
- extra_endpoints: [{
751
- api_key: api_key2,
752
- application_key: application_key2,
753
- url: base_url2
754
- }]
790
+ Chef::Handler::Datadog.new(api_key: API_KEY,
791
+ application_key: APPLICATION_KEY,
792
+ url: BASE_URL,
793
+ extra_endpoints: [{
794
+ api_key: api_key2,
795
+ application_key: application_key2,
796
+ url: base_url2
797
+ }])
798
+ end
799
+
800
+ let(:dogs) do
801
+ handler.instance_variable_get(:@dogs)
755
802
  end
803
+
756
804
  # Construct a good run_status
757
805
  before(:each) do
806
+ dogs.each do |dog|
807
+ # Define mock functions to avoid failures when connecting to the app.example.com endpoint
808
+ allow(dog).to receive(:emit_point).and_return(true)
809
+ allow(dog).to receive(:emit_event).and_return([200, "{'event': 'My event'}"])
810
+ allow(dog).to receive(:update_tags).and_return([201, "Created"])
811
+ end
812
+
758
813
  @node = Chef::Node.build('chef.handler.datadog.test')
759
814
  @node.send(:chef_environment, 'testing')
760
815
  @events = Chef::EventDispatch::Dispatcher.new
@@ -767,56 +822,51 @@ describe Chef::Handler::Datadog, :vcr => :new_episodes do
767
822
  @run_status.stop_clock
768
823
 
769
824
  @run_status.run_context = @run_context
825
+ end
770
826
 
771
- # Run the report
772
- handler.run_report_unsafe(@run_status)
827
+ it 'should create multiple Dogapi clients' do
828
+ expect(dogs.length).to eq(2)
773
829
  end
774
830
 
775
831
  context 'emits metrics' do
776
- it 'reports metrics' do
777
- expect(a_request(:post, METRICS_ENDPOINT).with(
778
- :query => { 'api_key' => API_KEY }
779
- )).to have_been_made.times(5)
832
+ it 'reports metrics to the first endpoint' do
833
+ expect(dogs[0]).to receive(:emit_point).exactly(5).times
780
834
 
781
- expect(a_request(:post, metrics_endpoint2).with(
782
- :query => { 'api_key' => api_key2 }
783
- )).to have_been_made.times(5)
835
+ handler.run_report_unsafe(@run_status)
836
+ end
837
+
838
+ it 'reports metrics to the second endpoint' do
839
+ expect(dogs[1]).to receive(:emit_point).exactly(5).times
840
+
841
+ handler.run_report_unsafe(@run_status)
784
842
  end
785
843
  end
786
844
 
787
845
  context 'emits events' do
788
- it 'posts an event' do
789
- expect(a_request(:post, EVENTS_ENDPOINT).with(
790
- :query => { 'api_key' => API_KEY },
791
- :body => hash_including(:msg_text => 'Chef updated 0 resources out of 0 resources total.'),
792
- :body => hash_including(:msg_title => "Chef completed in 5 seconds on #{@node.name} "),
793
- :body => hash_including(:tags => ['env:testing']),
794
- )).to have_been_made.times(1)
846
+ it 'posts an event to the first endpoint' do
847
+ expect(dogs[0]).to receive(:emit_event).exactly(:once)
795
848
 
796
- expect(a_request(:post, events_endpoint2).with(
797
- :query => { 'api_key' => api_key2 },
798
- :body => hash_including(:msg_text => 'Chef updated 0 resources out of 0 resources total.'),
799
- :body => hash_including(:msg_title => "Chef completed in 5 seconds on #{@node.name} "),
800
- :body => hash_including(:tags => ['env:testing']),
801
- )).to have_been_made.times(1)
849
+ handler.run_report_unsafe(@run_status)
850
+ end
851
+
852
+ it 'posts an event to the second endpoint' do
853
+ expect(dogs[1]).to receive(:emit_event).exactly(:once)
854
+
855
+ handler.run_report_unsafe(@run_status)
802
856
  end
803
857
  end
804
858
 
805
859
  context 'sets tags' do
806
- it 'puts the tags for the current node' do
807
- expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
808
- :query => { 'api_key' => API_KEY,
809
- 'application_key' => APPLICATION_KEY,
810
- 'source' => 'chef' },
811
- :body => { 'tags' => ['env:testing'] },
812
- )).to have_been_made.times(1)
860
+ it 'puts the tags for the current node on the first endpoint' do
861
+ expect(dogs[0]).to receive(:update_tags).exactly(:once)
813
862
 
814
- expect(a_request(:put, host_tag_endpoint2 + @node.name).with(
815
- :query => { 'api_key' => api_key2,
816
- 'application_key' => application_key2,
817
- 'source' => 'chef' },
818
- :body => { 'tags' => ['env:testing'] },
819
- )).to have_been_made.times(1)
863
+ handler.run_report_unsafe(@run_status)
864
+ end
865
+
866
+ it 'puts the tags for the current node on the second endpoint' do
867
+ expect(dogs[1]).to receive(:update_tags).exactly(:once)
868
+
869
+ handler.run_report_unsafe(@run_status)
820
870
  end
821
871
  end
822
872
  end