foreman_maintain 0.1.3 → 0.1.4

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/bin/passenger-recycler +23 -15
  3. data/config/foreman_maintain.yml.example +4 -0
  4. data/config/foreman_maintain.yml.packaging +2 -0
  5. data/definitions/checks/candlepin/validate_db.rb +9 -1
  6. data/definitions/checks/remote_execution/verify_settings_file_already_exists.rb +42 -0
  7. data/definitions/checks/repositories/validate.rb +33 -0
  8. data/definitions/features/candlepin_database.rb +19 -11
  9. data/definitions/features/downstream.rb +13 -0
  10. data/definitions/features/foreman_1_7_x.rb +3 -1
  11. data/definitions/features/foreman_proxy.rb +6 -5
  12. data/definitions/procedures/candlepin/delete_orphaned_records_from_env_content.rb +34 -0
  13. data/definitions/procedures/knowledge_base_article.rb +29 -0
  14. data/definitions/procedures/remote_execution/remove_existing_settingsd.rb +18 -0
  15. data/definitions/procedures/sync_plans/disable.rb +4 -2
  16. data/definitions/procedures/sync_plans/enable.rb +4 -2
  17. data/definitions/scenarios/upgrade_to_satellite_6_2.rb +1 -0
  18. data/definitions/scenarios/upgrade_to_satellite_6_2_z.rb +1 -0
  19. data/definitions/scenarios/upgrade_to_satellite_6_3.rb +2 -0
  20. data/definitions/scenarios/upgrade_to_satellite_6_3_z.rb +1 -0
  21. data/lib/foreman_maintain/cli/advanced/procedure/abstract_by_tag_command.rb +4 -2
  22. data/lib/foreman_maintain/cli/advanced/procedure/by_tag_command.rb +4 -2
  23. data/lib/foreman_maintain/cli/advanced/procedure/run_command.rb +1 -1
  24. data/lib/foreman_maintain/cli/base.rb +2 -2
  25. data/lib/foreman_maintain/concerns/base_database.rb +43 -0
  26. data/lib/foreman_maintain/concerns/metadata.rb +14 -1
  27. data/lib/foreman_maintain/concerns/system_helpers.rb +11 -0
  28. data/lib/foreman_maintain/config.rb +13 -5
  29. data/lib/foreman_maintain/context.rb +34 -0
  30. data/lib/foreman_maintain/detector.rb +1 -1
  31. data/lib/foreman_maintain/executable.rb +3 -1
  32. data/lib/foreman_maintain/runner/execution.rb +5 -1
  33. data/lib/foreman_maintain/scenario.rb +16 -3
  34. data/lib/foreman_maintain/upgrade_runner.rb +1 -1
  35. data/lib/foreman_maintain/version.rb +1 -1
  36. data/lib/foreman_maintain.rb +6 -0
  37. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8e9f70b0ee10a6f3d86da947c29b44f28425fe3d
4
- data.tar.gz: 25c1ffb8b8b12ff26a2ee7cad07f407b7586f276
3
+ metadata.gz: 65b1daa7e3ed6b36c77a34061c0cde3badf9cc0d
4
+ data.tar.gz: '08aedcc2e9c4242dc17b8d50b5bf356bd3349d28'
5
5
  SHA512:
6
- metadata.gz: ab4457e9ea8319b82ac952b5d389bd2156d384076d2d36db0150b51a04127b62393617327118d715ebb468bcf104ceaefda96cb86d641a0da8724d4ae29cb632
7
- data.tar.gz: 4d59d274a7f28c85f4c315766e276890fb9c5285225fd02dcf5aef62e495b08343e8becfcdd7cbb39ddf916b6be38180692dba4ffc83ff9f83fddc9570c12e80
6
+ metadata.gz: 8a7548a663107ef22475acefbe0b0a5dc5aeff92e816c6eaf0096b2ce344c43536af033d9d67fbbc5c36f976c4d6f7e0dbb6e6d8f0343e69ad678feaa907cdc6
7
+ data.tar.gz: 6e0a423955cd009992767a126168609ac9ec0d1687465089bfa1861798402157f8225f335ad452fa64ba04a751468d5804cac000faafe9a450d07d75109db6bf
@@ -41,31 +41,39 @@ def process_status?(pid)
41
41
  end
42
42
 
43
43
  require 'phusion_passenger'
44
+ PhusionPassenger.locate_directories
44
45
  require 'phusion_passenger/platform_info'
45
46
  require 'phusion_passenger/platform_info/ruby'
46
47
  require 'phusion_passenger/admin_tools/memory_stats'
47
- PhusionPassenger.locate_directories
48
48
  stats = PhusionPassenger::AdminTools::MemoryStats.new
49
- unless stats.platform_provides_private_dirty_rss_information?
50
- puts 'Please run as root or platform unsupported'
51
- exit 1
52
- end
53
49
  killed = 0
