foreman_maintain 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +75 -3
  3. data/config/foreman_maintain.yml.example +6 -0
  4. data/config/foreman_maintain.yml.packaging +6 -0
  5. data/definitions/checks/disk_speed_minimal.rb +1 -1
  6. data/definitions/checks/foreman_proxy/verify_dhcp_config_syntax.rb +17 -0
  7. data/definitions/checks/system_registration.rb +1 -1
  8. data/definitions/features/downstream.rb +31 -0
  9. data/definitions/features/foreman_1_7_x.rb +33 -0
  10. data/definitions/features/foreman_proxy.rb +72 -0
  11. data/definitions/features/sync_plans.rb +14 -20
  12. data/definitions/features/upstream.rb +4 -0
  13. data/definitions/procedures/foreman_tasks/delete.rb +2 -1
  14. data/definitions/procedures/hammer_setup.rb +4 -4
  15. data/definitions/procedures/installer/upgrade.rb +19 -0
  16. data/definitions/procedures/maintenance_mode/disable.rb +13 -0
  17. data/definitions/procedures/maintenance_mode/enable.rb +13 -0
  18. data/definitions/procedures/packages/install.rb +20 -0
  19. data/definitions/procedures/packages/update.rb +20 -0
  20. data/definitions/procedures/repositories/setup.rb +18 -0
  21. data/definitions/procedures/sync_plans/disable.rb +4 -0
  22. data/definitions/procedures/sync_plans/enable.rb +5 -0
  23. data/definitions/scenarios/upgrade_to_satellite_6_2.rb +77 -0
  24. data/lib/foreman_maintain.rb +5 -2
  25. data/lib/foreman_maintain/check.rb +11 -4
  26. data/lib/foreman_maintain/cli.rb +23 -0
  27. data/lib/foreman_maintain/cli/advanced/procedure/abstract_by_tag_command.rb +38 -0
  28. data/lib/foreman_maintain/cli/advanced/procedure/abstract_procedure_command.rb +17 -0
  29. data/lib/foreman_maintain/cli/advanced/procedure/by_tag_command.rb +32 -0
  30. data/lib/foreman_maintain/cli/advanced/procedure/run_command.rb +17 -0
  31. data/lib/foreman_maintain/cli/advanced/procedure_command.rb +11 -0
  32. data/lib/foreman_maintain/cli/advanced_command.rb +9 -0
  33. data/lib/foreman_maintain/cli/base.rb +52 -7
  34. data/lib/foreman_maintain/cli/health_command.rb +0 -12
  35. data/lib/foreman_maintain/cli/transform_clamp_options.rb +66 -0
  36. data/lib/foreman_maintain/cli/upgrade_command.rb +45 -33
  37. data/lib/foreman_maintain/concerns/metadata.rb +28 -2
  38. data/lib/foreman_maintain/concerns/scenario_metadata.rb +44 -0
  39. data/lib/foreman_maintain/concerns/system_helpers.rb +27 -5
  40. data/lib/foreman_maintain/config.rb +10 -5
  41. data/lib/foreman_maintain/core_ext.rb +5 -1
  42. data/lib/foreman_maintain/csv_parser.rb +81 -0
  43. data/lib/foreman_maintain/dependency_graph.rb +10 -48
  44. data/lib/foreman_maintain/error.rb +4 -0
  45. data/lib/foreman_maintain/executable.rb +64 -13
  46. data/lib/foreman_maintain/param.rb +1 -0
  47. data/lib/foreman_maintain/reporter.rb +84 -3
  48. data/lib/foreman_maintain/reporter/cli_reporter.rb +57 -21
  49. data/lib/foreman_maintain/runner.rb +80 -21
  50. data/lib/foreman_maintain/runner/execution.rb +29 -4
  51. data/lib/foreman_maintain/runner/stored_execution.rb +23 -0
  52. data/lib/foreman_maintain/scenario.rb +90 -7
  53. data/lib/foreman_maintain/upgrade_runner.rb +194 -0
  54. data/lib/foreman_maintain/utils.rb +1 -0
  55. data/lib/foreman_maintain/utils/curl_response.rb +21 -0
  56. data/lib/foreman_maintain/version.rb +1 -1
  57. metadata +24 -14
  58. data/definitions/checks/sync_plans/with_disabled_status.rb +0 -18
  59. data/definitions/checks/sync_plans/with_enabled_status.rb +0 -19
  60. data/definitions/procedures/install_package.rb +0 -17
  61. data/definitions/scenarios/pre_upgrade_check_foreman_1_14.rb +0 -13
  62. data/definitions/scenarios/pre_upgrade_check_satellite_6_0_z.rb +0 -14
  63. data/definitions/scenarios/pre_upgrade_check_satellite_6_1.rb +0 -14
  64. data/definitions/scenarios/pre_upgrade_check_satellite_6_1_z.rb +0 -14
  65. data/definitions/scenarios/pre_upgrade_check_satellite_6_2.rb +0 -14
  66. data/definitions/scenarios/pre_upgrade_check_satellite_6_2_z.rb +0 -14
  67. data/definitions/scenarios/pre_upgrade_check_satellite_6_3.rb +0 -14
  68. data/lib/foreman_maintain/object_cache.rb +0 -34
