Class: Kafo::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/kafo/configuration.rb

Constant Summary collapse

DEFAULT =
{
  ScenarioOption::NAME                      => '',
  ScenarioOption::DESCRIPTION               => '',
  ScenarioOption::ENABLED                   => true,
  ScenarioOption::LOG_DIR                   => '/var/log/kafo',
  ScenarioOption::LOG_OWNER                 => nil,
  ScenarioOption::LOG_GROUP                 => nil,
  ScenarioOption::STORE_DIR                 => '',
  ScenarioOption::LOG_NAME                  => 'configuration.log',
  ScenarioOption::LOG_LEVEL                 => 'notice',
  ScenarioOption::NO_PREFIX                 => false,
  ScenarioOption::MAPPING                   => {},
  ScenarioOption::ANSWER_FILE               => './config/answers.yaml',
  ScenarioOption::INSTALLER_DIR             => '.',
  ScenarioOption::MODULE_DIRS               => ['./modules'],
  ScenarioOption::COLORS                    => Kafo::ColorScheme.colors_possible?,
  ScenarioOption::COLOR_OF_BACKGROUND       => :dark,
  ScenarioOption::HOOK_DIRS                 => [],
  ScenarioOption::CHECK_DIRS                => nil,
  ScenarioOption::CUSTOM                    => {},
  ScenarioOption::FACTS                     => {},
  ScenarioOption::LOW_PRIORITY_MODULES      => [],
  ScenarioOption::VERBOSE                   => false,
  ScenarioOption::VERBOSE_LOG_LEVEL         => 'notice',
  ScenarioOption::SKIP_PUPPET_VERSION_CHECK => false,
  ScenarioOption::PARSER_CACHE_PATH         => nil,
  ScenarioOption::IGNORE_UNDOCUMENTED       => nil,
  ScenarioOption::ORDER                     => nil,
  ScenarioOption::HIERA_CONFIG              => nil,
  ScenarioOption::KAFO_MODULES_DIR          => nil,
  ScenarioOption::CONFIG_HEADER_FILE        => nil,
  ScenarioOption::DONT_SAVE_ANSWERS         => nil,
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file, persist = true) ⇒ Configuration

Returns a new instance of Configuration.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/kafo/configuration.rb', line 52

def initialize(file, persist = true)
  @config_file = file
  @persist     = persist
  configure_application
  @logger = KafoConfigure.logger

  @answer_file = app[:answer_file]
  begin
    @data = load_yaml_file(@answer_file)
  rescue Errno::ENOENT
    puts "No answer file at #{@answer_file} found, can not continue"
    KafoConfigure.exit(:no_answer_file)
  end

  @config_dir = File.dirname(@config_file)
  @scenario_id = Configuration.get_scenario_id(@config_file)
end

Instance Attribute Details

#answer_fileObject (readonly)

Returns the value of attribute answer_file.



12
13
14
# File 'lib/kafo/configuration.rb', line 12

def answer_file
  @answer_file
end

#config_fileObject (readonly)

Returns the value of attribute config_file.



12
13
14
# File 'lib/kafo/configuration.rb', line 12

def config_file
  @config_file
end

#scenario_idObject (readonly)

Returns the value of attribute scenario_id.



12
13
14
# File 'lib/kafo/configuration.rb', line 12

def scenario_id
  @scenario_id
end

Class Method Details

.get_scenario_id(filename) ⇒ Object



48
49
50
# File 'lib/kafo/configuration.rb', line 48

def self.get_scenario_id(filename)
  File.basename(filename, '.yaml')
end

Instance Method Details

#[](key) ⇒ Object

if a value is a true we return empty hash because we have no specific options for a particular puppet module



234
235
236
237
# File 'lib/kafo/configuration.rb', line 234

def [](key)
  value = @data[key]
  value.is_a?(Hash) ? value : {}
end

#add_mapping(module_name, mapping) ⇒ Object



169
170
171
172
# File 'lib/kafo/configuration.rb', line 169

def add_mapping(module_name, mapping)
  app[:mapping][module_name] = mapping
  save_configuration(app)
end

#add_module(name) ⇒ Object



161
162
163
164
165
166
167
# File 'lib/kafo/configuration.rb', line 161

def add_module(name)
  mod = PuppetModule.new(name, configuration: self).parse
  unless modules.map(&:name).include?(mod.name)
    mod.enable
    @modules << mod
  end
end

#answersObject



319
320
321
# File 'lib/kafo/configuration.rb', line 319

def answers
  @data
end

#appObject



95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/kafo/configuration.rb', line 95

def app
  @app ||= begin
    begin
      configuration = load_yaml_file(@config_file)
    rescue
      configuration = {}
    end

    result            = DEFAULT.merge(configuration || {})
    result[:module_dirs] = result[:modules_dir] || result[:module_dirs]
    result.delete(:modules_dir)
    result
  end
end

#check_dirsObject



145
146
147
# File 'lib/kafo/configuration.rb', line 145

def check_dirs
  [app[:check_dirs] || File.join(root_dir, 'checks')].flatten
