chef-handler-datadog 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +9 -9
  2. data/.gitignore +4 -3
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +36 -0
  5. data/.travis.yml +7 -2
  6. data/Appraisals +24 -0
  7. data/CHANGELOG.md +23 -0
  8. data/Gemfile +7 -1
  9. data/README.md +16 -3
  10. data/Rakefile +7 -7
  11. data/chef-handler-datadog.gemspec +17 -12
  12. data/gemfiles/chef_10.14.0.gemfile +12 -0
  13. data/gemfiles/chef_10.26.0.gemfile +13 -0
  14. data/gemfiles/chef_10.30.2.gemfile +12 -0
  15. data/gemfiles/chef_11.8.2.gemfile +13 -0
  16. data/lib/chef-handler-datadog.rb +4 -1
  17. data/lib/chef/handler/datadog.rb +112 -89
  18. data/spec/datadog_spec.rb +279 -0
  19. data/spec/spec_helper.rb +48 -0
  20. data/spec/support/cassettes/Chef_Handler_Datadog/failed_Chef_run/sets_event_title_correctly.yml +218 -0
  21. data/spec/support/cassettes/Chef_Handler_Datadog/failed_Chef_run/sets_priority_correctly.yml +218 -0
  22. data/spec/support/cassettes/Chef_Handler_Datadog/handles_no_application_key/fails_when_no_application_key_is_provided.yml +142 -0
  23. data/spec/support/cassettes/Chef_Handler_Datadog/handles_tags_correctly/sets_the_role_and_env_and_tags.yml +215 -0
  24. 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 +214 -0
  25. data/spec/support/cassettes/Chef_Handler_Datadog/reports_correct_hostname_on_an_ec2_node/uses_the_instance_id_when_config_is_specified.yml +214 -0
  26. data/spec/support/cassettes/Chef_Handler_Datadog/reports_correct_hostname_on_an_ec2_node/uses_the_instance_id_when_no_config_specified.yml +214 -0
  27. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/emits_events/posts_an_event.yml +214 -0
  28. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/emits_events/sets_priority_correctly.yml +214 -0
  29. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/emits_metrics/reports_metrics.yml +214 -0
  30. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/get_and_set_tags/gets_the_tags_for_the_current_node.yml +214 -0
  31. data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/get_and_set_tags/puts_the_tags_for_the_current_node.yml +214 -0
  32. data/spec/support/cassettes/Chef_Handler_Datadog/updated_resources/posts_an_event.yml +217 -0
  33. metadata +102 -15
  34. data/gemfiles/Gemfile.chef-10 +0 -5
  35. data/gemfiles/Gemfile.chef-11 +0 -5
  36. data/test/helper.rb +0 -18
  37. data/test/test_chef-handler-datadog.rb +0 -7