@@ -0,0 +1,9 @@
1
+ require 'foreman_maintain/cli/advanced/procedure_command'
2
+
3
+ module ForemanMaintain
4
+ module Cli
5
+ class AdvancedCommand < Base
6
+ subcommand 'procedure', 'Run maintain procedures manually', ProcedureCommand
7
+ end
8
+ end
9
+ end
@@ -1,12 +1,18 @@
1
+ require 'foreman_maintain/csv_parser'
2
+
1
3
  module ForemanMaintain
2
4
  module Cli
3
5
  class Base < Clamp::Command
4
6
  include Concerns::Finders
5
7
 
6
- def dashize(string)
8
+ def self.dashize(string)
7
9
  string.to_s.tr('_', '-')
8
10
  end
9
11
 
12
+ def dashize(string)
13
+ self.class.dashize(string)
14
+ end
15
+
10
16
  def underscorize(string)
11
17
  string.to_s.tr('-', '_')
12
18
  end
@@ -19,14 +25,23 @@ module ForemanMaintain
19
25
  HighLine.color("[#{dashize(string)}]", :cyan)
20
26
  end
21
27
 
28
+ def print_check_info(check)
29
+ desc = "#{label_string(check.label)} #{check.description}".ljust(80)
30
+ tags = check.tags.map { |t| tag_string(t) }.join(' ').to_s
31
+ puts "#{desc} #{tags}".strip
32
+ end
33
+
22
34
  def reporter
23
35
  @reporter ||= ForemanMaintain::Reporter::CLIReporter.new(STDOUT,
24
36
  STDIN,
25
37
  :assumeyes => assumeyes?)
26
38
  end
27
39
 
28
- def run_scenario(scenario)
29
- ForemanMaintain::Runner.new(reporter, scenario, :assumeyes => assumeyes?).run
40
+ def run_scenario(scenarios)
41
+ ForemanMaintain::Runner.new(reporter, scenarios,
42
+ :assumeyes => assumeyes?,
43
+ :whitelist => whitelist || [],
44
+ :force => force?).run
30
45
  end
31
46
 
32
47
  def available_checks
@@ -35,8 +50,28 @@ module ForemanMaintain
35
50
  ForemanMaintain.available_checks(filter)
36
51
  end
37
52
 
53
+ def available_procedures
54
+ filter = {}
55
+ filter[:tags] = tags if respond_to?(:tags)
56
+ ForemanMaintain.available_procedures(filter)
57
+ end
58
+
38
59
  def available_tags(collection)
