diff --git a/setup.cfg b/setup.cfg index 43c3e5cc7..cc7ee9d42 100644 --- a/setup.cfg +++ b/setup.cfg @@ -51,6 +51,7 @@ openstack.tripleoclient.v2 = tripleo_launch_heat = tripleoclient.v1.tripleo_launch_heat:LaunchHeat 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 @@ -114,7 +115,7 @@ openstack.tripleoclient.v2 = undercloud_upgrade = tripleoclient.v1.undercloud:UpgradeUndercloud undercloud_minion_install = tripleoclient.v1.undercloud_minion:InstallUndercloudMinion undercloud_minion_upgrade = tripleoclient.v1.undercloud_minion:UpgradeUndercloudMinion - undercloud_backup = tripleoclient.v2.undercloud_backup:BackupUndercloud + undercloud_backup = tripleoclient.v1.undercloud_backup:BackupUndercloud tripleo_validator_group_info = tripleoclient.v1.tripleo_validator:TripleOValidatorGroupInfo tripleo_validator_list = tripleoclient.v1.tripleo_validator:TripleOValidatorList tripleo_validator_run = tripleoclient.v1.tripleo_validator:TripleOValidatorRun diff --git a/tripleoclient/tests/v2/undercloud/__init__.py b/tripleoclient/tests/v1/overcloud_backup/__init__.py similarity index 100% rename from tripleoclient/tests/v2/undercloud/__init__.py rename to tripleoclient/tests/v1/overcloud_backup/__init__.py 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..ef0b55e84 --- /dev/null +++ b/tripleoclient/tests/v1/overcloud_backup/test_backup.py @@ -0,0 +1,255 @@ +# 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.app.options = fakes.FakeOptions() + 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( + workdir=mock.ANY, + playbook='cli-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_create_recover_image', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='prepare-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_rear', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='prepare-nfs-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_nfs_server', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='prepare-nfs-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_nfs_server', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='prepare-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_rear', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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(workdir=mock.ANY, + playbook='prepare-nfs-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_nfs_server', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + extra_vars={}), + call(workdir=mock.ANY, + playbook='prepare-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_rear', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='prepare-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_rear', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='prepare-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_setup_rear', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='cli-overcloud-backup.yaml', + inventory=parsed_args.inventory, + tags='bar_create_recover_image', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + extra_vars={} + ) diff --git a/tripleoclient/tests/v1/undercloud/test_backup.py b/tripleoclient/tests/v1/undercloud/test_backup.py new file mode 100644 index 000000000..4b262498b --- /dev/null +++ b/tripleoclient/tests/v1/undercloud/test_backup.py @@ -0,0 +1,363 @@ +# 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 undercloud_backup +from unittest.mock import call + + +class TestUndercloudBackup(utils.TestCommand): + + def setUp(self): + super(TestUndercloudBackup, self).setUp() + + # Get the command object to test + app_args = mock.Mock() + app_args.verbose_level = 1 + self.app.options = fakes.FakeOptions() + 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.utils.run_ansible_playbook', + autospec=True) + def test_undercloud_backup_withargs(self, mock_playbook): + arglist = [ + '--add-path', + '/tmp/foo.yaml', + '--add-path', + '/tmp/bar.yaml' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + workdir=mock.ANY, + playbook=mock.ANY, + inventory=mock.ANY, + tags=None, + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + extra_vars={'sources_path': + '/home/stack/,/tmp/bar.yaml,/tmp/foo.yaml'}) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_undercloud_backup_withargs_remove(self, mock_playbook): + arglist = [ + '--add-path', + '/tmp/foo.yaml', + '--exclude-path', + '/tmp/bar.yaml', + '--exclude-path', + '/home/stack/', + '--add-path', + '/tmp/bar.yaml' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + workdir=mock.ANY, + playbook=mock.ANY, + inventory=mock.ANY, + tags=None, + skip_tags=None, + verbosity=3, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + extra_vars={'sources_path': + '/tmp/foo.yaml'}) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_undercloud_backup_withargs_remove_double(self, mock_playbook): + arglist = [ + '--add-path', + '/tmp/foo.yaml', + '--add-path', + '/tmp/bar.yaml', + '--exclude-path', + '/tmp/foo.yaml', + '--exclude-path', + '/tmp/foo.yaml' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + workdir=mock.ANY, + playbook=mock.ANY, + inventory=mock.ANY, + tags=None, + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + extra_vars={'sources_path': + '/home/stack/,/tmp/bar.yaml'}) + + @mock.patch('tripleoclient.utils.run_ansible_playbook', + autospec=True) + def test_undercloud_backup_withargs_remove_unex(self, mock_playbook): + arglist = [ + '--add-path', + '/tmp/foo.yaml', + '--exclude-path', + '/tmp/non-existing-path.yaml' + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + mock_playbook.assert_called_once_with( + workdir=mock.ANY, + playbook=mock.ANY, + inventory=mock.ANY, + tags=None, + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + extra_vars={'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( + workdir=mock.ANY, + playbook='cli-undercloud-backup.yaml', + inventory=mock.ANY, + tags='bar_create_recover_image', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='prepare-undercloud-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_rear', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='prepare-nfs-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_nfs_server', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='prepare-nfs-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_nfs_server', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='prepare-undercloud-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_rear', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='prepare-undercloud-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_rear', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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(workdir=mock.ANY, + playbook='prepare-nfs-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_nfs_server', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + extra_vars=None), + call(workdir=mock.ANY, + playbook='prepare-undercloud-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_rear', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='prepare-nfs-backup.yaml', + inventory=mock.ANY, + tags='bar_setup_nfs_server', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + 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( + workdir=mock.ANY, + playbook='cli-undercloud-backup.yaml', + inventory=mock.ANY, + tags='bar_create_recover_image', + skip_tags=None, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + verbosity=3, + extra_vars=None + ) diff --git a/tripleoclient/tests/v2/undercloud/test_backup.py b/tripleoclient/tests/v2/undercloud/test_backup.py deleted file mode 100644 index b606913f3..000000000 --- a/tripleoclient/tests/v2/undercloud/test_backup.py +++ /dev/null @@ -1,156 +0,0 @@ -# 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.v2 import undercloud_backup - - -class TestUndercloudBackup(utils.TestCommand): - - def setUp(self): - super(TestUndercloudBackup, self).setUp() - - # Get the command object to test - app_args = mock.Mock() - app_args.verbose_level = 1 - self.app.options = fakes.FakeOptions() - 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.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( - workdir=mock.ANY, - playbook='cli-undercloud-backup.yaml', - inventory='localhost,', - playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, - verbosity=3, - extra_vars={ - 'sources_path': '/home/stack/' - } - ) - - @mock.patch('tripleoclient.utils.run_ansible_playbook', - autospec=True) - def test_undercloud_backup_withargs(self, mock_playbook): - arglist = [ - '--add-path', - '/tmp/foo.yaml', - '--add-path', - '/tmp/bar.yaml' - ] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - mock_playbook.assert_called_once_with( - workdir=mock.ANY, - playbook=mock.ANY, - inventory=mock.ANY, - playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, - verbosity=3, - extra_vars={'sources_path': - '/home/stack/,/tmp/bar.yaml,/tmp/foo.yaml'}) - - @mock.patch('tripleoclient.utils.run_ansible_playbook', - autospec=True) - def test_undercloud_backup_withargs_remove(self, mock_playbook): - arglist = [ - '--add-path', - '/tmp/foo.yaml', - '--exclude-path', - '/tmp/bar.yaml', - '--exclude-path', - '/home/stack/', - '--add-path', - '/tmp/bar.yaml' - ] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - mock_playbook.assert_called_once_with( - workdir=mock.ANY, - playbook=mock.ANY, - inventory=mock.ANY, - verbosity=3, - playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, - extra_vars={'sources_path': - '/tmp/foo.yaml'}) - - @mock.patch('tripleoclient.utils.run_ansible_playbook', - autospec=True) - def test_undercloud_backup_withargs_remove_double(self, mock_playbook): - arglist = [ - '--add-path', - '/tmp/foo.yaml', - '--add-path', - '/tmp/bar.yaml', - '--exclude-path', - '/tmp/foo.yaml', - '--exclude-path', - '/tmp/foo.yaml' - ] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - mock_playbook.assert_called_once_with( - workdir=mock.ANY, - playbook=mock.ANY, - inventory=mock.ANY, - playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, - verbosity=3, - extra_vars={'sources_path': - '/home/stack/,/tmp/bar.yaml'}) - - @mock.patch('tripleoclient.utils.run_ansible_playbook', - autospec=True) - def test_undercloud_backup_withargs_remove_unex(self, mock_playbook): - arglist = [ - '--add-path', - '/tmp/foo.yaml', - '--exclude-path', - '/tmp/non-existing-path.yaml' - ] - verifylist = [] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - mock_playbook.assert_called_once_with( - workdir=mock.ANY, - playbook=mock.ANY, - inventory=mock.ANY, - playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, - verbosity=3, - extra_vars={'sources_path': - '/home/stack/,/tmp/foo.yaml'}) diff --git a/tripleoclient/v1/overcloud_backup.py b/tripleoclient/v1/overcloud_backup.py new file mode 100644 index 000000000..c3dac995c --- /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( + playbook=playbook, + inventory=inventory, + workdir=tmp, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + tags=tags, + skip_tags=skip_tags, + verbosity=utils.playbook_verbosity(self=self), + 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 new file mode 100644 index 000000000..7b4716189 --- /dev/null +++ b/tripleoclient/v1/undercloud_backup.py @@ -0,0 +1,262 @@ +# 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 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__ + ".BackupUndercloud") + + +class BackupUndercloud(command.Command): + """Backup the undercloud""" + + 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'.") + ) + + # 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', + action='append', + default=['/home/stack/'], + help=_("Add additional files to backup. " + "Defaults to: /home/stack/ " + "i.e. --add-path /this/is/a/folder/ " + " --add-path /this/is/a/texfile.txt.") + ) + + parser.add_argument( + "--exclude-path", + default=[], + action="append", + help=_("Exclude path when performing the Undercloud Backup, " + "this option can be specified multiple times. " + "Defaults to: none " + "i.e. --exclude-path /this/is/a/folder/ " + " --exclude-path /this/is/a/texfile.txt.") + ) + + parser.add_argument( + '--save-swift', + default=False, + action='store_true', + help=_("Save backup to swift. " + "Defaults to: False " + "Special attention should be taken that " + "Swift itself is backed up if you call this multiple times " + "the backup size will grow exponentially.") + ) + + 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 _legacy_backup_undercloud(self, parsed_args): + """Legacy backup undercloud. + + This will allow for easier removal once the functionality + is no longer needed. + """ + + merge_paths = sorted(list(set(parsed_args.add_path))) + for exc in parsed_args.exclude_path: + if exc in merge_paths: + merge_paths.remove(exc) + + files_to_backup = ','.join(merge_paths) + + # Define the backup sources_path (files to backup). + # This is a comma separated string. + # I.e. "/this/is/a/folder/,/this/is/a/texfile.txt" + extra_vars = {"sources_path": files_to_backup} + if parsed_args.save_swift: + extra_vars.update({"save_swift": True}) + + LOG.debug(_('Launch the Undercloud Backup')) + self._run_ansible_playbook( + playbook='cli-undercloud-backup-legacy.yaml', + inventory='localhost, ', + tags=None, + 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( + playbook=playbook, + inventory=inventory, + workdir=tmp, + playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, + tags=tags, + skip_tags=skip_tags, + verbosity=utils.playbook_verbosity(self=self), + extra_vars=extra_vars + ) + + def take_action(self, parsed_args): + + if len(parsed_args.add_path) > 1 or parsed_args.save_swift: + + LOG.warning("The following flags will be deprecated:" + "[--add-path, --exclude-path, --init, --save-swift]") + + self._legacy_backup_undercloud(parsed_args) + + else: + self._run_backup_undercloud(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 Undercloud. 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/v2/undercloud_backup.py b/tripleoclient/v2/undercloud_backup.py deleted file mode 100644 index 155911ecb..000000000 --- a/tripleoclient/v2/undercloud_backup.py +++ /dev/null @@ -1,111 +0,0 @@ -# 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 argparse -import logging - -from osc_lib.command import command -from osc_lib.i18n import _ - -from tripleoclient import constants -from tripleoclient import utils - -LOG = logging.getLogger(__name__ + ".BackupUndercloud") - - -class BackupUndercloud(command.Command): - """Backup the undercloud""" - - def get_parser(self, prog_name): - parser = argparse.ArgumentParser( - description=self.get_description(), - prog=prog_name, - add_help=False - ) - - # Parameter to choose the files to backup - parser.add_argument( - '--add-path', - action='append', - default=['/home/stack/'], - help=_("Add additional files to backup. " - "Defaults to: /home/stack/ " - "i.e. --add-path /this/is/a/folder/ " - " --add-path /this/is/a/texfile.txt") - ) - parser.add_argument( - "--exclude-path", - default=[], - action="append", - help=_("Exclude path when performing the Undercloud Backup, " - "this option can be specified multiple times. " - "Defaults to: none " - "i.e. --exclude-path /this/is/a/folder/ " - " --exclude-path /this/is/a/texfile.txt") - ) - parser.add_argument( - '--save-swift', - default=False, - action='store_true', - help=_("Save backup to swift. " - "Defaults to: False " - "Special attention should be taken that " - "Swift itself is backed up if you call this multiple times " - "the backup size will grow exponentially") - ) - return parser - - def _run_backup_undercloud(self, parsed_args): - - merge_paths = sorted(list(set(parsed_args.add_path))) - for exc in parsed_args.exclude_path: - if exc in merge_paths: - merge_paths.remove(exc) - - files_to_backup = ','.join(merge_paths) - - # Define the backup sources_path (files to backup). - # This is a comma separated string. - # I.e. "/this/is/a/folder/,/this/is/a/texfile.txt" - extra_vars = {"sources_path": files_to_backup} - if parsed_args.save_swift: - extra_vars.update({"save_swift": True}) - - LOG.debug(_('Launch the Undercloud Backup')) - with utils.TempDirs() as tmp: - utils.run_ansible_playbook( - playbook='cli-undercloud-backup.yaml', - inventory='localhost,', - workdir=tmp, - playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS, - verbosity=utils.playbook_verbosity(self=self), - extra_vars=extra_vars - ) - - def take_action(self, parsed_args): - - self._run_backup_undercloud(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 Undercloud. The resulting #\n' - ' # backup file path will be shown on a successful execution. #\n' - ' # #\n' - ' # .-Stay safe and avoid future issues-. #\n' - ' #############################################################\n' - )