class Sensu::Settings::Loader

Attributes

loaded_files[R]

@!attribute [r] #loaded_files

@return [Array] loaded config files.
warnings[R]

@!attribute [r] warnings

@return [Array] loader warnings.

Public Class Methods

create_category_methods() click to toggle source

Create setting category accessors and methods to test the existence of definitions. Called in initialize().

# File lib/sensu/settings/loader.rb, line 43
def self.create_category_methods
  CATEGORIES.each do |category|
    define_method(category) do
      setting_category(category)
    end
    method_name = category.to_s.chop + "_exists?"
    define_method(method_name.to_sym) do |name|
      definition_exists?(category, name)
    end
  end
end
new() click to toggle source
# File lib/sensu/settings/loader.rb, line 17
def initialize
  @warnings = []
  @settings = default_settings
  @indifferent_access = false
  @loaded_files = []
  self.class.create_category_methods
end

Public Instance Methods

[](key) click to toggle source

Retrieve the setting object corresponding to a key, acting like a Hash object.

@param key [String, Symbol] @return [Object] value for key.

# File lib/sensu/settings/loader.rb, line 70
def [](key)
  to_hash[key]
end
default_settings() click to toggle source

Default settings.

@return [Hash] settings.

# File lib/sensu/settings/loader.rb, line 28
def default_settings
  default = {
    :transport => {
      :name => "rabbitmq",
      :reconnect_on_error => true
    }
  }
  CATEGORIES.each do |category|
    default[category] = {}
  end
  default
end
load_directory(directory) click to toggle source

Load settings from files in a directory. Files may be in nested directories.

@param [String] directory path.

# File lib/sensu/settings/loader.rb, line 124
def load_directory(directory)
  warning("loading config files from directory", :directory => directory)
  path = directory.gsub(/\(?=\S)/, "/")
  Dir.glob(File.join(path, "**{,/*/**}/*.json")).uniq.each do |file|
    load_file(file)
  end
end
load_env() click to toggle source

Load settings from the environment.

Loads: SENSU_TRANSPORT_NAME, RABBITMQ_URL, REDIS_URL,

SENSU_CLIENT_NAME, SENSU_CLIENT_ADDRESS
SENSU_CLIENT_SUBSCRIPTIONS, SENSU_API_PORT
# File lib/sensu/settings/loader.rb, line 79
def load_env
  load_transport_env
  load_rabbitmq_env
  load_redis_env
  load_client_env
  load_api_env
end
load_file(file) click to toggle source

Load settings from a JSON file.

@param [String] file path.

# File lib/sensu/settings/loader.rb, line 90
def load_file(file)
  if File.file?(file) && File.readable?(file)
    begin
      warning("loading config file", :file => file)
      contents = read_config_file(file)
      config = Sensu::JSON.load(contents)
      merged = deep_merge(@settings, config)
      unless @loaded_files.empty?
        changes = deep_diff(@settings, merged)
        warning("config file applied changes", {
          :file => file,
          :changes => changes
        })
      end
      @settings = merged
      @indifferent_access = false
      @loaded_files << file
    rescue Sensu::JSON::ParseError => error
      warning("config file must be valid json", {
        :file => file,
        :error => error.to_s
      })
      warning("ignoring config file", :file => file)
    end
  else
    warning("config file does not exist or is not readable", :file => file)
    warning("ignoring config file", :file => file)
  end
end
set_env!() click to toggle source