39
- collection.inject([]) { |array, check| array.concat(check.tags).uniq }.sort_by(&:to_s)
60
+ self.class.available_tags(collection)
61
+ end
62
+
63
+ def self.available_tags(collection)
64
+ collection.inject([]) { |array, item| array.concat(item.tags).uniq }.sort_by(&:to_s)
65
+ end
66
+
67
+ def self.option(switches, type, description, opts = {}, &block)
68
+ multivalued = opts.delete(:multivalued)
69
+ description += ' (comma-separated list)' if multivalued
70
+ super(switches, type, description, opts) do |value|
71
+ value = CSVParser.new.parse(value) if multivalued
72
+ value = instance_exec(value, &block) if block
73
+ value
74
+ end
40
75
  end
41
76
 
42
77
  def self.label_option
@@ -49,17 +84,27 @@ module ForemanMaintain
49
84
  end
50
85
 
51
86
  def self.tags_option
52
- option '--tags', 'tags',
87
+ option('--tags', 'tags',
53
88
  'Limit only for specific set of labels. ' \
54
- '(Use list-tags command to see available tags)' do |tags|
89
+ '(Use list-tags command to see available tags)',
90
+ :multivalued => true) do |tags|
55
91
  raise ArgumentError, 'value not specified' if tags.nil? || tags.empty?
56
- tags.split(',').map(&:strip).map { |tag| underscorize(tag).to_sym }
92
+ tags.map { |tag| underscorize(tag).to_sym }
57
93
  end
58
94
  end
59
95
 
60
96
  def self.interactive_option
61
97
  option ['-y', '--assumeyes'], :flag,
62
98
  'Automatically answer yes for all questions'
99
+
100
+ option ['-w', '--whitelist'], 'whitelist',
101
+ 'Comma-separated list of labels of steps to be ignored' do |whitelist|
102
+ raise ArgumentError, 'value not specified' if whitelist.nil? || whitelist.empty?
103
+ whitelist.split(',').map(&:strip)
104
+ end
105
+
106
+ option ['-f', '--force'], :flag,
107
+ 'Force steps that would be skipped as they were already run'
63
108
  end
64
109
  end
65
110
  end
@@ -9,24 +9,12 @@ module ForemanMaintain
9
9
  print_check_info(check)
10
10
  end
11
11
  end
12
-
13
- def print_check_info(check)
14
- desc = "#{label_string(check.label)} #{check.description}".ljust(80)
15
- tags = check.tags.map { |t| tag_string(t) }.join(' ').to_s
16
- puts "#{desc} #{tags}"
17
- end
18
12
  end
19
13
 
20
14
  subcommand 'list-tags', 'List the tags to use for filtering checks' do
21
15
  def execute
22
16
  available_tags(available_checks).each { |tag| puts tag_string(tag) }
23
17
  end
24
-
25
- def print_check_info(check)
26
- desc = "#{label_string(check.label)} #{check.description}".ljust(80)
27
- tags = check.tags.map { |t| tag_string(t) }.join(' ').to_s
28
- puts "#{desc} #{tags}"
29
- end
30
18
  end
31
19
 
32
20
  subcommand 'check', 'Run the health checks against the system' do
