From 200ba35d57e0140aeb3f922063c31ce121cf65e5 Mon Sep 17 00:00:00 2001 From: Frode Nordahl Date: Wed, 1 Aug 2018 15:31:24 +0200 Subject: [PATCH] Add functions: run command on leader, get leader settings --- unit_tests/test_zaza_model.py | 11 +++++++ .../utilities/test_zaza_utilities_juju.py | 33 +++++++++++++++++++ zaza/model.py | 28 ++++++++++++++++ zaza/utilities/juju.py | 17 ++++++++++ 4 files changed, 89 insertions(+) diff --git a/unit_tests/test_zaza_model.py b/unit_tests/test_zaza_model.py index 95bd7cb..d06c5d5 100644 --- a/unit_tests/test_zaza_model.py +++ b/unit_tests/test_zaza_model.py @@ -67,6 +67,7 @@ class TestModel(ut_utils.BaseTestCase): self.unit2.name = 'app/4' self.unit2.entity_id = 'app/4' self.unit2.machine = 'machine7' + self.unit2.run.side_effect = _run self.unit1.run.side_effect = _run self.unit1.scp_to.side_effect = _scp_to self.unit2.scp_to.side_effect = _scp_to @@ -255,6 +256,16 @@ class TestModel(ut_utils.BaseTestCase): expected) self.unit1.run.assert_called_once_with(cmd, timeout=None) + def test_run_on_leader(self): + self.patch_object(model, 'get_juju_model', return_value='mname') + expected = {'Code': '0', 'Stderr': '', 'Stdout': 'RESULT'} + self.cmd = cmd = 'somecommand someargument' + self.patch_object(model, 'Model') + self.Model.return_value = self.Model_mock + self.assertEqual(model.run_on_leader('app', cmd), + expected) + self.unit2.run.assert_called_once_with(cmd, timeout=None) + def test_get_relation_id(self): self.patch_object(model, 'get_juju_model', return_value='mname') self.patch_object(model, 'Model') diff --git a/unit_tests/utilities/test_zaza_utilities_juju.py b/unit_tests/utilities/test_zaza_utilities_juju.py index b43988d..db49cb7 100644 --- a/unit_tests/utilities/test_zaza_utilities_juju.py +++ b/unit_tests/utilities/test_zaza_utilities_juju.py @@ -194,3 +194,36 @@ class TestJujuUtils(ut_utils.BaseTestCase): 'aunit/0', 'relation-get --format=yaml -r "42" - "otherunit/0"') self.assertFalse(self.yaml.load.called) + + def test_leader_get(self): + self.patch_object(juju_utils, 'yaml') + self.patch_object(juju_utils, 'model') + data = {'foo': 'bar'} + self.model.run_on_leader.return_value = { + 'Code': 0, 'Stdout': str(data)} + juju_utils.leader_get('application') + self.model.run_on_leader.assert_called_with( + 'application', 'leader-get --format=yaml ') + self.yaml.load.assert_called_with(str(data)) + + def test_leader_get_key(self): + self.patch_object(juju_utils, 'yaml') + self.patch_object(juju_utils, 'model') + data = {'foo': 'bar'} + self.model.run_on_leader.return_value = { + 'Code': 0, 'Stdout': data['foo']} + juju_utils.leader_get('application', 'foo') + self.model.run_on_leader.assert_called_with( + 'application', 'leader-get --format=yaml foo') + self.yaml.load.assert_called_with(data['foo']) + + def test_leader_get_fails(self): + self.patch_object(juju_utils, 'yaml') + self.patch_object(juju_utils, 'model') + self.model.run_on_leader.return_value = { + 'Code': 1, 'Stderr': 'ERROR'} + with self.assertRaises(Exception): + juju_utils.leader_get('application') + self.model.run_on_leader.assert_called_with( + 'application', 'leader-get --format=yaml ') + self.assertFalse(self.yaml.load.called) diff --git a/zaza/model.py b/zaza/model.py index 944a74b..445fe8a 100644 --- a/zaza/model.py +++ b/zaza/model.py @@ -228,6 +228,34 @@ async def async_run_on_unit(unit_name, command, model_name=None, timeout=None): run_on_unit = sync_wrapper(async_run_on_unit) +async def async_run_on_leader(application_name, command, model_name=None, + timeout=None): + """Juju run on leader unit. + + :param application_name: Application to match + :type application_name: str + :param command: Command to execute + :type command: str + :param model_name: Name of model unit is in + :type model_name: str + :param timeout: How long in seconds to wait for command to complete + :type timeout: int + :returns: action.data['results'] {'Code': '', 'Stderr': '', 'Stdout': ''} + :rtype: dict + """ + async with run_in_model(model_name) as model: + for unit in model.applications[application_name].units: + is_leader = await unit.is_leader_from_status() + if is_leader: + action = await unit.run(command, timeout=timeout) + if action.data.get('results'): + return action.data.get('results') + else: + return {} + +run_on_leader = sync_wrapper(async_run_on_leader) + + async def async_get_unit_time(unit_name, model_name=None, timeout=None): """Get the current time (in seconds since Epoch) on the given unit. diff --git a/zaza/utilities/juju.py b/zaza/utilities/juju.py index 8d724c2..b1a1f5b 100644 --- a/zaza/utilities/juju.py +++ b/zaza/utilities/juju.py @@ -228,3 +228,20 @@ def get_relation_from_unit(entity, remote_entity, remote_interface_name): else: raise Exception('Error running remote command: "{}"' .format(result.get("Stderr"))) + + +def leader_get(application, key=''): + """Get leader settings from leader unit of named application. + + :param application: Application to get leader settings from. + :type application: str + :returns: dict with leader settings + :rtype: dict + """ + result = model.run_on_leader(application, + 'leader-get --format=yaml {}'.format(key)) + if result and int(result.get('Code')) == 0: + return yaml.load(result.get('Stdout')) + else: + raise Exception('Error running remote command: "{}"' + .format(result.get("Stderr")))