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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/bin/foreman-maintain +2 -1
  3. data/definitions/checks/backup/directory_ready.rb +1 -1
  4. data/definitions/checks/restore/validate_backup.rb +77 -0
  5. data/definitions/checks/restore/validate_hostname.rb +20 -0
  6. data/definitions/features/foreman_proxy.rb +6 -1
  7. data/definitions/features/foreman_tasks.rb +5 -1
  8. data/definitions/features/instance.rb +8 -0
  9. data/definitions/features/katello.rb +0 -1
  10. data/definitions/features/mongo.rb +51 -12
  11. data/definitions/features/pulp.rb +2 -1
  12. data/definitions/features/service.rb +36 -0
  13. data/definitions/features/tar.rb +16 -4
  14. data/definitions/procedures/backup/online/pg_global_objects.rb +3 -1
  15. data/definitions/procedures/backup/prepare_directory.rb +1 -1
  16. data/definitions/procedures/backup/pulp.rb +2 -1
  17. data/definitions/procedures/pulp/migrate.rb +21 -0
  18. data/definitions/procedures/restore/candlepin_dump.rb +30 -0
  19. data/definitions/procedures/restore/configs.rb +40 -0
  20. data/definitions/procedures/restore/confirmation.rb +17 -0
  21. data/definitions/procedures/restore/drop_databases.rb +39 -0
  22. data/definitions/procedures/restore/extract_files.rb +70 -0
  23. data/definitions/procedures/restore/foreman_dump.rb +30 -0
  24. data/definitions/procedures/restore/installer_reset.rb +39 -0
  25. data/definitions/procedures/restore/mongo_dump.rb +41 -0
  26. data/definitions/procedures/restore/pg_global_objects.rb +36 -0
  27. data/definitions/procedures/restore/postgres_owner.rb +18 -0
  28. data/definitions/procedures/selinux/set_file_security.rb +22 -0
  29. data/definitions/procedures/service/daemon_reload.rb +18 -0
  30. data/definitions/procedures/service/restart.rb +2 -2
  31. data/definitions/scenarios/restore.rb +91 -0
  32. data/lib/foreman_maintain/cli.rb +3 -1
  33. data/lib/foreman_maintain/cli/restore_command.rb +26 -0
  34. data/lib/foreman_maintain/concerns/base_database.rb +35 -1
  35. data/lib/foreman_maintain/concerns/system_helpers.rb +1 -5
  36. data/lib/foreman_maintain/reporter/cli_reporter.rb +2 -1
  37. data/lib/foreman_maintain/utils/backup.rb +225 -0
  38. data/lib/foreman_maintain/utils/command_runner.rb +4 -2
  39. data/lib/foreman_maintain/utils/mongo_core.rb +49 -0
  40. data/lib/foreman_maintain/version.rb +1 -1
  41. metadata +20 -2
