Use libjuju unit.run for juju_run

Use libjuju for juju run commands
Add unit test for model.run_on_unit
This commit is contained in:
David Ames
2018-04-11 16:28:55 -07:00
parent 16bc6c0df0
commit 6eae8a0fbb
3 changed files with 71 additions and 28 deletions

View File

@@ -12,6 +12,25 @@ class TestModel(ut_utils.BaseTestCase):
async def _scp_to(source, destination, user, proxy, scp_opts):
return
async def _run(command, timeout=None):
return self.action
self.action = mock.MagicMock()
self.action.data = {
'model-uuid': '1a035018-71ff-473e-8aab-d1a8d6b6cda7',
'id': 'e26ffb69-6626-4e93-8840-07f7e041e99d',
'receiver': 'glance/0',
'name': 'juju-run',
'parameters': {
'command': 'somecommand someargument', 'timeout': 0},
'status': 'completed',
'message': '',
'results': {'Code': '0', 'Stderr': '', 'Stdout': 'RESULT'},
'enqueued': '2018-04-11T23:13:42Z',
'started': '2018-04-11T23:13:42Z',
'completed': '2018-04-11T23:13:43Z'}
self.unit1 = mock.MagicMock()
self.unit1.public_address = 'ip1'
self.unit1.name = 'app/2'
@@ -22,6 +41,7 @@ class TestModel(ut_utils.BaseTestCase):
self.unit2.name = 'app/4'
self.unit2.entity_id = 'app/4'
self.unit2.machine = 'machine7'
self.unit1.run.side_effect = _run
self.unit1.scp_to.side_effect = _scp_to
self.unit2.scp_to.side_effect = _scp_to
self.units = [self.unit1, self.unit2]
@@ -144,3 +164,14 @@ class TestModel(ut_utils.BaseTestCase):
self.patch_object(model, 'get_units')
self.get_units.return_value = self.units
self.assertEqual(model.get_app_ips('model', 'app'), ['ip1', 'ip2'])
def test_run_on_unit(self):
expected = {'Code': '0', 'Stderr': '', 'Stdout': 'RESULT'}
self.cmd = cmd = 'somecommand someargument'
self.patch_object(model, 'Model')
self.patch_object(model, 'get_unit_from_name')
self.get_unit_from_name.return_value = self.unit1
self.Model.return_value = self.Model_mock
self.assertEqual(model.run_on_unit('app/2', 'modelname', cmd),
expected)
self.unit1.run.assert_called_once_with(cmd, timeout=None)

View File

@@ -178,23 +178,40 @@ def scp_from_unit(unit_name, model_name, source, destination, user='ubuntu',
run_in_model(model_name, scp_func, add_model_arg=True, awaitable=True))
def run_on_unit(unit, model_name, command):
def run_on_unit(unit_name, model_name, command, timeout=None):
"""Juju run on unit
:param unit: Unit object
:type unit: object
:param unit_name: Name of unit to match
:type unit: str
:param model_name: Name of model unit is in
:type model_name: str
:param command: Command to execute
:type command: str
:param timeout: DISABLED due to Issue #225
https://github.com/juju/python-libjuju/issues/225
:type timeout: int
:returns: action.data['results'] {'Code': '', 'Stderr': '', 'Stdout': ''}
:rtype: dict
"""
async def _run_on_unit(unit, command):
return await unit.run(command)
# Disabling timeout due to Issue #225
# https://github.com/juju/python-libjuju/issues/225
if timeout:
timeout = None
async def _run_on_unit(unit_name, command, model, timeout=None):
unit = get_unit_from_name(unit_name, model)
action = await unit.run(command, timeout=timeout)
if action.data.get('results'):
return action.data.get('results')
else:
return {}
run_func = functools.partial(
_run_on_unit,
unit,
command)
loop.run(
unit_name,
command,
timeout=timeout)
return loop.run(
run_in_model(model_name, run_func, add_model_arg=True, awaitable=True))

View File

@@ -156,7 +156,7 @@ def parse_arg(options, arg, multiargs=False):
return getattr(options, arg)
def remote_run(unit, remote_cmd=None, timeout=None, fatal=None):
def remote_run(unit, remote_cmd, timeout=None, fatal=None):
"""Run command on unit and return the output
NOTE: This function is pre-deprecated. As soon as libjuju unit.run is able
@@ -165,31 +165,26 @@ def remote_run(unit, remote_cmd=None, timeout=None, fatal=None):
:param remote_cmd: Command to execute on unit
:type remote_cmd: string
:param timeout: Timeout value for the command
:type arg: string
:type arg: int
:param fatal: Command failure condidered fatal or not
:type fatal: boolean
:returns: Juju run output
:rtype: string
"""
logging.warn("Deprecate as soon as possible. Use model.run_on_unit() as "
"soon as libjuju unit.run returns output.")
if fatal is None:
fatal = True
cmd = ['juju', 'run', '--unit', unit]
if timeout:
cmd.extend(['--timeout', str(timeout)])
if remote_cmd:
cmd.append(remote_cmd)
else:
cmd.append('uname -a')
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
output = p.communicate()
if six.PY3:
output = (output[0].decode('utf-8'), output[1])
if p.returncode != 0 and fatal:
raise Exception('Error running remote command')
return output
result = model.run_on_unit(unit,
lifecycle_utils.get_juju_model(),
remote_cmd,
timeout=timeout)
if result:
if int(result.get('Code')) == 0:
return result.get('Stdout')
else:
if fatal:
raise Exception('Error running remote command: {}'
.format(result.get('Stderr')))
return result.get('Stderr')
def get_pkg_version(application, pkg):
@@ -209,7 +204,7 @@ def get_pkg_version(application, pkg):
for unit in units:
cmd = 'dpkg -l | grep {}'.format(pkg)
out = remote_run(unit.entity_id, cmd)
versions.append(out[0].split()[2])
versions.append(out.split('\n')[0].split()[2])
if len(set(versions)) != 1:
raise Exception('Unexpected output from pkg version check')
return versions[0]