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.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/chef-handler-datadog.png)](http://badge.fury.io/rb/chef-handler-datadog)
|
5
6
|
[![Build Status](https://secure.travis-ci.org/DataDog/chef-handler-datadog.png?branch=master)](http://travis-ci.org/DataDog/chef-handler-datadog)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/DataDog/chef-handler-datadog.png)](https://codeclimate.com/github/DataDog/chef-handler-datadog)
|
8
|
+
[![Dependency Status](https://gemnasium.com/DataDog/chef-handler-datadog.png)](https://gemnasium.com/DataDog/chef-handler-datadog)
|
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
|
+
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/DataDog/chef-handler-datadog/trend.png)](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
|