Set Sensu settings related environment variables. This method sets `SENSU_LOADED_TEMPFILE` to a new temporary file path, a file containing the colon delimited list of loaded configuration files (using `create_loaded_tempfile!()`. The environment variable `SENSU_CONFIG_FILES` has been removed, due to the exec ARG_MAX (E2BIG) error when spawning processes after loading many configuration files (e.g. > 2000).

# File lib/sensu/settings/loader.rb, line 139
def set_env!
  ENV["SENSU_LOADED_TEMPFILE"] = create_loaded_tempfile!
end
to_hash() click to toggle source

Access settings as an indifferent hash.

@return [Hash] settings.

# File lib/sensu/settings/loader.rb, line 58
def to_hash
  unless @indifferent_access
    indifferent_access!
  end
  @settings
end
validate() click to toggle source

Validate the loaded settings.

@return [Array] validation failures.

# File lib/sensu/settings/loader.rb, line 146
def validate
  validator = Validator.new
  validator.run(@settings, sensu_service_name)
end

Private Instance Methods

create_loaded_tempfile!() click to toggle source

Create a temporary file containing the colon delimited list of loaded configuration files. Ruby TempFile is not used to create the temporary file as it would be removed if the Sensu service daemonizes (fork/detach). The file is created in the system temporary file directory for the platform (Linux, Windows, etc.) and the file name contains the Sensu service name to reduce the likelihood of one Sensu service affecting another.

@return [String] tempfile path.

# File lib/sensu/settings/loader.rb, line 334
def create_loaded_tempfile!
  dir = ENV["SENSU_LOADED_TEMPFILE_DIR"] || Dir.tmpdir
  file_name = "sensu_#{sensu_service_name}_loaded_files"
  path = File.join(dir, file_name)
  File.open(path, "w") do |file|
    file.write(@loaded_files.join(":"))
  end
  path
end
deep_diff(hash_one, hash_two) click to toggle source

Compare two hashes.

@param [Hash] hash_one to compare. @param [Hash] hash_two to compare. @return [Hash] comparison diff hash.

# File lib/sensu/settings/loader.rb, line 310
def deep_diff(hash_one, hash_two)
  keys = hash_one.keys.concat(hash_two.keys).uniq
  keys.inject(Hash.new) do |diff, key|
    unless hash_one[key] == hash_two[key]
      if hash_one[key].is_a?(Hash) && hash_two[key].is_a?(Hash)
        diff[key] = deep_diff(hash_one[key], hash_two[key])
      else
        diff[key] = [hash_one[key], hash_two[key]]
      end
    end
    diff
  end
end
deep_merge(hash_one, hash_two) click to toggle source

Deep merge two hashes.

@param [Hash] hash_one to serve as base. @param [Hash] hash_two to merge in. @return [Hash] deep merged hash.

# File lib/sensu/settings/loader.rb, line 290
def deep_merge(hash_one, hash_two)
  merged = hash_one.dup
  hash_two.each do |key, value|
    merged[key] = case
    when hash_one[key].is_a?(Hash) && value.is_a?(Hash)
      deep_merge(hash_one[key], value)
    when hash_one[key].is_a?(Array) && value.is_a?(Array)
      hash_one[key].concat(value).uniq
    else
      value
    end
  end
  merged
end
definition_exists?(category, name) click to toggle source

Check to see if a definition exists in a category.

@param [Symbol] category to inspect for the definition. @param [String] name of definition. @return [TrueClass, FalseClass]

# File lib/sensu/settings/loader.rb, line 168
def definition_exists?(category, name)
  @settings[category].has_key?(name.to_sym)
end
indifferent_access!() click to toggle source

Update settings to have indifferent access.

# File lib/sensu/settings/loader.rb, line 197
def indifferent_access!
  @settings = with_indifferent_access(@settings)
  @indifferent_access = true
end
indifferent_hash() click to toggle source

Creates an indifferent hash.

@return [Hash] indifferent hash.

# File lib/sensu/settings/loader.rb, line 175
def indifferent_hash
  Hash.new do |hash, key|
    if key.is_a?(String)
      hash[key.to_sym]
    end
  end
end
load_api_env() click to toggle source

Load Sensu API settings from the environment. This method sets the API port to `SENSU_API_PORT` if set.

# File lib/sensu/settings/loader.rb, line 255
def load_api_env
  if ENV["SENSU_API_PORT"]
    @settings[:api] ||= {}
    @settings[:api][:port] = ENV["SENSU_API_PORT"].to_i
    warning("using api port environment variable", :api => @settings[:api])
    @indifferent_access = false
  end
end
load_client_env() click to toggle source

Load Sensu client settings from the environment. This method loads client settings from several variables if `SENSU_CLIENT_NAME` is set: `SENSU_CLIENT_NAME`, `SENSU_CLIENT_ADDRESS`, and `SENSU_CLIENT_SUBSCRIPTIONS`. The Sensu client address defaults to the current system hostname and subscriptions defaults to an empty array.

# File lib/sensu/settings/loader.rb, line 242
def load_client_env
  if ENV["SENSU_CLIENT_NAME"]
    @settings[:client] ||= {}
    @settings[:client][:name] = ENV["SENSU_CLIENT_NAME"]
    @settings[:client][:address] = ENV.fetch("SENSU_CLIENT_ADDRESS", system_hostname)
    @settings[:client][:subscriptions] = ENV.fetch("SENSU_CLIENT_SUBSCRIPTIONS", "").split(",")
    warning("using sensu client environment variables", :client => @settings[:client])
    @indifferent_access = false
  end
end
load_rabbitmq_env() click to toggle source

Load Sensu RabbitMQ settings from the environment. This method sets the RabbitMQ settings to `RABBITMQ_URL` if set. The Sensu RabbitMQ transport accepts a URL string for options.

# File lib/sensu/settings/loader.rb, line 216
def load_rabbitmq_env
  if ENV["RABBITMQ_URL"]
    @settings[:rabbitmq] = ENV["RABBITMQ_URL"]
    warning("using rabbitmq url environment variable", :rabbitmq => @settings[:rabbitmq])
    @indifferent_access = false
  end
end
load_redis_env() click to toggle source

Load Sensu Redis settings from the environment. This method sets the Redis settings to `REDIS_URL` if set. The Sensu Redis library accepts a URL string for options, this applies to data storage and the transport.

# File lib/sensu/settings/loader.rb, line 228
def load_redis_env
  if ENV["REDIS_URL"]
    @settings[:redis] = ENV["REDIS_URL"]
    warning("using redis url environment variable", :redis => @settings[:redis])
    @indifferent_access = false
  end
end
load_transport_env() click to toggle source

Load Sensu transport settings from the environment. This method sets the Sensu transport name to `SENSU_TRANSPORT_NAME` if set.

# File lib/sensu/settings/loader.rb, line 205
def load_transport_env
  if ENV["SENSU_TRANSPORT_NAME"]
    @settings[:transport][:name] = ENV["SENSU_TRANSPORT_NAME"]
    warning("using sensu transport name environment variable", :transport => @settings[:transport])
    @indifferent_access = false
  end
end
read_config_file(file) click to toggle source

Read a configuration file and force its encoding to 8-bit ASCII, ignoring invalid characters. If there is a UTF-8 BOM, it will be removed. Some JSON parsers force ASCII but do not remove the UTF-8 BOM if present, causing encoding conversion errors. This method is for consistency across Sensu::JSON adapters and system platforms.

@param [String] file path to read. @return [String] file contents.

# File lib/sensu/settings/loader.rb, line 273
def read_config_file(file)
  contents = IO.read(file)
  if contents.respond_to?(:force_encoding)
    encoding = ::Encoding::ASCII_8BIT
    contents = contents.force_encoding(encoding)
    contents.sub!("\xEF\xBB\xBF".force_encoding(encoding), "")
  else
    contents.sub!(/^\357\273\277/, "")
  end
  contents
end
sensu_service_name() click to toggle source

Retrieve Sensu service name.

@return [String] service name.

# File lib/sensu/settings/loader.rb, line 347
def sensu_service_name
  File.basename($0).split("-").last
end
setting_category(category) click to toggle source

Retrieve setting category definitions.

@param [Symbol] category to retrive. @return [Array<Hash>] category definitions.

# File lib/sensu/settings/loader.rb, line 157
def setting_category(category)
  @settings[category].map do |name, details|
    details.merge(:name => name.to_s)
  end
end
system_hostname() click to toggle source

Retrieve the system hostname. If the hostname cannot be determined and an error is thrown, return “unknown”, the same value Sensu uses for JIT clients.

@return [String] system hostname.

# File lib/sensu/settings/loader.rb, line 356
def system_hostname
  Socket.gethostname rescue "unknown"
end
warning(message, data={}) click to toggle source

Record a warning.

@param message [String] warning message. @param data [Hash] warning context. @return [Array] current warnings.

# File lib/sensu/settings/loader.rb, line 365
def warning(message, data={})
  @warnings << {
    :message => message
  }.merge(data)
end
with_indifferent_access(hash) click to toggle source

Create a copy of a hash with indifferent access.

@param hash [Hash] hash to make indifferent. @return [Hash] indifferent version of hash.

# File lib/sensu/settings/loader.rb, line 187
def with_indifferent_access(hash)
  hash = indifferent_hash.merge(hash)
  hash.each do |key, value|
    if value.is_a?(Hash)
      hash[key] = with_indifferent_access(value)
    end
  end
end