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