class Chef::Handler::Datadog

Datadog handler to send Chef run details to Datadog

Attributes

config[R]

Public Class Methods

new(config = {}) click to toggle source

For the tags to work, the client must have created an Application Key on the “Account Settings” page here: app.datadoghq.com/account/settings It should be passed along from the node/role/environemnt attributes, as the default is nil.

# File lib/chef/handler/datadog.rb, line 19
def initialize(config = {})
  @config = Mash.new(config)

  @dogs = prepare_the_pack
end

Public Instance Methods

report() click to toggle source
# File lib/chef/handler/datadog.rb, line 25
def report
  # use datadog agent proxy settings, if available
  use_agent_proxy unless ENV['DATADOG_PROXY'].nil?

  # prepare the metrics, event, and tags information to be reported
  prepare_report_for_datadog

  @dogs.each do |dog|
    # post the report information to the datadog service
    Chef::Log.debug("Sending Chef report to #{dog.datadog_host}")
    send_report_to_datadog dog
  end
ensure
  # restore the env proxy settings before leaving to avoid downstream side-effects
  restore_env_proxies unless ENV['DATADOG_PROXY'].nil?
end

Private Instance Methods

config_url() click to toggle source
# File lib/chef/handler/datadog.rb, line 150
def config_url()
  url = 'https://app.datadoghq.com'
  url = 'https://app.' + @config[:site] unless @config[:site].nil?
  url = @config[:url] unless @config[:url].nil?
  url
end
endpoints() click to toggle source

return all endpoints as a list of triplets [url, api_key, application_key]

# File lib/chef/handler/datadog.rb, line 158
def endpoints
  validate_keys(@config[:api_key], @config[:application_key], true)

  # the first endpoint is always the url/site + apikey + appkey one
  endpoints = [[config_url(), @config[:api_key], @config[:application_key]]]

  # then add extra endpoints
  extra_endpoints = @config[:extra_endpoints] || []
  extra_endpoints.each do |endpoint|
    url = endpoint[:api_url] || endpoint[:url] || config_url()
    api_key = endpoint[:api_key]
    app_key = endpoint[:application_key]
    endpoints << [url, api_key, app_key] if validate_keys(api_key, app_key, false)
  end

  endpoints
end
prepare_report_for_datadog() click to toggle source

prepare metrics, event, and tags data for posting to datadog

# File lib/chef/handler/datadog.rb, line 45
def prepare_report_for_datadog
  # uses class method accessors for run_status and config
  hostname = resolve_correct_hostname
  # prepare chef run metrics
  @metrics =
      DatadogChefMetrics.new
      .with_hostname(hostname)
      .with_run_status(run_status)

  # Collect and prepare tags
  @tags =
      DatadogChefTags.new
      .with_hostname(hostname)
      .with_run_status(run_status)
      .with_tag_prefix(config[:tag_prefix])
      .with_retries(config[:tags_submission_retries])
      .with_tag_blacklist(config[:tags_blacklist_regex])
      .with_scope_prefix(config[:scope_prefix])
      .with_policy_tags_enabled(config[:send_policy_tags])

  # Build the chef event information
  @event =
      DatadogChefEvents.new
      .with_hostname(hostname)
      .with_run_status(run_status)
      .with_failure_notifications(@config['notify_on_failure'])
      .with_tags(@tags.combined_host_tags)
end
prepare_the_pack() click to toggle source

create and configure all the Dogapi Clients to be used

@return [Array] all Dogapi::Client to be used

# File lib/chef/handler/datadog.rb, line 129
def prepare_the_pack
  dogs = []
  endpoints.each do |url, api_key, app_key|
    begin
      dogs.push(Dogapi::Client.new(
                  api_key,
                  app_key,
                  nil,   # host
                  nil,   # device
                  false, # silent
                  nil,   # timeout
                  url,
                  config[:skip_ssl_validation]
      ))
    rescue => e
      Chef::Log.error("Could not create API Client '#{url}'\n #{e.to_s}")
    end
  end
  dogs
end
resolve_correct_hostname() click to toggle source

Select which hostname to report back to Datadog. Makes decision based on inputs from `config` and when absent, use the node's `ec2` attribute existence to make the decision.

@return [String] the hostname decided upon

# File lib/chef/handler/datadog.rb, line 95
def resolve_correct_hostname
  node = run_status.node
  use_ec2_instance_id = !config.key?(:use_ec2_instance_id) ||
                        (config.key?(:use_ec2_instance_id) && config[:use_ec2_instance_id])

  if config[:hostname]
    config[:hostname]
  elsif use_ec2_instance_id && node.attribute?('ec2') && node['ec2'].attribute?('instance_id')
    node['ec2']['instance_id']
  else
    node.name
  end
end
restore_env_proxies() click to toggle source

Restore environment proxy settings to pre-report values

# File lib/chef/handler/datadog.rb, line 121
def restore_env_proxies
  ENV['http_proxy'] = @env_http_proxy
  ENV['https_proxy'] = @env_https_proxy
end
send_report_to_datadog(dog) click to toggle source

Submit metrics, event, and tags information to datadog

@param dog [Dogapi::Client] Dogapi Client to be used

# File lib/chef/handler/datadog.rb, line 77
def send_report_to_datadog(dog)
  @metrics.emit_to_datadog dog
  @event.emit_to_datadog dog
  @tags.send_update_to_datadog dog
rescue => e
  Chef::Log.error("Could not send/emit to Datadog:\n" + e.to_s)
  Chef::Log.error('Event data to be submitted was:')
  Chef::Log.error(@event.event_title)
  Chef::Log.error(@event.event_body)
  Chef::Log.error('Tags to be set for this run:')
  Chef::Log.error(@tags.combined_host_tags)
end
use_agent_proxy() click to toggle source

Using the agent proxy settings requires setting http(s)_proxy env vars. However, original env var settings need to be preserved for restoration at the end of the handler.

# File lib/chef/handler/datadog.rb, line 112
def use_agent_proxy
  Chef::Log.info('Using agent proxy settings')
  @env_http_proxy = ENV['http_proxy']
  @env_https_proxy = ENV['https_proxy']
  ENV['http_proxy'] = ENV['DATADOG_PROXY']
  ENV['https_proxy'] = ENV['DATADOG_PROXY']
end
validate_keys(api_key, app_key, should_fail) click to toggle source

Validate endpoints config (api_key and application key) fails if incorrect and should_fail is true (needed for the default) Doesn't fail for the other endpoints but logs a warning

# File lib/chef/handler/datadog.rb, line 179
def validate_keys(api_key, app_key, should_fail)
  if api_key.nil?
    Chef::Log.warn('You need an API key to communicate with Datadog')
    fail ArgumentError, 'Missing Datadog Api Key' if should_fail
    return false
  end
  if app_key.nil?
    Chef::Log.warn('You need an application key to let Chef tag your nodes ' \
                   'in Datadog. Visit https://app.datadoghq.com/account/settings#api to ' \
                   'create one and update your datadog attributes in the datadog cookbook.')
    fail ArgumentError, 'Missing Datadog Application Key' if should_fail
    return false
  end
  true
end