end

#config_headerObject



244
245
246
247
248
# File 'lib/kafo/configuration.rb', line 244

def config_header
  files          = [app[:config_header_file], File.join(gem_root, '/config/config_header.txt')].compact
  file           = files.find { |f| File.exist?(f) }
  @config_header ||= file.nil? ? '' : File.read(file)
end

#configure_applicationObject



89
90
91
92
93
# File 'lib/kafo/configuration.rb', line 89

def configure_application
  result = app
  save_configuration(result)
  result
end

#gem_rootObject



153
154
155
# File 'lib/kafo/configuration.rb', line 153

def gem_root
  File.join(File.dirname(__FILE__), '../../')
end

#get_custom(key) ⇒ Object



110
111
112
# File 'lib/kafo/configuration.rb', line 110

def get_custom(key)
  custom_storage[key.to_sym]
end

#get_custom_fact(key) ⇒ Object



118
119
120
# File 'lib/kafo/configuration.rb', line 118

def get_custom_fact(key)
  custom_fact_storage[key.to_s]
end

#has_custom_fact?(key) ⇒ Boolean

Returns:

  • (Boolean)


126
127
128
# File 'lib/kafo/configuration.rb', line 126

def has_custom_fact?(key)
  custom_fact_storage.key?(key.to_s)
end

#kafo_modules_dirObject



157
158
159
# File 'lib/kafo/configuration.rb', line 157

def kafo_modules_dir
  app[:kafo_modules_dir] || (gem_root + '/modules')
end

#log_exists?Boolean

Returns:

  • (Boolean)


315
316
317
# File 'lib/kafo/configuration.rb', line 315

def log_exists?
  log_files.any? { |f| File.size(f) > 0 }
end

#log_fileObject



303
304
305
# File 'lib/kafo/configuration.rb', line 303

def log_file
  File.join(app[:log_dir], app[:log_name])
end

#log_filesObject



311
312
313
# File 'lib/kafo/configuration.rb', line 311

def log_files
  Dir.glob(log_files_pattern)
end

#log_files_patternObject



307
308
309
# File 'lib/kafo/configuration.rb', line 307

def log_files_pattern
  log_file.sub(/(\.log)\Z/i) { |suffix| "{.[0-9]*,}#{suffix}" }
end

#migrate_configuration(from_config, options = {}) ⇒ Object



174
175
176
177
178
179
180
181
182
183
184
# File 'lib/kafo/configuration.rb', line 174

def migrate_configuration(from_config, options = {})
  keys_to_skip = options.fetch(:skip, [])
  keys = [:log_dir, :log_name, :log_level, :no_prefix,
    :colors, :color_of_background, :custom, :verbose_log_level]
  keys += options.fetch(:with, [])
  keys.each do |key|
    next if keys_to_skip.include?(key)
    app[key] = from_config.app[key]
  end
  save_configuration(app)
end

#migrations_dirObject



336
337
338
# File 'lib/kafo/configuration.rb', line 336

def migrations_dir
  @config_file.gsub(/\.yaml$/, '.migrations')
end

#module(name) ⇒ Object



137
138
139
# File 'lib/kafo/configuration.rb', line 137

def module(name)
  modules.find { |m| m.name == name }
end

#module_dirsObject



149
150
151
# File 'lib/kafo/configuration.rb', line 149

def module_dirs
  [app[:module_dirs] || (app[:installer_dir] + '/modules')].flatten.map { |dir| File.expand_path(dir) }.uniq
end

#module_enabled?(mod) ⇒ Boolean

Returns:

  • (Boolean)


239
240
241
242
# File 'lib/kafo/configuration.rb', line 239

def module_enabled?(mod)
  value = @data[mod.is_a?(String) ? mod : mod.identifier]
  !!value || value.is_a?(Hash)
end

#modulesObject



130
131
132
133
134
135
# File 'lib/kafo/configuration.rb', line 130

def modules
  @modules ||= begin
    register_data_types
    @data.keys.map { |mod| PuppetModule.new(mod, configuration: self).parse }.sort
  end
end

#param(mod_name, param_name) ⇒ Object



261
262
263
264
# File 'lib/kafo/configuration.rb', line 261

def param(mod_name, param_name)
  mod = self.module(mod_name)
  mod.nil? ? nil : mod.params.find { |p| p.name == param_name }
end

#paramsObject



257
258
259
# File 'lib/kafo/configuration.rb', line 257

def params
  @params ||= modules.map(&:params).flatten
end

#params_changed(old_config) ⇒ Object



286
287
288
289
290
291
292
293
# File 'lib/kafo/configuration.rb', line 286

def params_changed(old_config)
  # finds params that had different value in the old config
  params.select do |par|
    next unless par.module.enabled?
    old_param = old_config.param(par.module.class_name, par.name)
    old_param && old_param.value != par.value
  end
end

#params_default_valuesObject



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/kafo/configuration.rb', line 186

