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.
- checksums.yaml +4 -4
- data/bin/passenger-recycler +23 -15
- data/config/foreman_maintain.yml.example +4 -0
- data/config/foreman_maintain.yml.packaging +2 -0
- data/definitions/checks/candlepin/validate_db.rb +9 -1
- data/definitions/checks/remote_execution/verify_settings_file_already_exists.rb +42 -0
- data/definitions/checks/repositories/validate.rb +33 -0
- data/definitions/features/candlepin_database.rb +19 -11
- data/definitions/features/downstream.rb +13 -0
- data/definitions/features/foreman_1_7_x.rb +3 -1
- data/definitions/features/foreman_proxy.rb +6 -5
- data/definitions/procedures/candlepin/delete_orphaned_records_from_env_content.rb +34 -0
- data/definitions/procedures/knowledge_base_article.rb +29 -0
- data/definitions/procedures/remote_execution/remove_existing_settingsd.rb +18 -0
- data/definitions/procedures/sync_plans/disable.rb +4 -2
- data/definitions/procedures/sync_plans/enable.rb +4 -2
- data/definitions/scenarios/upgrade_to_satellite_6_2.rb +1 -0
- data/definitions/scenarios/upgrade_to_satellite_6_2_z.rb +1 -0
- data/definitions/scenarios/upgrade_to_satellite_6_3.rb +2 -0
- data/definitions/scenarios/upgrade_to_satellite_6_3_z.rb +1 -0
- data/lib/foreman_maintain/cli/advanced/procedure/abstract_by_tag_command.rb +4 -2
- data/lib/foreman_maintain/cli/advanced/procedure/by_tag_command.rb +4 -2
- data/lib/foreman_maintain/cli/advanced/procedure/run_command.rb +1 -1
- data/lib/foreman_maintain/cli/base.rb +2 -2
- data/lib/foreman_maintain/concerns/base_database.rb +43 -0
- data/lib/foreman_maintain/concerns/metadata.rb +14 -1
- data/lib/foreman_maintain/concerns/system_helpers.rb +11 -0
- data/lib/foreman_maintain/config.rb +13 -5
- data/lib/foreman_maintain/context.rb +34 -0
- data/lib/foreman_maintain/detector.rb +1 -1
- data/lib/foreman_maintain/executable.rb +3 -1
- data/lib/foreman_maintain/runner/execution.rb +5 -1
- data/lib/foreman_maintain/scenario.rb +16 -3
- data/lib/foreman_maintain/upgrade_runner.rb +1 -1
- data/lib/foreman_maintain/version.rb +1 -1
- data/lib/foreman_maintain.rb +6 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65b1daa7e3ed6b36c77a34061c0cde3badf9cc0d
|
4
|
+
data.tar.gz: '08aedcc2e9c4242dc17b8d50b5bf356bd3349d28'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a7548a663107ef22475acefbe0b0a5dc5aeff92e816c6eaf0096b2ce344c43536af033d9d67fbbc5c36f976c4d6f7e0dbb6e6d8f0343e69ad678feaa907cdc6
|
7
|
+
data.tar.gz: 6e0a423955cd009992767a126168609ac9ec0d1687465089bfa1861798402157f8225f335ad452fa64ba04a751468d5804cac000faafe9a450d07d75109db6bf
|
data/bin/passenger-recycler
CHANGED
@@ -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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
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)
|
@@ -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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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['
|
51
|
+
uri = %r{://(([^/:]*):?([^/]*))/(.*)}.match(full_config['jpa.config.hibernate.connection.url'])
|
44
52
|
@configuration = {
|
45
|
-
'username' => full_config['
|
46
|
-
'password' => full_config['
|
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
|
-
'
|
51
|
-
'url' => full_config['
|
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
|
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
|
44
|
-
|
45
|
-
curl_http_status =
|
46
|
-
curl_http_resp = parse_json(
|
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
|
-
|
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(
|
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
|
-
|
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(
|
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,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
|
|
@@ -13,7 +13,7 @@ module ForemanMaintain
|
|
13
13
|
|
14
14
|
def self.params_for_tag(tag)
|
15
15
|
params = {}
|
16
|
-
ForemanMaintain.
|
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.
|
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.
|
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.
|
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.
|
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
|
107
|
-
'Comma-separated list of labels of steps to be
|
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 => []
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
178
|
+
# rubocop:enable Metrics/AbcSize
|
179
179
|
|
180
180
|
def with_non_empty_scenario(phase)
|
181
181
|
next_scenario = scenario(phase)
|
data/lib/foreman_maintain.rb
CHANGED
@@ -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.
|
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-
|
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
|