Module: ChefConfig::Mixin::TrainTransport

Includes:
Credentials
Defined in:
lib/chef-config/mixin/train_transport.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Credentials

#credentials_profile, #parse_credentials_file

Instance Attribute Details

#loggerObject

Returns the value of attribute logger.



28
29
30
# File 'lib/chef-config/mixin/train_transport.rb', line 28

def logger
  @logger
end

Instance Method Details

#build_transportObject



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# 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

#configObject

Raises:

  • (NotImplementedError)


138
139
140
# File 'lib/chef-config/mixin/train_transport.rb', line 138

def config
  raise NotImplementedError
end

#contains_split_fqdn?(hash, fqdn) ⇒ Boolean

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

Returns:

  • (Boolean)


61
62
63
64
65
66
67
68
69
70
# 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_pathObject

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)

Raises:

  • (ArgumentError)


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# 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

#initialize(logger) ⇒ Object



30
31
32
# File 'lib/chef-config/mixin/train_transport.rb', line 30

def initialize(logger)
  @logger = logger
end

#load_credentials(profile) ⇒ Object

Returns a RFC099 credentials profile as a hash



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 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