chef-handler-datadog 0.12.1 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
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