From f78252db419f6acf58edb79b7d80f3c9181960c9 Mon Sep 17 00:00:00 2001 From: Quentin Madec Date: Mon, 19 Sep 2016 11:43:53 -0400 Subject: [PATCH] Add multiple enpoints/api_keys conf (#317) On both `dd-agent` and `handler` --- .travis.yml | 1 + attributes/default.rb | 8 +++ recipes/dd-agent.rb | 16 ++++- recipes/dd-handler.rb | 12 +++- spec/dd-agent_spec.rb | 59 +++++++++++++++++++ spec/dd-handler_spec.rb | 95 ++++++++++++++++++++++++++++++ templates/default/datadog.conf.erb | 4 +- 7 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 spec/dd-handler_spec.rb diff --git a/.travis.yml b/.travis.yml index 0c647f17..c6753947 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ before_script: - eval "$(/opt/chefdk/bin/chef shell-init bash)" - chef gem install coveralls -v '~> 0.8.13' - chef gem install json_spec -v '~> 1.1.4' + - chef gem install chef-handler-datadog script: - chef --version diff --git a/attributes/default.rb b/attributes/default.rb index b3758a6f..5cea2f7b 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -26,6 +26,14 @@ # Create an application key on the Account Settings page default['datadog']['application_key'] = nil +# Use this attribute to send data to additional accounts +# (agent and handler if enabled) +# The key can be anything you want, 'prod' is used there as an example +default['datadog']['extra_endpoints']['prod']['enabled'] = nil +default['datadog']['extra_endpoints']['prod']['api_key'] = nil +default['datadog']['extra_endpoints']['prod']['application_key'] = nil +default['datadog']['extra_endpoints']['prod']['url'] = nil # optional + # Add this prefix to all Chef tags sent to Datadog: "#{tag_prefix}#{tag}" # This makes it easy to group hosts in Datadog by their Chef tags, but might be counterproductive # if your Chef tags are already in the "#{tag_group}:#{value}" form. diff --git a/recipes/dd-agent.rb b/recipes/dd-agent.rb index 45eb66cd..8d75dc81 100644 --- a/recipes/dd-agent.rb +++ b/recipes/dd-agent.rb @@ -53,6 +53,18 @@ # raise "Add a ['datadog']['api_key'] attribute to configure this node's Datadog Agent." if node['datadog'] && node['datadog']['api_key'].nil? +api_keys = [node['datadog']['api_key']] +dd_urls = [node['datadog']['url']] +node['datadog']['extra_endpoints'].each do |_, endpoint| + next unless endpoint['enabled'] + api_keys << endpoint['api_key'] + dd_urls << if endpoint['url'] + endpoint['url'] + else + node['datadog']['url'] + end +end + template agent_config_file do if is_windows owner 'Administrators' @@ -64,8 +76,8 @@ mode 0640 end variables( - :api_key => node['datadog']['api_key'], - :dd_url => node['datadog']['url'] + :api_keys => api_keys, + :dd_urls => dd_urls ) sensitive true if Chef::Resource.instance_methods(false).include?(:sensitive) end diff --git a/recipes/dd-handler.rb b/recipes/dd-handler.rb index f85641df..1b6ef247 100644 --- a/recipes/dd-handler.rb +++ b/recipes/dd-handler.rb @@ -46,11 +46,21 @@ ENV['DATADOG_PROXY'] = proxy_url.to_s end +extra_endpoints = [] +node['datadog']['extra_endpoints'].each do |_, endpoint| + next unless endpoint['enabled'] + endpoint = Mash.new(endpoint) + endpoint.delete('enabled') + extra_endpoints << endpoint +end + handler_config = { :api_key => node['datadog']['api_key'], :application_key => node['datadog']['application_key'], :use_ec2_instance_id => node['datadog']['use_ec2_instance_id'], - :tag_prefix => node['datadog']['tag_prefix'] + :tag_prefix => node['datadog']['tag_prefix'], + :url => node['datadog']['url'], + :extra_endpoints => extra_endpoints } unless node['datadog']['use_ec2_instance_id'] diff --git a/spec/dd-agent_spec.rb b/spec/dd-agent_spec.rb index 9e375607..ce8f0732 100644 --- a/spec/dd-agent_spec.rb +++ b/spec/dd-agent_spec.rb @@ -296,6 +296,65 @@ def set_env_var(name, value) .with_content(/^tags: datacenter:us-foo$/) end end + + context 'does accept extra endpoints' do + cached(:chef_run) do + ChefSpec::SoloRunner.new( + platform: 'ubuntu', + version: '12.04' + ) do |node| + node.set['datadog'] = { + 'api_key' => 'something1', + 'url' => 'https://app.example.com', + 'extra_endpoints' => { + 'example' => { + 'enabled' => true, + 'api_key' => 'something2', + 'url' => 'https://app.datadoghq.com' + } + } + } + node.set['languages'] = { 'python' => { 'version' => '2.6.2' } } + end.converge described_recipe + end + + it_behaves_like 'common linux resources' + + it 'uses the multiples apikeys and urls' do + expect(chef_run).to render_file('/etc/dd-agent/datadog.conf') + .with_content(/^api_key: something1,something2$/) + .with_content(%r{^dd_url: https://app.example.com,https://app.datadoghq.com$}) + end + end + + context 'does accept extra api_key' do + cached(:chef_run) do + ChefSpec::SoloRunner.new( + platform: 'ubuntu', + version: '12.04' + ) do |node| + node.set['datadog'] = { + 'api_key' => 'something1', + 'url' => 'https://app.example.com', + 'extra_endpoints' => { + 'example' => { + 'enabled' => true, + 'api_key' => 'something2' + } + } + } + node.set['languages'] = { 'python' => { 'version' => '2.6.2' } } + end.converge described_recipe + end + + it_behaves_like 'common linux resources' + + it 'uses the multiples apikeys and urls' do + expect(chef_run).to render_file('/etc/dd-agent/datadog.conf') + .with_content(/^api_key: something1,something2$/) + .with_content(%r{^dd_url: https://app.example.com,https://app.example.com$}) + end + end end context 'service action' do diff --git a/spec/dd-handler_spec.rb b/spec/dd-handler_spec.rb new file mode 100644 index 00000000..d81e5dcb --- /dev/null +++ b/spec/dd-handler_spec.rb @@ -0,0 +1,95 @@ +require 'spec_helper' + +shared_examples 'a chef-handler-datadog installer' do |version| + it 'includes chef_handler recipe' do + expect(chef_run).to include_recipe('chef_handler') + end + + it 'installs the right version of chef-handler-datadog' do + expect(chef_run).to install_chef_gem('chef-handler-datadog').with(version: version) + end +end + +shared_examples 'a chef-handler-datadog runner' do |extra_endpoints| + it 'runs the handler' do + handler_config = { + api_key: 'somethingnotnil', + application_key: 'somethingnotnil2', + use_ec2_instance_id: true, + tag_prefix: 'tag:', + url: 'https://app.datadoghq.com', + extra_endpoints: extra_endpoints || [] + } + + expect(chef_run).to enable_chef_handler('Chef::Handler::Datadog').with( + source: 'chef/handler/datadog', + arguments: [handler_config] + ) + end +end + +describe 'datadog::dd-handler' do + context 'standard usage' do + cached(:chef_run) do + ChefSpec::SoloRunner.new( + platform: 'ubuntu', + version: '14.04' + ) do |node| + node.set['datadog']['api_key'] = 'somethingnotnil' + node.set['datadog']['application_key'] = 'somethingnotnil2' + node.set['datadog']['chef_handler_enable'] = true + node.set['datadog']['use_ec2_instance_id'] = true + end.converge described_recipe + end + + it_behaves_like 'a chef-handler-datadog installer' + + it_behaves_like 'a chef-handler-datadog runner' + end + + context 'multiple endpoints' do + cached(:chef_run) do + ChefSpec::SoloRunner.new( + platform: 'ubuntu', + version: '14.04' + ) do |node| + node.set['datadog']['api_key'] = 'somethingnotnil' + node.set['datadog']['application_key'] = 'somethingnotnil2' + node.set['datadog']['chef_handler_enable'] = true + node.set['datadog']['use_ec2_instance_id'] = true + node.set['datadog']['extra_endpoints']['qqqq']['enabled'] = true + node.set['datadog']['extra_endpoints']['qqqq']['api_key'] = 'something' + node.set['datadog']['extra_endpoints']['qqqq']['application_key'] = 'something2' + end.converge described_recipe + end + + extra_endpoints = [ + Mash.new(api_key: 'something', + application_key: 'something2') + ] + + it_behaves_like 'a chef-handler-datadog installer' + + it_behaves_like 'a chef-handler-datadog runner', extra_endpoints + end + context 'multiple endpoints disabled' do + cached(:chef_run) do + ChefSpec::SoloRunner.new( + platform: 'ubuntu', + version: '14.04' + ) do |node| + node.set['datadog']['api_key'] = 'somethingnotnil' + node.set['datadog']['application_key'] = 'somethingnotnil2' + node.set['datadog']['chef_handler_enable'] = true + node.set['datadog']['use_ec2_instance_id'] = true + node.set['datadog']['extra_endpoints']['qqqq']['enabled'] = false + node.set['datadog']['extra_endpoints']['qqqq']['api_key'] = 'something' + node.set['datadog']['extra_endpoints']['qqqq']['application_key'] = 'something2' + end.converge described_recipe + end + + it_behaves_like 'a chef-handler-datadog installer' + + it_behaves_like 'a chef-handler-datadog runner' + end +end diff --git a/templates/default/datadog.conf.erb b/templates/default/datadog.conf.erb index 3488dc94..7b7c3db5 100644 --- a/templates/default/datadog.conf.erb +++ b/templates/default/datadog.conf.erb @@ -1,8 +1,8 @@ # Generated by Chef, local modifications will be overwritten [Main] -dd_url: <%= @dd_url %> -api_key: <%= @api_key %> +dd_url: <%= @dd_urls.join(',') %> +api_key: <%= @api_keys.join(',') %> check_freq: <%= node['datadog']['check_freq'] %> hostname: <%= node['datadog']['hostname'] %> use_mount: <%= node['datadog']['use_mount'] ? "yes" : "no" %>