foreman_maintain 0.0.2 → 0.0.3
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/README.md +107 -25
- data/bin/foreman-maintain +1 -0
- data/definitions/checks/disk_speed_minimal.rb +31 -19
- data/definitions/checks/foreman_tasks/invalid/check_old.rb +20 -0
- data/definitions/checks/foreman_tasks/invalid/check_pending_state.rb +20 -0
- data/definitions/checks/foreman_tasks/invalid/check_planning_state.rb +20 -0
- data/definitions/checks/foreman_tasks/not_paused.rb +29 -0
- data/definitions/checks/foreman_tasks/not_running.rb +14 -0
- data/definitions/checks/sync_plans/with_disabled_status.rb +18 -0
- data/definitions/checks/sync_plans/with_enabled_status.rb +18 -0
- data/definitions/checks/system_registration.rb +31 -0
- data/definitions/features/downstream.rb +5 -3
- data/definitions/features/foreman_1_11_x.rb +4 -2
- data/definitions/features/foreman_1_7_x.rb +5 -3
- data/definitions/features/foreman_database.rb +11 -5
- data/definitions/features/foreman_tasks.rb +118 -9
- data/definitions/features/sync_plans.rb +75 -0
- data/definitions/features/upstream.rb +5 -3
- data/definitions/procedures/foreman_tasks/delete.rb +33 -0
- data/definitions/procedures/foreman_tasks/resume.rb +14 -0
- data/definitions/procedures/foreman_tasks/ui_investigate.rb +19 -0
- data/definitions/procedures/hammer_setup.rb +50 -0
- data/definitions/procedures/install_package.rb +17 -0
- data/definitions/procedures/sync_plans/disable.rb +22 -0
- data/definitions/procedures/sync_plans/enable.rb +21 -0
- data/definitions/scenarios/pre_upgrade_check_foreman_1_14.rb +7 -6
- data/definitions/scenarios/pre_upgrade_check_satellite_6_0_z.rb +8 -6
- data/definitions/scenarios/pre_upgrade_check_satellite_6_1.rb +8 -6
- data/definitions/scenarios/pre_upgrade_check_satellite_6_1_z.rb +8 -6
- data/definitions/scenarios/pre_upgrade_check_satellite_6_2.rb +8 -6
- data/definitions/scenarios/pre_upgrade_check_satellite_6_2_z.rb +8 -6
- data/definitions/scenarios/pre_upgrade_check_satellite_6_3.rb +8 -6
- data/lib/foreman_maintain.rb +52 -5
- data/lib/foreman_maintain/check.rb +18 -12
- data/lib/foreman_maintain/cli/base.rb +9 -2
- data/lib/foreman_maintain/cli/health_command.rb +2 -1
- data/lib/foreman_maintain/cli/upgrade_command.rb +2 -0
- data/lib/foreman_maintain/concerns/hammer.rb +20 -0
- data/lib/foreman_maintain/concerns/logger.rb +1 -5
- data/lib/foreman_maintain/concerns/metadata.rb +138 -31
- data/lib/foreman_maintain/concerns/system_helpers.rb +36 -32
- data/lib/foreman_maintain/config.rb +40 -5
- data/lib/foreman_maintain/core_ext.rb +24 -0
- data/lib/foreman_maintain/detector.rb +12 -13
- data/lib/foreman_maintain/error.rb +28 -0
- data/lib/foreman_maintain/executable.rb +86 -11
- data/lib/foreman_maintain/feature.rb +1 -0
- data/lib/foreman_maintain/param.rb +47 -0
- data/lib/foreman_maintain/reporter.rb +20 -3
- data/lib/foreman_maintain/reporter/cli_reporter.rb +166 -66
- data/lib/foreman_maintain/runner.rb +56 -13
- data/lib/foreman_maintain/runner/execution.rb +8 -0
- data/lib/foreman_maintain/scenario.rb +46 -2
- data/lib/foreman_maintain/top_level_modules.rb +3 -0
- data/lib/foreman_maintain/utils.rb +2 -0
- data/lib/foreman_maintain/utils/command_runner.rb +101 -0
- data/lib/foreman_maintain/utils/disk/device.rb +5 -9
- data/lib/foreman_maintain/utils/hammer.rb +78 -0
- data/lib/foreman_maintain/version.rb +1 -1
- data/lib/foreman_maintain/yaml_storage.rb +48 -0
- metadata +27 -9
- data/definitions/checks/foreman_tasks_not_paused.rb +0 -14
- data/definitions/checks/foreman_tasks_not_running.rb +0 -10
- data/definitions/procedures/foreman_tasks_resume.rb +0 -13
- data/lib/foreman_maintain/logger.rb +0 -11
@@ -1,15 +1,21 @@
|
|
1
1
|
class Features::ForemanDatabase < ForemanMaintain::Feature
|
2
|
-
|
2
|
+
metadata do
|
3
|
+
label :foreman_database
|
3
4
|
|
4
|
-
|
5
|
-
|
5
|
+
confine do
|
6
|
+
File.exist?('/etc/foreman/database.yml')
|
7
|
+
end
|
6
8
|
end
|
7
9
|
|
8
10
|
def query(sql)
|
9
|
-
parse_csv(
|
11
|
+
parse_csv(query_csv(sql))
|
12
|
+
end
|
13
|
+
|
14
|
+
def query_csv(sql)
|
15
|
+
psql(%{COPY (#{sql}) TO STDOUT WITH CSV HEADER})
|
10
16
|
end
|
11
17
|
|
12
18
|
def psql(query)
|
13
|
-
execute("su - postgres -c 'psql -d foreman'", query)
|
19
|
+
execute("su - postgres -c 'psql -d foreman'", :stdin => query)
|
14
20
|
end
|
15
21
|
end
|
@@ -1,9 +1,35 @@
|
|
1
1
|
class Features::ForemanTasks < ForemanMaintain::Feature
|
2
|
-
|
2
|
+
MIN_AGE = 30
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
SAFE_TO_DELETE = %w[
|
5
|
+
Actions::Katello::Host::GenerateApplicability
|
6
|
+
Actions::Katello::RepositorySet::ScanCdn
|
7
|
+
Actions::Katello::Host::Hypervisors
|
8
|
+
Actions::Katello::Host::HypervisorsUpdate
|
9
|
+
Actions::Foreman::Host::ImportFacts
|
10
|
+
Actions::Candlepin::ListenOnCandlepinEvents
|
11
|
+
Actions::Katello::EventQueue::Monitor
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
metadata do
|
15
|
+
label :foreman_tasks
|
16
|
+
|
17
|
+
confine do
|
18
|
+
check_min_version('ruby193-rubygem-foreman-tasks', '0.6') ||
|
19
|
+
check_min_version('tfm-rubygem-foreman-tasks', '0.7')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def backup_tasks(state)
|
24
|
+
backup_table('dynflow_execution_plans', state, 'uuid') { |status| yield(status) }
|
25
|
+
backup_table('dynflow_steps', state) { |status| yield(status) }
|
26
|
+
backup_table('dynflow_actions', state) { |status| yield(status) }
|
27
|
+
|
28
|
+
yield('Backup Tasks [running]')
|
29
|
+
export_csv("SELECT * FROM foreman_tasks_tasks WHERE #{condition(state)}",
|
30
|
+
'foreman_tasks_tasks.csv', state)
|
31
|
+
yield('Backup Tasks [DONE]')
|
32
|
+
@backup_dir = nil
|
7
33
|
end
|
8
34
|
|
9
35
|
def running_tasks_count
|
@@ -13,10 +39,93 @@ class Features::ForemanTasks < ForemanMaintain::Feature
|
|
13
39
|
0
|
14
40
|
end
|
15
41
|
|
16
|
-
def paused_tasks_count
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
42
|
+
def paused_tasks_count(ignored_tasks = [])
|
43
|
+
sql = <<-SQL
|
44
|
+
SELECT count(*) AS count
|
45
|
+
FROM foreman_tasks_tasks
|
46
|
+
WHERE state IN ('paused')
|
47
|
+
SQL
|
48
|
+
unless ignored_tasks.empty?
|
49
|
+
sql << "AND label NOT IN (#{quotize(ignored_tasks)})"
|
50
|
+
end
|
51
|
+
feature(:foreman_database).query(sql).first['count'].to_i
|
52
|
+
end
|
53
|
+
|
54
|
+
def count(state)
|
55
|
+
feature(:foreman_database).query(<<-SQL).first['count'].to_i
|
56
|
+
SELECT count(*) AS count FROM foreman_tasks_tasks WHERE #{condition(state)}
|
57
|
+
SQL
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete(state)
|
61
|
+
tasks_condition = condition(state)
|
62
|
+
|
63
|
+
feature(:foreman_database).psql(<<-SQL)
|
64
|
+
BEGIN;
|
65
|
+
DELETE FROM dynflow_steps USING foreman_tasks_tasks WHERE (foreman_tasks_tasks.external_id = dynflow_steps.execution_plan_uuid) AND #{tasks_condition};
|
66
|
+
DELETE FROM dynflow_actions USING foreman_tasks_tasks WHERE (foreman_tasks_tasks.external_id = dynflow_actions.execution_plan_uuid) AND #{tasks_condition};
|
67
|
+
DELETE FROM dynflow_execution_plans USING foreman_tasks_tasks WHERE (foreman_tasks_tasks.external_id = dynflow_execution_plans.uuid) AND #{tasks_condition};
|
68
|
+
DELETE FROM foreman_tasks_tasks WHERE #{tasks_condition};
|
69
|
+
COMMIT;
|
70
|
+
SQL
|
71
|
+
|
72
|
+
count(state)
|
73
|
+
end
|
74
|
+
|
75
|
+
def condition(state)
|
76
|
+
raise 'Invalid State' unless valid(state)
|
77
|
+
|
78
|
+
if state == :old
|
79
|
+
old_tasks_condition
|
80
|
+
else
|
81
|
+
tasks_condition(state)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def backup_dir(state)
|
88
|
+
@backup_dir ||=
|
89
|
+
"/var/lib/foreman/backup-tasks/#{state}/#{Time.now.strftime('%Y-%m-%d_%H-%M-%S')}"
|
90
|
+
end
|
91
|
+
|
92
|
+
def backup_table(table, state, fkey = 'execution_plan_uuid')
|
93
|
+
yield("Backup #{table} [running]")
|
94
|
+
sql = "SELECT #{table}.* FROM foreman_tasks_tasks JOIN #{table} ON\
|
95
|
+
(foreman_tasks_tasks.external_id = #{table}.#{fkey})"
|
96
|
+
export_csv(sql, "#{table}.csv", state)
|
97
|
+
yield("Backup #{table} [DONE]")
|
98
|
+
end
|
99
|
+
|
100
|
+
def export_csv(sql, file_name, state)
|
101
|
+
dir = prepare_for_backup(state)
|
102
|
+
filepath = "#{dir}/#{file_name}"
|
103
|
+
execute("echo \"COPY (#{sql}) TO STDOUT WITH CSV;\" \
|
104
|
+
| su - postgres -c '/usr/bin/psql -d foreman' | bzip2 -9 > #{filepath}.bz2")
|
105
|
+
end
|
106
|
+
|
107
|
+
def old_tasks_condition(state = "'stopped', 'paused'")
|
108
|
+
"foreman_tasks_tasks.state IN (#{state}) AND " \
|
109
|
+
"foreman_tasks_tasks.started_at < CURRENT_DATE - INTERVAL '#{MIN_AGE} days'"
|
110
|
+
end
|
111
|
+
|
112
|
+
def prepare_for_backup(state)
|
113
|
+
dir = backup_dir(state)
|
114
|
+
execute("mkdir -p #{dir}")
|
115
|
+
dir
|
116
|
+
end
|
117
|
+
|
118
|
+
def quotize(array)
|
119
|
+
array.map { |el| "'#{el}'" }.join(',')
|
120
|
+
end
|
121
|
+
|
122
|
+
def tasks_condition(state)
|
123
|
+
safe_to_delete_tasks = quotize(SAFE_TO_DELETE)
|
124
|
+
"foreman_tasks_tasks.state = '#{state}' AND " \
|
125
|
+
"foreman_tasks_tasks.label IN (#{safe_to_delete_tasks})"
|
126
|
+
end
|
127
|
+
|
128
|
+
def valid(state)
|
129
|
+
[:old, :planning, :pending].include?(state)
|
21
130
|
end
|
22
131
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class Features::SyncPlans < ForemanMaintain::Feature
|
2
|
+
metadata do
|
3
|
+
label :sync_plans
|
4
|
+
end
|
5
|
+
|
6
|
+
def active_sync_plans_count
|
7
|
+
feature(:foreman_database).query(
|
8
|
+
<<-SQL
|
9
|
+
SELECT count(*) AS count FROM katello_sync_plans WHERE enabled ='t'
|
10
|
+
SQL
|
11
|
+
).first['count'].to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
def ids_by_status(enabled = true)
|
15
|
+
enabled = enabled ? 't' : 'f'
|
16
|
+
feature(:foreman_database).query(
|
17
|
+
<<-SQL
|
18
|
+
SELECT id FROM katello_sync_plans WHERE enabled ='#{enabled}'
|
19
|
+
SQL
|
20
|
+
).map { |r| r['id'].to_i }
|
21
|
+
end
|
22
|
+
|
23
|
+
def disabled_plans_count
|
24
|
+
data[:disabled].length
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_disable(ids)
|
28
|
+
update_records(ids, false)
|
29
|
+
end
|
30
|
+
|
31
|
+
def make_enable
|
32
|
+
update_records(data[:disabled], true)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def update_records(ids, enabled)
|
38
|
+
updated_record_ids = []
|
39
|
+
ids.each do |sp_id|
|
40
|
+
result = hammer("sync-plan update --id #{sp_id} --enabled #{enabled}")
|
41
|
+
if result.include?('Sync plan updated')
|
42
|
+
updated_record_ids << sp_id
|
43
|
+
else
|
44
|
+
raise result
|
45
|
+
end
|
46
|
+
end
|
47
|
+
updated_record_ids
|
48
|
+
ensure
|
49
|
+
new_data = sync_plan_data(enabled, updated_record_ids)
|
50
|
+
save_state(new_data)
|
51
|
+
end
|
52
|
+
|
53
|
+
def data
|
54
|
+
upgrade_storage = ForemanMaintain.storage(:upgrade)
|
55
|
+
@data ||= upgrade_storage.data.fetch(:sync_plans, :enabled => [], :disabled => [])
|
56
|
+
@data
|
57
|
+
end
|
58
|
+
|
59
|
+
def sync_plan_data(enabled, new_ids)
|
60
|
+
sync_plan_hash = data
|
61
|
+
if enabled
|
62
|
+
sync_plan_hash[:disabled] -= new_ids
|
63
|
+
sync_plan_hash[:enabled] = new_ids
|
64
|
+
else
|
65
|
+
sync_plan_hash[:disabled].concat(new_ids)
|
66
|
+
end
|
67
|
+
sync_plan_hash
|
68
|
+
end
|
69
|
+
|
70
|
+
def save_state(sync_plan_hash = {})
|
71
|
+
storage = ForemanMaintain.storage(:upgrade)
|
72
|
+
storage[:sync_plans] = sync_plan_hash
|
73
|
+
storage.save
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Procedures::ForemanTasks
|
2
|
+
class Delete < ForemanMaintain::Procedure
|
3
|
+
metadata do
|
4
|
+
param :state, 'In what state should the task be deleted'
|
5
|
+
end
|
6
|
+
|
7
|
+
def run
|
8
|
+
with_spinner("Deleting #{@state} task") do |spinner|
|
9
|
+
count_tasks_before = feature(:foreman_tasks).count(@state)
|
10
|
+
|
11
|
+
if count_tasks_before > 0
|
12
|
+
spinner.update "Backup #{@state} tasks"
|
13
|
+
|
14
|
+
feature(:foreman_tasks).backup_tasks(@state) do |backup_progress|
|
15
|
+
spinner.update backup_progress
|
16
|
+
end
|
17
|
+
|
18
|
+
spinner.update "Deleting #{@state} tasks [running]"
|
19
|
+
count_tasks_later = feature(:foreman_tasks).delete(@state)
|
20
|
+
spinner.update "Deleting #{@state} tasks [DONE]"
|
21
|
+
end
|
22
|
+
|
23
|
+
spinner.update(
|
24
|
+
"Deleted #{@state} stopped and paused tasks: #{count_tasks_before - count_tasks_later}"
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def description
|
30
|
+
"Delete #{@state} tasks"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Procedures::ForemanTasks
|
2
|
+
class Resume < ForemanMaintain::Procedure
|
3
|
+
include ForemanMaintain::Concerns::Hammer
|
4
|
+
|
5
|
+
metadata do
|
6
|
+
for_feature :foreman_tasks
|
7
|
+
description 'resume paused tasks'
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
output << hammer('task resume')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
module Procedures::ForemanTasks
|
3
|
+
class UiInvestigate < ForemanMaintain::Procedure
|
4
|
+
metadata do
|
5
|
+
for_feature :foreman_tasks
|
6
|
+
description 'investigate the tasks via UI'
|
7
|
+
param :search_query
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :search_query
|
11
|
+
|
12
|
+
def run
|
13
|
+
ask(<<-MESSAGE.strip_heredoc)
|
14
|
+
Go to https://#{hostname}/foreman_tasks/tasks?search=#{CGI.escape(@search_query.to_s)}
|
15
|
+
press ENTER after the paused tasks are resolved.
|
16
|
+
MESSAGE
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Procedures::HammerSetup < ForemanMaintain::Procedure
|
2
|
+
def run
|
3
|
+
setup_from_default || setup_from_answers
|
4
|
+
puts "New settings saved into #{hammer.config_file}"
|
5
|
+
hammer.run_command('architecture list') # if not setup properly, an error will be risen
|
6
|
+
end
|
7
|
+
|
8
|
+
def necessary?
|
9
|
+
!hammer.ready?
|
10
|
+
end
|
11
|
+
|
12
|
+
def description
|
13
|
+
'Setup hammer'
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def setup_from_default
|
19
|
+
used_default_file = hammer.setup_from_default
|
20
|
+
if used_default_file
|
21
|
+
puts "Using defaults from #{used_default_file}"
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def setup_from_answers
|
27
|
+
loop do
|
28
|
+
username, password = ask_for_credentials
|
29
|
+
break if username.nil?
|
30
|
+
if hammer.setup_from_answers(username, password)
|
31
|
+
return true
|
32
|
+
else
|
33
|
+
puts 'Invalid credentials'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def ask_for_credentials
|
39
|
+
username = ask('Hammer username [admin]:')
|
40
|
+
return if username.nil?
|
41
|
+
username = 'admin' if username.empty?
|
42
|
+
password = ask('Hammer password:', :password => true)
|
43
|
+
return if password.nil?
|
44
|
+
[username.strip, password.strip]
|
45
|
+
end
|
46
|
+
|
47
|
+
def hammer
|
48
|
+
ForemanMaintain::Utils::Hammer.instance
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Procedures::InstallPackage < ForemanMaintain::Procedure
|
2
|
+
metadata do
|
3
|
+
param :packages, 'List of packages to install', :array => true
|
4
|
+
end
|
5
|
+
|
6
|
+
def run
|
7
|
+
install_packages(@packages, :assumeyes => assumeyes?)
|
8
|
+
end
|
9
|
+
|
10
|
+
def necessary?
|
11
|
+
@packages.any? { |package| package_version(package).nil? }
|
12
|
+
end
|
13
|
+
|
14
|
+
def description
|
15
|
+
"Install package(s) #{@packages.join(', ')}"
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Procedures::SyncPlans
|
2
|
+
class Disable < ForemanMaintain::Procedure
|
3
|
+
metadata do
|
4
|
+
for_feature :sync_plans
|
5
|
+
description 'disable active sync plans'
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
disable_all_enabled_sync_plans
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def disable_all_enabled_sync_plans
|
15
|
+
with_spinner('disabling sync plans') do |spinner|
|
16
|
+
ids = feature(:sync_plans).ids_by_status(true)
|
17
|
+
feature(:sync_plans).make_disable(ids)
|
18
|
+
spinner.update "Total #{ids.length} sync plans are now disabled."
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|