@@ -0,0 +1,66 @@
1
+ module ForemanMaintain
2
+ module Cli
3
+ module TransformClampOptions
4
+ def self.included(base)
5
+ base.send(:include, OptionsToParams)
6
+ base.extend(ParamsToOptions)
7
+ end
8
+
9
+ module OptionsToParams
10
+ def options_to_params
11
+ @params ||= self.class.recognised_options.inject({}) do |par, option|
12
+ par[option_sym(option)] = send(option.read_method) if metadata_option?(option)
13
+ par
14
+ end
15
+ end
16
+
17
+ def get_params_for(definition)
18
+ all_params = options_to_params
19
+ params = {}
20
+ definition.params.values.each do |param|
21
+ params[param.name] = all_params[param.name]
22
+ end
23
+ params
24
+ end
25
+
26
+ private
27
+
28
+ def option_sym(option)
29
+ option.switches.first[2..-1].to_sym
30
+ end
31
+
32
+ def metadata_option?(option)
33
+ !option.switches.include?('--help') && !option.switches.include?('--assumeyes')
34
+ end
35
+ end
36
+
37
+ module ParamsToOptions
38
+ def params_to_options(params)
39
+ params.values.each do |param|
40
+ param_to_option(param)
41
+ end
42
+ end
43
+
44
+ def param_to_option(param, custom = {})
45
+ switches = custom.fetch(:switches, option_switches(param))
46
+ opt_type = custom.fetch(:type, option_type(param))
47
+ description = custom.fetch(:description, param.description)
48
+ options = custom.fetch(:options, {})
49
+
50
+ # clamp doesnt allow required flags
51
+ options[:required] ||= param.required? unless param.flag?
52
+ options[:multivalued] ||= param.array?
53
+ option(switches, opt_type, description, options)
54
+ end
55
+
56
+ def option_switches(param)
57
+ ['--' + dashize(param.name.to_s)]
58
+ end
59
+
60
+ def option_type(param)
61
+ param.flag? ? :flag : param.name.to_s.upcase
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,57 +1,69 @@
1
1
  module ForemanMaintain
2
2
  module Cli
3
3
  class UpgradeCommand < Base
4
- def tags_to_versions
5
- { :satellite_6_0_z => '6.0.z',
6
- :satellite_6_1 => '6.1',
7
- :satellite_6_1_z => '6.1.z',
8
- :satellite_6_2 => '6.2',
9
- :satellite_6_2_z => '6.2.z',
10
- :satellite_6_3 => '6.3' }
4
+ def self.target_version_option
5
+ option '--target-version', 'TARGET_VERSION', 'Target version of the upgrade',
6
+ :required => false
11
7
  end
12
8
 
13
- # We search for scenarios available for the system and determine
14
- # user-friendly version numbers for it.
15
- # This method returns a hash of mapping the versions to scenarios to run
16
- # The tag is determining which kind of scenario we're searching for
17
- # (such as pre_upgrade_check)
18
- def available_target_versions(tag)
19
- conditions = { :tags => [tag] }
20
- find_scenarios(conditions).inject({}) do |hash, scenario|
21
- # find tag that represent the version upgrade
22
- version_tag = scenario.tags.find { |t| tags_to_versions.key?(t) }
23
- if version_tag
24
- hash.update(tags_to_versions[version_tag] => scenario)
25
- else
26
- hash
27
- end
9
+ def validate_target_version!
10
+ unless UpgradeRunner.available_targets.include?(target_version)
11
+ message_start = if target_version
12
+ "Can't upgrade to #{target_version}"
13
+ else
14
+ '--target-version not specified'
15
+ end
16
+ message = <<-MESSAGE.strip_heredoc
17
+ #{message_start}
18
+ Possible target versions are:
19
+ MESSAGE
20
+ versions = UpgradeRunner.available_targets.join("\n")
21
+ raise Error::UsageError, message + versions
28
22
  end
29
23
  end
30
24
 
25
+ def upgrade_runner
26
+ return @upgrade_runner if defined? @upgrade_runner
27
+ validate_target_version!
28
+ @upgrade_runner = ForemanMaintain::UpgradeRunner.new(target_version, reporter,
29
+ :assumeyes => assumeyes?,
30
+ :whitelist => whitelist || [],
31
+ :force => force?).tap(&:load)
32
+ end
33
+
31
34
  def print_versions(target_versions)
32
- target_versions.keys.sort.each { |version| puts version }
35
+ target_versions.sort.each { |version| puts version }
33
36
  end
34
37
 
35
38
  subcommand 'list-versions', 'List versions this system is upgradable to' do
36
39
  def execute
