chef-handler-datadog 0.2.0 → 0.3.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.
- checksums.yaml +9 -9
- data/.gitignore +4 -3
- data/.rspec +1 -0
- data/.rubocop.yml +36 -0
- data/.travis.yml +7 -2
- data/Appraisals +24 -0
- data/CHANGELOG.md +23 -0
- data/Gemfile +7 -1
- data/README.md +16 -3
- data/Rakefile +7 -7
- data/chef-handler-datadog.gemspec +17 -12
- data/gemfiles/chef_10.14.0.gemfile +12 -0
- data/gemfiles/chef_10.26.0.gemfile +13 -0
- data/gemfiles/chef_10.30.2.gemfile +12 -0
- data/gemfiles/chef_11.8.2.gemfile +13 -0
- data/lib/chef-handler-datadog.rb +4 -1
- data/lib/chef/handler/datadog.rb +112 -89
- data/spec/datadog_spec.rb +279 -0
- data/spec/spec_helper.rb +48 -0
- data/spec/support/cassettes/Chef_Handler_Datadog/failed_Chef_run/sets_event_title_correctly.yml +218 -0
- data/spec/support/cassettes/Chef_Handler_Datadog/failed_Chef_run/sets_priority_correctly.yml +218 -0
- data/spec/support/cassettes/Chef_Handler_Datadog/handles_no_application_key/fails_when_no_application_key_is_provided.yml +142 -0
- data/spec/support/cassettes/Chef_Handler_Datadog/handles_tags_correctly/sets_the_role_and_env_and_tags.yml +215 -0
- 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
- 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
- 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
- data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/emits_events/posts_an_event.yml +214 -0
- data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/emits_events/sets_priority_correctly.yml +214 -0
- data/spec/support/cassettes/Chef_Handler_Datadog/reports_metrics_event_and_sets_tags/emits_metrics/reports_metrics.yml +214 -0
- 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
- 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
- data/spec/support/cassettes/Chef_Handler_Datadog/updated_resources/posts_an_event.yml +217 -0
- metadata +102 -15
- data/gemfiles/Gemfile.chef-10 +0 -5
- data/gemfiles/Gemfile.chef-11 +0 -5
- data/test/helper.rb +0 -18
- data/test/test_chef-handler-datadog.rb +0 -7
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NzQzODBiZTM2NjkxZDlhZTQ5OWVhNDAwZWQyODk5ZjY5NjMzMWRkNw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
7
|
-
|
6
|
+
YmI2ZTljMTFjMDQ1YjEzOWJjNzBiNTFkMzMzMzBmY2QyODhjODMxMQ==
|
7
|
+
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZGJiZDVlYTQ3M2RlZjg0ZDNiOTA4OGVmMGEzZDdhOGY4MDkwMmQ4MzAzNWYy
|
10
|
+
NGM5MjJhOWI3MjgxMDNmOTczNmMwM2MwM2U1YjA0MTI3NTJjOThmZWFiZGM4
|
11
|
+
ZDUzYzA1MWQxMWNjODVhZjNlNGZmMTJkYTY3ZGZmNGFkNmYwNGI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZDE4ODE4NTdjMzAxZTgwZTkzM2M5N2Q0ZjExNGFhZTg1MThhOGMyYjAzNTYw
|
14
|
+
NmI1NWI2YWRmM2FmYjNiOGExNzU5MmQzYTU5ODJhMjhlNjI1MDQ5NTYzZDMz
|
15
|
+
NGE4OTBmNTMyYzQzZTEzN2ZiMTU3ZDAzMDEzZGIzMzUzNTk0MTA=
|
data/.gitignore
CHANGED
@@ -29,9 +29,6 @@ pkg
|
|
29
29
|
#
|
30
30
|
.DS_Store
|
31
31
|
|
32
|
-
# For RVM
|
33
|
-
.rvmrc
|
34
|
-
|
35
32
|
# For TextMate
|
36
33
|
*.tmproj
|
37
34
|
# tmtags
|
@@ -53,8 +50,12 @@ pkg
|
|
53
50
|
json
|
54
51
|
rake
|
55
52
|
Gemfile.lock
|
53
|
+
gemfiles/*.lock
|
56
54
|
|
57
55
|
# For Ruby Managers:
|
58
56
|
.ruby-gemset
|
59
57
|
.ruby-version
|
60
58
|
.rvmrc
|
59
|
+
|
60
|
+
# Any environment-specific files
|
61
|
+
.env
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
AllCops:
|
2
|
+
Includes:
|
3
|
+
- chef-handler-datadog.gemspec
|
4
|
+
- Appraisals
|
5
|
+
- Gemfile
|
6
|
+
- Rakefile
|
7
|
+
|
8
|
+
# We want to continue to support Ruby 1.8.x for now
|
9
|
+
HashSyntax:
|
10
|
+
EnforcedStyle: hash_rockets
|
11
|
+
|
12
|
+
# 80 characters is a nice goal, but not worth currently changing in existing
|
13
|
+
# code for the sake of changing it to conform to a length set in 1928 (IBM).
|
14
|
+
LineLength:
|
15
|
+
Max: 150
|
16
|
+
|
17
|
+
#####
|
18
|
+
# These exceptions are good goals to attain, and probably will over time,
|
19
|
+
# so periodic disabling and re-running to inspect values is suggested.
|
20
|
+
|
21
|
+
# TODO: Main class is currently over 100 lines of code, making comprehending
|
22
|
+
# it harder. With refactors and simplifications, we can bring this down,
|
23
|
+
# but for now, let's not make it too much worse.
|
24
|
+
ClassLength:
|
25
|
+
Max: 160
|
26
|
+
|
27
|
+
# TODO: this is currently down to 12 from 22, and should be a constant
|
28
|
+
# goal to reduce method complexity. The accepted goal is 6.
|
29
|
+
CyclomaticComplexity:
|
30
|
+
Max: 12
|
31
|
+
|
32
|
+
# TODO: The main method `report` is now down from 85 lines. As refactors
|
33
|
+
# continue, this should drop. However, the goal of 10 lines in a method may
|
34
|
+
# be a little lofty.
|
35
|
+
MethodLength:
|
36
|
+
Max: 78
|
data/.travis.yml
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
3
|
- 1.9.3
|
4
|
+
bundler_args: --without=localdev
|
4
5
|
gemfile:
|
5
|
-
- gemfiles/
|
6
|
-
- gemfiles/
|
6
|
+
- gemfiles/chef_10.14.0.gemfile
|
7
|
+
- gemfiles/chef_10.26.0.gemfile
|
8
|
+
- gemfiles/chef_10.30.2.gemfile
|
9
|
+
- gemfiles/chef_11.8.2.gemfile
|
10
|
+
env:
|
11
|
+
- API_KEY=somefakeapikey APPLICATION_KEY=somefakeapplicationkey
|
data/Appraisals
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Describe any version dependencies here.
|
4
|
+
|
5
|
+
%w(
|
6
|
+
10.14.0
|
7
|
+
10.30.2
|
8
|
+
).each do |tv|
|
9
|
+
appraise "chef-#{tv}" do
|
10
|
+
gem 'chef', tv
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Due to some oddity in json gem version pinning for versions that have
|
15
|
+
# conflicts, specify best version here.
|
16
|
+
%w(
|
17
|
+
10.26.0
|
18
|
+
11.8.2
|
19
|
+
).each do |tv|
|
20
|
+
appraise "chef-#{tv}" do
|
21
|
+
gem 'chef', tv
|
22
|
+
gem 'json', '1.7.7'
|
23
|
+
end
|
24
|
+
end
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
Changes
|
2
2
|
=======
|
3
|
+
|
4
|
+
# 0.3.0 / 2014-01-23
|
5
|
+
|
6
|
+
* [MISC] **Breaking Change**: Chef 0.9.x is no longer supported. Extra code implemented for 0.9 versions has been removed. [@miketheman][]
|
7
|
+
* [BUGFIX] Report correct response when failing to submit tags, [#39][] [@miketheman][]
|
8
|
+
* [OPTIMIZE] Refactor hostname resolution to its own method, simplify `report` method. [@miketheman][]
|
9
|
+
* [OPTIMIZE] Refactor metrics reporting to its own method, simplify `report` method. [@miketheman][]
|
10
|
+
* [OPTIMIZE] Refactor tagging get/set to own methods, simplify `report` method. [@miketheman][]
|
11
|
+
* [MISC] Converted `opts` to an instance variable of `config` to reduce the amount of instance variables passing around. [@miketheman][]
|
12
|
+
* [OPTIMIZE] Don't try to tag node when Application Key isn't provided, [#31][] [@miketheman][]
|
13
|
+
* [OPTIMIZE] Only load in the parts of the Chef gem that are used. [@miketheman][]
|
14
|
+
* [OPTIMIZE] Change order in which event_data is constructed, to not lose the full backtrace, [#37][] [@miketheman][]
|
15
|
+
|
16
|
+
Testing suite: [#18][], [@miketheman][]
|
17
|
+
* Removed Tailor testing in favor of Rubocop
|
18
|
+
* Added Appraisals with specific Chef versions to be tested
|
19
|
+
* Added RSpec testing via VCR and Webmock
|
20
|
+
|
3
21
|
# 0.2.0 / 2013-10-31
|
4
22
|
|
5
23
|
* [BUGFIX] moved Chef gem dependency to development, [#34][] [@miketheman][]
|
@@ -10,8 +28,13 @@ Changes
|
|
10
28
|
# 0.1.2 / 2013-04-03
|
11
29
|
|
12
30
|
And all other versions were prior to this. See git history for more.
|
31
|
+
|
13
32
|
<!--- The following link definition list is generated by PimpMyChangelog --->
|
33
|
+
[#18]: https://github.com/DataDog/chef-handler-datadog/issues/18
|
34
|
+
[#31]: https://github.com/DataDog/chef-handler-datadog/issues/31
|
14
35
|
[#34]: https://github.com/DataDog/chef-handler-datadog/issues/34
|
36
|
+
[#37]: https://github.com/DataDog/chef-handler-datadog/issues/37
|
37
|
+
[#39]: https://github.com/DataDog/chef-handler-datadog/issues/39
|
15
38
|
[@alq]: https://github.com/alq
|
16
39
|
[@miketheman]: https://github.com/miketheman
|
17
40
|
[@remh]: https://github.com/remh
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,10 @@
|
|
2
2
|
|
3
3
|
An Exception and Report Handler for Chef.
|
4
4
|
|
5
|
+
[](http://badge.fury.io/rb/chef-handler-datadog)
|
5
6
|
[](http://travis-ci.org/DataDog/chef-handler-datadog)
|
7
|
+
[](https://codeclimate.com/github/DataDog/chef-handler-datadog)
|
8
|
+
[](https://gemnasium.com/DataDog/chef-handler-datadog)
|
6
9
|
|
7
10
|
## Using chef-handler-datadog
|
8
11
|
|
@@ -10,14 +13,24 @@ The Datadog Docs on [Chef](http://docs.datadoghq.com/guides/chef/#deployhandler)
|
|
10
13
|
|
11
14
|
## Contributing to chef-handler-datadog
|
12
15
|
|
13
|
-
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
16
|
+
* Check out the latest `master` to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
14
17
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
15
18
|
* Fork the project
|
16
19
|
* Start a feature/bugfix branch
|
20
|
+
* Place a `.env` file in the root of the project with `API_KEY` and `APPLICATION_KEY`:
|
21
|
+
|
22
|
+
API_KEY: myapikey
|
23
|
+
APPLICATION_KEY: chefhandlerspecificapplicationkey
|
24
|
+
|
25
|
+
This file is intentionally .gitignored to prevent security exposure.
|
26
|
+
|
27
|
+
* Run `rake` to execute tests, ensure they pass
|
17
28
|
* Commit and push until you are happy with your contribution
|
18
29
|
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
19
|
-
* Please try not to mess with the Rakefile
|
30
|
+
* Please try not to mess with the `Rakefile`, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
20
31
|
|
21
32
|
## Copyright
|
22
33
|
|
23
|
-
Copyright (c) 2012-
|
34
|
+
Copyright (c) 2012-2014 Datadog, Inc. See LICENSE.txt for further details.
|
35
|
+
|
36
|
+
[](https://bitdeli.com/free "Bitdeli Badge")
|
data/Rakefile
CHANGED
@@ -3,15 +3,15 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'bundler/gem_tasks'
|
5
5
|
|
6
|
+
require 'appraisal'
|
7
|
+
require 'rake/clean'
|
6
8
|
require 'rspec/core/rake_task'
|
7
|
-
require '
|
9
|
+
require 'rubocop/rake_task'
|
8
10
|
|
9
|
-
task :default => :
|
11
|
+
task :default => [:cops, :spec]
|
12
|
+
|
13
|
+
CLEAN.include(['coverage/', 'doc/', 'pkg/'])
|
10
14
|
|
11
15
|
RSpec::Core::RakeTask.new(:spec)
|
12
16
|
|
13
|
-
|
14
|
-
task.file_set('lib/**/*.rb', "code") do |style|
|
15
|
-
style.max_line_length 160, :level => :warn
|
16
|
-
end
|
17
|
-
end
|
17
|
+
Rubocop::RakeTask.new(:cops)
|
@@ -1,28 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
require File.expand_path('../lib/chef-handler-datadog', __FILE__)
|
2
3
|
|
3
4
|
Gem::Specification.new do |gem|
|
4
|
-
gem.name =
|
5
|
+
gem.name = 'chef-handler-datadog'
|
5
6
|
gem.summary = %q{Chef Handler for DataDog events and metrics}
|
6
7
|
gem.description = %q{This Handler will report the events and metrics for a chef-client run to DataDog.}
|
7
|
-
gem.license =
|
8
|
+
gem.license = 'BSD'
|
8
9
|
gem.version = ChefHandlerDatadog::VERSION
|
9
10
|
|
10
|
-
gem.files = `git ls-files`.split($\)
|
11
|
-
gem.executables = gem.files.grep(
|
12
|
-
gem.test_files = gem.files.grep(
|
11
|
+
gem.files = `git ls-files`.split($\) # rubocop:disable SpecialGlobalVars
|
12
|
+
gem.executables = gem.files.grep(/^bin\//).map { |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(/^(test|spec|features)\//)
|
13
14
|
gem.require_paths = ['lib']
|
14
15
|
gem.extra_rdoc_files = ['README.md', 'LICENSE.txt']
|
15
16
|
|
16
|
-
gem.add_dependency 'dogapi',
|
17
|
+
gem.add_dependency 'dogapi', '>= 1.2'
|
17
18
|
|
19
|
+
gem.add_development_dependency 'appraisal', '~> 1.0.0.beta2'
|
18
20
|
gem.add_development_dependency 'bundler'
|
19
|
-
gem.add_development_dependency 'chef',
|
21
|
+
gem.add_development_dependency 'chef', '>= 10', '<= 12'
|
22
|
+
gem.add_development_dependency 'dotenv'
|
20
23
|
gem.add_development_dependency 'rake'
|
21
24
|
gem.add_development_dependency 'rspec'
|
22
|
-
gem.add_development_dependency '
|
23
|
-
gem.add_development_dependency '
|
25
|
+
gem.add_development_dependency 'rubocop'
|
26
|
+
gem.add_development_dependency 'simplecov'
|
27
|
+
gem.add_development_dependency 'vcr'
|
28
|
+
gem.add_development_dependency 'webmock'
|
24
29
|
|
25
|
-
gem.authors = [
|
26
|
-
gem.email = [
|
27
|
-
gem.homepage =
|
30
|
+
gem.authors = ['Mike Fiedler', 'Adam Jacob', 'Alexis Le-Quoc']
|
31
|
+
gem.email = ['package@datadoghq.com']
|
32
|
+
gem.homepage = 'http://www.datadoghq.com/'
|
28
33
|
end
|
data/lib/chef-handler-datadog.rb
CHANGED
data/lib/chef/handler/datadog.rb
CHANGED
@@ -1,82 +1,72 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
require 'rubygems'
|
2
|
-
require 'chef'
|
3
3
|
require 'chef/handler'
|
4
4
|
require 'dogapi'
|
5
5
|
|
6
6
|
class Chef
|
7
7
|
class Handler
|
8
|
+
# Datadog handler to send Chef run details to Datadog
|
8
9
|
class Datadog < Chef::Handler
|
10
|
+
attr_reader :config
|
9
11
|
|
10
12
|
# For the tags to work, the client must have created an Application Key on the
|
11
13
|
# "Account Settings" page here: https://app.datadoghq.com/account/settings
|
12
14
|
# It should be passed along from the node/role/environemnt attributes, as the default is nil.
|
13
|
-
def initialize(
|
14
|
-
|
15
|
-
|
16
|
-
@
|
17
|
-
# If we're on ec2, use the instance by default, unless instructed otherwise
|
18
|
-
@use_ec2_instance_id = !opts.has_key?(:use_ec2_instance_id) || opts.has_key?(:use_ec2_instance_id) && opts[:use_ec2_instance_id]
|
19
|
-
@dog = Dogapi::Client.new(@api_key, application_key = @application_key)
|
15
|
+
def initialize(config = {})
|
16
|
+
@config = config
|
17
|
+
# If *any* api_key is not provided, this will fail immediately.
|
18
|
+
@dog = Dogapi::Client.new(config[:api_key], config[:application_key])
|
20
19
|
end
|
21
20
|
|
22
21
|
def report
|
23
22
|
# resolve correct hostname
|
24
|
-
hostname = run_status.node
|
25
|
-
if @use_ec2_instance_id && run_status.node.attribute?("ec2") && run_status.node.ec2.attribute?("instance_id")
|
26
|
-
hostname = run_status.node.ec2.instance_id
|
27
|
-
end
|
23
|
+
hostname = select_hostname(run_status.node)
|
28
24
|
|
29
25
|
# Send the metrics
|
30
|
-
|
31
|
-
@dog.emit_point("chef.resources.total", run_status.all_resources.length, :host => hostname)
|
32
|
-
@dog.emit_point("chef.resources.updated", run_status.updated_resources.length, :host => hostname)
|
33
|
-
@dog.emit_point("chef.resources.elapsed_time", run_status.elapsed_time, :host => hostname)
|
34
|
-
Chef::Log.debug("Submitted chef metrics back to Datadog")
|
35
|
-
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT => e
|
36
|
-
Chef::Log.error("Could not send metrics to Datadog. Connection error:\n" + e)
|
37
|
-
end
|
26
|
+
emit_metrics_to_datadog(hostname, run_status)
|
38
27
|
|
39
28
|
# Build the correct event
|
40
|
-
event_title =
|
41
|
-
run_time = pluralize(run_status.elapsed_time,
|
29
|
+
event_title = ''
|
30
|
+
run_time = pluralize(run_status.elapsed_time, 'second')
|
42
31
|
if run_status.success?
|
43
|
-
alert_type =
|
44
|
-
event_priority =
|
32
|
+
alert_type = 'success'
|
33
|
+
event_priority = 'low'
|
45
34
|
event_title << "Chef completed in #{run_time} on #{hostname} "
|
46
35
|
else
|
47
36
|
event_title << "Chef failed in #{run_time} on #{hostname} "
|
48
37
|
end
|
49
38
|
|
50
39
|
event_data = "Chef updated #{run_status.updated_resources.length} resources out of #{run_status.all_resources.length} resources total."
|
40
|
+
|
41
|
+
if run_status.failed?
|
42
|
+
alert_type = 'error'
|
43
|
+
event_priority = 'normal'
|
44
|
+
event_data << "\n@@@\n#{run_status.formatted_exception}\n@@@\n"
|
45
|
+
event_data << "\n@@@\n#{run_status.backtrace.join("\n")}\n@@@\n"
|
46
|
+
end
|
47
|
+
|
51
48
|
if run_status.updated_resources.length.to_i > 0
|
52
49
|
event_data << "\n@@@\n"
|
53
50
|
run_status.updated_resources.each do |r|
|
54
|
-
event_data << "- #{r.to_s} (#{defined_at
|
51
|
+
event_data << "- #{r.to_s} (#{r.defined_at})\n"
|
55
52
|
end
|
56
53
|
event_data << "\n@@@\n"
|
57
54
|
end
|
58
55
|
|
59
|
-
if run_status.failed?
|
60
|
-
alert_type = "error"
|
61
|
-
event_priority = "normal"
|
62
|
-
event_data << "\n@@@\n#{run_status.formatted_exception}\n@@@\n"
|
63
|
-
event_data << "\n@@@\n#{run_status.backtrace.join("\n")}\n@@@\n"
|
64
|
-
end
|
65
|
-
|
66
56
|
# Submit the details back to Datadog
|
67
57
|
begin
|
68
58
|
# Send the Event data
|
69
59
|
evt = @dog.emit_event(Dogapi::Event.new(event_data,
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
60
|
+
:msg_title => event_title,
|
61
|
+
:event_type => 'config_management.run',
|
62
|
+
:event_object => hostname,
|
63
|
+
:alert_type => alert_type,
|
64
|
+
:priority => event_priority,
|
65
|
+
:source_type_name => 'chef'
|
76
66
|
), :host => hostname)
|
77
67
|
|
78
68
|
begin
|
79
|
-
# FIXME nice-to-have: abstract format of return value away a bit
|
69
|
+
# FIXME: nice-to-have: abstract format of return value away a bit
|
80
70
|
# in dogapi directly. See https://github.com/DataDog/dogapi-rb/issues/18
|
81
71
|
if evt.length < 2
|
82
72
|
Chef::Log.warn("Unexpected response from Datadog Event API: #{evt}")
|
@@ -93,38 +83,25 @@ class Chef
|
|
93
83
|
Chef::Log.warn("Could not determine whether chef run was successfully submitted to Datadog: #{evt}")
|
94
84
|
end
|
95
85
|
|
96
|
-
#
|
97
|
-
|
98
|
-
host_tags.delete_if { |tag| tag.start_with?('role:') }
|
99
|
-
|
100
|
-
# Get list of chef roles, rename them to tag format
|
101
|
-
chef_roles = node.run_list.roles
|
102
|
-
chef_roles.collect! { |role| "role:" + role }
|
103
|
-
|
104
|
-
# Get the chef environment (as long as it's not '_default')
|
105
|
-
if node.respond_to?('chef_environment') && node.chef_environment != '_default'
|
106
|
-
host_tags.delete_if { |tag| tag.start_with?('env:') }
|
107
|
-
host_tags << "env:" + node.chef_environment
|
108
|
-
end
|
109
|
-
|
110
|
-
# Combine (union) both arrays. Removes dupes, preserves non-chef tags.
|
111
|
-
new_host_tags = host_tags | chef_roles
|
112
|
-
|
113
|
-
if @application_key.nil?
|
86
|
+
# Update tags
|
87
|
+
if config[:application_key].nil?
|
114
88
|
Chef::Log.warn("You need an application key to let Chef tag your nodes " \
|
115
89
|
"in Datadog. Visit https://app.datadoghq.com/account/settings#api to " \
|
116
90
|
"create one and update your datadog attributes in the datadog cookbook."
|
117
91
|
)
|
92
|
+
fail ArgumentError, 'Missing Datadog Application Key'
|
118
93
|
else
|
94
|
+
new_host_tags = get_combined_tags(hostname, node)
|
95
|
+
|
119
96
|
# Replace all tags with the new tags
|
120
97
|
rc = @dog.update_tags(hostname, new_host_tags)
|
121
98
|
begin
|
122
99
|
# See FIXME above about why I feel dirty repeating this code here
|
123
100
|
if rc.length < 2
|
124
|
-
Chef::Log.warn("Unexpected response from Datadog Event API: #{
|
101
|
+
Chef::Log.warn("Unexpected response from Datadog Event API: #{rc}")
|
125
102
|
else
|
126
103
|
if rc[0].to_i / 100 != 2
|
127
|
-
Chef::Log.warn("Could not submit #{new_host_tags} tags for #{hostname} to Datadog: #{
|
104
|
+
Chef::Log.warn("Could not submit #{new_host_tags} tags for #{hostname} to Datadog: #{rc}")
|
128
105
|
else
|
129
106
|
Chef::Log.debug("Successfully updated #{hostname}'s tags to #{new_host_tags.join(', ')}")
|
130
107
|
end
|
@@ -135,48 +112,94 @@ class Chef
|
|
135
112
|
end
|
136
113
|
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT => e
|
137
114
|
Chef::Log.error("Could not connect to Datadog. Connection error:\n" + e)
|
138
|
-
Chef::Log.error(
|
115
|
+
Chef::Log.error('Data to be submitted was:')
|
139
116
|
Chef::Log.error(event_title)
|
140
117
|
Chef::Log.error(event_data)
|
141
|
-
Chef::Log.error(
|
118
|
+
Chef::Log.error('Tags to be set for this run:')
|
142
119
|
Chef::Log.error(new_host_tags)
|
143
120
|
end
|
144
121
|
end
|
145
122
|
|
146
123
|
private
|
147
124
|
|
125
|
+
# Emit Chef metrics to Datadog
|
126
|
+
#
|
127
|
+
# @param hostname [String] resolved hostname to attach to series
|
128
|
+
# @param run_status [Chef::RunStatus] current run status
|
129
|
+
def emit_metrics_to_datadog(hostname, run_status)
|
130
|
+
@dog.emit_point('chef.resources.total', run_status.all_resources.length, :host => hostname)
|
131
|
+
@dog.emit_point('chef.resources.updated', run_status.updated_resources.length, :host => hostname)
|
132
|
+
@dog.emit_point('chef.resources.elapsed_time', run_status.elapsed_time, :host => hostname)
|
133
|
+
Chef::Log.debug('Submitted Chef metrics back to Datadog')
|
134
|
+
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT => e
|
135
|
+
Chef::Log.error("Could not send metrics to Datadog. Connection error:\n" + e)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Call Datadog API for a given hostname and retrieve the current list
|
139
|
+
# of Datadog tags - not the same as Chef 'tags' - rather all tags in
|
140
|
+
# are `key:value` e.g. `role:database-master`.
|
141
|
+
# Build up an array of Datadog tags to send back
|
142
|
+
#
|
143
|
+
# @param hostname [String]
|
144
|
+
# @return [Array] an array of current Datadog tags, roles, env
|
145
|
+
def get_combined_tags(hostname, node)
|
146
|
+
host_tags = get_host_tags(hostname)
|
147
|
+
host_tags << get_node_env(node)
|
148
|
+
|
149
|
+
chef_roles = get_node_roles(node)
|
150
|
+
chef_tags = get_node_tags(node)
|
151
|
+
|
152
|
+
# Combine (union) all arrays. Removes dupes, preserves non-Chef tags.
|
153
|
+
host_tags | chef_roles | chef_tags
|
154
|
+
end
|
155
|
+
|
156
|
+
# Get current tags, drop any that will be replaced
|
157
|
+
def get_host_tags(hostname)
|
158
|
+
tags = @dog.host_tags(hostname)[1]['tags'] || []
|
159
|
+
tags.delete_if { |tag| tag.start_with?('role:', 'env:', 'tag:') }
|
160
|
+
end
|
161
|
+
|
162
|
+
def get_node_roles(node)
|
163
|
+
node.run_list.roles.map! { |role| 'role:' + role }
|
164
|
+
end
|
165
|
+
|
166
|
+
def get_node_env(node)
|
167
|
+
'env:' + node.chef_environment if node.respond_to?('chef_environment')
|
168
|
+
end
|
169
|
+
|
170
|
+
def get_node_tags(node)
|
171
|
+
node.tags.map! { |tag| 'tag:' + tag }
|
172
|
+
end
|
173
|
+
|
148
174
|
def pluralize(number, noun)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
"#{number.round} #{noun}s"
|
155
|
-
end
|
156
|
-
rescue
|
157
|
-
Chef::Log.warn("Cannot make #{number} more legible")
|
158
|
-
"#{number} #{noun}s"
|
175
|
+
case number
|
176
|
+
when 0..1
|
177
|
+
"less than 1 #{noun}"
|
178
|
+
else
|
179
|
+
"#{number.round} #{noun}s"
|
159
180
|
end
|
181
|
+
rescue
|
182
|
+
Chef::Log.warn("Cannot make #{number} more legible")
|
183
|
+
"#{number} #{noun}s"
|
160
184
|
end
|
161
185
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
186
|
+
# Select which hostname to report back to Datadog.
|
187
|
+
# Makes decision based on inputs from `config` and when absent, use the
|
188
|
+
# node's `ec2` attribute existence to make the decision.
|
189
|
+
#
|
190
|
+
# @param node [Chef::Node] from `run_status`, can feasibly any `node`
|
191
|
+
# @return [String] the hostname decided upon
|
192
|
+
def select_hostname(node)
|
193
|
+
use_ec2_instance_id = !config.key?(:use_ec2_instance_id) ||
|
194
|
+
(config.key?(:use_ec2_instance_id) &&
|
195
|
+
config[:use_ec2_instance_id])
|
196
|
+
|
197
|
+
if use_ec2_instance_id && node.attribute?('ec2') && node.ec2.attribute?('instance_id')
|
198
|
+
node.ec2.instance_id
|
175
199
|
else
|
176
|
-
|
200
|
+
node.name
|
177
201
|
end
|
178
202
|
end
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
end #end class Chef
|
203
|
+
end # end class Datadog
|
204
|
+
end # end class Handler
|
205
|
+
end # end class Chef
|