diff --git a/releasenotes/notes/upgrade_update_prompt-f6ace53f02b62fa0.yaml b/releasenotes/notes/upgrade_update_prompt-f6ace53f02b62fa0.yaml new file mode 100644 index 000000000..3fa17f5d8 --- /dev/null +++ b/releasenotes/notes/upgrade_update_prompt-f6ace53f02b62fa0.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + The upgrade/update commands have a prompt by default now that ask for + confirmation before proceeding. It'll prevent an operator to run the + command and cause the problems to infrastructure. + This prompt can be skipped with --yes/-y argument. diff --git a/tripleoclient/constants.py b/tripleoclient/constants.py index 3e98a16e3..b0e7a01ce 100644 --- a/tripleoclient/constants.py +++ b/tripleoclient/constants.py @@ -193,10 +193,17 @@ UNDERCLOUD_EXTRA_PACKAGES = [ "tripleo-ansible" ] -# UPGRADE_PROMPT -UPGRADE_PROMPT = _('It is strongly recommended to perform a backup ' +UPGRADE_PROMPT = _('You are about to run a UPGRADE command. ' + 'It is strongly recommended to perform a backup ' 'before the upgrade. Are you sure you want to ' 'upgrade [y/N]?') UPGRADE_NO = _('User did not confirm upgrade, so exiting. ' - 'Consider using the --yes parameter if you ' + 'Consider using the --yes/-y parameter if you ' 'prefer to skip this warning in the future') +UPDATE_PROMPT = _('You are about to run a UPDATE command. ' + 'It is strongly recommended to perform a backup ' + 'before the update. Are you sure you want to ' + 'update [y/N]?') +UPDATE_NO = _('User did not confirm update, so exiting. ' + 'Consider using the --yes/-y parameter if you ' + 'prefer to skip this warning in the future') diff --git a/tripleoclient/exceptions.py b/tripleoclient/exceptions.py index 8f94dcb7d..55c8589a9 100644 --- a/tripleoclient/exceptions.py +++ b/tripleoclient/exceptions.py @@ -133,6 +133,14 @@ class UndercloudUpgradeNotConfirmed(Base): """Undercloud upgrade security question not confirmed.""" +class OvercloudUpdateNotConfirmed(Base): + """Overcloud Update security question not confirmed.""" + + +class OvercloudUpgradeNotConfirmed(Base): + """Overcloud Update security question not confirmed.""" + + class CellExportError(Base): """Cell export failed""" diff --git a/tripleoclient/tests/v1/overcloud_external_update/test_overcloud_external_update.py b/tripleoclient/tests/v1/overcloud_external_update/test_overcloud_external_update.py index 4a59ab067..3e686dd68 100644 --- a/tripleoclient/tests/v1/overcloud_external_update/test_overcloud_external_update.py +++ b/tripleoclient/tests/v1/overcloud_external_update/test_overcloud_external_update.py @@ -34,13 +34,16 @@ class TestOvercloudExternalUpdateRun(fakes.TestOvercloudExternalUpdateRun): self.mock_uuid4 = uuid4_patcher.start() self.addCleanup(self.mock_uuid4.stop) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_update_with_user_and_tags(self, mock_open, mock_execute, - mock_expanduser, update_ansible): + mock_expanduser, update_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--ssh-user', 'tripleo-admin', '--tags', 'ceph'] @@ -66,13 +69,16 @@ class TestOvercloudExternalUpdateRun(fakes.TestOvercloudExternalUpdateRun): extra_vars={} ) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_update_with_user_and_extra_vars(self, mock_open, mock_execute, - mock_expanduser, update_ansible): + mock_expanduser, update_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--ssh-user', 'tripleo-admin', '--extra-vars', 'key1=val1', diff --git a/tripleoclient/tests/v1/overcloud_external_upgrade/test_overcloud_external_upgrade.py b/tripleoclient/tests/v1/overcloud_external_upgrade/test_overcloud_external_upgrade.py index 31404e31c..db8e650a6 100644 --- a/tripleoclient/tests/v1/overcloud_external_upgrade/test_overcloud_external_upgrade.py +++ b/tripleoclient/tests/v1/overcloud_external_upgrade/test_overcloud_external_upgrade.py @@ -34,13 +34,16 @@ class TestOvercloudExternalUpgradeRun(fakes.TestOvercloudExternalUpgradeRun): self.mock_uuid4 = uuid4_patcher.start() self.addCleanup(self.mock_uuid4.stop) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_upgrade_with_user_and_tags(self, mock_open, mock_execute, - mock_expanduser, update_ansible): + mock_expanduser, update_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--ssh-user', 'tripleo-admin', '--tags', 'ceph'] @@ -66,13 +69,16 @@ class TestOvercloudExternalUpgradeRun(fakes.TestOvercloudExternalUpgradeRun): extra_vars={} ) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_upgrade_with_user_and_extra_vars(self, mock_open, mock_execute, - mock_expanduser, update_ansible): + mock_expanduser, update_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--ssh-user', 'tripleo-admin', '--extra-vars', 'key1=val1', diff --git a/tripleoclient/tests/v1/overcloud_update/test_overcloud_update.py b/tripleoclient/tests/v1/overcloud_update/test_overcloud_update.py index 69e94f6a7..06cfa0826 100644 --- a/tripleoclient/tests/v1/overcloud_update/test_overcloud_update.py +++ b/tripleoclient/tests/v1/overcloud_update/test_overcloud_update.py @@ -36,6 +36,8 @@ class TestOvercloudUpdatePrepare(fakes.TestOvercloudUpdatePrepare): self.mock_uuid4 = uuid4_patcher.start() self.addCleanup(self.mock_uuid4.stop) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.' '_get_undercloud_host_entry', autospec=True, return_value='192.168.0.1 uc.ctlplane.localhost uc.ctlplane') @@ -53,7 +55,8 @@ class TestOvercloudUpdatePrepare(fakes.TestOvercloudUpdatePrepare): '_deploy_tripleo_heat_templates_tmpdir', autospec=True) def test_update_out(self, mock_deploy, mock_open, mock_copy, mock_yaml, mock_abspath, mock_update, mock_logger, - mock_get_stack, mock_get_undercloud_host_entry): + mock_get_stack, mock_get_undercloud_host_entry, + mock_confirm): mock_stack = mock.Mock(parameters={'DeployIdentifier': ''}) mock_stack.stack_name = 'overcloud' mock_get_stack.return_value = mock_stack @@ -77,6 +80,8 @@ class TestOvercloudUpdatePrepare(fakes.TestOvercloudUpdatePrepare): container='overcloud', ) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.utils.get_stack', autospec=True) @mock.patch('tripleoclient.workflows.package_update.update', @@ -89,7 +94,7 @@ class TestOvercloudUpdatePrepare(fakes.TestOvercloudUpdatePrepare): '_deploy_tripleo_heat_templates', autospec=True) def test_update_failed(self, mock_deploy, mock_copy, mock_yaml, mock_abspath, mock_open, mock_update, - mock_get_stack): + mock_get_stack, mock_confirm): mock_stack = mock.Mock(parameters={'DeployIdentifier': ''}) mock_stack.stack_name = 'overcloud' mock_get_stack.return_value = mock_stack @@ -124,13 +129,16 @@ class TestOvercloudUpdateRun(fakes.TestOvercloudUpdateRun): self.mock_uuid4 = uuid4_patcher.start() self.addCleanup(self.mock_uuid4.stop) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_update_with_playbook_and_user(self, mock_open, mock_execute, - mock_expanduser, update_ansible): + mock_expanduser, update_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--limit', 'Compute', '--playbook', 'fake-playbook.yaml', @@ -159,13 +167,16 @@ class TestOvercloudUpdateRun(fakes.TestOvercloudUpdateRun): extra_vars=None ) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_update_limit_with_all_playbooks(self, mock_open, mock_execute, - mock_expanduser, update_ansible): + mock_expanduser, update_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--limit', 'Compute', '--playbook', 'all'] verifylist = [ @@ -192,13 +203,16 @@ class TestOvercloudUpdateRun(fakes.TestOvercloudUpdateRun): extra_vars=None ) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_update_with_no_limit( - self, mock_open, mock_execute, mock_expanduser, update_ansible): + self, mock_open, mock_execute, mock_expanduser, update_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = [] verifylist = [ @@ -219,9 +233,11 @@ class TestOvercloudUpdateConverge(fakes.TestOvercloudUpdateConverge): app_args.verbose_level = 1 self.cmd = overcloud_update.UpdateConverge(self.app, app_args) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch( 'tripleoclient.v1.overcloud_deploy.DeployOvercloud.take_action') - def test_update_converge(self, deploy_action): + def test_update_converge(self, deploy_action, mock_confirm): argslist = ['--templates', '--stack', 'cloud'] verifylist = [ ('stack', 'cloud') diff --git a/tripleoclient/tests/v1/overcloud_upgrade/test_overcloud_upgrade.py b/tripleoclient/tests/v1/overcloud_upgrade/test_overcloud_upgrade.py index e63911e84..451ff9158 100644 --- a/tripleoclient/tests/v1/overcloud_upgrade/test_overcloud_upgrade.py +++ b/tripleoclient/tests/v1/overcloud_upgrade/test_overcloud_upgrade.py @@ -37,6 +37,8 @@ class TestOvercloudUpgradePrepare(fakes.TestOvercloudUpgradePrepare): self.mock_uuid4 = uuid4_patcher.start() self.addCleanup(self.mock_uuid4.stop) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.' 'take_action') @mock.patch('tripleoclient.workflows.deployment.' @@ -58,7 +60,8 @@ class TestOvercloudUpgradePrepare(fakes.TestOvercloudUpgradePrepare): add_env, mock_get_config, mock_enable_ssh_admin, - mock_overcloud_deploy): + mock_overcloud_deploy, + mock_confirm): mock_stack = mock.Mock(parameters={'DeployIdentifier': ''}) mock_stack.stack_name = 'overcloud' @@ -92,6 +95,8 @@ class TestOvercloudUpgradePrepare(fakes.TestOvercloudUpgradePrepare): parsed_args.overcloud_ssh_user, mock.ANY, 10, 10) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.' 'take_action') @mock.patch('tripleoclient.utils.get_stack', @@ -100,7 +105,8 @@ class TestOvercloudUpgradePrepare(fakes.TestOvercloudUpgradePrepare): @mock.patch('six.moves.builtins.open') @mock.patch('yaml.load') def test_upgrade_failed(self, mock_yaml, mock_open, - add_env, mock_get_stack, mock_overcloud_deploy): + add_env, mock_get_stack, mock_overcloud_deploy, + mock_confirm): mock_overcloud_deploy.side_effect = exceptions.DeploymentError() mock_yaml.return_value = {'fake_container': 'fake_value'} mock_stack = mock.Mock(parameters={'DeployIdentifier': ''}) @@ -144,13 +150,16 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun): self.mock_uuid4 = uuid4_patcher.start() self.addCleanup(self.mock_uuid4.stop) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_upgrade_limit_with_playbook_and_user( - self, mock_open, mock_execute, mock_expanduser, upgrade_ansible): + self, mock_open, mock_execute, mock_expanduser, upgrade_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--limit', 'Compute, Controller', '--playbook', 'fake-playbook.yaml', @@ -178,13 +187,16 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun): extra_vars=None ) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_upgrade_limit_all_playbooks_skip_validation( - self, mock_open, mock_execute, mock_expanduser, upgrade_ansible): + self, mock_open, mock_execute, mock_expanduser, upgrade_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--limit', 'Compute', '--playbook', 'all', '--skip-tags', 'validation'] @@ -213,13 +225,16 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun): extra_vars=None ) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_upgrade_limit_all_playbooks_only_validation( - self, mock_open, mock_execute, mock_expanduser, upgrade_ansible): + self, mock_open, mock_execute, mock_expanduser, upgrade_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--limit', 'Compute', '--playbook', 'all', '--tags', 'validation'] @@ -248,13 +263,16 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun): extra_vars=None ) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_upgrade_nodes_with_playbook_no_skip_tags( - self, mock_open, mock_execute, mock_expanduser, upgrade_ansible): + self, mock_open, mock_execute, mock_expanduser, upgrade_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--limit', 'compute-0,compute-1', '--playbook', 'fake-playbook.yaml', ] @@ -281,13 +299,16 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun): extra_vars=None ) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_upgrade_node_all_playbooks_skip_tags_default( - self, mock_open, mock_execute, mock_expanduser, upgrade_ansible): + self, mock_open, mock_execute, mock_expanduser, upgrade_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--limit', 'swift-1', '--playbook', 'all'] verifylist = [ @@ -314,13 +335,16 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun): extra_vars=None ) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @mock.patch('oslo_concurrency.processutils.execute') @mock.patch('six.moves.builtins.open') def test_upgrade_node_all_playbooks_skip_tags_all_supported( - self, mock_open, mock_execute, mock_expanduser, upgrade_ansible): + self, mock_open, mock_execute, mock_expanduser, upgrade_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--limit', 'swift-1', '--playbook', 'all', '--skip-tags', 'pre-upgrade,validation'] @@ -362,6 +386,8 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun): self.assertRaises(ParserException, lambda: self.check_parser( self.cmd, argslist, verifylist)) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @@ -369,7 +395,8 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun): @mock.patch('six.moves.builtins.open') # it is 'validation' not 'validations' def test_upgrade_skip_tags_validations(self, mock_open, mock_execute, - mock_expanduser, upgrade_ansible): + mock_expanduser, upgrade_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--limit', 'overcloud-compute-1', '--skip-tags', 'validations'] @@ -385,6 +412,8 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun): self.assertRaises(exceptions.InvalidConfiguration, lambda: self.cmd.take_action(parsed_args)) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @@ -392,7 +421,8 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun): @mock.patch('six.moves.builtins.open') # should only support the constants.MAJOR_UPGRADE_SKIP_TAGS def test_upgrade_skip_tags_unsupported_validation_anything_else( - self, mock_open, mock_execute, mock_expanduser, upgrade_ansible): + self, mock_open, mock_execute, mock_expanduser, upgrade_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--limit', 'overcloud-compute-1', '--skip-tags', 'validation,anything-else'] @@ -408,6 +438,8 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun): self.assertRaises(exceptions.InvalidConfiguration, lambda: self.cmd.take_action(parsed_args)) + @mock.patch('tripleoclient.utils.prompt_user_for_confirmation', + return_value=True) @mock.patch('tripleoclient.workflows.package_update.update_ansible', autospec=True) @mock.patch('os.path.expanduser') @@ -415,7 +447,8 @@ class TestOvercloudUpgradeRun(fakes.TestOvercloudUpgradeRun): @mock.patch('six.moves.builtins.open') # should only support the constants.MAJOR_UPGRADE_SKIP_TAGS def test_upgrade_skip_tags_unsupported_pre_upgrade_anything_else( - self, mock_open, mock_execute, mock_expanduser, upgrade_ansible): + self, mock_open, mock_execute, mock_expanduser, upgrade_ansible, + mock_confirm): mock_expanduser.return_value = '/home/fake/' argslist = ['--limit', 'overcloud-compute-1', '--skip-tags', 'pre-upgrade,anything-else'] diff --git a/tripleoclient/v1/overcloud_external_update.py b/tripleoclient/v1/overcloud_external_update.py index c731c3146..0b2e96084 100644 --- a/tripleoclient/v1/overcloud_external_update.py +++ b/tripleoclient/v1/overcloud_external_update.py @@ -18,6 +18,8 @@ from oslo_log import log as logging from osc_lib.i18n import _ from osc_lib import utils +from tripleoclient.exceptions import OvercloudUpdateNotConfirmed + from tripleoclient import command from tripleoclient import constants from tripleoclient import utils as oooutils @@ -91,6 +93,12 @@ class ExternalUpdateRun(command.Command): 'system command instead of running Ansible' 'via the TripleO mistral workflows.') ) + parser.add_argument('-y', '--yes', default=False, + action='store_true', + help=_("Use -y or --yes to skip the confirmation " + "required before any upgrade " + "operation. Use this with caution! "), + ) parser.add_argument( '--limit', action='store', @@ -105,6 +113,12 @@ class ExternalUpdateRun(command.Command): def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) + + if (not parsed_args.yes + and not oooutils.prompt_user_for_confirmation( + constants.UPDATE_PROMPT, self.log)): + raise OvercloudUpdateNotConfirmed(constants.UPDATE_NO) + clients = self.app.client_manager orchestration = clients.orchestration verbosity = self.app_args.verbose_level diff --git a/tripleoclient/v1/overcloud_external_upgrade.py b/tripleoclient/v1/overcloud_external_upgrade.py index 3da54b870..1e3260a32 100644 --- a/tripleoclient/v1/overcloud_external_upgrade.py +++ b/tripleoclient/v1/overcloud_external_upgrade.py @@ -18,6 +18,8 @@ from oslo_log import log as logging from osc_lib.i18n import _ from osc_lib import utils +from tripleoclient.exceptions import OvercloudUpgradeNotConfirmed + from tripleoclient import command from tripleoclient import constants from tripleoclient import utils as oooutils @@ -91,6 +93,13 @@ class ExternalUpgradeRun(command.Command): 'system command instead of running Ansible' 'via the TripleO mistral workflows.') ) + parser.add_argument('-y', '--yes', default=False, + action='store_true', + help=_("Use -y or --yes to skip the confirmation " + "required before any upgrade " + "operation. Use this with caution! "), + ) + parser.add_argument( '--limit', action='store', @@ -105,6 +114,12 @@ class ExternalUpgradeRun(command.Command): def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) + + if (not parsed_args.yes + and not oooutils.prompt_user_for_confirmation( + constants.UPGRADE_PROMPT, self.log)): + raise OvercloudUpgradeNotConfirmed(constants.UPGRADE_NO) + clients = self.app.client_manager orchestration = clients.orchestration verbosity = self.app_args.verbose_level diff --git a/tripleoclient/v1/overcloud_update.py b/tripleoclient/v1/overcloud_update.py index 02f054a14..0034d2e11 100644 --- a/tripleoclient/v1/overcloud_update.py +++ b/tripleoclient/v1/overcloud_update.py @@ -18,6 +18,8 @@ from oslo_log import log as logging from osc_lib.i18n import _ from osc_lib import utils +from tripleoclient.exceptions import OvercloudUpdateNotConfirmed + from tripleoclient import command from tripleoclient import constants from tripleoclient import utils as oooutils @@ -41,10 +43,22 @@ class UpdatePrepare(DeployOvercloud): def get_parser(self, prog_name): parser = super(UpdatePrepare, self).get_parser(prog_name) + parser.add_argument('-y', '--yes', default=False, + action='store_true', + help=_("Use -y or --yes to skip the confirmation " + "required before any update operation. " + "Use this with caution! "), + ) return parser def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) + + if (not parsed_args.yes + and not oooutils.prompt_user_for_confirmation( + constants.UPDATE_PROMPT, self.log)): + raise OvercloudUpdateNotConfirmed(constants.UPDATE_NO) + clients = self.app.client_manager stack = oooutils.get_stack(clients.orchestration, @@ -152,10 +166,23 @@ class UpdateRun(command.Command): help=_('A list of tags to skip when running the' ' config-download ansible-playbook command.') ) + parser.add_argument( + '-y', '--yes', + default=False, + action='store_true', + help=_("Use -y or --yes to skip the confirmation required before " + "any update operation. Use this with caution! "), + ) return parser def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) + + if (not parsed_args.yes + and not oooutils.prompt_user_for_confirmation( + constants.UPDATE_PROMPT, self.log)): + raise OvercloudUpdateNotConfirmed(constants.UPDATE_NO) + clients = self.app.client_manager orchestration = clients.orchestration verbosity = self.app_args.verbose_level @@ -201,9 +228,24 @@ class UpdateConverge(DeployOvercloud): log = logging.getLogger(__name__ + ".UpdateConverge") + def get_parser(self, prog_name): + parser = super(UpdateConverge, self).get_parser(prog_name) + parser.add_argument('-y', '--yes', default=False, + action='store_true', + help=_("Use -y or --yes to skip the confirmation " + "required before any update operation. " + "Use this with caution! "), + ) + return parser + def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) + if (not parsed_args.yes + and not oooutils.prompt_user_for_confirmation( + constants.UPDATE_PROMPT, self.log)): + raise OvercloudUpdateNotConfirmed(constants.UPDATE_NO) + # Add the update-converge.yaml environment to unset noops templates_dir = (parsed_args.templates or constants.TRIPLEO_HEAT_TEMPLATES) diff --git a/tripleoclient/v1/overcloud_upgrade.py b/tripleoclient/v1/overcloud_upgrade.py index 13eede967..864a1fe7e 100644 --- a/tripleoclient/v1/overcloud_upgrade.py +++ b/tripleoclient/v1/overcloud_upgrade.py @@ -18,6 +18,8 @@ from oslo_log import log as logging from osc_lib.i18n import _ from osc_lib import utils +from tripleoclient.exceptions import OvercloudUpgradeNotConfirmed + from tripleoclient import command from tripleoclient import constants from tripleoclient import exceptions @@ -50,11 +52,22 @@ class UpgradePrepare(DeployOvercloud): def get_parser(self, prog_name): parser = super(UpgradePrepare, self).get_parser(prog_name) + parser.add_argument('-y', '--yes', default=False, + action='store_true', + help=_("Use -y or --yes to skip the confirmation " + "required before any upgrade " + "operation. Use this with caution! "), + ) return parser def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) + if (not parsed_args.yes + and not oooutils.prompt_user_for_confirmation( + constants.UPGRADE_PROMPT, self.log)): + raise OvercloudUpgradeNotConfirmed(constants.UPGRADE_NO) + # Throw deprecation warning if service is enabled and # ask user if upgrade should still be continued. if parsed_args.environment_files: @@ -186,7 +199,8 @@ class UpgradeRun(command.Command): help=_('Name or ID of heat stack ' '(default=Env: OVERCLOUD_STACK_NAME)'), default=utils.env('OVERCLOUD_STACK_NAME', - default='overcloud')) + default='overcloud') + ) parser.add_argument('--no-workflow', dest='no_workflow', action='store_true', default=False, @@ -194,7 +208,12 @@ class UpgradeRun(command.Command): 'system command instead of running Ansible' 'via the TripleO mistral workflows.') ) - + parser.add_argument('-y', '--yes', default=False, + action='store_true', + help=_("Use -y or --yes to skip the confirmation " + "required before any upgrade " + "operation. Use this with caution! ") + ) return parser def _validate_skip_tags(self, skip_tags): @@ -209,6 +228,12 @@ class UpgradeRun(command.Command): def take_action(self, parsed_args): self.log.debug("take_action(%s)" % parsed_args) + + if (not parsed_args.yes + and not oooutils.prompt_user_for_confirmation( + constants.UPGRADE_PROMPT, self.log)): + raise OvercloudUpgradeNotConfirmed(constants.UPGRADE_NO) + clients = self.app.client_manager verbosity = self.app_args.verbose_level orchestration = clients.orchestration