@@ -0,0 +1,279 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe Chef::Handler::Datadog, :vcr => :new_episodes do
5
+ # The #report method currently long and clunky, and we need to simulate a
6
+ # Chef run to test all aspects of this, as well as push values into the test.
7
+ before(:all) do
8
+ # This is used in validating that requests have actually been made,
9
+ # as in a 'Fucntional test'. We've recorded the tests with VCR, and use
10
+ # these to assert that the final product is correct. This is also
11
+ # exercising the API client, which may be helpful as well.
12
+ # There is a fair amount of duplication in the repsonse returned.
13
+ BASE_URL = 'https://app.datadoghq.com'
14
+ EVENTS_ENDPOINT = BASE_URL + '/api/v1/events'
15
+ HOST_TAG_ENDPOINT = BASE_URL + '/api/v1/tags/hosts/'
16
+ METRICS_ENDPOINT = BASE_URL + '/api/v1/series'
17
+ end
18
+
19
+ before(:each) do
20
+ @handler = Chef::Handler::Datadog.new(
21
+ :api_key => API_KEY,
22
+ :application_key => APPLICATION_KEY,
23
+ )
24
+ end
25
+
26
+ describe 'reports metrics event and sets tags' do
27
+ # Construct a good run_status
28
+ before(:each) do
29
+ @node = Chef::Node.build('chef.handler.datadog.test')
30
+ @node.send(:chef_environment, 'testing')
31
+ @events = Chef::EventDispatch::Dispatcher.new
32
+ @run_context = Chef::RunContext.new(@node, {}, @events)
33
+ @run_status = Chef::RunStatus.new(@node, @events)
34
+
35
+ @expected_time = Time.now
36
+ Time.stub(:now).and_return(@expected_time, @expected_time + 5)
37
+ @run_status.start_clock
38
+ @run_status.stop_clock
39
+
40
+ @run_status.run_context = @run_context
41
+
42
+ # Run the report
43
+ @handler.run_report_unsafe(@run_status)
44
+ end
45
+
46
+ context 'emits metrics' do
47
+ it 'reports metrics' do
48
+ expect(a_request(:post, METRICS_ENDPOINT).with(
49
+ :query => { 'api_key' => @handler.config[:api_key] }
50
+ )).to have_been_made.times(3)
51
+ end
52
+ end
53
+
54
+ context 'emits events' do
55
+ it 'posts an event' do
56
+ expect(a_request(:post, EVENTS_ENDPOINT).with(
57
+ :query => { 'api_key' => @handler.config[:api_key] },
58
+ :body => hash_including(:msg_text => 'Chef updated 0 resources out of 0 resources total.'),
59
+ :body => hash_including(:msg_title => "Chef completed in 5 seconds on #{@node.name} "),
60
+ )).to have_been_made.times(1)
61
+ end
62
+
63
+ it 'sets priority correctly' do
64
+ expect(a_request(:post, EVENTS_ENDPOINT).with(
65
+ :query => { 'api_key' => @handler.config[:api_key] },
66
+ :body => hash_including(:priority => 'low'),
67
+ )).to have_been_made.times(1)
68
+ end
69
+ end
70
+
71
+ context 'get and set tags' do
72
+ it 'gets the tags for the current node' do
73
+ expect(a_request(:get, HOST_TAG_ENDPOINT + @node.name).with(
74
+ :query => { 'api_key' => @handler.config[:api_key],
75
+ 'application_key' => @handler.config[:application_key] },
76
+ )).to have_been_made.times(1)
77
+ end
78
+
79
+ it 'puts the tags for the current node' do
80
+ expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
81
+ :query => { 'api_key' => @handler.config[:api_key],
82
+ 'application_key' => @handler.config[:application_key] },
83
+ :body => { 'tags' => ['env:testing'] },
84
+ )).to have_been_made.times(1)
85
+ end
86
+ end
87
+ end
88
+
89
+ describe 'reports correct hostname on an ec2 node' do
90
+ before(:each) do
91
+ @node = Chef::Node.build('chef.handler.datadog.test-ec2')
92
+ @node.send(:chef_environment, 'testing')
93
+
94
+ @node.automatic_attrs['ec2'] = { :instance_id => 'i-123456' }
95
+
96
+ @run_context = Chef::RunContext.new(@node, {}, @events)
97
+ @run_status = Chef::RunStatus.new(@node, @events)
98
+ @expected_time = Time.now
99
+ Time.stub(:now).and_return(@expected_time, @expected_time + 5)
100
+ @run_status.start_clock
101
+ @run_status.stop_clock
102
+ @run_status.run_context = @run_context
103
+ end
104
+
105
+ it 'uses the instance id when no config specified' do
106
+ @handler.run_report_unsafe(@run_status)
107
+
108
+ expect(a_request(:post, EVENTS_ENDPOINT).with(
109
+ :query => { 'api_key' => @handler.config[:api_key] },
110
+ :body => hash_including(:msg_title => 'Chef completed in 5 seconds on i-123456 '),
111
+ :body => hash_including(:host => 'i-123456'),
112
+ )).to have_been_made.times(1)
113
+ end
114
+
115
+ it 'uses the instance id when config is specified' do
116
+ @handler.config[:use_ec2_instance_id] = true
117
+ @handler.run_report_unsafe(@run_status)
118
+
119
+ expect(a_request(:post, EVENTS_ENDPOINT).with(
120
+ :query => { 'api_key' => @handler.config[:api_key] },
121
+ :body => hash_including(:msg_title => 'Chef completed in 5 seconds on i-123456 '),
122
+ :body => hash_including(:host => 'i-123456'),
123
+ )).to have_been_made.times(1)
124
+ end
125
+
126
+ it 'does not use the instance id when config specified to false' do
127
+ @handler.config[:use_ec2_instance_id] = false
128
+ @handler.run_report_unsafe(@run_status)
129
+
130
+ expect(a_request(:post, EVENTS_ENDPOINT).with(
131
+ :query => { 'api_key' => @handler.config[:api_key] },
132
+ :body => hash_including(:msg_title => "Chef completed in 5 seconds on #{@node.name} "),
133
+ :body => hash_including(:host => @node.name),
134
+ )).to have_been_made.times(1)
135
+ end
136
+ end
137
+
138
+ describe 'handles tags correctly' do
139
+ before(:each) do
140
+ @node = Chef::Node.build('chef.handler.datadog.test-tags')
141
+
142
+ @node.send(:chef_environment, 'hostile')
143
+ @node.send(:run_list, 'role[highlander]')
144
+ @node.normal.tags = ['the_one_and_only']
145
+
146
+ @events = Chef::EventDispatch::Dispatcher.new
147
+ @run_context = Chef::RunContext.new(@node, {}, @events)
148
+ @run_status = Chef::RunStatus.new(@node, @events)
149
+
150
+ @expected_time = Time.now
151
+ Time.stub(:now).and_return(@expected_time, @expected_time + 5)
152
+ @run_status.start_clock
153
+ @run_status.stop_clock
154
+
155
+ @run_status.run_context = @run_context
156
+
157
+ # Run the report
158
+ @handler.run_report_unsafe(@run_status)
159
+ end
160
+
161
+ it 'sets the role and env and tags' do
162
+ expect(a_request(:put, HOST_TAG_ENDPOINT + @node.name).with(
163
+ :query => { 'api_key' => @handler.config[:api_key],
164
+ 'application_key' => @handler.config[:application_key] },
165
+ :body => hash_including(:tags => [
166
+ 'env:hostile', 'role:highlander', 'tag:the_one_and_only'
167
+ ]),
168
+ )).to have_been_made.times(1)
169
+ end
170
+ end
171
+
172
+ describe 'handles no application_key' do
173
+ before(:each) do
174
+ @node = Chef::Node.build('chef.handler.datadog.test-noapp')
175
+
176
+ @node.send(:chef_environment, 'hostile')
177
+ @node.send(:run_list, 'role[highlander]')
178
+ @node.normal.tags = ['the_one_and_only']
179
+
180
+ @events = Chef::EventDispatch::Dispatcher.new
181
+ @run_context = Chef::RunContext.new(@node, {}, @events)
182
+ @run_status = Chef::RunStatus.new(@node, @events)
183
+
184
+ @expected_time = Time.now
185
+ Time.stub(:now).and_return(@expected_time, @expected_time + 5)
186
+ @run_status.start_clock
187
+ @run_status.stop_clock
188
+
189
+ @run_status.run_context = @run_context
190
+ end
191
+
192
+ it 'fails when no application key is provided' do
193
+ @handler.config[:application_key] = nil
194
+
195
+ # TODO: figure out how to capture output of Chef::Log
196
+ # Run the report, catch the error
197
+ expect { @handler.run_report_unsafe(@run_status) }.to raise_error
198
+ end
199
+ end
200
+
201
+ describe 'failed Chef run' do
202
+ before(:each) do
203
+ @node = Chef::Node.build('chef.handler.datadog.test-failed')
204
+
205
+ @node.send(:chef_environment, 'hostile')
206
+ @node.send(:run_list, 'role[highlander]')
207
+ @node.normal.tags = ['the_one_and_only']
208
+
209
+ @events = Chef::EventDispatch::Dispatcher.new
210
+ @run_context = Chef::RunContext.new(@node, {}, @events)
211
+ @run_status = Chef::RunStatus.new(@node, @events)
212
+
213
+ @expected_time = Time.now
214
+ Time.stub(:now).and_return(@expected_time, @expected_time + 2)
215
+ @run_status.start_clock
216
+ @run_status.stop_clock
217
+
218
+ @run_status.run_context = @run_context
219
+
220
+ # Construct an exception
221
+ exception = Chef::Exceptions::UnsupportedAction.new('Something awry.')
222
+ exception.set_backtrace(['file.rb:2', 'file.rb:1'])
223
+ @run_status.exception = exception
224
+
225
+ # Run the report
226
+ @handler.run_report_unsafe(@run_status)
227
+ end
228
+
229
+ it 'sets event title correctly' do
230
+ expect(a_request(:post, EVENTS_ENDPOINT).with(
231
+ :query => { 'api_key' => @handler.config[:api_key] },
232
+ :body => hash_including(:msg_title => "Chef failed in 2 seconds on #{@node.name} "),
233
+ )).to have_been_made.times(1)
234
+ end
235
+
236
+ it 'sets priority correctly' do
237
+ expect(a_request(:post, EVENTS_ENDPOINT).with(
238
+ :query => { 'api_key' => @handler.config[:api_key] },
239
+ :body => hash_including(:alert_type => 'success'),
240
+ :body => hash_including(:priority => 'normal'),
241
+ )).to have_been_made.times(1)
242
+ end
243
+ end
244
+
245
+ describe 'updated resources' do
246
+ before(:each) do
247
+ @node = Chef::Node.build('chef.handler.datadog.test-resources')
248
+ @node.send(:chef_environment, 'resources')
249
+ @events = Chef::EventDispatch::Dispatcher.new
250
+ @run_context = Chef::RunContext.new(@node, {}, @events)
251
+ @run_status = Chef::RunStatus.new(@node, @events)
252
+
253
+ all_resources = [Chef::Resource.new('whiskers'), Chef::Resource.new('paws')]
254
+ all_resources.first.updated_by_last_action(true)
255
+ @run_context.resource_collection.all_resources.replace(all_resources)
256
+
257
+ @expected_time = Time.now
258
+ Time.stub(:now).and_return(@expected_time, @expected_time + 8)
259
+ @run_status.start_clock
260
+ @run_status.stop_clock
261
+
262
+ @run_status.run_context = @run_context
263
+
264
+ # Run the report
265
+ @handler.run_report_unsafe(@run_status)
266
+ end
267
+
268
+ it 'posts an event' do
269
+ expect(a_request(:post, EVENTS_ENDPOINT).with(
270
+ :query => { 'api_key' => @handler.config[:api_key] },
271
+ :body => hash_including(:msg_text => 'Chef updated 1 resources out of 2 resources total.'),
272
+ :body => hash_including(:msg_title => "Chef completed in 8 seconds on #{@node.name} "),
273
+ )).to have_been_made.times(1)
274
+ end
275
+ end
276
+
277
+ # TODO: test failures:
278
+ # @run_status.exception = Exception.new('Boy howdy!')
279
+ end
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+
5
+ require 'dotenv'
6
+ require 'rspec'
7
+ require 'vcr'
8
+ require 'webmock/rspec'
9
+
10
+ # Include our code
11
+ require 'chef/handler/datadog'
12
+
13
+ # Load credentials from .env
14
+ Dotenv.load
15
+
16
+ API_KEY = ENV['API_KEY']
17
+ APPLICATION_KEY = ENV['APPLICATION_KEY']
18
+
19
+ RSpec.configure do |config|
20
+ config.treat_symbols_as_metadata_keys_with_true_values = true
21
+ config.run_all_when_everything_filtered = true
22
+ config.filter_run :focus
23
+
24
+ # Run specs in random order to surface order dependencies. If you find an
25
+ # order dependency and want to debug it, you can fix the order by providing
26
+ # the seed, which is printed after each run.
27
+ # --seed 1234
28
+ config.order = 'random'
29
+ end
30
+
31
+ VCR.configure do |c|
32
+ c.cassette_library_dir = 'spec/support/cassettes'
33
+ c.configure_rspec_metadata!
34
+ c.default_cassette_options = {
35
+ :record => :once,
36
+ # :record => :new_episodes, # uncomment during development
37
+ }
38
+
39
+ # Remove any test-specific data
40
+ c.before_record do |i|
41
+ i.response.headers.delete('Set-Cookie')
42
+ i.response.headers.delete('X-Dd-Version')
43
+ end
44
+ c.filter_sensitive_data('<API_KEY>') { API_KEY }
45
+ c.filter_sensitive_data('<APPLICATION_KEY>') { APPLICATION_KEY }
46
+
47
+ c.hook_into :webmock
48
+ end
@@ -0,0 +1,218 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://app.datadoghq.com/api/v1/series?api_key=<API_KEY>
6
+ body:
7
+ encoding: UTF-8
8
+ string: ! '{"series":[{"metric":"chef.resources.total","points":[[1390096494,0.0]],"type":"gauge","host":"chef.handler.datadog.test-failed","device":null}]}'
9
+ headers:
10
+ Accept:
11
+ - ! '*/*'
12
+ User-Agent:
13
+ - Ruby
14
+ Content-Type:
15
+ - application/json
16
+ response:
17
+ status:
18
+ code: 202
19
+ message: Accepted
20
+ headers:
21
+ Content-Type:
22
+ - text/json; charset=UTF-8
23
+ Date:
24
+ - Sun, 19 Jan 2014 01:54:44 GMT
25
+ Server:
26
+ - dogdispatcher/4.10.0
27
+ Content-Length:
28
+ - '15'
29
+ Connection:
30
+ - keep-alive
31
+ body:
32
+ encoding: US-ASCII
33
+ string: ! '{"status":"ok"}'
34
+ http_version:
35
+ recorded_at: Sun, 19 Jan 2014 01:54:54 GMT
36
+ - request:
37
+ method: post
38
+ uri: https://app.datadoghq.com/api/v1/series?api_key=<API_KEY>
39
+ body:
40
+ encoding: UTF-8
41
+ string: ! '{"series":[{"metric":"chef.resources.updated","points":[[1390096494,0.0]],"type":"gauge","host":"chef.handler.datadog.test-failed","device":null}]}'
42
+ headers:
43
+ Accept:
44
+ - ! '*/*'
45
+ User-Agent:
46
+ - Ruby
47
+ Content-Type:
48
+ - application/json
49
+ response:
50
+ status:
51
+ code: 202
52
+ message: Accepted
53
+ headers:
54
+ Content-Type:
55
+ - text/json; charset=UTF-8
56
+ Date:
57
+ - Sun, 19 Jan 2014 01:54:48 GMT
58
+ Server:
59
+ - dogdispatcher/4.10.0
60
+ Content-Length:
61
+ - '15'
62
+ Connection:
63
+ - keep-alive
64
+ body:
65
+ encoding: US-ASCII
66
+ string: ! '{"status":"ok"}'
67
+ http_version:
68
+ recorded_at: Sun, 19 Jan 2014 01:54:54 GMT
69
+ - request:
70
+ method: post
71
+ uri: https://app.datadoghq.com/api/v1/series?api_key=<API_KEY>
72
+ body:
73
+ encoding: UTF-8
74
+ string: ! '{"series":[{"metric":"chef.resources.elapsed_time","points":[[1390096494,2.0]],"type":"gauge","host":"chef.handler.datadog.test-failed","device":null}]}'
75
+ headers:
76
+ Accept:
77
+ - ! '*/*'
78
+ User-Agent:
79
+ - Ruby
80
+ Content-Type:
81
+ - application/json
82
+ response:
83
+ status:
84
+ code: 202
85
+ message: Accepted
86
+ headers:
87
+ Content-Type:
88
+ - text/json; charset=UTF-8
89
+ Date:
90
+ - Sun, 19 Jan 2014 01:54:48 GMT
91
+ Server:
92
+ - dogdispatcher/4.10.0
93
+ Content-Length:
94
+ - '15'
95
+ Connection:
96
+ - keep-alive
97
+ body:
98
+ encoding: US-ASCII
99
+ string: ! '{"status":"ok"}'
100
+ http_version:
101
+ recorded_at: Sun, 19 Jan 2014 01:54:54 GMT
102
+ - request:
103
+ method: post
104
+ uri: https://app.datadoghq.com/api/v1/events?api_key=<API_KEY>
105
+ body:
106
+ encoding: UTF-8
107
+ string: ! '{"msg_text":"Chef updated 0 resources out of 0 resources total.\n@@@\nChef::Exceptions::UnsupportedAction:
108
+ Something awry.\n@@@\n\n@@@\nfile.rb:2\nfile.rb:1\n@@@\n","date_happened":1390096494,"msg_title":"Chef
109
+ failed in 2 seconds on chef.handler.datadog.test-failed ","priority":"normal","parent":null,"tags":[],"aggregation_key":"chef.handler.datadog.test-failed","alert_type":"error","event_type":"config_management.run","source_type_name":"chef","title":"Chef
110
+ failed in 2 seconds on chef.handler.datadog.test-failed ","text":"Chef updated
111
+ 0 resources out of 0 resources total.\n@@@\nChef::Exceptions::UnsupportedAction:
112
+ Something awry.\n@@@\n\n@@@\nfile.rb:2\nfile.rb:1\n@@@\n","host":"chef.handler.datadog.test-failed","device":null}'
113
+ headers:
114
+ Accept:
115
+ - ! '*/*'
116
+ User-Agent:
117
+ - Ruby
118
+ Content-Type:
119
+ - application/json
120
+ response:
121
+ status:
122
+ code: 202
123
+ message: Accepted
124
+ headers:
125
+ Content-Type:
126
+ - text/json; charset=UTF-8
127
+ Date:
128
+ - Sun, 19 Jan 2014 01:54:48 GMT
129
+ Server:
130
+ - dogdispatcher/4.10.0
131
+ Content-Length:
132
+ - '474'
133
+ Connection:
134
+ - keep-alive
135
+ body:
136
+ encoding: US-ASCII
137
+ string: ! '{"status": "ok", "event": {"priority": "normal", "date_happened":
138
+ 1390096494, "handle": null, "title": "Chef failed in 2 seconds on chef.handler.datadog.test-failed
139
+ ", "url": "https://app.datadoghq.com/event/jump_to?event_id=2111137870265175278",
140
+ "text": "Chef updated 0 resources out of 0 resources total.\n@@@\nChef::Exceptions::UnsupportedAction:
141
+ Something awry.\n@@@\n\n@@@\nfile.rb:2\nfile.rb:1\n@@@\n", "tags": [], "related_event_id":
142
+ null, "id": 2111137870265175278}}'
143
+ http_version:
144
+ recorded_at: Sun, 19 Jan 2014 01:54:54 GMT
145
+ - request:
146
+ method: get
147
+ uri: https://app.datadoghq.com/api/v1/tags/hosts/chef.handler.datadog.test-failed?api_key=<API_KEY>&application_key=<APPLICATION_KEY>
148
+ body:
149
+ encoding: US-ASCII
150
+ string: ''
151
+ headers:
152
+ Accept:
153
+ - ! '*/*'
154
+ User-Agent:
155
+ - Ruby
156
+ response:
157
+ status:
158
+ code: 200
159
+ message: OK
160
+ headers:
161
+ Cache-Control:
162
+ - no-cache
163
+ Content-Type:
164
+ - application/json
165
+ Date:
166
+ - Sun, 19 Jan 2014 01:54:49 GMT
167
+ Pragma:
168
+ - no-cache
169
+ Server:
170
+ - gunicorn/0.17.4
171
+ Content-Length:
172
+ - '44'
173
+ Connection:
174
+ - keep-alive
175
+ body:
176
+ encoding: US-ASCII
177
+ string: ! '{"tags": ["env:hostile", "role:highlander"]}'
178
+ http_version:
179
+ recorded_at: Sun, 19 Jan 2014 01:54:54 GMT
180
+ - request:
181
+ method: put
182
+ uri: https://app.datadoghq.com/api/v1/tags/hosts/chef.handler.datadog.test-failed?api_key=<API_KEY>&application_key=<APPLICATION_KEY>
183
+ body:
184
+ encoding: UTF-8
185
+ string: ! '{"tags":["env:hostile","role:highlander","tag:the_one_and_only"]}'
186
+ headers:
187
+ Accept:
188
+ - ! '*/*'
189
+ User-Agent:
190
+ - Ruby
191
+ Content-Type:
192
+ - application/json
193
+ response:
194
+ status:
195
+ code: 201
196
+ message: Created
197
+ headers:
198
+ Cache-Control:
199
+ - no-cache
200
+ Content-Type:
201
+ - application/json
202
+ Date:
203
+ - Sun, 19 Jan 2014 01:54:49 GMT
204
+ Pragma:
205
+ - no-cache
206
+ Server:
207
+ - gunicorn/0.17.4
208
+ Content-Length:
209
+ - '88'
210
+ Connection:
211
+ - keep-alive
212
+ body:
213
+ encoding: US-ASCII
214
+ string: ! '{"host": "chef.handler.datadog.test-failed", "tags": ["env:hostile",
215
+ "role:highlander"]}'
216
+ http_version:
217
+ recorded_at: Sun, 19 Jan 2014 01:54:54 GMT
218
+ recorded_with: VCR 2.8.0