Fix ansible-playbook-3 symlink

The symlink needs to be created with sudo because if validations are
enabled, the call to run ansible-playbook-3 is before the "sudo tripleo deploy
command".

This patch moves the symlink into a function, that will be called before
the preflight if enabled and during the tripleo deploy/upgrade command,
which should cover standalone deployment and upgrade.

Change-Id: I1ce9b3df6c937cd796728d4fc5921fcf1023e5db
This commit is contained in:
Emilien Macchi 2019-02-27 09:49:09 -05:00
parent 88d3dfd5e7
commit 2a6f876bd7
5 changed files with 58 additions and 25 deletions

View File

@ -1345,3 +1345,33 @@ class TestConfigParser(TestCase):
self.assertRaises(exceptions.NotFound,
utils.get_config_value,
'does-not-exist', 'foo', 'bar')
class TestAnsibleSymlink(TestCase):
@mock.patch('tripleoclient.utils.run_command')
@mock.patch('os.path.exists', side_effect=[False, True])
def test_ansible_symlink_needed(self, mock_path, mock_cmd):
utils.ansible_symlink()
python_version = sys.version_info[0]
ansible_playbook_cmd = "ansible-playbook-{}".format(python_version)
mock_cmd.assert_called_once_with(['sudo', 'ln', '-s',
'/usr/bin/' + ansible_playbook_cmd,
'/usr/bin/ansible-playbook'],
name='ansible-playbook-symlink')
@mock.patch('tripleoclient.utils.run_command')
@mock.patch('os.path.exists', side_effect=[True, False])
def test_ansible3_symlink_needed(self, mock_path, mock_cmd):
utils.ansible_symlink()
python_version = sys.version_info[0]
ansible_playbook_cmd = "ansible-playbook-{}".format(python_version)
mock_cmd.assert_called_once_with(['sudo', 'ln', '-s',
'/usr/bin/ansible-playbook',
'/usr/bin/' + ansible_playbook_cmd],
name='ansible-playbook-3-symlink')
@mock.patch('tripleoclient.utils.run_command')
@mock.patch('os.path.exists', side_effect=[False, False])
def test_ansible_symlink_not_needed(self, mock_path, mock_cmd):
utils.ansible_symlink()
mock_cmd.assert_not_called()

View File

@ -930,7 +930,8 @@ class TestDeployUndercloud(TestPluginV1):
return_value=('CREATE_COMPLETE', 0))
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy.'
'_set_default_plan')
def test_take_action_standalone(self, mock_def_plan, mock_poll,
@mock.patch('tripleoclient.utils.ansible_symlink')
def test_take_action_standalone(self, mock_slink, mock_def_plan, mock_poll,
mock_environ, mock_geteuid, mock_puppet,
mock_killheat, mock_launchheat,
mock_download, mock_tht,
@ -939,7 +940,7 @@ class TestDeployUndercloud(TestPluginV1):
mock_tarball, mock_templates_dir,
mock_open, mock_os, mock_user, mock_cc,
mock_chmod, mock_ac):
mock_slink.side_effect = 'fake-cmd'
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1',
'--templates', '/tmp/thtroot',
@ -972,7 +973,9 @@ class TestDeployUndercloud(TestPluginV1):
mock_cleanupdirs.assert_called_once()
self.assertEqual(mock_killheat.call_count, 2)
def test_take_action(self):
@mock.patch('tripleoclient.utils.ansible_symlink')
def test_take_action(self, mock_slink):
mock_slink.side_effect = 'fake-cmd'
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1',
'--templates', '/tmp/thtroot',
@ -983,7 +986,9 @@ class TestDeployUndercloud(TestPluginV1):
@mock.patch('tripleoclient.v1.tripleo_deploy.Deploy._standalone_deploy',
return_value=1)
def test_take_action_failure(self, mock_deploy):
@mock.patch('tripleoclient.utils.ansible_symlink')
def test_take_action_failure(self, mock_slink, mock_deploy):
mock_slink.side_effect = 'fake-cmd'
parsed_args = self.check_parser(self.cmd,
['--local-ip', '127.0.0.1',
'--templates', '/tmp/thtroot',

View File

@ -1472,3 +1472,20 @@ def get_config_value(cfg, section, option):
option=option,
config=cfg))
return val
def ansible_symlink():
# https://bugs.launchpad.net/tripleo/+bug/1812837
python_version = sys.version_info[0]
ansible_playbook_cmd = "ansible-playbook-{}".format(python_version)
cmd = ['sudo', 'ln', '-s']
if not os.path.exists('/usr/bin/ansible-playbook'):
if os.path.exists('/usr/bin/' + ansible_playbook_cmd):
cmd.extend(['/usr/bin/' + ansible_playbook_cmd,
'/usr/bin/ansible-playbook'])
run_command(cmd, name='ansible-playbook-symlink')
else:
if not os.path.exists('/usr/bin/' + ansible_playbook_cmd):
cmd.extend(['/usr/bin/ansible-playbook',
'/usr/bin/' + ansible_playbook_cmd])
run_command(cmd, name='ansible-playbook-3-symlink')

View File

@ -106,27 +106,6 @@ class Deploy(command.Command):
ansible_playbook_cmd = "ansible-playbook-{}".format(python_version)
python_cmd = "python{}".format(python_version)
def __new__(cls, *args, **kwargs):
# https://bugs.launchpad.net/tripleo/+bug/1812837
if os.getuid() != 0:
cls.log.warning('Will not consider symlink creation (E_NOROOT).')
else:
if not os.path.exists('/usr/bin/ansible-playbook'):
if os.path.exists('/usr/bin/' + cls.ansible_playbook_cmd):
if not os.path.exists('/usr/bin/ansible-playbook'):
os.symlink('/usr/bin/' + cls.ansible_playbook_cmd,
'/usr/bin/ansible-playbook')
else:
if not os.path.exists('/usr/bin/' + cls.ansible_playbook_cmd):
if not os.path.exists(
'/usr/bin/' + cls.ansible_playbook_cmd):
os.symlink('/usr/bin/ansible-playbook',
'/usr/bin/' + cls.ansible_playbook_cmd)
if cls.python_version == 3:
return super().__new__(cls)
else:
return super(Deploy, cls).__new__(cls, *args, **kwargs)
def _is_undercloud_deploy(self, parsed_args):
return parsed_args.standalone_role == 'Undercloud' and \
parsed_args.stack == 'undercloud'
@ -1366,6 +1345,7 @@ class Deploy(command.Command):
def take_action(self, parsed_args):
self.log.debug("take_action(%s)" % parsed_args)
utils.ansible_symlink()
unconf_msg = _('User did not confirm upgrade, so exiting. '
'Consider using the --yes parameter if you '
'prefer to skip this warning in the future')

View File

@ -683,6 +683,7 @@ def prepare_undercloud_deploy(upgrade=False, no_validations=False,
utils.set_hostname(CONF.get('undercloud_hostname'))
if CONF.get('enable_validations') and not no_validations:
utils.ansible_symlink()
undercloud_preflight.check(verbose_level, upgrade)
deploy_args += ['-e', os.path.join(
tht_templates, "environments/tripleo-validations.yaml")]