def params_default_values
  @params_default_values ||= begin
    execution_env = ExecutionEnvironment.new(self)
    KafoConfigure.exit_handler.register_cleanup_path(execution_env.directory)

    puppetconf = execution_env.configure_puppet('noop' => true)

    dump_manifest = <<EOS
      #{includes}
      class { '::kafo_configure::dump_values':
        lookups   => [#{param_lookups_to_dump}],
        variables => [#{params_to_dump}],
      }
EOS

    @logger.info "Loading default values from puppet modules..."
    command = PuppetCommand.new(dump_manifest, [], puppetconf, self).command
    stdout, stderr, status = Open3.capture3(*PuppetCommand.format_command(command))

    @logger.debug stdout
    @logger.debug stderr

    unless status.success?
      log = app[:log_dir] + '/' + app[:log_name]

      if (version_mismatch = /kafo_configure::puppet_version_failure: (.+?\))/.match(stderr))
        puts version_mismatch[1]
        puts "Cannot continue due to incompatible version of Puppet. Use --skip-puppet-version-check to disable this check."
        @logger.error version_mismatch[1]
        @logger.error 'Incompatible version of Puppet used, cannot continue'
        KafoConfigure.exit(:puppet_version_error)
      else
        puts "Could not get default values, check log file at #{log} for more information"
        @logger.error command
        @logger.error stderr
        @logger.error 'Could not get default values, cannot continue'
        KafoConfigure.exit(:defaults_error)
      end
    end

    @logger.info "... finished loading default values from puppet modules."

    load_yaml_from_output(stdout.split($/))
  end
end

#params_missing(old_config) ⇒ Object



295
296
297
298
299
300
301
# File 'lib/kafo/configuration.rb', line 295

def params_missing(old_config)
  # finds params that are present but will be missing in the new config
  old_config.params.select do |par|
    next if !par.module.enabled? || !module_enabled?(par.module.name)
    param(par.module.class_name, par.name).nil?
  end
end

#parser_cacheObject



340
341
342
343
344
# File 'lib/kafo/configuration.rb', line 340

def parser_cache
  if app[:parser_cache_path]
    @parser_cache ||= Kafo::ParserCacheReader.new_from_file(app[:parser_cache_path])
  end
end

#preset_defaults_from_other_config(other_config) ⇒ Object



280
281
282
283
284
# File 'lib/kafo/configuration.rb', line 280

def preset_defaults_from_other_config(other_config)
  params_changed(other_config).each do |par|
    param(par.module.class_name, par.name).value = other_config.param(par.module.class_name, par.name).value
  end
end

#preset_defaults_from_puppetObject



266
267
268
269
270
271
# File 'lib/kafo/configuration.rb', line 266

def preset_defaults_from_puppet
  # set values based on default_values
  params.each do |param|
    param.set_default_from_dump(params_default_values)
  end
end

#preset_defaults_from_yamlObject



273
274
275
276
277
278
# File 'lib/kafo/configuration.rb', line 273

def preset_defaults_from_yaml
  # set values based on YAML
  params.each do |param|
    param.set_value_by_config(self)
  end
end

#root_dirObject



141
142
143
# File 'lib/kafo/configuration.rb', line 141

def root_dir
  File.expand_path(app[:installer_dir])
end

#run_migrationsObject



323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/kafo/configuration.rb', line 323

def run_migrations
  migrations = Kafo::Migrations.new(migrations_dir)
  @app, @data = migrations.run(app, answers)
  if migrations.migrations.count > 0
    @modules = nil # force the lazy loaded modules to reload next time they are used
    save_configuration(app)
    store(answers)
    migrations.store_applied
    @logger.notice("#{migrations.migrations.count} migration/s were applied. Updated configuration was saved.")
  end
  migrations.migrations.count
end

#save_configuration(configuration) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/kafo/configuration.rb', line 70

def save_configuration(configuration)
  return true unless @persist

  trimmed = configuration.reject do |key, value|
    !DEFAULT.key?(key) || value.nil?
  end

  begin
    FileUtils.touch @config_file
    File.chmod 0600, @config_file
    File.open(@config_file, 'w') do |file|
      file.write(format(YAML.dump(trimmed.sort.to_h)))
    end
  rescue Errno::EACCES
    puts "Insufficient permissions to write to #{@config_file}, can not continue"
    KafoConfigure.exit(:insufficient_permissions)
  end
end

#set_custom(key, value) ⇒ Object



114
115
116
# File 'lib/kafo/configuration.rb', line 114

def set_custom(key, value)
  custom_storage[key.to_sym] = value
end

#set_custom_fact(key, value) ⇒ Object



122
123
124
# File 'lib/kafo/configuration.rb', line 122

def set_custom_fact(key, value)
  custom_fact_storage[key.to_s] = value
end

#store(data, file = nil) ⇒ Object



250
251
252
253
254
255
# File 'lib/kafo/configuration.rb', line 250

def store(data, file = nil)
  filename = file || answer_file
  FileUtils.touch filename
  File.chmod 0600, filename
  File.open(filename, 'w') { |f| f.write(config_header + format(YAML.dump(data))) }
end