From ae257a0955cf0cc6f01f5ed5898b0d53d8ff0b49 Mon Sep 17 00:00:00 2001 From: David Ames Date: Fri, 27 Apr 2018 17:25:07 +0000 Subject: [PATCH] Functionality to enable mojo's use of zaza Without introducing mojoisms into zaza there are some changes that are required to enable mojo's use of zaza. The goal is to keep mojo specific utilities in openstack-mojo-specs and to move any generalized tools here in zaza. This change updates some generalized zaza tools to enable mojo to use them. --- unit_tests/test_zaza_charm_lifecycle_utils.py | 45 +++++++++++++++---- unit_tests/test_zaza_model.py | 11 +++++ zaza/charm_lifecycle/utils.py | 15 ++++++- zaza/configure/network.py | 12 +++-- zaza/model.py | 19 ++++++++ 5 files changed, 87 insertions(+), 15 deletions(-) diff --git a/unit_tests/test_zaza_charm_lifecycle_utils.py b/unit_tests/test_zaza_charm_lifecycle_utils.py index edf3647..0bd1594 100644 --- a/unit_tests/test_zaza_charm_lifecycle_utils.py +++ b/unit_tests/test_zaza_charm_lifecycle_utils.py @@ -1,6 +1,4 @@ -import os -import tempfile -import yaml +import mock import zaza.charm_lifecycle.utils as lc_utils import unit_tests.utils as ut_utils @@ -9,12 +7,22 @@ import unit_tests.utils as ut_utils class TestCharmLifecycleUtils(ut_utils.BaseTestCase): def test_get_charm_config(self): - f = tempfile.NamedTemporaryFile(delete=False, mode='w') - f.write(yaml.dump({'test_config': 'someconfig'})) - f.close() - charm_config = lc_utils.get_charm_config(yaml_file=f.name) - os.unlink(f.name) - self.assertEqual(charm_config, {'test_config': 'someconfig'}) + self.patch("builtins.open", + new_callable=mock.mock_open(), + name="_open") + self.patch_object(lc_utils, 'yaml') + _yaml = "testconfig: someconfig" + _yaml_dict = {'test_config': 'someconfig'} + self.yaml.load.return_value = _yaml_dict + _filename = "filename" + _fileobj = mock.MagicMock() + _fileobj.__enter__.return_value = _yaml + self._open.return_value = _fileobj + + self.assertEqual(lc_utils.get_charm_config(yaml_file=_filename), + _yaml_dict) + self._open.assert_called_once_with(_filename, "r") + self.yaml.load.assert_called_once_with(_yaml) def test_get_class(self): self.assertEqual( @@ -22,3 +30,22 @@ class TestCharmLifecycleUtils(ut_utils.BaseTestCase): 'test_zaza_charm_lifecycle_utils.' 'TestCharmLifecycleUtils')()), type(self)) + + def test_get_juju_model(self): + self.patch_object(lc_utils.os, 'environ') + self.patch_object(lc_utils.model, 'get_current_model') + self.get_current_model.return_value = 'modelsmodel' + + def _get_env(key): + return _env.get(key) + self.environ.__getitem__.side_effect = _get_env + _env = {"JUJU_MODEL": 'envmodel'} + + # JUJU_ENV environment variable set + self.assertEqual(lc_utils.get_juju_model(), 'envmodel') + self.get_current_model.assert_not_called() + + # No envirnment variable + self.environ.__getitem__.side_effect = KeyError + self.assertEqual(lc_utils.get_juju_model(), 'modelsmodel') + self.get_current_model.assert_called_once() diff --git a/unit_tests/test_zaza_model.py b/unit_tests/test_zaza_model.py index 26ee41a..7b78f39 100644 --- a/unit_tests/test_zaza_model.py +++ b/unit_tests/test_zaza_model.py @@ -80,12 +80,18 @@ class TestModel(ut_utils.BaseTestCase): async def _disconnect(): return + async def _connect(): + return + + self.Model_mock.connect.side_effect = _connect self.Model_mock.connect_model.side_effect = _connect_model self.Model_mock.disconnect.side_effect = _disconnect self.Model_mock.applications = self.mymodel.applications self.Model_mock.units = { 'app/2': self.unit1, 'app/4': self.unit2} + self.model_name = "testmodel" + self.Model_mock.info.name = self.model_name def test_run_in_model(self): self.patch_object(model, 'Model') @@ -363,3 +369,8 @@ class TestModel(ut_utils.BaseTestCase): 'workload-status-message': 'Sure, I could do something'}}, timeout=1) self.assertTrue(self.system_ready) + + def test_get_current_model(self): + self.patch_object(model, 'Model') + self.Model.return_value = self.Model_mock + self.assertEqual(model.get_current_model(), self.model_name) diff --git a/zaza/charm_lifecycle/utils.py b/zaza/charm_lifecycle/utils.py index 3f5d1dc..571053f 100644 --- a/zaza/charm_lifecycle/utils.py +++ b/zaza/charm_lifecycle/utils.py @@ -2,6 +2,8 @@ import importlib import os import yaml +from zaza import model + BUNDLE_DIR = "./tests/bundles/" DEFAULT_TEST_CONFIG = "./tests/tests.yaml" @@ -47,9 +49,18 @@ def set_juju_model(model_name): def get_juju_model(): - """Retrieve current model from environment + """Retrieve current model + + First check the environment for JUJU_MODEL. If this is not set, get the + current active model. :returns: In focus model name :rtype: str """ - return os.environ["JUJU_MODEL"] + + try: + # Check the environment + return os.environ["JUJU_MODEL"] + except KeyError: + # If unset connect get the current active model + return model.get_current_model() diff --git a/zaza/configure/network.py b/zaza/configure/network.py index 5105938..06bcd19 100755 --- a/zaza/configure/network.py +++ b/zaza/configure/network.py @@ -199,7 +199,7 @@ def setup_gateway_ext_port(network_config, keystone_session=None): net_id=net_id) -def run_from_cli(): +def run_from_cli(**kwargs): """Run network configurations from CLI Use a YAML file of network configuration settings to configure the @@ -217,6 +217,7 @@ def run_from_cli(): start_floating_ip: 10.5.150.0 end_floating_ip: 10.5.200.254 + :param kwargs: Allow for override of argparse options :returns: None :rtype: None """ @@ -235,9 +236,12 @@ def run_from_cli(): default="network.yaml") # Handle CLI options options = parser.parse_args() - net_topology = _local_utils.parse_arg(options, "net_topology") - net_topology_file = _local_utils.parse_arg(options, "net_topology_file") - ignore_env_vars = _local_utils.parse_arg(options, "ignore_env_vars") + net_topology = (kwargs.get('net_toplogoy') or + _local_utils.parse_arg(options, "net_topology")) + net_topology_file = (kwargs.get('net_topology_file') or + _local_utils.parse_arg(options, "net_topology_file")) + ignore_env_vars = (kwargs.get('ignore_env_vars') or + _local_utils.parse_arg(options, "ignore_env_vars")) logging.info("Setting up %s network" % (net_topology)) network_config = _local_utils.get_network_config( diff --git a/zaza/model.py b/zaza/model.py index f3485fc..b0eceac 100644 --- a/zaza/model.py +++ b/zaza/model.py @@ -562,6 +562,25 @@ def get_actions(model_name, application_name): return yaml.load(subprocess.check_output(cmd)) +async def async_get_current_model(): + """Return the current active model name + + Connect to the current active model and return its name. + + :returns: String curenet model name + :rtype: str + """ + + model = Model() + await model.connect() + model_name = model.info.name + await model.disconnect() + return model_name + + +get_current_model = sync_wrapper(async_get_current_model) + + def main(): # Run the deploy coroutine in an asyncio event loop, using a helper # that abstracts loop creation and teardown.