module ChefConfig::Mixin::TrainTransport

Attributes

logger[RW]

Public Class Methods

new(logger) click to toggle source
# File lib/chef-config/mixin/train_transport.rb, line 30
def initialize(logger)
  @logger = logger
end

Public Instance Methods

build_transport() click to toggle source
# File lib/chef-config/mixin/train_transport.rb, line 102
def build_transport
  return nil unless config.target_mode?

  # TODO: Consider supporting parsing the protocol from a URI passed to `--target`
  #
  train_config = {}

  # Load the target_mode config context from config, and place any valid settings into the train configuration
  tm_config = config.target_mode

  # Load the credentials file, and place any valid settings into the train configuration
  credentials = load_credentials(tm_config.host)

  protocol = credentials[:transport_protocol] || tm_config.protocol
  train_config = tm_config.to_hash.select { |k| Train.options(protocol).key?(k) }
  logger.trace("Using target mode options from #{ChefUtils::Dist::Infra::PRODUCT} config file: #{train_config.keys.join(", ")}") if train_config

  if credentials
    valid_settings = credentials.select { |k| Train.options(protocol).key?(k) }
    valid_settings[:enable_password] = credentials[:enable_password] if credentials.key?(:enable_password)
    train_config.merge!(valid_settings)
    logger.trace("Using target mode options from credentials file: #{valid_settings.keys.join(", ")}") if valid_settings
  end

  train_config[:logger] = logger

  # Train handles connection retries for us
  Train.create(protocol, train_config)
rescue SocketError => e # likely a dns failure, not caught by train
  e.message.replace "Error connecting to #{train_config[:target]} via #{protocol} - #{e.message}"
  raise e
rescue Train::PluginLoadError
  logger.error("Invalid target mode protocol: #{protocol}")
  exit(1)
end
config() click to toggle source
# File lib/chef-config/mixin/train_transport.rb, line 138
def config
  raise NotImplementedError
end
contains_split_fqdn?(hash, fqdn) click to toggle source

Toml creates hashes when a key is separated by periods, e.g.

host.example.org

> { host: { example: { org: {} } } }

Returns true if the above example is true

A hostname has to be specified as [‘host.example.org’] This will be a common mistake so we should catch it

# File lib/chef-config/mixin/train_transport.rb, line 61
def contains_split_fqdn?(hash, fqdn)
  fqdn.split(".").reduce(hash) do |h, k|
    v = h[k]
    if Hash === v
      v
    else
      break false
    end
  end
end
credentials_file_path() click to toggle source

ChefConfig::Mixin::Credentials.credentials_file_path is designed around knife, overriding it here.

Credentials file preference:

1) target_mode.credentials_file 2) /etc/chef/TARGET_MODE_HOST/credentials 3) credentials_file_path from parent ($HOME/.chef/credentials)

# File lib/chef-config/mixin/train_transport.rb, line 81
def credentials_file_path
  tm_config = config.target_mode
  profile = tm_config.host

  credentials_file =
    if tm_config.credentials_file && File.exist?(tm_config.credentials_file)
      tm_config.credentials_file
    elsif File.exist?(config.platform_specific_path("#{ChefConfig::Config.etc_chef_dir}/#{profile}/credentials"))
      config.platform_specific_path("#{ChefConfig::Config.etc_chef_dir}/#{profile}/credentials")
    else
      super
    end

  raise ArgumentError, "No credentials file found for target '#{profile}'" unless credentials_file
  raise ArgumentError, "Credentials file specified for target mode does not exist: '#{credentials_file}'" unless File.exist?(credentials_file)

  logger.debug("Loading credentials file '#{credentials_file}' for target '#{profile}'")

  credentials_file
end
load_credentials(profile) click to toggle source

Returns a RFC099 credentials profile as a hash

# File lib/chef-config/mixin/train_transport.rb, line 37
def load_credentials(profile)
  # Tomlrb.load_file returns a hash with keys as strings
  credentials = parse_credentials_file
  if contains_split_fqdn?(credentials, profile)
    logger.warn("Credentials file #{credentials_file_path} contains target '#{profile}' as a Hash, expected a string.")
    logger.warn("Hostnames must be surrounded by single quotes, e.g. ['host.example.org']")
  end

  # host names must be specified in credentials file as ['foo.example.org'] with quotes
  if !credentials.nil? && !credentials[profile].nil?
    credentials[profile].transform_keys(&:to_sym) # return symbolized keys to match Train.options()
  else
    nil
  end
end