Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Defer evaluation of api and app keys + read from run_state #395

Merged
merged 3 commits into from
Jan 24, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
[run_state] Improve CI, documentation and backwards compatibility
CI and documentation:
* make rubocop pass, mostly by disabling some cops on a few
blocks/methods where I couldn't find good alternatives.
* move the extra_config logic to the `datadog.conf.erb` template.
* add spec tests
* document pulling api/app keys from node `run_state` in README
and default attributes file

BC improvemnts:
* rename `attr` to `attribute` in `recipe_helpers.rb`
* keep raising an exception when no `api_key` is present (at converge
time instead of compile time)
  • Loading branch information
olivielpeau committed Jan 24, 2017
commit d20d9b989186b99a72d6320ee3f2a22aaa9e306e
5 changes: 5 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ Metrics/BlockLength:
- 'spec/**/*.rb'
- 'test/**/*.rb'


# Slightly longer methods are fine
Metrics/MethodLength:
Max: 15

# TODO: add encoding headers
Style/Encoding:
Enabled: false
Expand Down
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Datadog Cookbook

Chef recipes to deploy Datadog's components and configuration automatically.

**NB: This README may refer to features that are not released yet. Please check the README of the
git tag/the gem version you're using for your version's documentation**

Requirements
============
- chef >= 10.14
Expand Down Expand Up @@ -86,10 +89,16 @@ Usage