37
- print_versions(available_target_versions(:pre_upgrade_check))
40
+ print_versions(UpgradeRunner.available_targets)
41
+ end
42
+ end
43
+
44
+ subcommand 'check', 'Run pre-upgrade checks before upgrading to specified version' do
45
+ target_version_option
46
+ interactive_option
47
+
48
+ def execute
49
+ upgrade_runner.run_phase(:pre_upgrade_checks)
50
+ exit upgrade_runner.exit_code
38
51
  end
39
52
  end
40
53
 
41
- subcommand 'check', 'Run pre-upgrade checks for upgradeing to specified version' do
42
- parameter 'TARGET_VERSION', 'Target version of the upgrade', :required => false
54
+ subcommand 'run', 'Run full upgrade to a specified version' do
55
+ target_version_option
43
56
  interactive_option
57
+ option '--phase', 'phase', 'run only a specific phase', :required => false
44
58
 
45
59
  def execute
46
- versions_to_scenarios = available_target_versions(:pre_upgrade_check)
47
- scenario = versions_to_scenarios[target_version]
48
- if scenario
49
- run_scenario(scenario)
60
+ if phase
61
+ upgrade_runner.run_phase(phase.to_sym)
50
62
  else
51
- puts "The specified version #{target_version} is unavailable"
52
- puts 'Possible target versions are:'
53
- print_versions(versions_to_scenarios)
63
+ upgrade_runner.run
54
64
  end
65
+ upgrade_runner.save
66
+ exit upgrade_runner.exit_code
55
67
  end
56
68
  end
57
69
  end
@@ -90,6 +90,12 @@ module ForemanMaintain
90
90
  end
91
91
  end
92
92
 
93
+ # Ensure to not run the step twice: expects the scenario to be persisted
94
+ # between runs to work properly
95
+ def run_once
96
+ @data[:run_once] = true
97
+ end
98
+
93
99
  def self.eval_dsl(metadata, &block)
94
100
  new(metadata).tap do |dsl|
95
101
  dsl.instance_eval(&block)
@@ -131,11 +137,15 @@ module ForemanMaintain
131
137
  def metadata(&block)
132
138
  @metadata ||= initialize_metadata
133
139
  if block
134
- DSL.eval_dsl(@metadata, &block)
140
+ metadata_class.eval_dsl(@metadata, &block)
135
141
  end
136
142
  @metadata
137
143
  end
138
144
 
145
+ def metadata_class
146
+ DSL
147
+ end
148
+
139
149
  def label
140
150
  metadata[:label] || generate_label
141
151
  end
@@ -149,7 +159,7 @@ module ForemanMaintain
149
159
  end
150
160
 
151
161
  def params
152
- metadata[:params] || []
162
+ metadata[:params] || {}
153
163
  end
154
164
 
155
165
  def before
@@ -160,6 +170,10 @@ module ForemanMaintain
160
170
  metadata[:after] || []
161
171
  end
162
172
 
173
+ def run_once?
174
+ metadata[:run_once]
175
+ end
176
+
163
177
  def initialize_metadata
