kafo 4.1.0 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +619 -9
- data/README.md +3 -2
- data/doc/kafo_run.png +0 -0
- data/doc/kafo_run.uml +2 -0
- data/doc/plantuml.jar +0 -0
- data/lib/kafo/app_option/declaration.rb +19 -0
- data/lib/kafo/app_option/definition.rb +16 -0
- data/lib/kafo/configuration.rb +29 -7
- data/lib/kafo/exit_handler.rb +1 -1
- data/lib/kafo/help_builders/base.rb +5 -3
- data/lib/kafo/help_builders/basic.rb +13 -2
- data/lib/kafo/hook_context.rb +101 -26
- data/lib/kafo/hooking.rb +20 -13
- data/lib/kafo/kafo_configure.rb +145 -121
- data/lib/kafo/logger.rb +13 -123
- data/lib/kafo/logging.rb +128 -0
- data/lib/kafo/puppet_log_parser.rb +11 -5
- data/lib/kafo/scenario_manager.rb +22 -16
- data/lib/kafo/system_checker.rb +1 -1
- data/lib/kafo/version.rb +1 -1
- data/lib/kafo/wizard.rb +7 -7
- data/modules/kafo_configure/spec/fixtures/manifests/site.pp +0 -0
- metadata +12 -7
data/README.md
CHANGED
@@ -79,8 +79,8 @@ All configuration related files are to be found in the config directory.
|
|
79
79
|
|
80
80
|
You can supply custom location for your scenario configuration and answer files
|
81
81
|
and change configuration and answer files names using options:
|
82
|
-
```
|
83
|
-
kafofy --help
|
82
|
+
```console
|
83
|
+
$ kafofy --help
|
84
84
|
Usage: kafofy [options]
|
85
85
|
-c, --config_dir DIR location of the scenarios configuration directory [./config/installer-scenarios.d/]
|
86
86
|
-s, --scenario SCENARIO scenario file name (without extension) [default]
|
@@ -736,6 +736,7 @@ We currently support the following hooks.
|
|
736
736
|
* pre_commit - after validations or interactive wizard have completed, all parameter values are set but not yet stored in the answer file
|
737
737
|
* pre - just before puppet is executed to converge system, after parameter values are stored in the answer file
|
738
738
|
* post - just after puppet is executed to converge system
|
739
|
+
* pre_exit - happens during exit handling, before exit is completed
|
739
740
|
|
740
741
|
For better understanding when the hooks are executed see the [diagram](doc/kafo_run.png).
|
741
742
|
|
data/doc/kafo_run.png
CHANGED
Binary file
|
data/doc/kafo_run.uml
CHANGED
data/doc/plantuml.jar
ADDED
Binary file
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'definition'
|
2
|
+
|
3
|
+
module Kafo
|
4
|
+
module AppOption
|
5
|
+
module Declaration
|
6
|
+
|
7
|
+
include Clamp::Option::Declaration
|
8
|
+
|
9
|
+
def app_option(switches, type, description, opts = {}, &block)
|
10
|
+
AppOption::Definition.new(switches, type, description, opts).tap do |option|
|
11
|
+
block ||= option.default_conversion_block
|
12
|
+
define_accessors_for(option, &block)
|
13
|
+
declared_options << option
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Kafo
|
2
|
+
module AppOption
|
3
|
+
class Definition < Clamp::Option::Definition
|
4
|
+
|
5
|
+
def initialize(switches, type, description, options = {})
|
6
|
+
@advanced = options.fetch(:advanced, false)
|
7
|
+
super(switches, type, description, options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def advanced?
|
11
|
+
@advanced
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/kafo/configuration.rb
CHANGED
@@ -15,9 +15,11 @@ module Kafo
|
|
15
15
|
:description => '',
|
16
16
|
:enabled => true,
|
17
17
|
:log_dir => '/var/log/kafo',
|
18
|
+
:log_owner => nil,
|
19
|
+
:log_group => nil,
|
18
20
|
:store_dir => '',
|
19
21
|
:log_name => 'configuration.log',
|
20
|
-
:log_level => '
|
22
|
+
:log_level => 'notice',
|
21
23
|
:no_prefix => false,
|
22
24
|
:mapping => {},
|
23
25
|
:answer_file => './config/answers.yaml',
|
@@ -26,11 +28,20 @@ module Kafo
|
|
26
28
|
:colors => Kafo::ColorScheme.colors_possible?,
|
27
29
|
:color_of_background => :dark,
|
28
30
|
:hook_dirs => [],
|
31
|
+
:check_dirs => nil,
|
29
32
|
:custom => {},
|
30
33
|
:facts => {},
|
31
34
|
:low_priority_modules => [],
|
32
|
-
:
|
33
|
-
:
|
35
|
+
:verbose => false,
|
36
|
+
:verbose_log_level => 'notice',
|
37
|
+
:skip_puppet_version_check => false,
|
38
|
+
:parser_cache_path => nil,
|
39
|
+
:ignore_undocumented => nil,
|
40
|
+
:order => nil,
|
41
|
+
:hiera_config => nil,
|
42
|
+
:kafo_modules_dir => nil,
|
43
|
+
:config_header_file => nil,
|
44
|
+
:dont_save_answers => nil,
|
34
45
|
}
|
35
46
|
|
36
47
|
def self.get_scenario_id(filename)
|
@@ -57,10 +68,17 @@ module Kafo
|
|
57
68
|
|
58
69
|
def save_configuration(configuration)
|
59
70
|
return true unless @persist
|
71
|
+
|
72
|
+
trimmed = configuration.reject do |key, value|
|
73
|
+
!DEFAULT.key?(key) || value.nil?
|
74
|
+
end
|
75
|
+
|
60
76
|
begin
|
61
77
|
FileUtils.touch @config_file
|
62
78
|
File.chmod 0600, @config_file
|
63
|
-
File.open(@config_file, 'w')
|
79
|
+
File.open(@config_file, 'w') do |file|
|
80
|
+
file.write(format(YAML.dump(trimmed.sort.to_h)))
|
81
|
+
end
|
64
82
|
rescue Errno::EACCES
|
65
83
|
puts "Insufficient permissions to write to #{@config_file}, can not continue"
|
66
84
|
KafoConfigure.exit(:insufficient_permissions)
|
@@ -104,6 +122,10 @@ module Kafo
|
|
104
122
|
custom_fact_storage[key.to_s] = value
|
105
123
|
end
|
106
124
|
|
125
|
+
def has_custom_fact?(key)
|
126
|
+
custom_fact_storage.key?(key.to_s)
|
127
|
+
end
|
128
|
+
|
107
129
|
def modules
|
108
130
|
@modules ||= begin
|
109
131
|
register_data_types
|
@@ -175,7 +197,7 @@ module Kafo
|
|
175
197
|
}
|
176
198
|
EOS
|
177
199
|
|
178
|
-
@logger.
|
200
|
+
@logger.notice 'Loading default values from puppet modules...'
|
179
201
|
command = PuppetCommand.new(dump_manifest, [], puppetconf, self).command
|
180
202
|
stdout, stderr, status = Open3.capture3(*PuppetCommand.format_command(command))
|
181
203
|
|
@@ -200,7 +222,7 @@ EOS
|
|
200
222
|
end
|
201
223
|
end
|
202
224
|
|
203
|
-
@logger.
|
225
|
+
@logger.notice "... finished"
|
204
226
|
|
205
227
|
load_yaml_from_output(stdout.split($/))
|
206
228
|
end
|
@@ -305,7 +327,7 @@ EOS
|
|
305
327
|
save_configuration(app)
|
306
328
|
store(answers)
|
307
329
|
migrations.store_applied
|
308
|
-
@logger.
|
330
|
+
@logger.notice("#{migrations.migrations.count} migration/s were applied. Updated configuration was saved.")
|
309
331
|
end
|
310
332
|
migrations.migrations.count
|
311
333
|
end
|
data/lib/kafo/exit_handler.rb
CHANGED
@@ -26,8 +26,8 @@ module Kafo
|
|
26
26
|
def exit(code, &block)
|
27
27
|
@exit_code = translate_exit_code(code)
|
28
28
|
block.call if block
|
29
|
+
KafoConfigure.hooking.execute(:pre_exit, log_stage: false)
|
29
30
|
logger.debug "Exit with status code: #{@exit_code} (signal was #{code})"
|
30
|
-
logger.dump_errors unless KafoConfigure.verbose
|
31
31
|
cleanup
|
32
32
|
Kernel.exit(@exit_code)
|
33
33
|
end
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Kafo
|
4
4
|
module HelpBuilders
|
5
|
-
DEFAULT_GROUP_NAME
|
6
|
-
DEFAULT_MODULE_NAME
|
5
|
+
DEFAULT_GROUP_NAME = 'Basic'
|
6
|
+
DEFAULT_MODULE_NAME = 'Generic'
|
7
7
|
IGNORE_IN_GROUP_NAME = /\s*parameters:?/
|
8
8
|
|
9
9
|
class Base < Clamp::Help::Builder
|
@@ -15,12 +15,14 @@ module Kafo
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def add_list(heading, items)
|
18
|
+
return if items.empty?
|
18
19
|
if heading == 'Options'
|
19
20
|
puts "\n#{heading}:"
|
20
21
|
|
21
22
|
data = by_module(items)
|
23
|
+
|
22
24
|
sorted_keys(data).each do |section|
|
23
|
-
if section ==
|
25
|
+
if section == DEFAULT_MODULE_NAME
|
24
26
|
add_list(header(1, section), data[section])
|
25
27
|
else
|
26
28
|
add_module(section, data[section])
|
@@ -4,8 +4,15 @@ module Kafo
|
|
4
4
|
module HelpBuilders
|
5
5
|
class Basic < Base
|
6
6
|
def add_module(name, items)
|
7
|
-
|
8
|
-
|
7
|
+
pruned = except_resets(items)
|
8
|
+
pruned = except_advanced(pruned)
|
9
|
+
data = by_parameter_groups(pruned)
|
10
|
+
add_list(module_header(name), data[DEFAULT_GROUP_NAME])
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_list(heading, items)
|
14
|
+
pruned = except_advanced(items)
|
15
|
+
super(heading, pruned)
|
9
16
|
end
|
10
17
|
|
11
18
|
def string
|
@@ -17,6 +24,10 @@ module Kafo
|
|
17
24
|
def except_resets(items)
|
18
25
|
items.select { |i| !i.help.first.strip.start_with?('--reset-') || !i.help.last.include?('to the default value (') }
|
19
26
|
end
|
27
|
+
|
28
|
+
def except_advanced(items)
|
29
|
+
items.reject { |item| item.respond_to?(:advanced?) && item.advanced? }
|
30
|
+
end
|
20
31
|
end
|
21
32
|
end
|
22
33
|
end
|
data/lib/kafo/hook_context.rb
CHANGED
@@ -3,49 +3,71 @@ require 'kafo/base_context'
|
|
3
3
|
|
4
4
|
module Kafo
|
5
5
|
class HookContext < BaseContext
|
6
|
+
# @return [Kafo::KafoConfigure]
|
6
7
|
attr_reader :kafo
|
7
8
|
|
8
|
-
def self.execute(kafo, &hook)
|
9
|
-
# TODO can be removed in 0.6, is DEPRECATED since 0.5
|
10
|
-
# instance_exec can be later changed to instance eval when people stop using |kafo| in their hooks
|
11
|
-
# and rely only on hook context DSL
|
12
|
-
if hook.arity > 0
|
13
|
-
kafo.logger.warn "Hook '#{name}' is using block with arguments which is DEPRECATED, access to kafo instance is " +
|
14
|
-
"provided by hook DSL, please remove |kafo| from your hook block"
|
15
|
-
end
|
16
|
-
new(kafo).instance_exec(kafo, &hook)
|
17
|
-
end
|
18
|
-
|
19
|
-
def initialize(kafo)
|
20
|
-
@kafo = kafo
|
21
|
-
end
|
22
|
-
|
23
9
|
# some of hooks won't print any message because logger is not yet configured
|
24
10
|
# configuration of logger depends on application configration (log level etc.)
|
25
|
-
#
|
11
|
+
#
|
12
|
+
# @return [Kafo::Logger]
|
13
|
+
#
|
14
|
+
# @example
|
26
15
|
# logger.warn "this combindation of parameters is untested"
|
27
|
-
|
28
|
-
|
16
|
+
attr_reader :logger
|
17
|
+
|
18
|
+
def self.execute(kafo, logger, &hook)
|
19
|
+
new(kafo, logger).instance_eval(&hook)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(kafo, logger)
|
23
|
+
@kafo = kafo
|
24
|
+
@logger = logger
|
29
25
|
end
|
30
26
|
|
31
27
|
# if you want to add new app_option be sure to do as soon as possible (usually boot hook)
|
32
|
-
# otherwise it may be
|
33
|
-
#
|
28
|
+
# otherwise it may be too late (e.g. when displaying help)
|
29
|
+
#
|
30
|
+
# @return [Clamp::Option]
|
31
|
+
#
|
32
|
+
# @example
|
34
33
|
# app_option '--log-level', 'LEVEL', 'Log level for log file output', :default => config.app[:log_level]:
|
34
|
+
#
|
35
|
+
# @example
|
35
36
|
# app_option ['-n', '--noop'], :flag, 'Run puppet in noop mode?', :default => false
|
36
37
|
def app_option(*args)
|
37
38
|
self.kafo.class.app_option(*args)
|
38
39
|
end
|
39
40
|
|
40
|
-
#
|
41
|
+
# Returns whether the given app option exists. This is useful when there's a conditional option that is
|
42
|
+
# determined during boot; this helper can be used in later hooks to determine whether the option exists.
|
43
|
+
#
|
44
|
+
# @param [Symbol, String] option
|
45
|
+
def app_option?(option)
|
46
|
+
self.kafo.config.app.key?(option.to_sym)
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param [Symbol, String] option
|
50
|
+
#
|
51
|
+
# @example
|
41
52
|
# app_value(:log_level)
|
53
|
+
#
|
42
54
|
# note the dash to underscore convention
|
43
55
|
def app_value(option)
|
44
56
|
self.kafo.config.app[option.to_sym]
|
45
57
|
end
|
46
58
|
|
47
|
-
#
|
59
|
+
# Return the parameter of a module. Note that the module may not actually
|
60
|
+
# be enabled.
|
61
|
+
#
|
62
|
+
# @param [String] module_name
|
63
|
+
# @param [String] parameter_name
|
64
|
+
#
|
65
|
+
# @return [Kafo::Param, nil]
|
66
|
+
#
|
67
|
+
# @example
|
48
68
|
# param('foreman', 'interface').value = 'eth0'
|
69
|
+
#
|
70
|
+
# @example
|
49
71
|
# param('foreman', 'interface').value = app_option('bind_on_interface')
|
50
72
|
def param(module_name, parameter_name)
|
51
73
|
self.kafo.param(module_name, parameter_name)
|
@@ -56,8 +78,14 @@ module Kafo
|
|
56
78
|
# part of answer file so it also preserves parameter values between runs. It also list
|
57
79
|
# its options in help output. You can also specify mapping for this module as a second
|
58
80
|
# parameter.
|
59
|
-
#
|
81
|
+
#
|
82
|
+
# @param [String] module_name
|
83
|
+
# @param [Hash, nil] mapping
|
84
|
+
#
|
85
|
+
# @example
|
60
86
|
# add_module('my_module')
|
87
|
+
#
|
88
|
+
# @example
|
61
89
|
# add_module('foreman::plugin::staypuft', {:dir_name => 'foreman', :manifest_name => 'plugin/staypuft'})
|
62
90
|
def add_module(module_name, mapping = nil)
|
63
91
|
self.kafo.config.add_mapping(module_name, mapping) if mapping
|
@@ -65,61 +93,108 @@ module Kafo
|
|
65
93
|
end
|
66
94
|
|
67
95
|
# Check if a module is enabled in the current configuration.
|
68
|
-
#
|
96
|
+
#
|
97
|
+
# @param [String] module_name
|
98
|
+
#
|
99
|
+
# @example
|
69
100
|
# module_enabled?('example')
|
70
101
|
def module_enabled?(module_name)
|
71
102
|
mod = self.kafo.module(module_name)
|
72
103
|
!mod.nil? && mod.enabled?
|
73
104
|
end
|
74
105
|
|
106
|
+
# Check if a module is present in the current configuration.
|
107
|
+
#
|
108
|
+
# @param [String] module_name
|
109
|
+
#
|
110
|
+
# @example
|
111
|
+
# module_present?('example')
|
112
|
+
def module_present?(module_name)
|
113
|
+
mod = self.kafo.module(module_name)
|
114
|
+
!mod.nil?
|
115
|
+
end
|
116
|
+
|
75
117
|
# You can trigger installer exit by this method. You must specify exit code as a first
|
76
118
|
# argument. You can also specify a symbol alias which is built-in (see exit_handler.rb
|
77
119
|
# for more details).
|
78
|
-
#
|
120
|
+
#
|
121
|
+
# @param [Integer, Symbol] code
|
122
|
+
#
|
123
|
+
# @example
|
79
124
|
# exit(0)
|
125
|
+
#
|
126
|
+
# @example
|
80
127
|
# exit(:manifest_error)
|
81
128
|
def exit(code)
|
82
129
|
self.kafo.class.exit(code)
|
83
130
|
end
|
84
131
|
|
85
132
|
# You can load a custom config value that has been saved using store_custom_config
|
133
|
+
#
|
134
|
+
# @param [Symbol] key
|
86
135
|
def get_custom_config(key)
|
87
136
|
self.kafo.config.get_custom(key)
|
88
137
|
end
|
89
138
|
|
90
139
|
# You can save any value into kafo configuration file, this is useful if you need to
|
91
140
|
# share a value between more hooks and persist the values for next run
|
141
|
+
#
|
142
|
+
# @param [Symbol] key
|
143
|
+
# @param [Object] value
|
92
144
|
def store_custom_config(key, value)
|
93
145
|
self.kafo.config.set_custom(key, value)
|
94
146
|
end
|
95
147
|
|
96
148
|
# Load a custom fact from the custom fact storage as saved by store_custom_fact
|
149
|
+
#
|
150
|
+
# @param [Symbol] key
|
97
151
|
def get_custom_fact(key)
|
98
152
|
self.kafo.config.get_custom_fact(key)
|
99
153
|
end
|
100
154
|
|
101
|
-
# Store
|
155
|
+
# Store any custom fact. This will show up as kafo.scenario.custom.your_fact.
|
102
156
|
# It is possible to use structures such as arrays and hashes besides the
|
103
157
|
# obvious ones such as strings, integers, booleans.
|
104
158
|
#
|
105
159
|
# These facts can also be used in Hiera hierachy definitions.
|
160
|
+
#
|
161
|
+
# @param [Symbol] key
|
162
|
+
# @param [Object] value
|
106
163
|
def store_custom_fact(key, value)
|
107
164
|
self.kafo.config.set_custom_fact(key, value)
|
108
165
|
end
|
109
166
|
|
167
|
+
# Check whether a custom fact exists, regardless of whether or not it has a value.
|
168
|
+
#
|
169
|
+
# @param [Symbol] key
|
170
|
+
def has_custom_fact?(key)
|
171
|
+
self.kafo.config.has_custom_fact?(key)
|
172
|
+
end
|
173
|
+
|
110
174
|
# Return the id of the current scenario
|
175
|
+
#
|
176
|
+
# @return [String]
|
111
177
|
def scenario_id
|
112
178
|
self.kafo.config.scenario_id
|
113
179
|
end
|
114
180
|
|
115
181
|
# Return the path to the current scenario
|
182
|
+
#
|
183
|
+
# @return [String]
|
116
184
|
def scenario_path
|
117
185
|
self.kafo.config.config_file
|
118
186
|
end
|
119
187
|
|
120
188
|
# Return the actual data in the current scenario
|
189
|
+
#
|
190
|
+
# @return [Hash]
|
121
191
|
def scenario_data
|
122
192
|
self.kafo.config.app
|
123
193
|
end
|
194
|
+
|
195
|
+
# Return the current exit code
|
196
|
+
def exit_code
|
197
|
+
self.kafo.exit_code
|
198
|
+
end
|
124
199
|
end
|
125
200
|
end
|
data/lib/kafo/hooking.rb
CHANGED
@@ -2,15 +2,16 @@ require 'kafo/hook_context'
|
|
2
2
|
|
3
3
|
module Kafo
|
4
4
|
class Hooking
|
5
|
-
# pre_migrations - just after kafo reads its configuration - useful for config file updates. Only in this stage it is posible to request config reload (`Kafo.request_config_reload`) to get in our changes
|
6
|
-
# boot - before kafo is ready to work, useful for adding new app arguments, logger won't work yet
|
7
|
-
# init - just after hooking is initialized and kafo is configured, parameters have no values yet
|
8
|
-
# pre_values - just before value from CLI is set to parameters (they already have default values)
|
9
|
-
# pre_validations - just after system checks and before validations are executed (and before interactive wizard is started), at this point all parameter values are already set but not yet stored in answer file
|
10
|
-
# pre_commit - after validations or interactive wizard have completed, all parameter values are set but not yet stored in the answer file
|
11
|
-
# pre - just before puppet is executed to converge system
|
12
|
-
# post - just after puppet is executed to converge system
|
13
|
-
|
5
|
+
# * pre_migrations - just after kafo reads its configuration - useful for config file updates. Only in this stage it is posible to request config reload (`Kafo.request_config_reload`) to get in our changes
|
6
|
+
# * boot - before kafo is ready to work, useful for adding new app arguments, logger won't work yet
|
7
|
+
# * init - just after hooking is initialized and kafo is configured, parameters have no values yet
|
8
|
+
# * pre_values - just before value from CLI is set to parameters (they already have default values)
|
9
|
+
# * pre_validations - just after system checks and before validations are executed (and before interactive wizard is started), at this point all parameter values are already set but not yet stored in answer file
|
10
|
+
# * pre_commit - after validations or interactive wizard have completed, all parameter values are set but not yet stored in the answer file
|
11
|
+
# * pre - just before puppet is executed to converge system
|
12
|
+
# * post - just after puppet is executed to converge system
|
13
|
+
# * pre_exit - happens during exit handling, before exit is completed
|
14
|
+
TYPES = [:pre_migrations, :boot, :init, :pre_values, :pre_validations, :pre_commit, :pre, :post, :pre_exit]
|
14
15
|
|
15
16
|
attr_accessor :hooks, :kafo
|
16
17
|
|
@@ -44,14 +45,16 @@ module Kafo
|
|
44
45
|
@loaded
|
45
46
|
end
|
46
47
|
|
47
|
-
def execute(group)
|
48
|
-
logger
|
48
|
+
def execute(group, log_stage: true)
|
49
|
+
logger = Logger.new(group)
|
50
|
+
logger.notice "Executing hooks in group #{group}" if log_stage
|
49
51
|
self.hooks[group].keys.sort_by(&:to_s).each do |name|
|
50
52
|
hook = self.hooks[group][name]
|
51
|
-
result = HookContext.execute(self.kafo, &hook)
|
53
|
+
result = HookContext.execute(self.kafo, logger, &hook)
|
52
54
|
logger.debug "Hook #{name} returned #{result.inspect}"
|
53
55
|
end
|
54
|
-
logger.
|
56
|
+
logger.notice "All hooks in group #{group} finished" if log_stage
|
57
|
+
@group = nil
|
55
58
|
end
|
56
59
|
|
57
60
|
def register_pre_migrations(name, &block)
|
@@ -86,6 +89,10 @@ module Kafo
|
|
86
89
|
register(:post, name, &block)
|
87
90
|
end
|
88
91
|
|
92
|
+
def register_pre_exit(name, &block)
|
93
|
+
register(:pre_exit, name, &block)
|
94
|
+
end
|
95
|
+
|
89
96
|
private
|
90
97
|
|
91
98
|
def register(group, name, &block)
|