50
+
51
+ def get_process_start(pid)
52
+ `ps -p#{pid} -o start=`.strip
53
+ rescue StandardError => e
54
+ verbose "Error: #{e.message} \nReturning '?'"
55
+ '?'
56
+ end
57
+
58
+ def get_rss_info(process)
59
+ get_pid_mem_kb = process.private_dirty_rss || process.rss
60
+ get_pid_mem_mb = format('%.0f', get_pid_mem_kb / 1024)
61
+ [get_pid_mem_kb, get_pid_mem_mb]
62
+ end
63
+
54
64
  stats.passenger_processes.each do |p|
55
65
  pid = p.pid.to_i
56
- debug "Checking #{pid} with RSS of #{p.private_dirty_rss}"
57
- next unless p.private_dirty_rss > CONFIG[:MAX_PRIV_RSS_MEMORY]
58
- started = begin
59
- `ps -p#{pid} -o start=`.strip
60
- rescue StandardError => e
61
- verbose "Error: #{e.message} \nReturning '?'"
62
- '?'
63
- end
66
+ started = get_process_start(pid)
67
+ get_pid_mem_kb, get_pid_mem_mb = get_rss_info(p)
68
+ debug_message = "Checking #{pid} with RSS of #{get_pid_mem_kb}"
69
+ verbose_message = "Terminating #{pid} (started #{started}) with private" \
70
+ " RSS size of #{get_pid_mem_mb} MB"
71
+ debug debug_message
72
+ next unless get_pid_mem_kb > CONFIG[:MAX_PRIV_RSS_MEMORY]
64
73
  status_ps = `ps -p#{pid} -u`
65
74
  status_all = `passenger-status 2> /dev/null`
66
75
  status_backtraces = `passenger-status --show=backtraces 2>/dev/null`
67
- verbose "Terminating #{pid} (started #{started}) with private dirty RSS" \
68
- " size of #{p.private_dirty_rss} MB"
76
+ verbose verbose_message
69
77
  Process.kill 'SIGUSR1', pid
70
78
  sleep CONFIG[:GRACEFUL_SHUTDOWN_SLEEP]
71
79
  kill(pid)
@@ -19,3 +19,7 @@
19
19
 
20
20
  # Mention path where foreman-proxy certificates stored on filesystem
21
21
  # :foreman_proxy_cert_path: '/etc/foreman'
22
+
23
+ # Mention directory path to store candlepin db backups
24
+ # :db_backup_dir: '/var/lib/foreman-maintain/db-backups'
25
+
@@ -20,3 +20,5 @@
20
20
  # Mention path where foreman-proxy certificates stored on filesystem
21
21
  # :foreman_proxy_cert_path: '/etc/foreman'
22
22
 
23
+ # Mention directory path to store candlepin db backups
24
+ # :db_backup_dir: '/var/lib/foreman-maintain/db-backups'
@@ -10,7 +10,15 @@ module Checks::Candlepin
10
10
  end
11
11
 
12
12
  def run
13
- feature(:candlepin_database).execute_cpdb_validate_cmd
13
+ result, result_msg = feature(:candlepin_database).execute_cpdb_validate_cmd
14
+ next_steps = []
15
+ if feature(:downstream) && feature(:downstream).current_minor_version == '6.2'
16
+ next_steps.concat(
17
+ [Procedures::Candlepin::DeleteOrphanedRecordsFromEnvContent.new,
18
+ Procedures::KnowledgeBaseArticle.new(:doc => 'fix_cpdb_validate_failure')]
19
+ )
20
+ end
21
+ assert(result == 0, result_msg, :next_steps => next_steps)
14
22
  end
15
23
  end
16
24
  end
@@ -0,0 +1,42 @@
1
+ module Checks::RemoteExecution
2
+ class VerifySettingsFileAlreadyExists < ForemanMaintain::Check
3
+ metadata do
4
+ description 'Check to verify remote_execution_ssh settings already exist'
5
+
6
+ confine do
7
+ feature(:downstream) &&
8
+ feature(:downstream).current_minor_version == '6.2' &&
9
+ find_package('tfm-rubygem-smart_proxy_dynflow_core') &&
10
+ file_exists?('/etc/smart_proxy_dynflow_core')
11
+ end
12
+ end
13
+
14
+ def run
15
+ if file_exists?(settingd_dir_path)
16
+ symlinks = find_symlinks(settingd_dir_path)
17
+ assert(
18
+ symlinks.empty?,
19
+ failure_msg(settingd_dir_path, symlinks),
20
+ :next_steps => [
21
+ Procedures::RemoteExecution::RemoveExistingSettingsd.new(
22
+ :dirpath => settingd_dir_path
23
+ )
24
+ ]
25
+ )
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def failure_msg(dir_path, symlinks)
32
+ 'Settings related to remote_execution_ssh are already present'\
33
+ " under #{dir_path} and " \
34
+ "\nit would conflict with the installer from the next version." \
35
+ "\nsymlinks available - #{symlinks.join(', ')}"
36
+ end
37
+
38
+ def settingd_dir_path
39
+ '/etc/smart_proxy_dynflow_core/settings.d'
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,33 @@
1
+ module Checks::Repositories
2
+ class Validate < ForemanMaintain::Check
3
+ metadata do
4
+ description 'Validate availability of repositories'
5
+
6
+ confine do
7
+ feature(:downstream)
8
+ end
9
+
10
+ param :version,
11
+ 'Version for which repositories needs to be validated',
12
+ :required => true
13
+
14
+ manual_detection
15
+ end
16
+
17
+ def run
18
+ with_spinner("Validating availability of repositories for #{@version}") do |spinner|
19
+ absent_repos = feature(:downstream).absent_repos(@version)
20
+ unless absent_repos.empty?
21
+ spinner.update('Some repositories missing, calling `subscription-manager refresh`')
22
+ feature(:downstream).rhsm_refresh
23
+ absent_repos = feature(:downstream).absent_repos(@version)
24
+ end
25
+ unless absent_repos.empty?
26
+ fail!(
27
+ "Following repositories are not available on your system: #{absent_repos.join(', ')}"
28
+ )
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -27,12 +27,20 @@ class Features::CandlepinDatabase < ForemanMaintain::Feature
27
27
 
