class Kafo::KafoConfigure
Attributes
check_dirs[RW]
config[RW]
config_file[RW]
exit_handler[RW]
gem_root[RW]
hooking[W]
kafo_modules_dir[RW]
logger[RW]
module_dirs[RW]
root_dir[RW]
scenario_manager[RW]
store[RW]
verbose[RW]
puppet_report[RW]
Public Class Methods
exit(code, &block)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 59 def exit(code, &block) exit_handler.exit(code, &block) end
exit_code()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 63 def exit_code self.exit_handler.exit_code end
help(*args)
click to toggle source
Calls superclass method
# File lib/kafo/kafo_configure.rb, line 71 def help(*args) kafo = args.pop builder_class = kafo.full_help? ? HelpBuilders::Advanced : HelpBuilders::Basic args.push builder_class.new(kafo.params) super(*args) end
hooking()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 49 def hooking @hooking ||= Hooking.new end
in_help_mode?()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 67 def in_help_mode? ARGV.include?('--help') || ARGV.include?('--full-help') || ARGV.include?('-h') end
new(*args)
click to toggle source
Calls superclass method
# File lib/kafo/kafo_configure.rb, line 101 def initialize(*args) self.class.preset_color_scheme self.class.logger = Logger.new self.class.exit_handler = ExitHandler.new @progress_bar = nil @config_reload_requested = false scenario_manager = setup_scenario_manager self.class.scenario_manager = scenario_manager # Handle --list-scenarios before we need them scenario_manager.list_available_scenarios if ARGV.include?('--list-scenarios') scenario_manager.check_enable_scenario scenario_manager.check_disable_scenario setup_config(config_file) self.class.hooking.execute(:pre_migrations) reload_config applied_total = self.class.config.run_migrations request_config_reload if applied_total > 0 if ARGV.include?('--migrations-only') verbose = ARGV.include?('--verbose') || ARGV.include?('-v') Logging.setup(verbose: verbose) self.class.logger.notice('Log buffers flushed') self.class.exit(0) end reload_config if scenario_manager.configured? scenario_manager.check_scenario_change(self.class.config_file) if scenario_manager.scenario_changed?(self.class.config_file) && !self.class.in_help_mode? prev_config = scenario_manager.load_configuration(scenario_manager.previous_scenario) prev_config.run_migrations self.class.config.migrate_configuration(prev_config, :skip => [:log_name]) setup_config(self.class.config_file) self.class.logger.notice("Due to scenario change the configuration (#{self.class.config_file}) was updated with #{scenario_manager.previous_scenario} and reloaded.") end end super self.class.hooking.execute(:boot) set_app_options # define args for installer # we need to parse app config params using clamp even before run method does it # so we limit parsing only to app config options (because of --help and later defined params) parse clamp_app_arguments parse_app_arguments # set values from ARGS to config.app if ARGV.any? { |option| ['--help', '--full-help'].include? option } Logging.setup_verbose(level: :error) else Logging.setup(verbose: config.app[:verbose]) end logger.notice("Loading installer configuration. This will take some time.") self.class.set_color_scheme self.class.hooking.execute(:init) set_parameters # here the params gets parsed and we need app config populated set_options end
preset_color_scheme()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 88 def preset_color_scheme match = ARGV.join(' ').match(/--color-of-background[ =](\w+)/) background = match && match[1] ColorScheme.new(:background => background, :colors => use_colors?).setup end
run()
click to toggle source
Calls superclass method
# File lib/kafo/kafo_configure.rb, line 53 def run return super rescue SystemExit self.exit_handler.exit(self.exit_code) # fail in initialize end
set_color_scheme()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 94 def set_color_scheme ColorScheme.new( :background => config.app[:color_of_background], :colors => use_colors?).setup end
use_colors?()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 78 def use_colors? if config colors = config.app[:colors] else colors = ARGV.include?('--no-colors') ? false : nil colors = ARGV.include?('--colors') ? true : nil if colors.nil? end colors end
Public Instance Methods
add_module(name)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 250 def add_module(name) config.add_module(name) reset_params_cache self.module(name) end
config()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 165 def config self.class.config end
enabled_params()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 241 def enabled_params params.select { |p| p.module.enabled? } end
execute()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 189 def execute parse_cli_arguments if !config.app[:verbose] @progress_bar = config.app[:colors] ? ProgressBars::Colored.new : ProgressBars::BlackWhite.new end unless skip_checks_i_know_better? unless SystemChecker.check puts "Your system does not meet configuration criteria" self.class.exit(:invalid_system) end end self.class.hooking.execute(:pre_validations) if interactive? wizard = Wizard.new(self) wizard.run else unless validate_all puts "Error during configuration, exiting" self.class.exit(:invalid_values) end end self.class.hooking.execute(:pre_commit) unless dont_save_answers? || noop? config.configure_application store_params self.class.scenario_manager.link_last_scenario(self.class.config_file) if self.class.scenario_manager.configured? end run_installation return self rescue SystemExit return self end
exit_code()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 226 def exit_code self.class.exit_code end
help()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 230 def help self.class.help(invocation_path, self) end
logger()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 173 def logger self.class.logger end
module(name)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 260 def module(name) modules.detect { |m| m.name == name } end
modules()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 256 def modules config.modules.sort end
param(mod, name)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 264 def param(mod, name) config.param(mod, name) end
params()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 234 def params @params ||= modules.map(&:params).flatten rescue KafoParsers::ModuleName => e puts e self.class.exit(:unknown_module) end
request_config_reload()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 268 def request_config_reload @config_reload_requested = true end
reset_params_cache()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 245 def reset_params_cache @params = nil params end
run(*args)
click to toggle source
Calls superclass method
# File lib/kafo/kafo_configure.rb, line 177 def run(*args) started_at = Time.now logger.debug("Running installer with args #{args.inspect}") if config.app[:verbose] logger.notice("Running installer with log based terminal output at level #{config.app[:verbose_log_level].upcase}.") logger.notice("Use -l to set the terminal output log level to ERROR, WARN, NOTICE, INFO, or DEBUG. See --full-help for definitions.") end super ensure logger.debug("Installer finished in #{Time.now - started_at} seconds") end
store()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 169 def store self.class.store end
Private Instance Methods
app_option(*args, &block)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 325 def app_option(*args, &block) self.class.app_option(*args, &block) end
argument_missing?(value)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 467 def argument_missing?(value) !!self.class.declared_options.find { |opt| opt.handles?(value) } end
build_yes_no_variants(s)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 427 def build_yes_no_variants(s) [ s.sub('[no-]', ''), s.sub('[no-]', 'no-') ] end
clamp_app_arguments()
click to toggle source
ARGV can contain values for attributes e.g. ['-l', 'info'] so we accept either allowed args or those that does not start with '-' and are right after accepted argument
# File lib/kafo/kafo_configure.rb, line 411 def clamp_app_arguments @allowed_clamp_app_arguments = self.class.declared_options.map do |option| option.switches.map { |s| is_yes_no_flag?(s) ? build_yes_no_variants(s) : s } end @allowed_clamp_app_arguments.flatten! last_was_accepted = false ARGV.select do |arg| last_was_accepted = is_allowed_attribute_name?(arg) || (last_was_accepted && is_value?(arg)) end end
config_file()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 566 def config_file return CONFIG_FILE if defined?(CONFIG_FILE) && File.exist?(CONFIG_FILE) return self.class.scenario_manager.select_scenario if self.class.scenario_manager.configured? return '/etc/kafo/kafo.yaml' if File.exist?('/etc/kafo/kafo.yaml') return "#{::RbConfig::CONFIG['sysconfdir']}/kafo/kafo.yaml" if File.exist?("#{::RbConfig::CONFIG['sysconfdir']}/kafo/kafo.yaml") File.join(Dir.pwd, 'config', 'kafo.yaml') end
is_allowed_attribute_name?(str)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 431 def is_allowed_attribute_name?(str) str =~ /([a-zA-Z0-9_-]*)([= ].*)?/ && @allowed_clamp_app_arguments.include?($1) end
is_value?(str)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 435 def is_value?(str) !str.start_with?('-') end
is_yes_no_flag?(s)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 423 def is_yes_no_flag?(s) s.include?('[no-]') end
normalize_encoding(line)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 574 def normalize_encoding(line) line.valid_encoding? ? line : line.encode('UTF-16be', :invalid => :replace, :replace => '?').encode('UTF-8') end
parse_app_arguments()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 439 def parse_app_arguments self.class.declared_options.each do |option| name = option.attribute_name value = send(option.flag? ? "#{name}?" : name) config.app[name.to_sym] = value.nil? ? option.default_value : value end end
parse_cli_arguments()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 447 def parse_cli_arguments # enable/disable modules according to CLI config.modules.each { |mod| send("enable_#{mod.name}?") ? mod.enable : mod.disable } # set and reset values coming from CLI arguments params.each do |param| if send("reset_#{u(with_prefix(param))}?") param.unset_value end variable_name = u(with_prefix(param)) variable_name += '_list' if param.multivalued? cli_value = instance_variable_get("@#{variable_name}") if argument_missing?(cli_value) puts "Parameter #{with_prefix(param)} is missing a value on the command line" self.class.exit(:missing_argument) end param.value = cli_value unless cli_value.nil? end end
progress_log(method, message, logger)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 557 def progress_log(method, message, logger) @progress_bar.print_error(message + "\n") if method == :error && @progress_bar logger.send(method, message) end
reload_config()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 293 def reload_config if @config_reload_requested scenario_manager = setup_scenario_manager self.class.scenario_manager = scenario_manager setup_config(self.class.config_file) self.class.logger.notice('Installer configuration was reloaded') @config_reload_requested = false end end
run_installation()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 487 def run_installation self.class.hooking.execute(:pre) execution_env = ExecutionEnvironment.new(config) self.class.exit_handler.register_cleanup_path(execution_env.directory) execution_env.store_answers puppetconf = execution_env.configure_puppet( 'color' => false, 'evaltrace' => true, 'noop' => !!noop?, 'profile' => !!profile?, 'show_diff' => true, ) self.class.exit_handler.exit_code = 0 exit_status = nil options = [ '--verbose', '--debug', '--detailed-exitcodes', ] begin command = PuppetCommand.new('include kafo_configure', options, puppetconf).command log_parser = PuppetLogParser.new logger = Logger.new('configure') logger.notice("Starting system configuration.") PTY.spawn(*PuppetCommand.format_command(command)) do |stdin, stdout, pid| stdin.each do |line| line = normalize_encoding(line) method, message = log_parser.parse(line) progress_log(method, message, logger) if (output = line.match(/(?:.+\]): Starting to evaluate the resource(?: \((?<count>\d+) of (?<total>\d+)\))?/)) if (output[:count].to_i % 250) == 1 && output[:count].to_i != 1 logger.notice("#{output[:count].to_i - 1} configuration steps out of #{output[:total]} steps complete.") end end @progress_bar.update(line) if @progress_bar end rescue Errno::EIO # we reach end of input exit_status = PTY.check(pid, true) if exit_status.nil? # process is still running begin Process.wait(pid) rescue Errno::ECHILD # process could exit meanwhile so we rescue end self.class.exit_handler.exit_code = $?.exitstatus end end rescue PTY::ChildExited => e # could be raised by PTY.check self.class.exit_handler.exit_code = e.status.exitstatus end @progress_bar.close if @progress_bar logger.notice "System configuration has finished." if (last_report = execution_env.reports.last) # For debugging: you can easily copy the last report to fixtures # FileUtils.cp(last_report, File.join(__dir__, '..', '..', 'test', 'fixtures', 'reports', File.basename(last_report))) self.puppet_report = PuppetReport.load_report_file(last_report) end self.class.hooking.execute(:post) self.class.exit(exit_code) end
set_app_options()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 348 def set_app_options app_option ['--[no-]colors'], :flag, 'Use color output on STDOUT', :default => config.app[:colors], :advanced => true app_option ['--color-of-background'], 'COLOR', 'Your terminal background is :bright or :dark', :default => config.app[:color_of_background], :advanced => true app_option ['--dont-save-answers'], :flag, "Skip saving answers to '#{self.class.config.answer_file}'?", :default => config.app[:dont_save_answers], :advanced => true app_option '--ignore-undocumented', :flag, 'Ignore inconsistent parameter documentation', :default => config.app[:ignore_undocumented], :advanced => true app_option ['-i', '--interactive'], :flag, 'Run in interactive mode' app_option '--log-level', 'LEVEL', 'Log level for log file output', :default => config.app[:log_level], :advanced => true app_option ['-n', '--noop'], :flag, 'Run puppet in noop mode?', :default => false app_option ['-p', '--profile'], :flag, 'Run puppet in profile mode?', :default => false, :advanced => true app_option ['-s', '--skip-checks-i-know-better'], :flag, 'Skip all system checks', :default => false app_option ['--skip-puppet-version-check'], :flag, 'Skip check for compatible Puppet versions', :default => false, :advanced => true app_option ['-v', '--[no-]verbose'], :flag, 'Display log on STDOUT instead of progressbar', :default => config.app[:verbose] app_option ['-l', '--verbose-log-level'], 'LEVEL', terminal_log_levels_message, :default => 'notice' app_option ['-S', '--scenario'], 'SCENARIO', 'Use installation scenario' app_option ['--disable-scenario'], 'SCENARIO', 'Disable installation scenario', :advanced => true app_option ['--enable-scenario'], 'SCENARIO', 'Enable installation scenario', :advanced => true app_option ['--list-scenarios'], :flag, 'List available installation scenarios' app_option ['--force'], :flag, 'Force change of installation scenario', :advanced => true app_option ['--compare-scenarios'], :flag, 'Show changes between last used scenario and the scenario specified with -S or --scenario argument', :advanced => true app_option ['--migrations-only'], :flag, 'Apply migrations to a selected scenario and exit', :advanced => true app_option ['--[no-]parser-cache'], :flag, 'Force use or bypass of Puppet module parser cache', :advanced => true end
set_options()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 388 def set_options app_option '--full-help', :flag, "print complete help" do @full_help = true request_help end modules.each do |mod| app_option d("--[no-]enable-#{mod.name}"), :flag, "Enable '#{mod.name}' puppet module", :default => mod.enabled? end params.sort.each do |param| doc = param.doc.nil? ? 'UNDOCUMENTED' : param.doc.join("\n") app_option parametrize(param), '', doc + " (current: #{param.value_to_s})", :multivalued => param.multivalued? app_option parametrize(param, 'reset-'), :flag, "Reset #{param.name} to the default value (#{param.default_to_s})" end end
set_parameters()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 315 def set_parameters config.preset_defaults_from_puppet self.class.hooking.execute(:pre_values) config.preset_defaults_from_yaml if self.class.scenario_manager.scenario_changed?(config.config_file) prev_scenario = self.class.scenario_manager.load_and_setup_configuration(self.class.scenario_manager.previous_scenario) config.preset_defaults_from_other_config(prev_scenario) end end
setup_config(conf_file)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 274 def setup_config(conf_file) self.class.config_file = conf_file self.class.config = Configuration.new(self.class.config_file) if self.class.config.parser_cache self.class.config.parser_cache.force = true if ARGV.include?('--parser-cache') self.class.config.parser_cache.force = false if ARGV.include?('--no-parser-cache') end self.class.root_dir = self.class.config.root_dir self.class.check_dirs = self.class.config.check_dirs self.class.module_dirs = self.class.config.module_dirs self.class.gem_root = self.class.config.gem_root self.class.kafo_modules_dir = self.class.config.kafo_modules_dir self.class.hooking.load self.class.store = setup_store self.class.hooking.kafo = self end
setup_scenario_manager()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 303 def setup_scenario_manager ScenarioManager.new((defined?(CONFIG_DIR) && CONFIG_DIR) || (defined?(CONFIG_FILE) && CONFIG_FILE)) end
setup_store()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 307 def setup_store store = Store.new() store_path = self.class.config.app[:store_dir] store_path = File.expand_path(File.join(CONFIG_DIR, '../store.d')) if store_path.empty? && defined?(CONFIG_DIR) store.add_dir(store_path) if File.exist?(store_path) store end
store_params(file = nil)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 471 def store_params(file = nil) data = Hash[config.modules.map { |mod| [mod.identifier, mod.enabled? ? mod.params_hash : false] }] config.store(data, file) end
terminal_log_levels_message()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 329 def terminal_log_levels_message if ARGV.include?('--full-help') <<~HEREDOC.chomp Log level for log based terminal output. The available levels are ERROR - Only show errors which prevented the installer from completing successfully. WARN - Deprecation warnings and other information users may want to be aware of. NOTICE - High level information about installer execution and progress. INFO - More detailed information about execution and progress. Also shows when the installer makes a change to system configuration. DEBUG - Show all information about execution, including configuration items where no change was needed. HEREDOC else <<~HEREDOC.chomp Log level for log based terminal output. The available levels are ERROR, WARN, NOTICE, INFO, DEBUG. See --full-help for definitions. HEREDOC end end
unset()
click to toggle source
# File lib/kafo/kafo_configure.rb, line 562 def unset params.select { |p| p.module.enabled? && p.value_set.nil? } end
validate_all(logging = true)
click to toggle source
# File lib/kafo/kafo_configure.rb, line 476 def validate_all(logging = true) logger.info "Running validation checks." results = enabled_params.map do |param| result = param.valid? errors = param.validation_errors.join(', ') progress_log(:error, "Parameter #{with_prefix(param)} invalid: #{errors}", logger) if logging && !result result end results.all? end