@@ -0,0 +1,30 @@
1
+ module Procedures::Restore
2
+ class CandlepinDump < ForemanMaintain::Procedure
3
+ metadata do
4
+ description 'Restore candlepin postgresql dump from backup'
5
+ param :backup_dir,
6
+ 'Path to backup directory',
7
+ :required => true
8
+ preparation_steps { Checks::Candlepin::DBUp.new }
9
+ confine do
10
+ feature(:candlepin_database)
11
+ end
12
+ end
13
+
14
+ def run
15
+ backup = ForemanMaintain::Utils::Backup.new(@backup_dir)
16
+
17
+ with_spinner('Restoring candlepin postgresql dump') do |spinner|
18
+ restore_candlepin_dump(backup, spinner)
19
+ end
20
+ end
21
+
22
+ def restore_candlepin_dump(backup, spinner)
23
+ if backup.file_map[:candlepin_dump][:present]
24
+ spinner.update('Restoring candlepin dump')
25
+ local = feature(:candlepin_database).local?
26
+ feature(:candlepin_database).restore_dump(backup.file_map[:candlepin_dump][:path], local)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,40 @@
1
+ module Procedures::Restore
2
+ class Configs < ForemanMaintain::Procedure
3
+ metadata do
4
+ description 'Restore configs from backup'
5
+
6
+ param :backup_dir,
7
+ 'Path to backup directory',
8
+ :required => true
9
+ end
10
+
11
+ def run
12
+ backup = ForemanMaintain::Utils::Backup.new(@backup_dir)
13
+ with_spinner('Resetting') do |spinner|
14
+ spinner.update('Restoring configs')
15
+ clean_conflicting_data
16
+ restore_configs(backup)
17
+ end
18
+ end
19
+
20
+ def restore_configs(backup)
21
+ tar_options = {
22
+ :overwrite => true,
23
+ :listed_incremental => '/dev/null',
24
+ :command => 'extract',
25
+ :directory => '/',
26
+ :archive => backup.file_map[:config_files][:path],
27
+ :gzip => true
28
+ }
29
+
30
+ feature(:tar).run(tar_options)
31
+ end
32
+
33
+ private
34
+
35
+ def clean_conflicting_data
36
+ # tar is unable to --overwrite dir with symlink
37
+ execute('rm -rf /usr/share/foreman-proxy/.ssh')
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,17 @@
1
+ module Procedures::Restore
2
+ class Confirmation < ForemanMaintain::Procedure
3
+ metadata do
4
+ description 'Confirm dropping databases and running restore'
5
+ tags :restore
6
+ end
7
+
8
+ def run
9
+ warning = "\nWARNING: This script will drop and restore your database.\n" \
10
+ "Your existing installation will be replaced with the backup database.\n" \
11
+ "Once this operation is complete there is no going back.\n" \
12
+ 'Do you want to proceed?'
13
+ answer = ask_decision(warning, 'y(yes), q(quit)')
14
+ abort! unless answer == :yes
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,39 @@
1
+ module Procedures::Restore
2
+ class DropDatabases < ForemanMaintain::Procedure
3
+ metadata do
4
+ description 'Drop postgresql databases'
5
+
6
+ param :backup_dir,
7
+ 'Path to backup directory',
8
+ :required => true
9
+
10
+ confine do
11
+ feature(:foreman_database) || feature(:candlepin_database)
12
+ end
13
+ end
14
+
15
+ def run
16
+ backup = ForemanMaintain::Utils::Backup.new(@backup_dir)
17
+
18
+ with_spinner('Dropping databases') do |spinner|
19
+ feature(:service).handle_services(spinner, 'start', :only => ['postgresql'])
20
+ drop_foreman(backup, spinner)
21
+ drop_candlepin(backup, spinner)
22
+ end
23
+ end
24
+
25
+ def drop_foreman(backup, spinner)
26
+ if backup.file_map[:foreman_dump][:present]
27
+ spinner.update('Dropping foreman database')
28
+ feature(:foreman_database).dropdb
29
+ end
30
+ end
31
+
32
+ def drop_candlepin(backup, spinner)
33
+ if backup.file_map[:candlepin_dump][:present]
34
+ spinner.update('Dropping candlepin database')
35
+ feature(:candlepin_database).dropdb
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,70 @@
1
+ module Procedures::Restore
2
+ class ExtractFiles < ForemanMaintain::Procedure
3
+ metadata do
4
+ description 'Extract any existing tar files in backup'
5
+
6
+ param :backup_dir,
7
+ 'Path to backup directory',
8
+ :required => true
9
+ end
10
+
11
+ def run
12
+ backup = ForemanMaintain::Utils::Backup.new(@backup_dir)
13
+ with_spinner('Extracting Files') do |spinner|
14
+ if backup.file_map[:pulp_data][:present]
15
+ spinner.update('Extracting pulp data')
16
+ extract_pulp_data(backup)
17
+ end
18
+ if backup.file_map[:mongo_data][:present]
19
+ spinner.update('Extracting mongo data')
20
+ extract_mongo_data(backup)
21
+ end
22
+ if backup.file_map[:pgsql_data][:present]
23
+ spinner.update('Extracting pgsql data')
24
+ extract_pgsql_data(backup)
25
+ end
26
+ end
27
+ end
28
+
29
+ def base_tar
30
+ {
31
+ :overwrite => true,
32
+ :listed_incremental => '/dev/null',
33
+ :command => 'extract',
34
+ :directory => '/'
35
+ }
36
+ end
37
+
38
+ def extract_pulp_data(backup)
39
+ pulp_data_tar = if backup.pulp_tar_split?
40
+ base_tar.merge(
41
+ :multi_volume => true,
42
+ :split_data => true,
43
+ :archive => backup.file_map[:pulp_data][:path]
44
+ )
45
+ else
46
+ base_tar.merge(
47
+ :archive => backup.file_map[:pulp_data][:path]
48
+ )
49
+ end
50
+
51
+ feature(:tar).run(pulp_data_tar)
52
+ end
53
+
54
+ def extract_mongo_data(backup)
55
+ mongo_data_tar = base_tar.merge(
56
+ :archive => backup.file_map[:mongo_data][:path],
57
+ :gzip => true
58
+ )
59
+ feature(:tar).run(mongo_data_tar)
60
+ end
61
+
62
+ def extract_pgsql_data(backup)
63
+ pgsql_data_tar = base_tar.merge(
64
+ :archive => backup.file_map[:pgsql_data][:path],
65
+ :gzip => true
66
+ )
67
+ feature(:tar).run(pgsql_data_tar)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,30 @@
1
+ module Procedures::Restore
2
+ class ForemanDump < ForemanMaintain::Procedure
3
+ metadata do
4
+ description 'Restore foreman postgresql dump from backup'
5
+ param :backup_dir,
6
+ 'Path to backup directory',
7
+ :required => true
8
+ preparation_steps { Checks::Foreman::DBUp.new }
9
+ confine do
10
+ feature(:foreman_database)
11
+ end
12
+ end
13
+
14
+ def run
15
+ backup = ForemanMaintain::Utils::Backup.new(@backup_dir)
16
+
17
+ with_spinner('Restoring foreman postgresql dump') do |spinner|
18
+ restore_foreman_dump(backup, spinner)
19
+ end
20
+ end
21
+
22
+ def restore_foreman_dump(backup, spinner)
23
+ if backup.file_map[:foreman_dump][:present]
24
+ spinner.update('Restoring foreman dump')
25
+ local = feature(:foreman_database).local?
26
+ feature(:foreman_database).restore_dump(backup.file_map[:foreman_dump][:path], local)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,39 @@
1
+ module Procedures::Restore
2
+ class InstallerReset < ForemanMaintain::Procedure
3
+ metadata do
4
+ description 'Run installer reset'
5
+
6
+ param :incremental_backup,
7
+ 'Is the backup incremental?'
8
+ end
9
+
10
+ def run
11
+ with_spinner('Resetting') do |spinner|
12
+ if @incremental_backup
13
+ spinner.update('Skipping installer reset for incremental update')
14
+ else
15
+ spinner.update('Installer reset')
16
+ execute!(installer_cmd)
17
+ end
18
+ end
19
+ end
20
+
21
+ def installer_cmd
22
+ installer = "yes | #{feature(:installer).installer_command} "
23
+ installer << '-v --reset '
24
+ if feature(:instance).foreman_proxy_with_content?
25
+ installer << '--foreman-proxy-register-in-foreman false '
26
+ end
27
+
28
+ # We always disable system checks to avoid unnecessary errors. The installer should have
29
+ # already ran since this is to be run on an existing system, which means installer checks
30
+ # has already been skipped
31
+ if feature(:foreman_proxy) &&
32
+ feature(:foreman_proxy).with_content? &&
33
+ check_min_version('katello-installer-base', '3.2.0')
34
+ installer << '--disable-system-checks '
35
+ end
36
+ installer
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,41 @@
1
+ module Procedures::Restore
2
+ class MongoDump < ForemanMaintain::Procedure
3
+ metadata do
4
+ description 'Restore mongo dump'
5
+ for_feature :pulp
6
+ param :backup_dir,
7
+ 'Path to backup directory',
8
+ :required => true
9
+ preparation_steps do
10
+ [Checks::Mongo::DBUp.new, Checks::Mongo::ToolsInstalled.new]
11
+ end
12
+ confine do
13
+ feature(:mongo) && feature(:pulp)
14
+ end
15
+ end
16
+
17
+ def run
18
+ backup = ForemanMaintain::Utils::Backup.new(@backup_dir)
19
+ with_spinner('Restoring mongo dump') do |spinner|
20
+ handle_mongo_service('start', spinner)
21
+ drop_and_restore_mongo(backup, spinner)
22
+ handle_mongo_service('stop', spinner)
23
+ end
24
+ end
25
+
26
+ def handle_mongo_service(action, spinner)
27
+ if feature(:instance).database_local?(:mongo)
28
+ feature(:service).handle_services(spinner, action,
29
+ :only => feature(:mongo).services.keys)
30
+ end
31
+ end
32
+
33
+ def drop_and_restore_mongo(backup, spinner)
34
+ spinner.update('Dropping pulp_database')
35
+ feature(:mongo).dropdb
36
+
37
+ spinner.update('Restoring mongo dump')
38
+ feature(:mongo).restore(backup.file_map[:mongo_dump][:path])
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,36 @@
1
+ module Procedures::Restore
2
+ class PgGlobalObjects < ForemanMaintain::Procedure
3
+ include ForemanMaintain::Concerns::SystemHelpers
4
+
5
+ metadata do
6
+ description 'Restore any existing postgresql global objects from backup'
7
+
8
+ param :backup_dir,
9
+ 'Path to backup directory',
10
+ :required => true
11
+
12
+ confine do
13
+ feature(:foreman_database) || feature(:candlepin_database)
14
+ end
15
+ end
16
+
17
+ def run
18
+ backup = ForemanMaintain::Utils::Backup.new(@backup_dir)
19
+ restore_global_objects(backup.file_map[:pg_globals][:path])
20
+ end
21
+
22
+ def restore_global_objects(pg_global_file)
23
+ if feature(:instance).postgresql_local?
24
+ with_spinner('') do |spinner|
25
+ feature(:service).handle_services(spinner, 'start', :only => ['postgresql'])
26
+
27
+ spinner.update('Restoring postgresql global objects')
28
+ local_db = feature(:foreman_database).local? ? :foreman_database : :candlepin_database
29
+ feature(local_db).restore_pg_globals(pg_global_file)
30
+ end
31
+ else
32
+ skip 'Restore of global objects is not supported for remote databases.'
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,18 @@
1
+ module Procedures::Restore
2
+ class PostgresOwner < ForemanMaintain::Procedure
3
+ include ForemanMaintain::Concerns::SystemHelpers
4
+ metadata do
5
+ description 'Make postgres owner of backup directory'
6
+
7
+ param :backup_dir,
8
+ 'Path to backup directory',
9
+ :required => true
10
+ end
11
+
12
+ def run
13
+ if feature(:instance).foreman_proxy_with_content?
14
+ FileUtils.chown(nil, 'postgres', @backup_dir)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ module Procedures::Selinux
2
+ class SetFileSecurity < ForemanMaintain::Procedure
3
+ metadata do
4
+ description 'Setting file security'
5
+
6
+ param :incremental_backup,
7
+ 'Is the backup incremental?',
8
+ :required => true
9
+ manual_detection
10
+ end
11
+
12
+ def run
13
+ with_spinner('Restoring SELinux context') do |spinner|
14
+ if @incremental_backup
15
+ spinner.update('Skipping for incremental update')
16
+ else
17
+ execute!('restorecon -Rn /')
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ module Procedures::Service
2
+ class DaemonReload < ForemanMaintain::Procedure
3
+ include ForemanMaintain::Concerns::SystemHelpers
4
+ metadata do
5
+ description 'Run daemon reload'
6
+
7
+ confine do
8
+ systemd_installed?
9
+ end
10
+ end
11
+
12
+ def run
13
+ unless feature(:instance).foreman_proxy_with_content?
14
+ execute!('systemctl daemon-reload')
15
+ end
16
+ end
17
+ end
18
+ end
@@ -28,11 +28,11 @@ module Procedures::Service
28
28
  break