28
28
  def execute_cpdb_validate_cmd
29
29
  main_cmd = cpdb_validate_cmd
30
- unless main_cmd.empty?
31
- main_cmd += format_shell_args(
32
- '-u' => configuration['username'], '-p' => configuration[%(password)]
33
- )
34
- execute!(main_cmd, :hidden_patterns => [configuration['password']])
35
- end
30
+ return [true, nil] if main_cmd.empty?
31
+ main_cmd += format_shell_args(
32
+ '-u' => configuration['username'], '-p' => configuration[%(password)]
33
+ )
34
+ execute_with_status(main_cmd, :hidden_patterns => [configuration['password']])
35
+ end
36
+
37
+ def env_content_ids_with_null_content
38
+ sql = <<-SQL
39
+ SELECT ec.id
40
+ FROM cp_env_content ec
41
+ LEFT JOIN cp_content c ON ec.contentid = c.id WHERE c.id IS NULL
42
+ SQL
43
+ query(sql).map { |r| r['id'] }
36
44
  end
37
45
 
38
46
  private
@@ -40,15 +48,15 @@ class Features::CandlepinDatabase < ForemanMaintain::Feature
40
48
  def load_configuration
41
49
  raw_config = File.read(CANDLEPIN_DB_CONFIG)
42
50
  full_config = Hash[raw_config.scan(/(^[^#\n][^=]*)=(.*)/)]
43
- uri = %r{://(([^/:]*):?([^/]*))/(.*)}.match(full_config['org.quartz.dataSource.myDS.URL'])
51
+ uri = %r{://(([^/:]*):?([^/]*))/(.*)}.match(full_config['jpa.config.hibernate.connection.url'])
44
52
  @configuration = {
45
- 'username' => full_config['org.quartz.dataSource.myDS.user'],
46
- 'password' => full_config['org.quartz.dataSource.myDS.password'],
53
+ 'username' => full_config['jpa.config.hibernate.connection.username'],
54
+ 'password' => full_config['jpa.config.hibernate.connection.password'],
47
55
  'database' => uri[4],
48
56
  'host' => uri[2],
49
57
  'port' => uri[3] || '5432',
50
- 'driver' => full_config['org.quartz.dataSource.myDS.driver'],
51
- 'url' => full_config['org.quartz.dataSource.myDS.URL']
58
+ 'driver_class' => full_config['jpa.config.hibernate.connection.driver_class'],
59
+ 'url' => full_config['jpa.config.hibernate.connection.url']
52
60
  }
53
61
  end
54
62
 
@@ -29,6 +29,19 @@ class Features::Downstream < ForemanMaintain::Feature
29
29
  end
30
30
  end
31
31
 
32
+ def absent_repos(version)
33
+ all_repo_lines = execute(%(LANG=en_US.utf-8 subscription-manager repos --list | ) +
34
+ %(grep '^Repo ID:')).split("\n")
35
+ all_repos = all_repo_lines.map { |line| line.split(/\s+/).last }
36
+ repos_required = rh_repos(version)
37
+ repos_found = repos_required & all_repos
38
+ repos_required - repos_found
39
+ end
40
+
41
+ def rhsm_refresh
42
+ execute!(%(subscription-manager refresh))
43
+ end
44
+
32
45
  private
33
46
 
34
47
  def rh_repos(sat_version)
@@ -35,7 +35,9 @@ class Features::Foreman_1_7_x < ForemanMaintain::Feature
35
35
 
36
36
  def del_custom_iptables_chain(name)
37
37
  return unless execute?("iptables -L #{name}") # the chain is already gone
38
- execute!("iptables -D INPUT -j #{name}")
38
+ if execute?("iptables -L INPUT | tail -n +3 | grep '^#{name} '")
39
+ execute!("iptables -D INPUT -j #{name}")
40
+ end
39
41
  execute!("iptables -F #{name}")
40
42
  execute!("iptables -X #{name}")
41
43
  end
@@ -34,16 +34,17 @@ class Features::ForemanProxy < ForemanMaintain::Feature
34
34
  next unless str.include?('HTTP')
35
35
  http_line = str
36
36
  end
37
+ return http_line if http_line.empty?
37
38
  http_line.split(curl_http_status.to_s).last.strip
38
39
  end
39
40
  end
40
41
 
41
42
  def run_dhcp_curl
42
43
  curl_resp = execute(dhcp_curl_cmd)
43
- array_output = curl_resp.split(/\r\n/)
44
- result_array = array_output.last.split(/\n/)
45
- curl_http_status = result_array.delete_at(result_array.length - 1).strip.to_i
46
- curl_http_resp = parse_json(result_array.join(''))
44
+ array_output = curl_resp.split(/\r?\n/)
45
+ status_str = array_output.last
46
+ curl_http_status = (status_str ? status_str.strip : status_str).to_i
47
+ curl_http_resp = parse_json(array_output[0])
47
48
  ForemanMaintain::Utils::CurlResponse.new(
48
49
  curl_http_resp,
49
50
  curl_http_status,
@@ -55,7 +56,7 @@ class Features::ForemanProxy < ForemanMaintain::Feature
55
56
  dhcp_curl_resp = run_dhcp_curl
56
57
  success = true
57
58
  if dhcp_curl_resp.http_code.eql?(200)
58
- if dhcp_curl_resp.result.empty?
59
+ if dhcp_curl_resp.result.to_s.empty?
59
60
  success = false
60
61
  puts "Verify DHCP Settings. Response: #{dhcp_curl_resp.result.inspect}"
61
62
  end
@@ -0,0 +1,34 @@
1
+ module Procedures::Candlepin
2
+ class DeleteOrphanedRecordsFromEnvContent < ForemanMaintain::Procedure
3
+ metadata do
4
+ description 'Delete orphaned record(s) from cp_env_content with unresolvable content'
5
+ label :candlepin_delete_orphaned_records_from_env_content
6
+
7
+ confine do
8
+ feature(:candlepin_database) &&
9
+ feature(:downstream) &&
10
+ feature(:downstream).current_minor_version == '6.2' &&
11
+ feature(:candlepin_database).table_exist?('cp_env_content')
12
+ end
13
+ end
14
+
15
+ def run
16
+ with_spinner('Deleting cp_env_content record(s) with unresolvable content') do |spinner|
17
+ spinner.update 'Finding cp_env_content records with unresolvable content'
18
+ env_content_ids = feature(:candlepin_database).env_content_ids_with_null_content
19
+ if env_content_ids.empty?
20
+ spinner.update 'No orphaned records found'
21
+ else
22
+ spinner.update 'Taking a backup of the candlepin database'
23
+ feature(:candlepin_database).perform_backup
24
+
25
+ puts "Total #{env_content_ids.length} records with unresolvable content"
26
+ spinner.update 'Deleting record(s) from cp_env_content table'
27
+ feature(:candlepin_database).delete_records_by_ids(
28
+ 'cp_env_content', env_content_ids
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ class Procedures::KnowledgeBaseArticle < ForemanMaintain::Procedure
2
+ metadata do
3
+ description 'Show knowledge base article for troubleshooting'
4
+
5
+ confine do
6
+ feature(:downstream)
7
+ end
8
+ param :doc,
9
+ 'Document name required to select a correct article',
10
+ :required => true
11
+ advanced_run false
12
+ end
13
+
14
+ def run
15
+ ask(<<-MESSAGE.strip_heredoc)
16
+ Go to #{kcs_documents[@doc]}
17
+ please follow steps from above article to resolve this issue
18
+ press ENTER once done.
19
+ MESSAGE
20
+ end
21
+
22
+ private
23
+
24
+ def kcs_documents
25
+ {
26
+ 'fix_cpdb_validate_failure' => 'https://access.redhat.com/solutions/3362821'
27
+ }
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ module Procedures::RemoteExecution
2
+ class RemoveExistingSettingsd < ForemanMaintain::Procedure
3
+ metadata do
4
+ param :dirpath,
5
+ 'Directory path for settings.d folder',
6
+ :required => true
7
+ description 'Remove existing settings.d directory before installer run.' \
8
+ "\n The next run of the installer will re-create the directory properly."
9
+ advanced_run false
10
+ end
11
+
12
+ def run
13
+ with_spinner("Removing existing #{@dirpath} directory") do |_spinner|
14
+ execute!("rm -rf #{@dirpath}")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -17,14 +17,16 @@ module Procedures::SyncPlans
17
17
  private
18
18
 
19
19
  def disable_all_enabled_sync_plans
20
- feature(:sync_plans).load_from_storage(storage)
20
+ default_storage = ForemanMaintain.storage(:default)
21
+ feature(:sync_plans).load_from_storage(default_storage)
21
22
  with_spinner('disabling sync plans') do |spinner|
22
23
  ids = feature(:sync_plans).ids_by_status(true)
23
24
  feature(:sync_plans).make_disable(ids)
24
25
  spinner.update "Total #{ids.length} sync plans are now disabled."
25
26
  end
26
27
  ensure
27
- feature(:sync_plans).save_to_storage(storage)
28
+ feature(:sync_plans).save_to_storage(default_storage)
29
+ default_storage.save
28
30
  end
29
31
  end
30
32
  end
@@ -18,13 +18,15 @@ module Procedures::SyncPlans
18
18
  private
19
19
 
20
20
  def enabled_sync_plans
21
- feature(:sync_plans).load_from_storage(storage)
21
+ default_storage = ForemanMaintain.storage(:default)
22
+ feature(:sync_plans).load_from_storage(default_storage)
22
23
  with_spinner('re-enabling sync plans') do |spinner|
23
24
  record_ids = feature(:sync_plans).make_enable
24
25
  spinner.update "Total #{record_ids.length} sync plans are now enabled."
25
26
  end
26
27
  ensure
27
- feature(:sync_plans).save_to_storage(storage)
28
+ feature(:sync_plans).save_to_storage(default_storage)
29
+ default_storage.save
28
30
  end
29
31
  end
30
32
  end
@@ -21,6 +21,7 @@ module Scenarios::Satellite_6_2
21
21
  def compose
22
22
  add_steps(find_checks(:default))
23
23
  add_steps(find_checks(:pre_upgrade))
24
+ add_step(Checks::Repositories::Validate.new(:version => '6.2'))
24
25
  end
25
26
  end
26
27
 
@@ -21,6 +21,7 @@ module Scenarios::Satellite_6_2_z
21
21
  def compose
22
22
  add_steps(find_checks(:default))
23
23
  add_steps(find_checks(:pre_upgrade))
24
+ add_step(Checks::Repositories::Validate.new(:version => '6.2'))
24
25
  end
25
26
  end
26
27
 
@@ -21,6 +21,8 @@ module Scenarios::Satellite_6_3
21
21
  def compose
22
22
  add_steps(find_checks(:default))
23
23
  add_steps(find_checks(:pre_upgrade))
24
+ add_step(Checks::RemoteExecution::VerifySettingsFileAlreadyExists.new)
25
+ add_step(Checks::Repositories::Validate.new(:version => '6.3'))
24
26
  end
25
27
  end
26
28
 
@@ -21,6 +21,7 @@ module Scenarios::Satellite_6_3_z
21
21
  def compose
22
22
  add_steps(find_checks(:default))
23
23
  add_steps(find_checks(:pre_upgrade))
24
+ add_step(Checks::Repositories::Validate.new(:version => '6.3'))
24
25
  end
25
26
  end
26
27
 
@@ -13,7 +13,7 @@ module ForemanMaintain
13
13
 
14
14
  def self.params_for_tag(tag)
15
15
  params = {}
16
- ForemanMaintain.available_procedures(:tags => tag).each do |procedure|
16
+ ForemanMaintain.allowed_available_procedures(:tags => tag).each do |procedure|
17
17
  procedure.params.each_value do |param|
18
18
  unless params.key?(param.name)
19
19
  params[param.name] = { :instance => param, :procedures => [] }
@@ -35,7 +35,9 @@ module ForemanMaintain
35
35
  tag = underscorize(invocation_path.split.last).to_sym
36
36
  scenario = ForemanMaintain::Scenario.new
37
37
 
38
- ForemanMaintain.available_procedures(:tags => tag).sort_by(&:label).each do |procedure|
38
+ ForemanMaintain.allowed_available_procedures(
39
+ :tags => tag
40
+ ).sort_by(&:label).each do |procedure|
39
41
  scenario.add_step(procedure.new(get_params_for(procedure)))
40
42
  end
41
43
 
@@ -4,12 +4,14 @@ module ForemanMaintain
4
4
  module Cli
5
5
  module Procedure
6
6
  class ByTagCommand < Base
7
- available_tags(ForemanMaintain.available_procedures(nil)).each do |tag|
7
+ available_tags(ForemanMaintain.allowed_available_procedures(nil)).each do |tag|
8
8
  klass = Class.new(AbstractByTagCommand) do
9
9
  tag_params_to_options(tag)
10
10
  interactive_option
11
11
  end
12
- procedures = ForemanMaintain.available_procedures(:tags => tag).map do |procedure|
12
+ procedures = ForemanMaintain.allowed_available_procedures(
13
+ :tags => tag
14
+ ).map do |procedure|
13
15
  procedure.label.to_s
14
16
  end
15
17
 
@@ -4,7 +4,7 @@ module ForemanMaintain
4
4
  module Cli
5
5
  module Procedure
6
6
  class RunCommand < Base
7
- ForemanMaintain.available_procedures(nil).each do |procedure|
7
+ ForemanMaintain.allowed_available_procedures(nil).each do |procedure|
8
8
  klass = Class.new(AbstractProcedureCommand) do
9
9
  params_to_options(procedure.params)
10
10
  interactive_option
@@ -103,8 +103,8 @@ module ForemanMaintain
103
103
  option ['-y', '--assumeyes'], :flag,
104
104
  'Automatically answer yes for all questions'
105
105
 
106
- option ['-w', '--whitelist'], 'whitelist',
107
- 'Comma-separated list of labels of steps to be ignored' do |whitelist|
106
+ option(['-w', '--whitelist'], 'whitelist',
107
+ 'Comma-separated list of labels of steps to be skipped') do |whitelist|
108
108
  raise ArgumentError, 'value not specified' if whitelist.nil? || whitelist.empty?
109
109
  whitelist.split(',').map(&:strip)
110
110
  end
@@ -22,6 +22,49 @@ module ForemanMaintain
22
22
  psql('SELECT 1 as ping', config)
23
23
  end
24
24
 
25
+ def backup_file_path(config = configuration)
26
+ dump_file_name = "#{config['database']}_#{Time.now.strftime('%Y-%m-%d_%H-%M-%S')}.dump"
27
+ "#{backup_dir}/#{dump_file_name}.bz2"
28
+ end
29
+
30
+ def backup_db_command(file_path, config = configuration)
31
+ pg_dump_cmd = "pg_dump -Fc #{config['database']}"
32
+ "runuser - postgres -c '#{pg_dump_cmd}' | bzip2 -9 > #{file_path}"
33
+ end
34
+
35
+ def backup_dir
36
+ @backup_dir ||= File.expand_path(ForemanMaintain.config.db_backup_dir)
37
+ end
38
+
39
+ def perform_backup(config = configuration)
40
+ file_path = backup_file_path(config)
41
+ backup_cmd = backup_db_command(file_path, config)
42
+ execute!(backup_cmd)
43
+ puts "\n Note: Database backup file path - #{file_path}"
44
+ puts "\n In case of any exception, use above dump file to restore DB."
45
+ end
46
+
47
+ def table_exist?(table_name)
48
+ sql = <<-SQL
49
+ SELECT EXISTS ( SELECT *
50
+ FROM information_schema.tables WHERE table_name = '#{table_name}' )
51
+ SQL
52
+ result = query(sql)
53
+ return false if result.nil? || (result && result.empty?)
54
+ result.first['exists'].eql?('t')
55
+ end
56
+
57
+ def delete_records_by_ids(tbl_name, rec_ids)
58
+ quotize_rec_ids = rec_ids.map { |el| "'#{el}'" }.join(',')
59
+ unless quotize_rec_ids.empty?
60
+ psql(<<-SQL)
61
+ BEGIN;
62
+ DELETE FROM #{tbl_name} WHERE id IN (#{quotize_rec_ids});
63
+ COMMIT;
64
+ SQL
65
+ end
66
+ end
67
+
25
68
  private
26
69
 
27
70
  def psql_db_connection_str(config)
@@ -96,6 +96,10 @@ module ForemanMaintain
96
96
  @data[:run_once] = true
97
97
  end
98
98
 
99
+ def advanced_run(advanced_run)
100
+ @data[:advanced_run] = advanced_run
101
+ end
102
+
99
103
  def self.eval_dsl(metadata, &block)
100
104
  new(metadata).tap do |dsl|
101
105
  dsl.instance_eval(&block)
@@ -174,13 +178,18 @@ module ForemanMaintain
174
178
  metadata[:run_once]
175
179
  end
176
180
 
181
+ def advanced_run?
182
+ metadata[:advanced_run]
183
+ end
184
+
177
185
  def initialize_metadata
178
186
  { :tags => [],
179
187
  :confine_blocks => [],
180
188
  :params => {},
181
189
  :preparation_steps_blocks => [],
182
190
  :before => [],
183
- :after => [] }.tap do |metadata|
191
+ :after => [],
192
+ :advanced_run => true }.tap do |metadata|
184
193
  if superclass.respond_to?(:metadata)
185
194
  metadata[:label] = superclass.metadata[:label]
186
195
  end
@@ -271,6 +280,10 @@ module ForemanMaintain
271
280
  def preparation_steps(*args)
272
281
  self.class.preparation_steps(*args)
273
282
  end
283
+
284
+ def advanced_run?
285
+ self.class.advanced_run?
286
+ end
274
287
  end
275
288
  end
276
289
  end
@@ -61,6 +61,11 @@ module ForemanMaintain
61
61
  command_runner.output
62
62
  end
63
63
 
64
+ def execute_with_status(command, options = {})
65
+ result_msg = execute(command, options)
66
+ [$CHILD_STATUS.to_i, result_msg]
67
+ end
68
+
64
69
  def file_exists?(filename)
65
70
  File.exist?(filename)
66
71
  end
@@ -142,6 +147,12 @@ module ForemanMaintain
142
147
  def format_shell_args(options = {})
143
148
  options.map { |shell_optn, val| " #{shell_optn} '#{shellescape(val)}'" }.join
144
149
  end
150
+
151
+ def find_symlinks(dir_path)
152
+ cmd = "find '#{dir_path}' -maxdepth 1 -type l"
153
+ result = execute(cmd).strip
154
+ result.split(/\n/)
155
+ end
145
156
  end
146
157
  end
147
158
  end
@@ -3,7 +3,8 @@ module ForemanMaintain
3
3
  class Config
4
4
  attr_accessor :pre_setup_log_messages,
5
5
  :config_file, :definitions_dirs, :log_level, :log_dir, :log_file_size,
6
- :storage_file, :backup_dir, :foreman_proxy_cert_path
6
+ :storage_file, :backup_dir, :foreman_proxy_cert_path,
7
+ :db_backup_dir
7
8
 
8
9
  def initialize(options)
9
10
  @pre_setup_log_messages = []
@@ -12,10 +13,7 @@ module ForemanMaintain
12
13
  @definitions_dirs = @options.fetch(:definitions_dirs,
13
14
  [File.join(source_path, 'definitions')])
14
15
  load_log_configs
15
- @storage_file = @options.fetch(:storage_file, 'data.yml')
16
- @backup_dir = find_dir_path(
17
- @options.fetch(:backup_dir, '/var/lib/foreman-maintain')
18
- )
16
+ load_backup_dir_paths
19
17
  @foreman_proxy_cert_path = @options.fetch(:foreman_proxy_cert_path, '/etc/foreman')
20
18
  end
21
19
 
@@ -27,6 +25,16 @@ module ForemanMaintain
27
25
  @log_file_size = @options.fetch(:log_file_size, 10_000)
28
26
  end
29
27
 
28
+ def load_backup_dir_paths
29
+ @storage_file = @options.fetch(:storage_file, 'data.yml')
30
+ @backup_dir = find_dir_path(
31
+ @options.fetch(:backup_dir, '/var/lib/foreman-maintain')
32
+ )
33
+ @db_backup_dir = find_dir_path(
34
+ @options.fetch(:db_backup_dir, '/var/lib/foreman-maintain/db-backups')
35
+ )
36
+ end
37
+
30
38
  def load_config
31
39
  if File.exist?(config_file)
32
40
  YAML.load(File.open(config_file)) || {}
@@ -0,0 +1,34 @@
1
+ module ForemanMaintain
2
+ class Context
3
+ def initialize(data = {})
4
+ @data = data
5
+ @mapping = {}
6
+ end
7
+
8
+ def set(key, value, mapping = {})
9
+ @data[key] = value
10
+ map(key, mapping)
11
+ end
12
+
13
+ def get(key, default = nil)
14
+ @data.fetch(key, default)
15
+ end
16
+
17
+ def to_hash
18
+ @data
19
+ end
20
+
21
+ def map(key, mapping = {})
22
+ @mapping[key] ||= {}
23
+ @mapping[key].merge!(mapping)
24
+ end
25
+
26
+ def params_for(definition)
27
+ @mapping.inject({}) do |params, (key, mapping)|
28
+ target = mapping[definition]
29
+ params[target] = @data[key] unless target.nil?
30
+ params
31
+ end
32
+ end
33
+ end
34
+ end
@@ -50,7 +50,7 @@ module ForemanMaintain
50
50
 
51
51
  def find_present_classes(object_base_class)
52
52
  object_base_class.all_sub_classes.reduce([]) do |array, object_class|
53
- array << object_class if object_class.present?
53
+ array << object_class if object_class.autodetect? && object_class.present?
54
54
  array
55
55
  end
56
56
  end
@@ -116,7 +116,9 @@ module ForemanMaintain
116
116
  # internal method called by executor
117
117
  def __run__(execution)
118
118
  setup_execution_state(execution)
119
- run
119
+ unless skipped?
120
+ run
121
+ end
120
122
  end
121
123
 
122
124
  # method defined both on object and class to ensure we work always with object
@@ -66,16 +66,20 @@ module ForemanMaintain
66
66
 
67
67
  def run
68
68
  @reporter.before_execution_starts(self)
69
+
69
70
  if skip?
70
71
  @status = :already_run
71
72
  return
72
73
  end
73
- @status = :running
74
+
75
+ @status = whitelisted? ? :skipped : :running
76
+
74
77
  with_metadata_calculation do
75
78
  capture_errors do
76
79
  step.__run__(self)
77
80
  end
78
81
  end
82
+
79
83
  # change the state only when not modified
80
84
  @status = :success if @status == :running
81
85
  ensure
@@ -6,7 +6,7 @@ module ForemanMaintain
6
6
  include Concerns::Finders
7
7
  extend Concerns::Finders
8
8
 
9
- attr_reader :steps
9
+ attr_reader :steps, :context
10
10
 
11
11
  class FilteredScenario < Scenario
12
12
  metadata do
@@ -79,14 +79,19 @@ module ForemanMaintain
79
79
  end
80
80
  end
81
81
 
82
- def initialize
82
+ def initialize(context_data = {})
83
83
  @steps = []
84
+ @context = Context.new(context_data)
85
+ set_context_mapping
84
86
  compose
85
87
  end
86
88
 
87
89
  # Override to compose steps for the scenario
88
90
  def compose; end
89
91
 
92
+ # Override to map context for the scenario
93
+ def set_context_mapping; end
94
+
90
95
  def preparation_steps
91
96
  # we first take the preparation steps defined for the scenario + collect
92
97
  # preparation steps for the steps inside the scenario
@@ -141,7 +146,15 @@ module ForemanMaintain
141
146
  end
142
147
 
143
148
  def add_step(step)
144
- add_steps([step])
149
+ add_steps([step]) unless step.nil?
150
+ end
151
+
152
+ def add_step_with_context(definition)
153
+ add_step(definition.send(:new, context.params_for(definition))) if definition.present?
154
+ end
155
+
156
+ def add_steps_with_context(*definitions)
157
+ definitions.flatten.each { |definition| add_step_with_context(definition) }
145
158
  end
146
159
 
147
160
  def self.inspect
@@ -175,7 +175,7 @@ module ForemanMaintain
175
175
  The upgrade failed and system was restored to pre-upgrade state.
176
176
  MESSAGE
177
177
  end
178
- # rubocop:enable Metrics/AbcSize, Lint/NonLocalExitFromIterator
178
+ # rubocop:enable Metrics/AbcSize
179
179
 
180
180
  def with_non_empty_scenario(phase)
181
181
  next_scenario = scenario(phase)
@@ -1,3 +1,3 @@
1
1
  module ForemanMaintain
2
- VERSION = '0.1.3'.freeze
2
+ VERSION = '0.1.4'.freeze
3
3
  end
@@ -20,6 +20,7 @@ module ForemanMaintain
20
20
  require 'foreman_maintain/top_level_modules'
21
21
  require 'foreman_maintain/yaml_storage'
22
22
  require 'foreman_maintain/config'
23
+ require 'foreman_maintain/context'
23
24
  require 'foreman_maintain/detector'
24
25
  require 'foreman_maintain/dependency_graph'
25
26
  require 'foreman_maintain/param'
@@ -91,6 +92,11 @@ module ForemanMaintain
91
92
  detector.available_procedures(*args)
92
93
  end
93
94
 
95
+ def allowed_available_procedures(*args)
96
+ procedures = detector.available_procedures(*args)
97
+ procedures.select(&:advanced_run?)
98
+ end
99
+
94
100
  def init_logger
95
101
  # Note - If timestamp added to filename then number of log files i.e second
96
102
  # argument to Logger.new will not work as expected
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_maintain
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Nečas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-31 00:00:00.000000000 Z
11
+ date: 2018-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: clamp
@@ -120,6 +120,8 @@ files:
120
120
  - definitions/checks/foreman_tasks/not_paused.rb
121
121
  - definitions/checks/foreman_tasks/not_running.rb
122
122
  - definitions/checks/hammer_ping.rb
123
+ - definitions/checks/remote_execution/verify_settings_file_already_exists.rb
124
+ - definitions/checks/repositories/validate.rb
123
125
  - definitions/checks/system_registration.rb
124
126
  - definitions/features/candlepin_database.rb
125
127
  - definitions/features/downstream.rb
@@ -135,6 +137,7 @@ files:
135
137
  - definitions/features/pulp.rb
136
138
  - definitions/features/sync_plans.rb
137
139
  - definitions/features/upstream.rb
140
+ - definitions/procedures/candlepin/delete_orphaned_records_from_env_content.rb
138
141
  - definitions/procedures/foreman_tasks/delete.rb
139
142
  - definitions/procedures/foreman_tasks/fetch_tasks_status.rb
140
143
  - definitions/procedures/foreman_tasks/resume.rb
@@ -144,11 +147,13 @@ files:
144
147
  - definitions/procedures/katello_service/restart.rb
145
148
  - definitions/procedures/katello_service/start.rb
146
149
  - definitions/procedures/katello_service/stop.rb
150
+ - definitions/procedures/knowledge_base_article.rb
147
151
  - definitions/procedures/maintenance_mode/disable.rb
148
152
  - definitions/procedures/maintenance_mode/enable.rb
149
153
  - definitions/procedures/packages/install.rb
150
154
  - definitions/procedures/packages/update.rb
151
155
  - definitions/procedures/passenger_recycler.rb
156
+ - definitions/procedures/remote_execution/remove_existing_settingsd.rb
152
157
  - definitions/procedures/repositories/setup.rb
153
158
  - definitions/procedures/sync_plans/disable.rb
154
159
  - definitions/procedures/sync_plans/enable.rb
@@ -177,6 +182,7 @@ files:
177
182
  - lib/foreman_maintain/concerns/scenario_metadata.rb
178
183
  - lib/foreman_maintain/concerns/system_helpers.rb
179
184
  - lib/foreman_maintain/config.rb
185
+ - lib/foreman_maintain/context.rb
180
186
  - lib/foreman_maintain/core_ext.rb
181
187
  - lib/foreman_maintain/csv_parser.rb
182
188
  - lib/foreman_maintain/dependency_graph.rb