foreman_maintain 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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