diff --git a/setup.cfg b/setup.cfg index 71c40729e..01b75b6bd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -52,6 +52,7 @@ openstack.tripleoclient.v1 = tripleo_deploy = tripleoclient.v1.tripleo_deploy:Deploy tripleo_upgrade = tripleoclient.v1.tripleo_upgrade:Upgrade overcloud_admin_authorize = tripleoclient.v1.overcloud_admin:Authorize + overcloud_backup = tripleoclient.v1.overcloud_backup:BackupOvercloud overcloud_netenv_validate = tripleoclient.v1.overcloud_netenv_validate:ValidateOvercloudNetenv overcloud_cell_export = tripleoclient.v1.overcloud_cell:ExportCell overcloud_config_download = tripleoclient.v1.overcloud_config:DownloadConfig diff --git a/tripleoclient/tests/v1/overcloud_backup/__init__.py b/tripleoclient/tests/v1/overcloud_backup/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tripleoclient/tests/v1/overcloud_backup/test_backup.py b/tripleoclient/tests/v1/overcloud_backup/test_backup.py new file mode 100644 index 000000000..d08b68992 --- /dev/null +++ b/tripleoclient/tests/v1/overcloud_backup/test_backup.py @@ -0,0 +1,254 @@ +# Copyright 2018 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock + +from osc_lib.tests import utils + +from tripleoclient import constants +# from tripleoclient.tests import fakes +from tripleoclient.v1 import overcloud_backup +from unittest.mock import call + + +class TestOvercloudBackup(utils.TestCommand): + + def setUp(self): + super(TestOvercloudBackup, self).setUp() + + # Get the command object to test + app_args = mock.Mock() + app_args.verbose_level = 1 + self.cmd = overcloud_backup.BackupOvercloud(self.app, app_args) + self.app.client_manager.workflow_engine = mock.Mock() + self.workflow = self.app.client_manager.workflow_engine + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_overcloud_backup_noargs(self, mock_playbook): + arglist = [] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='cli-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_create_recover_image', + skip_tags=None, + verbosity=1, + extra_vars={} + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_overcloud_backup_init(self, mock_playbook): + arglist = [ + '--init' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_rear', + skip_tags=None, + verbosity=1, + extra_vars={} + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_overcloud_backup_init_nfs(self, mock_playbook): + arglist = [ + '--init', + 'nfs' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-nfs-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_nfs_server', + skip_tags=None, + verbosity=1, + extra_vars={} + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_overcloud_backup_setup_nfs(self, mock_playbook): + arglist = [ + '--setup-nfs' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-nfs-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_nfs_server', + skip_tags=None, + verbosity=1, + extra_vars={} + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_overcloud_backup_setup_rear(self, mock_playbook): + arglist = [ + '--setup-rear', + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_rear', + skip_tags=None, + verbosity=1, + extra_vars={} + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', autospec=True) + def test_overcloud_backup_setup_nfs_rear_with_inventory(self, + mock_playbook): + arglist = [ + '--setup-nfs', + '--setup-rear', + '--inventory', + '/tmp/test_inventory.yaml' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + calls = [call(logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-nfs-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_nfs_server', + skip_tags=None, + verbosity=1, + extra_vars={}), + call(logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_rear', + skip_tags=None, + verbosity=1, + extra_vars={})] + + mock_playbook.assert_has_calls(calls) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_overcloud_backup_setup_rear_extra_vars_inline(self, + mock_playbook): + arglist = [ + '--setup-rear', + '--extra-vars', + '{"tripleo_backup_and_restore_nfs_server": "192.168.24.1"}' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + extra_vars_dict = { + 'tripleo_backup_and_restore_nfs_server': '192.168.24.1' + } + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_rear', + skip_tags=None, + verbosity=1, + extra_vars=extra_vars_dict + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_overcloud_backup_setup_rear_with_extra_vars(self, mock_playbook): + arglist = [ + '--setup-rear', + '--extra-vars', + '/tmp/test_vars.yaml' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_rear', + skip_tags=None, + verbosity=1, + extra_vars='/tmp/test_vars.yaml' + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_overcloud_backup_inventory(self, mock_playbook): + arglist = [ + '--inventory', + '/tmp/test_inventory.yaml' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='cli-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_create_recover_image', + skip_tags=None, + verbosity=1, + extra_vars={} + ) diff --git a/tripleoclient/tests/v1/undercloud/test_backup.py b/tripleoclient/tests/v1/undercloud/test_backup.py index d55b4dbd9..e6f556202 100644 --- a/tripleoclient/tests/v1/undercloud/test_backup.py +++ b/tripleoclient/tests/v1/undercloud/test_backup.py @@ -16,7 +16,10 @@ import mock from osc_lib.tests import utils + +from tripleoclient import constants from tripleoclient.v1 import undercloud_backup +from unittest.mock import call class TestUndercloudBackup(utils.TestCommand): @@ -25,22 +28,12 @@ class TestUndercloudBackup(utils.TestCommand): super(TestUndercloudBackup, self).setUp() # Get the command object to test - self.cmd = undercloud_backup.BackupUndercloud(self.app, None) + app_args = mock.Mock() + app_args.verbose_level = 1 + self.cmd = undercloud_backup.BackupUndercloud(self.app, app_args) self.app.client_manager.workflow_engine = mock.Mock() self.workflow = self.app.client_manager.workflow_engine - @mock.patch('tripleoclient.workflows.undercloud_backup.backup', - autospec=True) - def test_undercloud_backup_noargs(self, plan_mock): - arglist = [] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - plan_mock.assert_called_once_with( - mock.ANY, {'sources_path': '/home/stack/'}) - @mock.patch('tripleoclient.workflows.undercloud_backup.backup', autospec=True) def test_undercloud_backup_withargs(self, plan_mock): @@ -120,3 +113,221 @@ class TestUndercloudBackup(utils.TestCommand): plan_mock.assert_called_once_with( mock.ANY, {'sources_path': '/home/stack/,/tmp/foo.yaml'}) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_undercloud_backup_noargs(self, mock_playbook): + arglist = [] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='cli-undercloud-backup.yaml', + inventory=mock.ANY, + tags='bar_create_recover_image', + skip_tags=None, + verbosity=1, + extra_vars=None + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_undercloud_backup_init(self, mock_playbook): + arglist = [ + '--init' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-undercloud-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_rear', + skip_tags=None, + verbosity=1, + extra_vars=None + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_undercloud_backup_init_nfs(self, mock_playbook): + arglist = [ + '--init', + 'nfs' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-nfs-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_nfs_server', + skip_tags=None, + verbosity=1, + extra_vars=None + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_undercloud_backup_setup_nfs(self, mock_playbook): + arglist = [ + '--setup-nfs' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-nfs-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_nfs_server', + skip_tags=None, + verbosity=1, + extra_vars=None + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_undercloud_backup_setup_rear(self, mock_playbook): + arglist = [ + '--setup-rear' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-undercloud-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_rear', + skip_tags=None, + verbosity=1, + extra_vars=None + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_undercloud_backup_setup_rear_extra_vars_inline(self, + mock_playbook): + arglist = [ + '--setup-rear', + '--extra-vars', + '{"tripleo_backup_and_restore_nfs_server": "192.168.24.1"}' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + extra_vars_dict = { + 'tripleo_backup_and_restore_nfs_server': '192.168.24.1' + } + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-undercloud-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_rear', + skip_tags=None, + verbosity=1, + extra_vars=extra_vars_dict + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', autospec=True) + def test_undercloud_backup_setup_nfs_rear_with_inventory(self, + mock_playbook): + arglist = [ + '--setup-nfs', + '--setup-rear', + '--inventory', + '/tmp/test_inventory.yaml' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + calls = [call(logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-nfs-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_nfs_server', + skip_tags=None, + verbosity=1, + extra_vars=None), + call(logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-undercloud-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_rear', + skip_tags=None, + verbosity=1, + extra_vars=None)] + + mock_playbook.assert_has_calls(calls) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_undercloud_backup_setup_nfs_with_extra_vars(self, mock_playbook): + arglist = [ + '--setup-nfs', + '--extra-vars', + '/tmp/test_vars.yaml' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='prepare-nfs-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_nfs_server', + skip_tags=None, + verbosity=1, + extra_vars='/tmp/test_vars.yaml' + ) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_undercloud_backup_inventory(self, mock_playbook): + arglist = [ + '--inventory', + '/tmp/test_inventory.yaml' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + logger=mock.ANY, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + playbook='cli-undercloud-backup.yaml', + inventory=mock.ANY, + tags='bar_create_recover_image', + skip_tags=None, + verbosity=1, + extra_vars=None + ) diff --git a/tripleoclient/v1/overcloud_backup.py b/tripleoclient/v1/overcloud_backup.py new file mode 100644 index 000000000..2e5518cee --- /dev/null +++ b/tripleoclient/v1/overcloud_backup.py @@ -0,0 +1,214 @@ +# Copyright 2020 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import argparse +import logging +import os +import yaml + +from osc_lib.command import command +from osc_lib.i18n import _ + +from tripleoclient import constants +from tripleoclient import utils + +LOG = logging.getLogger(__name__ + ".BackupOvercloud") + + +class BackupOvercloud(command.Command): + """Backup the Overcloud""" + + def get_parser(self, prog_name): + parser = argparse.ArgumentParser( + description=self.get_description(), + prog=prog_name, + add_help=False + ) + + parser.add_argument( + '--init', + const='rear', + nargs='?', + action='store', + help=_("Initialize environment for backup," + "using 'rear' or 'nfs' as args " + "which will check for package install " + "and configured ReaR or NFS server. " + "Defaults to: rear. " + "i.e. --init rear. " + "WARNING: This flag will be deprecated" + "and replaced by '--setup-rear' and" + "'--setup-nfs'.") + ) + + parser.add_argument( + '--setup-nfs', + default=False, + action='store_true', + help=_("Setup the NFS server on the backup node " + "which will install required packages " + "and configuration on the host 'BackupNode' " + "in the ansible inventory.") + ) + + parser.add_argument( + '--setup-rear', + default=False, + action='store_true', + help=_("Setup ReaR on the overcloud 'Controller' hosts which will " + "install and configure ReaR.") + ) + + parser.add_argument( + '--inventory', + default='/home/stack/tripleo-inventory.yaml', + help=_("Tripleo inventory file generated with " + "tripleo-ansible-inventory command. " + "Defaults to: /home/stack/tripleo-inventory.yaml.") + ) + + parser.add_argument( + '--storage-ip', + help=_("Storage IP is an optional parameter " + "which allows for an ip of a storage " + "server to be specified, overriding the " + "default undercloud. " + "WARNING: This flag will be deprecated in " + "favor of '--extra-vars' which will allow " + "to pass this and other variables.") + ) + + parser.add_argument( + '--extra-vars', + default=None, + action='store', + help=_("Set additional variables as Dict or as " + "an absolute path of a JSON or YAML file type. " + "i.e. --extra-vars '{\"key\": \"val\", " + " \"key2\": \"val2\"}' " + "i.e. --extra-vars /path/to/my_vars.yaml " + "i.e. --extra-vars /path/to/my_vars.json. " + "For more information about the variables that " + "can be passed, visit: https://opendev.org/openstack/" + "tripleo-ansible/src/branch/master/tripleo_ansible/" + "roles/backup_and_restore/defaults/main.yml.") + ) + + return parser + + def _parse_extra_vars(self, raw_extra_vars): + + if raw_extra_vars is None: + return {} + elif os.path.exists(raw_extra_vars): + with open(raw_extra_vars, 'r') as fp: + extra_vars = yaml.safe_load(fp.read()) + else: + try: + extra_vars = yaml.safe_load(raw_extra_vars) + except yaml.YAMLError as exc: + raise RuntimeError( + _('--extra-vars is not an existing file and cannot be ' + 'parsed as YAML / JSON: %s') % exc) + + return extra_vars + + def _run_backup_overcloud(self, parsed_args): + """Backup defined overcloud nodes.""" + + extra_vars = self._parse_extra_vars(parsed_args.extra_vars) + + if parsed_args.storage_ip: + storage_ip = parsed_args.storage_ip + + extra_vars[ + 'tripleo_backup_and_restore_nfs_server' + ] = storage_ip + + if parsed_args.setup_nfs is True or parsed_args.init == 'nfs': + + LOG.debug(_('Setting up NFS Backup node')) + self._run_ansible_playbook( + playbook='prepare-nfs-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_nfs_server', + skip_tags=None, + extra_vars=extra_vars + ) + + if parsed_args.setup_rear is True or parsed_args.init == 'rear': + + LOG.debug(_('Installing ReaR on controller nodes')) + self._run_ansible_playbook( + playbook='prepare-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_rear', + skip_tags=None, + extra_vars=extra_vars + ) + + if (parsed_args.setup_nfs is False and + parsed_args.setup_rear is False and + parsed_args.init is None): + + LOG.debug(_('Starting Overcloud Backup')) + self._run_ansible_playbook( + playbook='cli-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_create_recover_image', + skip_tags=None, + extra_vars=extra_vars + ) + + def _run_ansible_playbook(self, + playbook, + inventory, + tags, + skip_tags, + extra_vars): + """Run ansible playbook""" + + # with utils.TempDirs() as tmp: + utils.run_ansible_playbook( + logger=LOG, + playbook=playbook, + inventory=inventory, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + tags=tags, + skip_tags=skip_tags, + verbosity=self.app_args.verbose_level, + extra_vars=extra_vars + ) + + def take_action(self, parsed_args): + + if parsed_args.init: + + LOG.warning("The following flags will be deprecated:" + "[--init, --storage-ip]") + + self._run_backup_overcloud(parsed_args) + print( + '\n' + ' #############################################################\n' + ' # Disclaimer #\n' + ' # Backup verification is the End Users responsibility #\n' + ' # Please verify backup integrity before any possible #\n' + ' # disruptive actions against the Overcloud. The resulting #\n' + ' # backup file path will be shown on a successful execution. #\n' + ' # #\n' + ' # .-Stay safe and avoid future issues-. #\n' + ' #############################################################\n' + ) diff --git a/tripleoclient/v1/undercloud_backup.py b/tripleoclient/v1/undercloud_backup.py index 5dc342a56..c6f896270 100644 --- a/tripleoclient/v1/undercloud_backup.py +++ b/tripleoclient/v1/undercloud_backup.py @@ -15,9 +15,14 @@ import argparse import logging +import os +import yaml from osc_lib.command import command from osc_lib.i18n import _ + +from tripleoclient import constants +from tripleoclient import utils from tripleoclient.workflows import undercloud_backup LOG = logging.getLogger(__name__ + ".BackupUndercloud") @@ -33,6 +38,51 @@ class BackupUndercloud(command.Command): add_help=False ) + parser.add_argument( + '--init', + const='rear', + nargs='?', + action='store', + help=_("Initialize environment for backup," + "using 'rear' or 'nfs' as args " + "which will check for package install " + "and configured ReaR or NFS server. " + "Defaults to: rear. " + "i.e. --init rear. " + "WARNING: This flag will be deprecated" + "and replaced by '--setup-rear' and" + "'--setup-nfs'.") + ) + + # New flags for tripleo-ansible backup and restore role. + parser.add_argument( + '--setup-nfs', + default=False, + action='store_true', + help=_("Setup the NFS server on the backup node" + "which will install required packages" + "and configuration on the host 'BackupNode' " + "in the ansible inventory.") + + ) + + parser.add_argument( + '--setup-rear', + default=False, + action='store_true', + help=_("Setup ReaR on the 'Undercloud' host which will" + "install and configure ReaR.") + ) + + parser.add_argument( + '--inventory', + action='store', + default='/home/stack/tripleo-inventory.yaml', + help=_("Tripleo inventory file generated with" + "tripleo-ansible-inventory command. " + "Defaults to: /home/stack/tripleo-inventory.yaml.") + ) + # Parameter to choose the files to backup parser.add_argument( '--add-path', @@ -53,10 +103,99 @@ class BackupUndercloud(command.Command): "i.e. --exclude-path /this/is/a/folder/ " " --exclude-path /this/is/a/texfile.txt") ) + + parser.add_argument( + '--extra-vars', + default=None, + action='store', + help=_("Set additional variables as Dict or as " + "an absolute path of a JSON or YAML file type. " + "i.e. --extra-vars '{\"key\": \"val\", " + "\"key2\": \"val2\"}' " + "i.e. --extra-vars /path/to/my_vars.yaml " + "i.e. --extra-vars /path/to/my_vars.json. " + "For more information about the variables that " + "can be passed, visit: https://opendev.org/openstack/" + "tripleo-ansible/src/branch/master/tripleo_ansible/" + "roles/backup_and_restore/defaults/main.yml.") + ) + return parser + def _parse_extra_vars(self, raw_extra_vars): + + if raw_extra_vars is None: + return raw_extra_vars + elif os.path.exists(raw_extra_vars): + with open(raw_extra_vars, 'r') as fp: + extra_vars = yaml.safe_load(fp.read()) + + else: + try: + extra_vars = yaml.safe_load(raw_extra_vars) + except yaml.YAMLError as exc: + raise RuntimeError( + _('--extra-vars is not an existing file and cannot be ' + 'parsed as YAML / JSON: %s') % exc) + + return extra_vars + def _run_backup_undercloud(self, parsed_args): + extra_vars = self._parse_extra_vars(parsed_args.extra_vars) + + if parsed_args.setup_nfs is True or parsed_args.init == 'nfs': + + self._run_ansible_playbook( + playbook='prepare-nfs-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_nfs_server', + skip_tags=None, + extra_vars=extra_vars + ) + if parsed_args.setup_rear is True or parsed_args.init == 'rear': + + self._run_ansible_playbook( + playbook='prepare-undercloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_rear', + skip_tags=None, + extra_vars=extra_vars + ) + + if (parsed_args.setup_nfs is False and + parsed_args.setup_rear is False and + parsed_args.init is None): + + self._run_ansible_playbook( + playbook='cli-undercloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_create_recover_image', + skip_tags=None, + extra_vars=extra_vars) + + def _run_ansible_playbook(self, + playbook, + inventory, + tags, + skip_tags, + extra_vars): + """Run ansible playbook""" + + # with utils.TempDirs() as tmp: + utils.run_ansible_playbook( + logger=LOG, + playbook=playbook, + inventory=inventory, + workdir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + tags=tags, + skip_tags=skip_tags, + verbosity=self.app_args.verbose_level, + extra_vars=extra_vars + ) + + def _legacy_backup_undercloud(self, parsed_args): + clients = self.app.client_manager merge_paths = sorted(list(set(parsed_args.add_path))) @@ -84,6 +223,16 @@ class BackupUndercloud(command.Command): def take_action(self, parsed_args): + if len(parsed_args.add_path) > 1 or len(parsed_args.exclude_path) > 1: + + LOG.warning("The following flags will be deprecated:" + "[--add-path, --exclude-path, --init]") + + self._legacy_backup_undercloud(parsed_args) + + else: + self._run_backup_undercloud(parsed_args) + LOG.info(_( '\n' ' #############################################################\n' @@ -96,5 +245,3 @@ class BackupUndercloud(command.Command): ' # .-Stay safe and avoid future issues-. #\n' ' #############################################################\n') ) - - self._run_backup_undercloud(parsed_args)