foreman_maintain 0.2.1 → 0.2.2
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/foreman-maintain +2 -1
- data/definitions/checks/backup/directory_ready.rb +1 -1
- data/definitions/checks/restore/validate_backup.rb +77 -0
- data/definitions/checks/restore/validate_hostname.rb +20 -0
- data/definitions/features/foreman_proxy.rb +6 -1
- data/definitions/features/foreman_tasks.rb +5 -1
- data/definitions/features/instance.rb +8 -0
- data/definitions/features/katello.rb +0 -1
- data/definitions/features/mongo.rb +51 -12
- data/definitions/features/pulp.rb +2 -1
- data/definitions/features/service.rb +36 -0
- data/definitions/features/tar.rb +16 -4
- data/definitions/procedures/backup/online/pg_global_objects.rb +3 -1
- data/definitions/procedures/backup/prepare_directory.rb +1 -1
- data/definitions/procedures/backup/pulp.rb +2 -1
- data/definitions/procedures/pulp/migrate.rb +21 -0
- data/definitions/procedures/restore/candlepin_dump.rb +30 -0
- data/definitions/procedures/restore/configs.rb +40 -0
- data/definitions/procedures/restore/confirmation.rb +17 -0
- data/definitions/procedures/restore/drop_databases.rb +39 -0
- data/definitions/procedures/restore/extract_files.rb +70 -0
- data/definitions/procedures/restore/foreman_dump.rb +30 -0
- data/definitions/procedures/restore/installer_reset.rb +39 -0
- data/definitions/procedures/restore/mongo_dump.rb +41 -0
- data/definitions/procedures/restore/pg_global_objects.rb +36 -0
- data/definitions/procedures/restore/postgres_owner.rb +18 -0
- data/definitions/procedures/selinux/set_file_security.rb +22 -0
- data/definitions/procedures/service/daemon_reload.rb +18 -0
- data/definitions/procedures/service/restart.rb +2 -2
- data/definitions/scenarios/restore.rb +91 -0
- data/lib/foreman_maintain/cli.rb +3 -1
- data/lib/foreman_maintain/cli/restore_command.rb +26 -0
- data/lib/foreman_maintain/concerns/base_database.rb +35 -1
- data/lib/foreman_maintain/concerns/system_helpers.rb +1 -5
- data/lib/foreman_maintain/reporter/cli_reporter.rb +2 -1
- data/lib/foreman_maintain/utils/backup.rb +225 -0
- data/lib/foreman_maintain/utils/command_runner.rb +4 -2
- data/lib/foreman_maintain/utils/mongo_core.rb +49 -0
- data/lib/foreman_maintain/version.rb +1 -1
- metadata +20 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '078ab0c0f9b3bfe3b4a6a798aaa181bb0ecba87e'
|
4
|
+
data.tar.gz: 898a5faf68654553aafaa03c8afe026e33ddc8e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c512de5ef767ec004443beb7f32386ea113899b626ebe195ac69aeba6d2ec21cb66fcb4d93b8423fbbb8e3ee56bf54f95d11d59bc6fc892fa412b28b532f9e3b
|
7
|
+
data.tar.gz: 3be8f1aad6584b3565841633d3b6f6ef99c2fbf7eb7b986e34e58b7dce60fd775bde2a3dbed6ce3a11cbddaff0490ae82d31f126ae92cfa36f40807b77836491
|
data/bin/foreman-maintain
CHANGED
@@ -10,7 +10,7 @@ module Checks::Backup
|
|
10
10
|
|
11
11
|
def run
|
12
12
|
assert(File.directory?(@backup_dir), "Backup directory (#{@backup_dir}) does not exit.")
|
13
|
-
if
|
13
|
+
if feature(:instance).postgresql_local?
|
14
14
|
result = system("runuser - postgres -c 'test -w #{@backup_dir}'")
|
15
15
|
assert(result, "Postgres user needs write access to the backup directory \n" \
|
16
16
|
"Please allow the postgres user write access to #{@backup_dir}" \
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'foreman_maintain/utils/backup'
|
2
|
+
|
3
|
+
module Checks::Restore
|
4
|
+
class ValidateBackup < ForemanMaintain::Check
|
5
|
+
metadata do
|
6
|
+
description 'Validate backup has appropriate files'
|
7
|
+
|
8
|
+
param :backup_dir,
|
9
|
+
'Path to backup directory',
|
10
|
+
:required => true
|
11
|
+
manual_detection
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
backup = ForemanMaintain::Utils::Backup.new(@backup_dir)
|
16
|
+
assert(backup.valid_backup?, valid_backup_message(backup))
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid_backup_message(backup)
|
20
|
+
message = "\n"
|
21
|
+
message += "The given directory does not contain the required files or has too many files\n\n"
|
22
|
+
message += "All backup directories contain: #{backup.standard_files.join(', ')}\n"
|
23
|
+
message += required_files(backup)
|
24
|
+
message += 'Including pulp_data.tar is optional and '
|
25
|
+
message += "will restore pulp data to the filesystem if included.\n\n"
|
26
|
+
message += "Only the following files were found: #{backup.present_files.join(', ')}\n"
|
27
|
+
message
|
28
|
+
end
|
29
|
+
|
30
|
+
def required_files(backup)
|
31
|
+
message = ''
|
32
|
+
message += if feature(:instance).foreman_proxy_with_content?
|
33
|
+
required_fpc_files(backup)
|
34
|
+
elsif feature(:katello)
|
35
|
+
required_katello_files(backup)
|
36
|
+
else
|
37
|
+
required_foreman_files(backup)
|
38
|
+
end
|
39
|
+
message
|
40
|
+
end
|
41
|
+
|
42
|
+
def required_katello_files(backup)
|
43
|
+
backup_files_message(
|
44
|
+
backup.katello_online_files.join(', '),
|
45
|
+
backup.katello_offline_files.join(', '),
|
46
|
+
[backup.katello_online_files + backup.katello_offline_files].join(', ')
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def required_fpc_files(backup)
|
51
|
+
backup_files_message(
|
52
|
+
backup.fpc_online_files.join(', '),
|
53
|
+
backup.fpc_offline_files.join(', '),
|
54
|
+
[backup.fpc_online_files + backup.fpc_offline_files].join(', ')
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
def required_foreman_files(backup)
|
59
|
+
backup_files_message(
|
60
|
+
backup.foreman_online_files.join(', '),
|
61
|
+
backup.foreman_offline_files.join(', '),
|
62
|
+
[backup.foreman_online_files + backup.foreman_offline_files].join(', ')
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def backup_files_message(online_files, offline_files, logical_files)
|
67
|
+
message = ''
|
68
|
+
message += 'An online or remote database backup directory contains: '
|
69
|
+
message += "#{online_files}\n"
|
70
|
+
message += 'An offline backup directory contains: '
|
71
|
+
message += "#{offline_files}\n"
|
72
|
+
message += 'A logical backup directory contains: '
|
73
|
+
message += "#{logical_files}\n"
|
74
|
+
message
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'foreman_maintain/utils/backup'
|
2
|
+
|
3
|
+
module Checks::Restore
|
4
|
+
class ValidateHostname < ForemanMaintain::Check
|
5
|
+
metadata do
|
6
|
+
description 'Validate hostname is the same as backup'
|
7
|
+
|
8
|
+
param :backup_dir,
|
9
|
+
'Path to backup directory',
|
10
|
+
:required => true
|
11
|
+
manual_detection
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
msg = 'The hostname in the backup does not match the hostname of the system'
|
16
|
+
backup = ForemanMaintain::Utils::Backup.new(@backup_dir)
|
17
|
+
assert(backup.validate_hostname?, msg)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -17,6 +17,10 @@ class Features::ForemanProxy < ForemanMaintain::Feature
|
|
17
17
|
dhcp_req_pass? && !syntax_error_exists?
|
18
18
|
end
|
19
19
|
|
20
|
+
def with_content?
|
21
|
+
!!feature(:pulp)
|
22
|
+
end
|
23
|
+
|
20
24
|
def services
|
21
25
|
{
|
22
26
|
'foreman-proxy' => 20,
|
@@ -36,7 +40,8 @@ class Features::ForemanProxy < ForemanMaintain::Feature
|
|
36
40
|
def config_files(for_features = ['all'])
|
37
41
|
configs = [
|
38
42
|
'/etc/foreman-proxy',
|
39
|
-
'/usr/share/foreman-proxy/.ssh
|
43
|
+
'/usr/share/foreman-proxy/.ssh',
|
44
|
+
'/var/lib/foreman-proxy/ssh',
|
40
45
|
'/etc/smart_proxy_dynflow_core/settings.yml',
|
41
46
|
'/etc/sudoers.d/foreman-proxy'
|
42
47
|
]
|
@@ -108,7 +108,11 @@ class Features::ForemanTasks < ForemanMaintain::Feature
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def services
|
111
|
-
|
111
|
+
if check_min_version('foreman', '1.17')
|
112
|
+
{ 'dynflowd' => 30 }
|
113
|
+
else
|
114
|
+
{ 'foreman-tasks' => 30 }
|
115
|
+
end
|
112
116
|
end
|
113
117
|
|
114
118
|
private
|
@@ -29,6 +29,10 @@ class Features::Instance < ForemanMaintain::Feature
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
def database_remote?(feature)
|
33
|
+
!!feature(feature) && !feature(feature).local?
|
34
|
+
end
|
35
|
+
|
32
36
|
def database_local?(feature)
|
33
37
|
!!feature(feature) && feature(feature).local?
|
34
38
|
end
|
@@ -36,4 +40,8 @@ class Features::Instance < ForemanMaintain::Feature
|
|
36
40
|
def postgresql_local?
|
37
41
|
database_local?(:candlepin_database) || database_local?(:foreman_database)
|
38
42
|
end
|
43
|
+
|
44
|
+
def foreman_proxy_with_content?
|
45
|
+
feature(:foreman_proxy) && feature(:foreman_proxy).with_content? && !feature(:katello)
|
46
|
+
end
|
39
47
|
end
|
@@ -31,16 +31,31 @@ class Features::Mongo < ForemanMaintain::Feature
|
|
31
31
|
@configuration = load_db_config(config_file)
|
32
32
|
end
|
33
33
|
|
34
|
+
# guess mongo version from installed packages
|
35
|
+
# safe method to run mongo commands prior we know
|
36
|
+
# what version uses the target DB
|
37
|
+
def available_core
|
38
|
+
return @core unless @core.nil? # return correct mongo ver if known
|
39
|
+
if @available_core.nil?
|
40
|
+
@available_core = ForemanMaintain::Utils::MongoCoreInstalled.new
|
41
|
+
end
|
42
|
+
@available_core
|
43
|
+
end
|
44
|
+
|
34
45
|
def core
|
35
46
|
if @core.nil?
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
47
|
+
begin
|
48
|
+
version = server_version
|
49
|
+
@core = if version =~ /^3\.4/
|
50
|
+
load_mongo_core_34(version)
|
51
|
+
else
|
52
|
+
load_mongo_core_default(version)
|
53
|
+
end
|
54
|
+
rescue ForemanMaintain::Error::ExecutionError
|
55
|
+
# server version detection failed
|
56
|
+
logger.debug('Mongo version detection failed, choosing from installed versions')
|
57
|
+
@core = @available_core
|
58
|
+
end
|
44
59
|
end
|
45
60
|
@core
|
46
61
|
end
|
@@ -72,20 +87,27 @@ class Features::Mongo < ForemanMaintain::Feature
|
|
72
87
|
:hidden_patterns => [config['password']].compact)
|
73
88
|
end
|
74
89
|
|
90
|
+
def restore(dir, config = configuration)
|
91
|
+
cmd = base_command(core.restore_command, config,
|
92
|
+
"-d #{config['name']} #{File.join(dir, config['name'])}")
|
93
|
+
execute!(cmd, :hidden_patterns => [config['password']].compact)
|
94
|
+
end
|
95
|
+
|
75
96
|
def dropdb(config = configuration)
|
76
97
|
execute!(mongo_command("--eval 'db.dropDatabase()'", config),
|
77
98
|
:hidden_patterns => [config['password']].compact)
|
78
99
|
end
|
79
100
|
|
80
101
|
def ping(config = configuration)
|
81
|
-
execute?(mongo_command("--eval 'ping:1'"),
|
102
|
+
execute?(mongo_command("--eval 'ping:1'", config),
|
82
103
|
:hidden_patterns => [config['password']].compact)
|
83
104
|
end
|
84
105
|
|
85
106
|
def server_version(config = configuration)
|
86
107
|
# do not use any core methods as we need this prior the core is created
|
87
|
-
|
88
|
-
|
108
|
+
mongo_cmd = base_command(available_core.client_command, config,
|
109
|
+
"--eval 'db.version()' #{config['name']}")
|
110
|
+
version = execute!(mongo_cmd, :hidden_patterns => [config['password']].compact)
|
89
111
|
version.split("\n").last
|
90
112
|
end
|
91
113
|
|
@@ -98,7 +120,8 @@ class Features::Mongo < ForemanMaintain::Feature
|
|
98
120
|
:archive => backup_file,
|
99
121
|
:command => 'create',
|
100
122
|
:exclude => ['mongod.lock'],
|
101
|
-
:transform => 's,^,var/lib/mongodb/,S'
|
123
|
+
:transform => 's,^,var/lib/mongodb/,S',
|
124
|
+
:files => '*'
|
102
125
|
}.merge(extra_tar_options)
|
103
126
|
feature(:tar).run(tar_options)
|
104
127
|
end
|
@@ -110,6 +133,22 @@ class Features::Mongo < ForemanMaintain::Feature
|
|
110
133
|
|
111
134
|
private
|
112
135
|
|
136
|
+
def load_mongo_core_default(version)
|
137
|
+
unless find_package('mongodb')
|
138
|
+
raise ForemanMaintain::Error::Fail, 'Mongo client was not found'
|
139
|
+
end
|
140
|
+
logger.debug("Mongo #{version} detected, using default commands")
|
141
|
+
ForemanMaintain::Utils::MongoCore.new
|
142
|
+
end
|
143
|
+
|
144
|
+
def load_mongo_core_34(version)
|
145
|
+
unless find_package('rh-mongodb34-mongodb')
|
146
|
+
raise ForemanMaintain::Error::Fail, 'Mongo client ver. 3.4 was not found'
|
147
|
+
end
|
148
|
+
logger.debug("Mongo #{version} detected, using commands from rh-mongodb34 SCL")
|
149
|
+
ForemanMaintain::Utils::MongoCore34.new
|
150
|
+
end
|
151
|
+
|
113
152
|
def norm_value(value)
|
114
153
|
value = value.strip
|
115
154
|
case value
|
@@ -66,6 +66,42 @@ class Features::Service < ForemanMaintain::Feature
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def perform_action_on_service(action, service)
|
69
|
+
if service == 'postgresql'
|
70
|
+
if feature(:instance).postgresql_local?
|
71
|
+
perform_action_on_local_service(action, service)
|
72
|
+
end
|
73
|
+
if feature(:instance).database_remote?(:candlepin_database)
|
74
|
+
remote_db_message('Candlepin', :candlepin_database, action)
|
75
|
+
end
|
76
|
+
if feature(:instance).database_remote?(:foreman_database)
|
77
|
+
remote_db_message('Foreman', :foreman_database, action)
|
78
|
+
end
|
79
|
+
elsif service =~ /^.*mongod$/ && feature(:instance).database_remote?(:mongo)
|
80
|
+
remote_db_message('Pulp', :mongo, action)
|
81
|
+
else
|
82
|
+
perform_action_on_local_service(action, service)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def remote_db_message(app, db, action)
|
87
|
+
ping = !!feature(db).ping
|
88
|
+
message = if %w[enable disable].include?(action)
|
89
|
+
" - #{app} DB is remote. Can not #{action} the service."
|
90
|
+
else
|
91
|
+
'the service is on remote host. The DB is ' + (ping ? 'UP.' : 'DOWN.')
|
92
|
+
end
|
93
|
+
if action == 'status'
|
94
|
+
puts "\nFor #{app} DB #{message}\n"
|
95
|
+
else
|
96
|
+
print " - #{message}"
|
97
|
+
end
|
98
|
+
logger.info(message)
|
99
|
+
if action == 'start' && !ping
|
100
|
+
raise ForemanMaintain::Error::Fail, "The remote #{app} databse is down."
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def perform_action_on_local_service(action, service)
|
69
105
|
command = service_command(action, service)
|
70
106
|
if action == 'status'
|
71
107
|
status = execute(command)
|
data/definitions/features/tar.rb
CHANGED
@@ -14,7 +14,11 @@ class Features::Tar < ForemanMaintain::Feature
|
|
14
14
|
# @option options [String] :volume_size size of tar volume
|
15
15
|
# (will try to split the archive when set)
|
16
16
|
# @option options [String] :files (*) files to operate on
|
17
|
-
#
|
17
|
+
# @option options [String] :directory change to directory DIR
|
18
|
+
# @option options [Boolean] :multi_volume create/list/extract multi-volume archive
|
19
|
+
# @option options [Boolean] :overwrite overwrite existing files when extracting
|
20
|
+
# @option options [Boolean] :gzip filter the archive through gzip
|
21
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
18
22
|
def run(options = {})
|
19
23
|
volume_size = options.fetch(:volume_size, nil)
|
20
24
|
validate_volume_size(volume_size) unless volume_size.nil?
|
@@ -30,6 +34,9 @@ class Features::Tar < ForemanMaintain::Feature
|
|
30
34
|
tar_command << "--new-volume-script=#{split_tar_script}"
|
31
35
|
end
|
32
36
|
|
37
|
+
tar_command << '--overwrite' if options[:overwrite]
|
38
|
+
tar_command << '--gzip' if options[:gzip]
|
39
|
+
|
33
40
|
exclude = options.fetch(:exclude, [])
|
34
41
|
exclude.each do |ex|
|
35
42
|
tar_command << "--exclude=#{ex}"
|
@@ -41,12 +48,17 @@ class Features::Tar < ForemanMaintain::Feature
|
|
41
48
|
trans = options.fetch(:transform, nil)
|
42
49
|
tar_command << "--transform '#{trans}'" if trans
|
43
50
|
|
44
|
-
tar_command << '-
|
45
|
-
tar_command << options
|
51
|
+
tar_command << '-M' if options[:multi_volume]
|
52
|
+
tar_command << "--directory=#{options[:directory]}" if options[:directory]
|
53
|
+
|
54
|
+
if options[:files]
|
55
|
+
tar_command << '-S'
|
56
|
+
tar_command << options.fetch(:files, '*')
|
57
|
+
end
|
46
58
|
|
47
59
|
execute!(tar_command.join(' '))
|
48
60
|
end
|
49
|
-
# rubocop:enable Metrics/
|
61
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
50
62
|
|
51
63
|
def validate_volume_size(size)
|
52
64
|
if size.nil? || size !~ /^\d+[bBcGKkMPTw]?$/
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Procedures::Backup
|
2
2
|
module Online
|
3
3
|
class PgGlobalObjects < ForemanMaintain::Procedure
|
4
|
+
include ForemanMaintain::Concerns::SystemHelpers
|
5
|
+
|
4
6
|
metadata do
|
5
7
|
description 'Backup Postgres global objects online'
|
6
8
|
tags :backup
|
@@ -11,7 +13,7 @@ module Procedures::Backup
|
|
11
13
|
end
|
12
14
|
|
13
15
|
def run
|
14
|
-
if feature(:
|
16
|
+
if feature(:instance).postgresql_local?
|
15
17
|
local_db = feature(:foreman_database).local? ? :foreman_database : :candlepin_database
|
16
18
|
feature(local_db).backup_global_objects(File.join(@backup_dir, 'pg_globals.dump'))
|
17
19
|
else
|
@@ -33,7 +33,8 @@ module Procedures::Backup
|
|
33
33
|
:exclude => ['var/lib/pulp/katello-export'],
|
34
34
|
:listed_incremental => File.join(@backup_dir, '.pulp.snar'),
|
35
35
|
:transform => 's,^,var/lib/pulp/,S',
|
36
|
-
:volume_size => @tar_volume_size
|
36
|
+
:volume_size => @tar_volume_size,
|
37
|
+
:files => '*'
|
37
38
|
)
|
38
39
|
end
|
39
40
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Procedures::Pulp
|
2
|
+
class Migrate < ForemanMaintain::Procedure
|
3
|
+
metadata do
|
4
|
+
description 'Migrate pulp db'
|
5
|
+
for_feature :pulp
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
with_spinner('Migrating pulp') do |spinner|
|
10
|
+
necessary_services = feature(:mongo).services.keys + ['qpidd']
|
11
|
+
pulp_services = %w[pulp_celerybeat pulp_workers pulp_resource_manager]
|
12
|
+
|
13
|
+
feature(:service).handle_services(spinner, 'start', :only => necessary_services)
|
14
|
+
feature(:service).handle_services(spinner, 'stop', :only => pulp_services)
|
15
|
+
|
16
|
+
spinner.update('Migrating pulp database')
|
17
|
+
execute!('su - apache -s /bin/bash -c pulp-manage-db')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|