Fail early in case of error in env directory path

Specified environment directories were silently ignored if they didn't
exist, meaning a typo in a path argument might only be discovered very
late, after the deployment finishes.

The ~/.tripleo/environment special case is preserved, and will still be
silently ignored when not present.

Change-Id: I33760ef3f5ce04209ddaf06fb5522eb8375e4385
Closes-Bug: #1697031
This commit is contained in:
Julie Pichon 2017-06-19 16:06:26 +01:00 committed by Ana Krivokapic
parent 1645017e23
commit 7efe0f12c3
4 changed files with 105 additions and 2 deletions

View File

@ -0,0 +1,6 @@
---
fixes:
- |
``overcloud deploy`` now fails early if a path specified for
``--environment-directory`` does not exist. See `bug 1697031
<https://bugs.launchpad.net/tripleo/+bug/1697031>`__.

View File

@ -39,3 +39,6 @@ RHEL_REGISTRATION_EXTRACONFIG_NAME = (
# The name of the file which holds the plan environment contents
PLAN_ENVIRONMENT = 'plan-environment.yaml'
# This directory may contain additional environments to use during deploy
DEFAULT_ENV_DIRECTORY = "~/.tripleo/environments"

View File

@ -786,6 +786,47 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
parsed_args)
self.assertIn('tmp/doesnexit.yaml', str(error))
@mock.patch('tripleoclient.workflows.plan_management.tarball',
autospec=True)
@mock.patch('tripleoclient.utils.create_tempest_deployer_input',
autospec=True)
@mock.patch('tripleoclient.utils.write_overcloudrc', autospec=True)
@mock.patch('tripleoclient.utils.get_overcloud_endpoint', autospec=True)
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_deploy_postconfig', autospec=True)
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_update_parameters', autospec=True)
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_heat_deploy', autospec=True)
@mock.patch('shutil.copytree', autospec=True)
def test_environment_dirs_env_dir_not_found(self, mock_copy,
mock_deploy_heat,
mock_update_parameters,
mock_post_config,
mock_utils_endpoint,
mock_utils_createrc,
mock_utils_tempest,
mock_tarball):
clients = self.app.client_manager
workflow_client = clients.workflow_engine
workflow_client.action_executions.create.return_value = mock.MagicMock(
output='{"result":[]}')
mock_update_parameters.return_value = {}
mock_utils_endpoint.return_value = 'foo.bar'
os.mkdir(self.tmp_dir.join('env'))
os.mkdir(self.tmp_dir.join('common'))
arglist = ['--templates', '--environment-directory', '/tmp/notthere']
verifylist = [
('templates', '/usr/share/openstack-tripleo-heat-templates/'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
error = self.assertRaises(oscexc.CommandError, self.cmd.take_action,
parsed_args)
self.assertIn('/tmp/notthere', str(error))
@mock.patch('tripleoclient.utils.create_tempest_deployer_input',
autospec=True)
@mock.patch('tripleoclient.utils.write_overcloudrc', autospec=True)
@ -1483,3 +1524,40 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.cmd.take_action,
parsed_args)
self.assertFalse(mock_deploy_tmpdir.called)
class TestArgumentValidation(fakes.TestDeployOvercloud):
def setUp(self):
super(TestArgumentValidation, self).setUp()
def is_dir(arg):
if arg == '/tmp/real_dir':
return True
else:
return False
patcher = mock.patch('os.path.isdir')
mock_isdir = patcher.start()
mock_isdir.side_effect = is_dir
self.addCleanup(patcher.stop)
app_args = mock.Mock()
app_args.verbose_level = 1
self.validate = overcloud_deploy.DeployOvercloud(
self.app, app_args)._validate_args_environment_directory
def test_validate_env_dir(self):
self.assertIsNone(self.validate(['/tmp/real_dir']))
def test_validate_env_dir_empty(self):
self.assertIsNone(self.validate([]))
def test_validate_env_dir_not_a_real_directory(self):
self.assertRaises(oscexc.CommandError,
self.validate,
['/tmp/not_a_real_dir'])
def test_validate_env_dir_ignore_default_not_existing(self):
full_path = os.path.expanduser(constants.DEFAULT_ENV_DIRECTORY)
self.assertIsNone(self.validate([full_path]))

View File

@ -593,6 +593,23 @@ class DeployOvercloud(command.Command):
if parsed_args.validation_warnings_fatal:
raise exceptions.InvalidConfiguration()
if parsed_args.environment_directories:
self._validate_args_environment_directory(
parsed_args.environment_directories)
def _validate_args_environment_directory(self, directories):
default = os.path.expanduser(constants.DEFAULT_ENV_DIRECTORY)
nonexisting_dirs = []
for d in directories:
if not os.path.isdir(d) and d != default:
nonexisting_dirs.append(d)
if nonexisting_dirs:
raise oscexc.CommandError(
"Error: The following environment directories were not found"
": {0}".format(", ".join(nonexisting_dirs)))
def _get_default_role_counts(self, parsed_args):
if parsed_args.roles_file:
@ -686,8 +703,7 @@ class DeployOvercloud(command.Command):
parser.add_argument(
'--environment-directory', metavar='<HEAT ENVIRONMENT DIRECTORY>',
action='append', dest='environment_directories',
default=[os.path.join(os.environ.get('HOME', ''), '.tripleo',
'environments')],
default=[os.path.expanduser(constants.DEFAULT_ENV_DIRECTORY)],
help=_('Environment file directories that are automatically '
' added to the heat stack-create or heat stack-update'
' commands. Can be specified more than once. Files in'