1. Add this cookbook to your Chef Server, either by installing with knife or by adding it to your Berksfile:
```
cookbook 'datadog', '~> 2.1.0'
cookbook 'datadog', '~> 2.7.0'
```
2. Add your API Key as a node attribute via an `environment` or `role` or by declaring it in another cookbook at a higher precedence level.
3. Create an 'application key' for `chef_handler` [here](https://app.datadoghq.com/account/settings#api), and add it as a node attribute, as in Step #2.
2. Add your API Key either:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add at the top of the README that these instructions are not for 2.7.0?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

* as a node attribute via an `environment` or `role`, or
* as a node attribute by declaring it in another cookbook at a higher precedence level, or
* in the node `run_state` by setting `node.run_state['datadog']['api_key']` in another cookbook preceding `datadog`'s recipes in the run_list. This approach has the benefit of not storing the credential in clear text on the Chef Server.
3. Create an 'application key' for `chef_handler` [here](https://app.datadoghq.com/account/settings#api), and add it as a node attribute or in the run state, as in Step #2.

NB: if you're using the run state to store the api and app keys you need to set them at compile time before `datadog::dd-handler` in the run list.

4. Associate the recipes with the desired `roles`, i.e. "role:chef-client" should contain "datadog::dd-handler" and a "role:base" should start the agent with "datadog::dd-agent". Here's an example role with both recipes:
```
name 'example'
Expand Down
6 changes: 4 additions & 2 deletions attributes/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
# limitations under the License.
#

# Place your API Key here, or set it on the role/environment/node
# Place your API Key here, or set it on the role/environment/node, or set it on your
# node `run_state` under the key `['datadog']['api_key']`.
# The Datadog api key to associate your agent's data with your organization.
# Can be found here:
# https://app.datadoghq.com/account/settings
default['datadog']['api_key'] = nil

# Create an application key on the Account Settings page
# Create an application key on the Account Settings page.
# Set it as an attribute, or on your node `run_state` under the key `['datadog']['application_key']`
default['datadog']['application_key'] = nil

# Use this attribute to send data to additional accounts
Expand Down
8 changes: 4 additions & 4 deletions libraries/recipe_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ def application_key(node)

private

def run_state_or_attribute(node, attr)
if node.run_state.key?('datadog') && node.run_state['datadog'].key?(attr)
node.run_state['datadog'][attr]
def run_state_or_attribute(node, attribute)
if node.run_state.key?('datadog') && node.run_state['datadog'].key?(attribute)
node.run_state['datadog'][attribute]
else
node['datadog'][attr]
node['datadog'][attribute]
end
end
end
Expand Down
21 changes: 11 additions & 10 deletions recipes/dd-agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
# limitations under the License.
#

# Fail here at converge time if no api_key is set
ruby_block 'datadog-api-key-unset' do
block do
raise "Set ['datadog']['api_key'] as an attribute or on the node's run_state to configure this node's Datadog Agent."
end
only_if { Chef::Datadog.api_key(node).nil? }
end

is_windows = node['platform_family'] == 'windows'

# Install the agent
Expand Down Expand Up @@ -52,9 +60,8 @@
# the node's run_list and set the relevant attributes
#


template agent_config_file do
def template_vars
template agent_config_file do # rubocop:disable Metrics/BlockLength
def template_vars # rubocop:disable Metrics/AbcSize
api_keys = [Chef::Datadog.api_key(node)]
dd_urls = [node['datadog']['url']]
node['datadog']['extra_endpoints'].each do |_, endpoint|
Expand All @@ -66,15 +73,9 @@ def template_vars
node['datadog']['url']
end
end
extra_config = {}
node['datadog']['extra_config'].each do |option, value|
next if value.nil?
extra_config[option] = value
end
{
:api_keys => api_keys,
:dd_urls => dd_urls,
:extra_config => extra_config
:dd_urls => dd_urls
}
end
if is_windows
Expand Down
7 changes: 5 additions & 2 deletions recipes/dd-handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,19 @@
end

# Create the handler to run at the end of the Chef execution
chef_handler 'Chef::Handler::Datadog' do
def handler_config # rubocop:disable Metrics/AbcSize
chef_handler 'Chef::Handler::Datadog' do # rubocop:disable Metrics/BlockLength
def extra_endpoints
extra_endpoints = []
node['datadog']['extra_endpoints'].each do |_, endpoint|
next unless endpoint['enabled']
endpoint = Mash.new(endpoint)
endpoint.delete('enabled')
extra_endpoints << endpoint
end
extra_endpoints
end

def handler_config # rubocop:disable Metrics/AbcSize
config = {
:api_key => Chef::Datadog.api_key(node),
:application_key => Chef::Datadog.application_key(node),
Expand Down
64 changes: 64 additions & 0 deletions spec/dd-agent_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def set_env_var(name, value)
include EnvVar

context 'no version set' do
# This recipe needs to have an api_key, otherwise `raise` is called.
# It also depends on the version of Python present on the platform:
# 2.6 and up => datadog-agent is installed
# below 2.6 => datadog-agent-base is installed
Expand Down Expand Up @@ -372,7 +373,9 @@ def set_env_var(name, value)

it_behaves_like 'debianoids repo'
end
end

context 'datadog.conf configuration' do
context 'allows a string for tags' do
cached(:chef_run) do
ChefSpec::SoloRunner.new(
Expand Down Expand Up @@ -497,6 +500,67 @@ def set_env_var(name, value)
.with_content(%r{^dd_url: https://app.example.com,https://app.example.com$})
end
end

context 'with no api_key set' do
cached(:chef_run) do
ChefSpec::SoloRunner.new(
platform: 'ubuntu',
version: '12.04'
) do |node|
node.set['languages'] = { 'python' => { 'version' => '2.6.2' } }
end.converge described_recipe
end

it 'raises an error' do
expect(chef_run).to run_ruby_block('datadog-api-key-unset')
expect { chef_run.ruby_block('datadog-api-key-unset').old_run_action(:run) }.to raise_error(RuntimeError)
end
end

context 'with api_key set as node attribute and on node run_state' do
cached(:chef_run) do
ChefSpec::SoloRunner.new(
platform: 'ubuntu',
version: '12.04'
) do |node|
node.set['datadog'] = {
'api_key' => 'as_node_attribute',
'url' => 'https://app.example.com'
}
node.set['languages'] = { 'python' => { 'version' => '2.6.2' } }
node.run_state['datadog'] = { 'api_key' => 'on_run_state' }
end.converge described_recipe
end

it_behaves_like 'common linux resources'

it 'uses the api_key from the run_state' do
expect(chef_run).to render_file('/etc/dd-agent/datadog.conf')
.with_content(/^api_key: on_run_state$/)

expect(chef_run).not_to render_file('/etc/dd-agent/datadog.conf')
.with_content(/api_key: as_node_attribute/)
end
end

context 'with api_key set on node run_state only' do
cached(:chef_run) do
ChefSpec::SoloRunner.new(
platform: 'ubuntu',
version: '12.04'
) do |node|
node.set['languages'] = { 'python' => { 'version' => '2.6.2' } }
node.run_state['datadog'] = { 'api_key' => 'on_run_state' }
end.converge described_recipe
end

it_behaves_like 'common linux resources'

it 'uses the api_key from the run_state' do
expect(chef_run).to render_file('/etc/dd-agent/datadog.conf')
.with_content(/^api_key: on_run_state$/)
end
end
end

context 'does accept extra config options' do
Expand Down
43 changes: 43 additions & 0 deletions spec/dd-handler_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,48 @@
end
end

context 'with api and app keys set as node attributes and on node run_state' do
cached(:chef_run) do
ChefSpec::SoloRunner.new(
platform: 'ubuntu',
version: '14.04'
) do |node|
node.set['datadog']['api_key'] = 'api_overriden_by_run_state'
node.set['datadog']['application_key'] = 'app_overriden_by_run_state'
node.set['datadog']['chef_handler_enable'] = true
node.set['datadog']['use_ec2_instance_id'] = true
node.run_state['datadog'] = {
'api_key' => 'somethingnotnil',
'application_key' => 'somethingnotnil2'
}
end.converge described_recipe
end

it_behaves_like 'a chef-handler-datadog installer'

it_behaves_like 'a chef-handler-datadog runner'
end

context 'with keys set on node run_state only' do
cached(:chef_run) do
ChefSpec::SoloRunner.new(
platform: 'ubuntu',
version: '14.04'
) do |node|
node.set['datadog']['chef_handler_enable'] = true
node.set['datadog']['use_ec2_instance_id'] = true
node.run_state['datadog'] = {
'api_key' => 'somethingnotnil',
'application_key' => 'somethingnotnil2'
}
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(
Expand All @@ -93,6 +135,7 @@

it_behaves_like 'a chef-handler-datadog runner', extra_endpoints, nil
end

context 'multiple endpoints disabled' do
cached(:chef_run) do
ChefSpec::SoloRunner.new(
Expand Down
8 changes: 8 additions & 0 deletions spec/shared_examples.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@
end
end

shared_examples_for 'datadog conf' do
it 'does not complain about a missing api key' do
expect(chef_run).not_to run_ruby_block('datadog-api-key-unset')
end
end

shared_examples_for 'common linux resources' do
it_behaves_like 'datadog-agent service'
it_behaves_like 'datadog conf'

it 'includes the repository recipe' do
expect(chef_run).to include_recipe('datadog::repository')
Expand Down Expand Up @@ -50,6 +57,7 @@

shared_examples_for 'common windows resources' do
it_behaves_like 'datadog-agent service'
it_behaves_like 'datadog conf'

it 'ensures the Datadog config directory exists' do
expect(chef_run).to create_directory 'C:\ProgramData/Datadog'
Expand Down
6 changes: 4 additions & 2 deletions templates/default/datadog.conf.erb
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,13 @@ if node['datadog']['legacy_integrations']
end
-%>

<% if ! @extra_config.empty? -%>
<% if ! node['datadog']['extra_config'].empty? -%>
# ========================================================================== #
# Other config options
# ========================================================================== #
<% @extra_config.each do |k, v| -%>
<% node['datadog']['extra_config'].each do |k, v| -%>
<% if ! v.nil? -%>
<%= k %>: <%= v %>
<% end -%>
<% end -%>
<% end -%>