29
29
  elsif retry_count < (RETRIES_FOR_SERVICES_RESTART - 1)
30
30
  apply_sleep_before_retry(spinner, result)
31
+ else
32
+ raise 'Hammer ping failed!'
31
33
  end
32
34
  end
33
35
  end
34
- rescue StandardError => e
35
- logger.error e.message
36
36
  end
37
37
 
38
38
  def retry_message(retry_count)
@@ -0,0 +1,91 @@
1
+ require 'foreman_maintain/utils/backup'
2
+
3
+ module ForemanMaintain::Scenarios
4
+ class Restore < ForemanMaintain::Scenario
5
+ metadata do
6
+ description 'Restore backup'
7
+ param :backup_dir, 'Path to backup directory'
8
+ param :incremental_backup, 'Is the backup incremental?'
9
+ manual_detection
10
+ end
11
+
12
+ # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
13
+ def compose
14
+ backup = ForemanMaintain::Utils::Backup.new(context.get(:backup_dir))
15
+
16
+ add_steps(find_checks(:root_user))
17
+ supported_version_check
18
+ add_steps_with_context(Checks::Restore::ValidateBackup,
19
+ Procedures::Restore::Confirmation,
20
+ Checks::Restore::ValidateHostname,
21
+ Procedures::Selinux::SetFileSecurity,
22
+ Procedures::Restore::Configs,
23
+ Procedures::Restore::InstallerReset,
24
+ Procedures::Service::Stop)
25
+ add_steps_with_context(Procedures::Restore::ExtractFiles) if backup.tar_backups_exist?
26
+ drop_dbs(backup)
27
+ if backup.sql_dump_files_exist? && feature(:instance).postgresql_local?
28
+ add_step(Procedures::Service::Start.new(:only => ['postgresql']))
29
+ end
30
+ restore_sql_dumps(backup)
31
+ if backup.sql_dump_files_exist? && feature(:instance).postgresql_local?
32
+ add_step(Procedures::Service::Stop.new(:only => ['postgresql']))
33
+ end
34
+ restore_mongo_dump(backup)
35
+ add_steps_with_context(Procedures::Pulp::Migrate,
36
+ Procedures::Service::Start,
37
+ Procedures::Service::DaemonReload)
38
+ end
39
+ # rubocop:enable Metrics/MethodLength,Metrics/AbcSize
40
+
41
+ def drop_dbs(backup)
42
+ if backup.file_map[:candlepin_dump][:present] ||
43
+ backup.file_map[:foreman_dump][:present]
44
+ add_steps_with_context(Procedures::Restore::DropDatabases)
45
+ end
46
+ end
47
+
48
+ def restore_sql_dumps(backup)
49
+ if backup.file_map[:pg_globals][:present]
50
+ add_steps_with_context(Procedures::Restore::PgGlobalObjects)
51
+ end
52
+ if backup.file_map[:candlepin_dump][:present]
53
+ add_steps_with_context(Procedures::Restore::CandlepinDump)
54
+ end
55
+ if backup.file_map[:foreman_dump][:present]
56
+ add_steps_with_context(Procedures::Restore::ForemanDump)
57
+ end
58
+ end
59
+
60
+ def restore_mongo_dump(backup)
61
+ if backup.file_map[:mongo_dump][:present]
62
+ add_steps_with_context(Procedures::Restore::MongoDump)
63
+ end
64
+ end
65
+
66
+ def supported_version_check
67
+ if feature(:downstream) && feature(:downstream).less_than_version?('6.3')
68
+ msg = 'ERROR: Restore subcommand is supported by Satellite 6.3+. ' \
69
+ 'Please use katello-restore instead.'
70
+ abort(msg)
71
+ end
72
+ end
73
+
74
+ def set_context_mapping
75
+ context.map(:backup_dir,
76
+ Checks::Restore::ValidateBackup => :backup_dir,
77
+ Checks::Restore::ValidateHostname => :backup_dir,
78
+ Procedures::Restore::Configs => :backup_dir,
79
+ Procedures::Restore::DropDatabases => :backup_dir,
80
+ Procedures::Restore::PgGlobalObjects => :backup_dir,
81
+ Procedures::Restore::CandlepinDump => :backup_dir,
82
+ Procedures::Restore::ForemanDump => :backup_dir,
83
+ Procedures::Restore::ExtractFiles => :backup_dir,
84
+ Procedures::Restore::MongoDump => :backup_dir)
85
+
86
+ context.map(:incremental_backup,
87
+ Procedures::Selinux::SetFileSecurity => :incremental_backup,
88
+ Procedures::Restore::InstallerReset => :incremental_backup)
89
+ end
90
+ end
91
+ end