164
178
  { :tags => [],
165
179
  :confine_blocks => [],
@@ -230,10 +244,18 @@ module ForemanMaintain
230
244
  self.class.label
231
245
  end
232
246
 
247
+ def label_dashed
248
+ label.to_s.tr('_', '-')
249
+ end
250
+
233
251
  def description
234
252
  self.class.description
235
253
  end
236
254
 
255
+ def runtime_message
256
+ description + (params.empty? ? '' : " (#{params})")
257
+ end
258
+
237
259
  def tags
238
260
  self.class.tags
239
261
  end
@@ -242,6 +264,10 @@ module ForemanMaintain
242
264
  self.class.params
243
265
  end
244
266
 
267
+ def run_once?
268
+ self.class.run_once?
269
+ end
270
+
245
271
  def preparation_steps(*args)
246
272
  self.class.preparation_steps(*args)
247
273
  end
@@ -0,0 +1,44 @@
1
+ module ForemanMaintain
2
+ module Concerns
3
+ module ScenarioMetadata
4
+ class DSL < Metadata::DSL
5
+ VALID_STRATEGIES = [:fail_fast, :fail_slow].freeze
6
+
7
+ def initialize(*args)
8
+ super
9
+ # the default strategy is to fail as soon as first step fails
10
+ run_strategy :fail_fast
11
+ end
12
+
13
+ # Possible run strategies:
14
+ #
15
+ # * +:fail_fast+ - the scenario stops as soon as the first step fails
16
+ # * +:fail_slow+ - the step failure doesn't cause the scenario to stop:
17
+ # it runs all the steps, for the tailures to be reported
18
+ # at the end
19
+ def run_strategy(run_strategy)
20
+ unless VALID_STRATEGIES.include?(run_strategy)
21
+ raise "Run strategy #{run_strategy} not one of #{VALID_STRATEGIES}"
22
+ end
23
+ @data[:run_strategy] = run_strategy
24
+ end
25
+ end
26
+
27
+ module ClassMethods
28
+ # modules not to be included in autogenerated labels
29
+ def metadata_class
30
+ ScenarioMetadata::DSL
31
+ end
32
+ end
33
+
34
+ def self.included(klass)
35
+ klass.send(:include, Metadata)
36
+ klass.extend(ClassMethods)
37
+ end
38
+
39
+ def run_strategy
40
+ self.class.metadata[:run_strategy]
41
+ end
42
+ end
43
+ end
44
+ end
@@ -13,6 +13,17 @@ module ForemanMaintain
13
13
 
14
14
  # class we use for comparing the versions
15
15
  class Version < Gem::Version
16
+ def major
17
+ segments[0]
18
+ end
19
+
20
+ def minor
21
+ segments[1]
22
+ end
23
+
24
+ def build
25
+ segments[2]
26
+ end
16
27
  end
17
28
 
18
29
  def hostname
@@ -27,11 +38,16 @@ module ForemanMaintain
27
38
  Version.new(value)
28
39
  end
29
40
 
30
- def install_packages(packages, options = {})
41
+ def packages_action(action, packages, options = {})
42
+ expected_actions = [:install, :update]
43
+ unless expected_actions.include?(action)
44
+ raise ArgumentError, "Unexpected action #{action} expected #{expected_actions.inspect}"
45
+ end
31
46
  options.validate_options!(:assumeyes)
32
47
  yum_options = []
33
48
  yum_options << '-y' if options[:assumeyes]
34
- execute!("yum #{yum_options.join(' ')} install #{packages.join(' ')}", :interactive => true)
49
+ execute!("yum #{yum_options.join(' ')} #{action} #{packages.join(' ')}",
50
+ :interactive => true)
35
51
  end
36
52
 
37
53
  def check_min_version(name, minimal_version)
@@ -43,7 +59,7 @@ module ForemanMaintain
43
59
 
44
60
  def downstream_installation?
45
61
  execute?('rpm -q satellite') ||
46
- (execute('rpm -q foreman') =~ /6sat.noarch/)
62
+ (execute('rpm -q foreman') =~ /sat.noarch/)
47
63
  end
48
64
 
49
65
  def package_version(name)
@@ -51,8 +67,8 @@ module ForemanMaintain
51
67
  rpm_version(name)
52
68
  end
53
69
 
54
- def rpm_version(name)
55
- rpm_version = execute(%(rpm -q '#{name}' --queryformat="%{VERSION}"))
70
+ def rpm_version(name, queryformat = 'VERSION')
71
+ rpm_version = execute(%(rpm -q '#{name}' --queryformat="%{#{queryformat}}"))
56
72
  if $CHILD_STATUS.success?
57
73
  version(rpm_version)
58
74
  end
@@ -92,6 +108,12 @@ module ForemanMaintain
92
108
  def shellescape(string)
93
109
  Shellwords.escape(string)
94
110
  end
111
+
112
+ def json_parse(json_string)
113
+ JSON.parse(json_string)
114
+ rescue
115
+ nil
116
+ end
95
117
  end
96
118
  end
97
119
  end