From 8d9649bc1ff4701d9ffce6f5d20a62848dfc68c5 Mon Sep 17 00:00:00 2001 From: Hongbin Lu Date: Sat, 27 Jun 2015 17:48:09 -0400 Subject: [PATCH] Move conductor common implementations into module This allows common implementations to be reused later. Below is the list of methods that were moved and renamed: * handlers.k8s_conductor._retrieve_bay -> utils.retrieve_bay * handlers.bay_conductor._get_baymodel -> utils.retrieve_bay * handlers.k8s_conductor._retrieve_baymodel -> utils.retrieve_baymodel * handlers.k8s_conductor._object_has_stack -> utils.object_has_stack * handlers.k8s_conductor._retrieve_k8s_master_url -> k8s_api._retrieve_k8s_master_url * handlers.k8s_conductor.Handler.k8s_api -> k8s_api.create_k8s_api Change-Id: Ia10625f35667fd9309dc3627e2f2d31455dd19be Partially-Implements: blueprint magnum-smart-bay-scale-down --- magnum/conductor/handlers/bay_conductor.py | 10 +- magnum/conductor/handlers/docker_conductor.py | 3 +- magnum/conductor/handlers/k8s_conductor.py | 111 +------ magnum/conductor/k8s_api.py | 74 +++++ magnum/conductor/utils.py | 37 +++ magnum/opts.py | 2 +- .../conductor/handlers/test_bay_conductor.py | 9 - .../conductor/handlers/test_k8s_conductor.py | 278 +++--------------- magnum/tests/unit/conductor/test_k8s_api.py | 79 +++++ magnum/tests/unit/conductor/test_utils.py | 66 +++++ 10 files changed, 320 insertions(+), 349 deletions(-) create mode 100644 magnum/conductor/k8s_api.py create mode 100644 magnum/conductor/utils.py create mode 100644 magnum/tests/unit/conductor/test_k8s_api.py create mode 100644 magnum/tests/unit/conductor/test_utils.py diff --git a/magnum/conductor/handlers/bay_conductor.py b/magnum/conductor/handlers/bay_conductor.py index f7831fc5f5..76eeadf6f7 100644 --- a/magnum/conductor/handlers/bay_conductor.py +++ b/magnum/conductor/handlers/bay_conductor.py @@ -22,6 +22,7 @@ from magnum.common import clients from magnum.common import exception from magnum.common import short_id from magnum.conductor.template_definition import TemplateDefinition as TDef +from magnum.conductor import utils as conductor_utils from magnum.i18n import _ from magnum.i18n import _LE from magnum.i18n import _LI @@ -54,13 +55,8 @@ cfg.CONF.register_opts(bay_heat_opts, group='bay_heat') LOG = logging.getLogger(__name__) -def _get_baymodel(context, bay): - baymodel = objects.BayModel.get_by_uuid(context, bay.baymodel_id) - return baymodel - - def _extract_template_definition(context, bay): - baymodel = _get_baymodel(context, bay) + baymodel = conductor_utils.retrieve_baymodel(context, bay) cluster_distro = baymodel.cluster_distro cluster_coe = baymodel.coe definition = TDef.get_template_definition('vm', cluster_distro, @@ -108,7 +104,7 @@ def _update_stack(context, osc, bay): def _update_stack_outputs(context, stack, bay): - baymodel = _get_baymodel(context, bay) + baymodel = conductor_utils.retrieve_baymodel(context, bay) cluster_distro = baymodel.cluster_distro cluster_coe = baymodel.coe definition = TDef.get_template_definition('vm', cluster_distro, diff --git a/magnum/conductor/handlers/docker_conductor.py b/magnum/conductor/handlers/docker_conductor.py index 1882fc22ea..89b5ee7e0a 100644 --- a/magnum/conductor/handlers/docker_conductor.py +++ b/magnum/conductor/handlers/docker_conductor.py @@ -21,6 +21,7 @@ from magnum.common import docker_utils from magnum.common import exception from magnum.common import utils from magnum.conductor.handlers.common import docker_client +from magnum.conductor import utils as conductor_utils from magnum.i18n import _LE from magnum import objects from magnum.objects import container as obj_container @@ -100,7 +101,7 @@ class Handler(object): @classmethod def _docker_for_container(cls, context, container): - bay = objects.Bay.get_by_uuid(context, container.bay_uuid) + bay = conductor_utils.retrieve_bay(context, container) return cls._docker_for_bay(bay) @classmethod diff --git a/magnum/conductor/handlers/k8s_conductor.py b/magnum/conductor/handlers/k8s_conductor.py index 2b65a268ba..7efd652dd8 100644 --- a/magnum/conductor/handlers/k8s_conductor.py +++ b/magnum/conductor/handlers/k8s_conductor.py @@ -12,15 +12,12 @@ """Magnum Kubernetes RPC handler.""" -from oslo_config import cfg from oslo_log import log as logging -from magnum.common import clients from magnum.common import exception from magnum.common import k8s_manifest -from magnum.common.pythonk8sclient.client import ApivbetaApi -from magnum.common.pythonk8sclient.client import swagger -from magnum.i18n import _ +from magnum.conductor import k8s_api as k8s +from magnum.conductor import utils as conductor_utils from magnum import objects import ast @@ -29,58 +26,6 @@ from six.moves.urllib import error LOG = logging.getLogger(__name__) -kubernetes_opts = [ - cfg.StrOpt('k8s_protocol', - default='http', - help=_('Default protocol of k8s master endpoint ' - '(http or https).')), - cfg.IntOpt('k8s_port', - default=8080, - help=_('Default port of the k8s master endpoint.')), -] - -cfg.CONF.register_opts(kubernetes_opts, group='kubernetes') - - -def _retrieve_bay(context, obj): - bay_uuid = obj.bay_uuid - return objects.Bay.get_by_uuid(context, bay_uuid) - - -def _retrieve_baymodel(context, obj): - return objects.BayModel.get_by_uuid(context, obj.baymodel_id) - - -def _retrieve_k8s_master_url(context, obj): - apiserver_port = cfg.CONF.kubernetes.k8s_port - if hasattr(obj, 'bay_uuid'): - obj = _retrieve_bay(context, obj) - - baymodel = _retrieve_baymodel(context, obj) - if baymodel.apiserver_port is not None: - apiserver_port = baymodel.apiserver_port - - params = { - 'k8s_protocol': cfg.CONF.kubernetes.k8s_protocol, - 'k8s_port': apiserver_port, - 'api_address': obj.api_address - } - return "%(k8s_protocol)s://%(api_address)s:%(k8s_port)s" % params - - -def _object_has_stack(context, obj): - osc = clients.OpenStackClients(context) - if hasattr(obj, 'bay_uuid'): - obj = _retrieve_bay(context, obj) - - stack = osc.heat().stacks.get(obj.stack_id) - if (stack.stack_status == 'DELETE_COMPLETE' or - stack.stack_status == 'DELETE_IN_PROGRESS'): - return False - else: - return True - - class Handler(object): """These are the backend operations. They are executed by the backend service. API calls via AMQP (within the ReST API) trigger the @@ -90,30 +35,10 @@ class Handler(object): def __init__(self): super(Handler, self).__init__() - self._k8s_api = None - - @property - def k8s_api(self): - return self._k8s_api - - @k8s_api.setter - def k8s_api(self, k8s_master_url): - """Creates connection with Kubernetes master and - creates ApivbetaApi instance to call Kubernetes - APIs. - - :param k8s_master_url: Kubernetes master URL - """ - # build a connection with Kubernetes master - client = swagger.ApiClient(k8s_master_url) - - # create the ApivbetaApi class instance - self._k8s_api = ApivbetaApi.ApivbetaApi(client) def service_create(self, context, service): LOG.debug("service_create") - k8s_master_url = _retrieve_k8s_master_url(context, service) - self.k8s_api = k8s_master_url + self.k8s_api = k8s.create_k8s_api(context, service) manifest = k8s_manifest.parse(service.manifest) try: self.k8s_api.createService(body=manifest, @@ -127,8 +52,7 @@ class Handler(object): def service_update(self, context, service): LOG.debug("service_update %s", service.uuid) - k8s_master_url = _retrieve_k8s_master_url(context, service) - self.k8s_api = k8s_master_url + self.k8s_api = k8s.create_k8s_api(context, service) manifest = k8s_manifest.parse(service.manifest) try: self.k8s_api.replaceService(name=service.name, @@ -145,9 +69,8 @@ class Handler(object): def service_delete(self, context, uuid): LOG.debug("service_delete %s", uuid) service = objects.Service.get_by_uuid(context, uuid) - k8s_master_url = _retrieve_k8s_master_url(context, service) - self.k8s_api = k8s_master_url - if _object_has_stack(context, service): + self.k8s_api = k8s.create_k8s_api(context, service) + if conductor_utils.object_has_stack(context, service): try: self.k8s_api.deleteService(name=service.name, namespaces='default') @@ -164,8 +87,7 @@ class Handler(object): # Pod Operations def pod_create(self, context, pod): LOG.debug("pod_create") - k8s_master_url = _retrieve_k8s_master_url(context, pod) - self.k8s_api = k8s_master_url + self.k8s_api = k8s.create_k8s_api(context, pod) manifest = k8s_manifest.parse(pod.manifest) try: resp = self.k8s_api.createPod(body=manifest, namespaces='default') @@ -187,8 +109,7 @@ class Handler(object): def pod_update(self, context, pod): LOG.debug("pod_update %s", pod.uuid) - k8s_master_url = _retrieve_k8s_master_url(context, pod) - self.k8s_api = k8s_master_url + self.k8s_api = k8s.create_k8s_api(context, pod) manifest = k8s_manifest.parse(pod.manifest) try: self.k8s_api.replacePod(name=pod.name, body=manifest, @@ -204,9 +125,8 @@ class Handler(object): def pod_delete(self, context, uuid): LOG.debug("pod_delete %s", uuid) pod = objects.Pod.get_by_uuid(context, uuid) - k8s_master_url = _retrieve_k8s_master_url(context, pod) - self.k8s_api = k8s_master_url - if _object_has_stack(context, pod): + self.k8s_api = k8s.create_k8s_api(context, pod) + if conductor_utils.object_has_stack(context, pod): try: self.k8s_api.deletePod(name=pod.name, namespaces='default') @@ -223,8 +143,7 @@ class Handler(object): # Replication Controller Operations def rc_create(self, context, rc): LOG.debug("rc_create") - k8s_master_url = _retrieve_k8s_master_url(context, rc) - self.k8s_api = k8s_master_url + self.k8s_api = k8s.create_k8s_api(context, rc) manifest = k8s_manifest.parse(rc.manifest) try: self.k8s_api.createReplicationController(body=manifest, @@ -238,8 +157,7 @@ class Handler(object): def rc_update(self, context, rc): LOG.debug("rc_update %s", rc.uuid) - k8s_master_url = _retrieve_k8s_master_url(context, rc) - self.k8s_api = k8s_master_url + self.k8s_api = k8s.create_k8s_api(context, rc) manifest = k8s_manifest.parse(rc.manifest) try: self.k8s_api.replaceReplicationController(name=rc.name, @@ -256,9 +174,8 @@ class Handler(object): def rc_delete(self, context, uuid): LOG.debug("rc_delete %s", uuid) rc = objects.ReplicationController.get_by_uuid(context, uuid) - k8s_master_url = _retrieve_k8s_master_url(context, rc) - self.k8s_api = k8s_master_url - if _object_has_stack(context, rc): + self.k8s_api = k8s.create_k8s_api(context, rc) + if conductor_utils.object_has_stack(context, rc): try: self.k8s_api.deleteReplicationController(name=rc.name, namespaces='default') diff --git a/magnum/conductor/k8s_api.py b/magnum/conductor/k8s_api.py new file mode 100644 index 0000000000..5b2af3d3aa --- /dev/null +++ b/magnum/conductor/k8s_api.py @@ -0,0 +1,74 @@ +# Copyright 2015 Huawei Technologies Co.,LTD. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from oslo_config import cfg + +from magnum.common.pythonk8sclient.client import ApivbetaApi +from magnum.common.pythonk8sclient.client import swagger +from magnum.conductor import utils +from magnum.i18n import _ + + +kubernetes_opts = [ + cfg.StrOpt('k8s_protocol', + default='http', + help=_('Default protocol of k8s master endpoint ' + '(http or https).')), + cfg.IntOpt('k8s_port', + default=8080, + help=_('Default port of the k8s master endpoint.')), +] + +cfg.CONF.register_opts(kubernetes_opts, group='kubernetes') + + +class K8sAPI(ApivbetaApi.ApivbetaApi): + + def __init__(self, context, obj): + # retrieve the URL of the k8s API endpoint + k8s_master_url = self._retrieve_k8s_master_url(context, obj) + + # build a connection with Kubernetes master + client = swagger.ApiClient(k8s_master_url) + + super(K8sAPI, self).__init__(client) + + @staticmethod + def _retrieve_k8s_master_url(context, obj): + apiserver_port = cfg.CONF.kubernetes.k8s_port + if hasattr(obj, 'bay_uuid'): + obj = utils.retrieve_bay(context, obj) + + baymodel = utils.retrieve_baymodel(context, obj) + if baymodel.apiserver_port is not None: + apiserver_port = baymodel.apiserver_port + + params = { + 'k8s_protocol': cfg.CONF.kubernetes.k8s_protocol, + 'k8s_port': apiserver_port, + 'api_address': obj.api_address + } + return "%(k8s_protocol)s://%(api_address)s:%(k8s_port)s" % params + + +def create_k8s_api(context, obj): + """Create a kubernetes API client + + Creates connection with Kubernetes master and creates ApivbetaApi instance + to call Kubernetes APIs. + + :param context: The security context + :param obj: A bay or a k8s object (Pod, Service, ReplicationController) + """ + return K8sAPI(context, obj) diff --git a/magnum/conductor/utils.py b/magnum/conductor/utils.py new file mode 100644 index 0000000000..faef25753a --- /dev/null +++ b/magnum/conductor/utils.py @@ -0,0 +1,37 @@ +# Copyright 2015 Huawei Technologies Co.,LTD. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from magnum.common import clients +from magnum import objects + + +def retrieve_bay(context, obj): + return objects.Bay.get_by_uuid(context, obj.bay_uuid) + + +def retrieve_baymodel(context, bay): + return objects.BayModel.get_by_uuid(context, bay.baymodel_id) + + +def object_has_stack(context, obj): + osc = clients.OpenStackClients(context) + if hasattr(obj, 'bay_uuid'): + obj = retrieve_bay(context, obj) + + stack = osc.heat().stacks.get(obj.stack_id) + if (stack.stack_status == 'DELETE_COMPLETE' or + stack.stack_status == 'DELETE_IN_PROGRESS'): + return False + + return True diff --git a/magnum/opts.py b/magnum/opts.py index a01ef1f55b..b00c542242 100644 --- a/magnum/opts.py +++ b/magnum/opts.py @@ -44,5 +44,5 @@ def list_opts(): ('heat_client', magnum.common.clients.heat_client_opts), ('bay_heat', magnum.conductor.handlers.bay_conductor.bay_heat_opts), ('kubernetes', - magnum.conductor.handlers.k8s_conductor.kubernetes_opts), + magnum.conductor.k8s_api.kubernetes_opts), ] diff --git a/magnum/tests/unit/conductor/handlers/test_bay_conductor.py b/magnum/tests/unit/conductor/handlers/test_bay_conductor.py index 51dac0d9ca..99c421030f 100644 --- a/magnum/tests/unit/conductor/handlers/test_bay_conductor.py +++ b/magnum/tests/unit/conductor/handlers/test_bay_conductor.py @@ -54,15 +54,6 @@ class TestBayConductorWithK8s(base.TestCase): 'node_count': 1, } - @patch('magnum.objects.BayModel.get_by_uuid') - def test_get_baymodel(self, mock_objects_baymodel_get_by_uuid): - baymodel = objects.BayModel(self.context, **self.baymodel_dict) - mock_objects_baymodel_get_by_uuid.return_value = baymodel - bay = objects.Bay(self.context, **self.bay_dict) - - fetched_baymodel = bay_conductor._get_baymodel(self.context, bay) - self.assertEqual(baymodel, fetched_baymodel) - @patch('magnum.objects.BayModel.get_by_uuid') def test_extract_template_definition( self, diff --git a/magnum/tests/unit/conductor/handlers/test_k8s_conductor.py b/magnum/tests/unit/conductor/handlers/test_k8s_conductor.py index 4d1f8d39c6..34af91c0e8 100644 --- a/magnum/tests/unit/conductor/handlers/test_k8s_conductor.py +++ b/magnum/tests/unit/conductor/handlers/test_k8s_conductor.py @@ -50,89 +50,12 @@ class TestK8sConductor(base.TestCase): def mock_baymodel(self): return objects.BayModel({}) - @patch('magnum.objects.Bay.get_by_uuid') - def test_retrieve_bay_from_pod(self, - mock_bay_get_by_uuid): - expected_context = 'context' - expected_bay_uuid = 'bay_uuid' - - pod = self.mock_pod() - pod.bay_uuid = expected_bay_uuid - - k8s_conductor._retrieve_bay(expected_context, pod) - - mock_bay_get_by_uuid.assert_called_once_with(expected_context, - expected_bay_uuid) - - @patch('magnum.objects.Bay.get_by_uuid') - @patch('magnum.objects.BayModel.get_by_uuid') - def test_retrieve_k8s_master_url_from_pod( - self, - mock_baymodel_get_by_uuid, - mock_bay_get_by_uuid): - expected_context = 'context' - expected_api_address = 'api_address' - expected_baymodel_id = 'e74c40e0-d825-11e2-a28f-0800200c9a61' - expected_apiserver_port = 9999 - - pod = self.mock_pod() - pod.bay_uuid = 'bay_uuid' - bay = self.mock_bay() - bay.api_address = expected_api_address - bay.baymodel_id = expected_baymodel_id - baymodel = self.mock_baymodel() - baymodel.apiserver_port = expected_apiserver_port - - mock_bay_get_by_uuid.return_value = bay - mock_baymodel_get_by_uuid.return_value = baymodel - - actual_api_address = k8s_conductor._retrieve_k8s_master_url( - expected_context, pod) - self.assertEqual("http://%s:%d" % (expected_api_address, - expected_apiserver_port), - actual_api_address) - - @patch('magnum.objects.Bay.get_by_uuid') - @patch('magnum.objects.BayModel.get_by_uuid') - def test_retrieve_k8s_master_url_without_baymodel_apiserver_port( - self, - mock_baymodel_get_by_uuid, - mock_bay_get_by_uuid): - expected_context = 'context' - expected_api_address = 'api_address' - expected_baymodel_id = 'e74c40e0-d825-11e2-a28f-0800200c9a61' - expected_protocol = cfg.CONF.kubernetes.k8s_protocol - expected_apiserver_port = cfg.CONF.kubernetes.k8s_port - - resource = self.mock_pod() - resource.bay_uuid = 'bay_uuid' - bay = self.mock_bay() - bay.api_address = expected_api_address - bay.baymodel_id = expected_baymodel_id - baymodel = self.mock_baymodel() - baymodel.apiserver_port = None - - mock_bay_get_by_uuid.return_value = bay - mock_baymodel_get_by_uuid.return_value = baymodel - - actual_api_address = k8s_conductor._retrieve_k8s_master_url( - expected_context, resource) - self.assertEqual("%s://%s:%d" % (expected_protocol, - expected_api_address, - expected_apiserver_port), - actual_api_address) - - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') - def test_pod_create_with_success(self, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + def test_pod_create_with_success(self): expected_pod = self.mock_pod() expected_pod.create = mock.MagicMock() expected_pod.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: return_value = mock.MagicMock() return_value.status = mock.MagicMock() return_value.status.phase = 'Pending' @@ -145,18 +68,13 @@ class TestK8sConductor(base.TestCase): self.assertEqual('10.0.0.3', expected_pod.host) expected_pod.create.assert_called_once_with(self.context) - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') @patch('ast.literal_eval') - def test_pod_create_with_fail(self, mock_literal_eval, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + def test_pod_create_with_fail(self, mock_literal_eval): expected_pod = self.mock_pod() expected_pod.create = mock.MagicMock() expected_pod.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=500) mock_kube_api.return_value.createPod.side_effect = err @@ -167,19 +85,14 @@ class TestK8sConductor(base.TestCase): self.assertEqual('failed', expected_pod.status) expected_pod.create.assert_called_once_with(self.context) - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') @patch('ast.literal_eval') def test_pod_create_fail_on_existing_pod( - self, mock_literal_eval, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + self, mock_literal_eval): expected_pod = self.mock_pod() expected_pod.create = mock.MagicMock() expected_pod.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=409) mock_kube_api.return_value.createPod.side_effect = err @@ -190,24 +103,18 @@ class TestK8sConductor(base.TestCase): self.assertEqual('failed', expected_pod.status) self.assertFalse(expected_pod.create.called) - @patch('magnum.conductor.handlers.k8s_conductor._object_has_stack') - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') + @patch('magnum.conductor.utils.object_has_stack') @patch('magnum.objects.Pod.get_by_uuid') def test_pod_delete_with_success(self, mock_pod_get_by_uuid, - mock_retrieve_k8s_master_url, mock_object_has_stack): - expected_master_url = 'api_address' mock_pod = mock.MagicMock() mock_pod.name = 'test-pod' mock_pod.uuid = 'test-uuid' mock_pod_get_by_uuid.return_value = mock_pod - mock_retrieve_k8s_master_url.return_value = expected_master_url mock_object_has_stack.return_value = True - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: - + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: self.kube_handler.pod_delete(self.context, mock_pod.uuid) mock_kube_api.return_value.deletePod.assert_called_once_with( @@ -215,24 +122,19 @@ class TestK8sConductor(base.TestCase): namespaces='default') mock_pod.destroy.assert_called_once_with(self.context) - @patch('magnum.conductor.handlers.k8s_conductor._object_has_stack') - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') + @patch('magnum.conductor.utils.object_has_stack') @patch('magnum.objects.Pod.get_by_uuid') @patch('ast.literal_eval') def test_pod_delete_with_failure(self, mock_literal_eval, mock_pod_get_by_uuid, - mock_retrieve_k8s_master_url, mock_object_has_stack): - expected_master_url = 'api_address' mock_pod = mock.MagicMock() mock_pod.name = 'test-pod' mock_pod.uuid = 'test-uuid' mock_pod_get_by_uuid.return_value = mock_pod - mock_retrieve_k8s_master_url.return_value = expected_master_url mock_object_has_stack.return_value = True - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=500) mock_kube_api.return_value.deletePod.side_effect = err @@ -246,25 +148,20 @@ class TestK8sConductor(base.TestCase): namespaces='default') self.assertFalse(mock_pod.destroy.called) - @patch('magnum.conductor.handlers.k8s_conductor._object_has_stack') - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') + @patch('magnum.conductor.utils.object_has_stack') @patch('magnum.objects.Pod.get_by_uuid') @patch('ast.literal_eval') def test_pod_delete_succeeds_when_not_found( self, mock_literal_eval, mock_pod_get_by_uuid, - mock_retrieve_k8s_master_url, mock_object_has_stack): - expected_master_url = 'api_address' mock_pod = mock.MagicMock() mock_pod.name = 'test-pod' mock_pod.uuid = 'test-uuid' mock_pod_get_by_uuid.return_value = mock_pod - mock_retrieve_k8s_master_url.return_value = expected_master_url mock_object_has_stack.return_value = True - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=404) mock_kube_api.return_value.deletePod.side_effect = err @@ -276,37 +173,26 @@ class TestK8sConductor(base.TestCase): name=mock_pod.name, namespaces='default') mock_pod.destroy.assert_called_once_with(self.context) - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') - def test_service_create_with_success(self, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + def test_service_create_with_success(self): expected_service = self.mock_service() expected_service.create = mock.MagicMock() manifest = {"key": "value"} expected_service.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: - + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: self.kube_handler.service_create(self.context, expected_service) mock_kube_api.return_value.createService.assert_called_once_with( body=manifest, namespaces='default') expected_service.create.assert_called_once_with(self.context) - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') @patch('ast.literal_eval') - def test_service_create_with_failure(self, mock_literal_eval, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + def test_service_create_with_failure(self, mock_literal_eval): expected_service = self.mock_service() expected_service.create = mock.MagicMock() manifest = {"key": "value"} expected_service.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=404) mock_kube_api.return_value.createService.side_effect = err @@ -319,50 +205,39 @@ class TestK8sConductor(base.TestCase): body=manifest, namespaces='default') self.assertFalse(expected_service.create.called) - @patch('magnum.conductor.handlers.k8s_conductor._object_has_stack') - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') + @patch('magnum.conductor.utils.object_has_stack') @patch('magnum.objects.Service.get_by_uuid') def test_service_delete_with_success( self, mock_service_get_by_uuid, - mock_retrieve_k8s_master_url, mock_object_has_stack): - expected_master_url = 'api_address' mock_service = mock.MagicMock() mock_service.name = 'test-service' mock_service.uuid = 'test-uuid' mock_service_get_by_uuid.return_value = mock_service - mock_retrieve_k8s_master_url.return_value = expected_master_url mock_object_has_stack.return_value = True - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: - + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: self.kube_handler.service_delete(self.context, mock_service.uuid) mock_kube_api.return_value.deleteService.assert_called_once_with( name=mock_service.name, namespaces='default') mock_service.destroy.assert_called_once_with(self.context) - @patch('magnum.conductor.handlers.k8s_conductor._object_has_stack') - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') + @patch('magnum.conductor.utils.object_has_stack') @patch('magnum.objects.Service.get_by_uuid') @patch('ast.literal_eval') def test_service_delete_with_failure( self, mock_literal_eval, mock_service_get_by_uuid, - mock_retrieve_k8s_master_url, mock_object_has_stack): - expected_master_url = 'api_address' mock_service = mock.MagicMock() mock_service.name = 'test-service' mock_service.uuid = 'test-uuid' mock_service_get_by_uuid.return_value = mock_service - mock_retrieve_k8s_master_url.return_value = expected_master_url mock_object_has_stack.return_value = True - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=500) mock_kube_api.return_value.deleteService.side_effect = err @@ -376,25 +251,20 @@ class TestK8sConductor(base.TestCase): name=mock_service.name, namespaces='default') self.assertFalse(mock_service.destroy.called) - @patch('magnum.conductor.handlers.k8s_conductor._object_has_stack') - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') + @patch('magnum.conductor.utils.object_has_stack') @patch('magnum.objects.Service.get_by_uuid') @patch('ast.literal_eval') def test_service_delete_succeeds_when_not_found( self, mock_literal_eval, mock_service_get_by_uuid, - mock_retrieve_k8s_master_url, mock_object_has_stack): - expected_master_url = 'api_address' mock_service = mock.MagicMock() mock_service.name = 'test-service' mock_service.uuid = 'test-uuid' mock_service_get_by_uuid.return_value = mock_service - mock_retrieve_k8s_master_url.return_value = expected_master_url mock_object_has_stack.return_value = True - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=404) mock_kube_api.return_value.deleteService.side_effect = err @@ -406,36 +276,25 @@ class TestK8sConductor(base.TestCase): name=mock_service.name, namespaces='default') mock_service.destroy.assert_called_once_with(self.context) - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') - def test_rc_create_with_success(self, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + def test_rc_create_with_success(self): expected_rc = self.mock_rc() expected_rc.create = mock.MagicMock() manifest = {"key": "value"} expected_rc.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: - + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: self.kube_handler.rc_create({}, expected_rc) (mock_kube_api.return_value.createReplicationController .assert_called_once_with(body=manifest, namespaces='default')) - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') @patch('ast.literal_eval') - def test_rc_create_with_failure(self, mock_literal_eval, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + def test_rc_create_with_failure(self, mock_literal_eval): expected_rc = self.mock_rc() expected_rc.create = mock.MagicMock() manifest = {"key": "value"} expected_rc.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=500) (mock_kube_api.return_value.createReplicationController.side_effect @@ -449,24 +308,18 @@ class TestK8sConductor(base.TestCase): .assert_called_once_with(body=manifest, namespaces='default')) self.assertFalse(expected_rc.create.called) - @patch('magnum.conductor.handlers.k8s_conductor._object_has_stack') - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') + @patch('magnum.conductor.utils.object_has_stack') @patch('magnum.objects.ReplicationController.get_by_uuid') def test_rc_delete_with_success(self, mock_rc_get_by_uuid, - mock_retrieve_k8s_master_url, mock_object_has_stack): - expected_master_url = 'api_address' mock_rc = mock.MagicMock() mock_rc.name = 'test-rc' mock_rc.uuid = 'test-uuid' mock_rc_get_by_uuid.return_value = mock_rc - mock_retrieve_k8s_master_url.return_value = expected_master_url mock_object_has_stack.return_value = True - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: - + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: self.kube_handler.rc_delete(self.context, mock_rc.uuid) (mock_kube_api.return_value.deleteReplicationController @@ -474,24 +327,19 @@ class TestK8sConductor(base.TestCase): namespaces='default')) mock_rc.destroy.assert_called_once_with(self.context) - @patch('magnum.conductor.handlers.k8s_conductor._object_has_stack') - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') + @patch('magnum.conductor.utils.object_has_stack') @patch('magnum.objects.ReplicationController.get_by_uuid') @patch('ast.literal_eval') def test_rc_delete_with_failure(self, mock_literal_eval, mock_rc_get_by_uuid, - mock_retrieve_k8s_master_url, mock_object_has_stack): - expected_master_url = 'api_address' mock_rc = mock.MagicMock() mock_rc.name = 'test-rc' mock_rc.uuid = 'test-uuid' mock_rc_get_by_uuid.return_value = mock_rc - mock_retrieve_k8s_master_url.return_value = expected_master_url mock_object_has_stack.return_value = True - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=500) (mock_kube_api.return_value.deleteReplicationController.side_effect @@ -507,25 +355,20 @@ class TestK8sConductor(base.TestCase): namespaces='default')) self.assertFalse(mock_rc.destroy.called) - @patch('magnum.conductor.handlers.k8s_conductor._object_has_stack') - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') + @patch('magnum.conductor.utils.object_has_stack') @patch('magnum.objects.ReplicationController.get_by_uuid') @patch('ast.literal_eval') def test_rc_delete_succeeds_when_not_found( self, mock_literal_eval, mock_rc_get_by_uuid, - mock_retrieve_k8s_master_url, mock_object_has_stack): - expected_master_url = 'api_address' mock_rc = mock.MagicMock() mock_rc.name = 'test-rc' mock_rc.uuid = 'test-uuid' mock_rc_get_by_uuid.return_value = mock_rc - mock_retrieve_k8s_master_url.return_value = expected_master_url mock_object_has_stack.return_value = True - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=404) (mock_kube_api.return_value.deleteReplicationController.side_effect @@ -539,10 +382,7 @@ class TestK8sConductor(base.TestCase): namespaces='default')) self.assertTrue(mock_rc.destroy.called) - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') - def test_rc_update_with_success(self, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + def test_rc_update_with_success(self): expected_rc = self.mock_rc() expected_rc.uuid = 'test-uuid' expected_rc.name = 'test-name' @@ -551,10 +391,7 @@ class TestK8sConductor(base.TestCase): manifest = {"key": "value"} expected_rc.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: - + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: self.kube_handler.rc_update(self.context, expected_rc) (mock_kube_api.return_value.replaceReplicationController .assert_called_once_with(body=manifest, name=expected_rc.name, @@ -562,11 +399,8 @@ class TestK8sConductor(base.TestCase): expected_rc.refresh.assert_called_once_with(self.context) expected_rc.save.assert_called_once_with() - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') @patch('ast.literal_eval') - def test_rc_update_with_failure(self, mock_literal_eval, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + def test_rc_update_with_failure(self, mock_literal_eval): expected_rc = self.mock_rc() expected_rc.uuid = 'test-uuid' expected_rc.name = 'test-name' @@ -574,9 +408,7 @@ class TestK8sConductor(base.TestCase): manifest = {"key": "value"} expected_rc.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=404) (mock_kube_api.return_value.replaceReplicationController @@ -591,10 +423,7 @@ class TestK8sConductor(base.TestCase): namespaces='default')) self.assertFalse(expected_rc.update.called) - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') - def test_service_update_with_success(self, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + def test_service_update_with_success(self): expected_service = self.mock_service() expected_service.uuid = 'test-uuid' expected_service.name = 'test-name' @@ -603,10 +432,7 @@ class TestK8sConductor(base.TestCase): manifest = {"key": "value"} expected_service.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: - + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: self.kube_handler.service_update(self.context, expected_service) mock_kube_api.return_value.replaceService.assert_called_once_with( body=manifest, name=expected_service.name, @@ -614,20 +440,15 @@ class TestK8sConductor(base.TestCase): expected_service.refresh.assert_called_once_with(self.context) expected_service.save.assert_called_once_with() - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') @patch('ast.literal_eval') - def test_service_update_with_failure(self, mock_literal_eval, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + def test_service_update_with_failure(self, mock_literal_eval): expected_service = self.mock_service() expected_service.uuid = 'test-uuid' expected_service.name = 'test-name' expected_service.refresh = mock.MagicMock() manifest = {"key": "value"} expected_service.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=404) mock_kube_api.return_value.replaceService.side_effect = err @@ -641,10 +462,7 @@ class TestK8sConductor(base.TestCase): namespaces='default') self.assertFalse(expected_service.refresh.called) - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') - def test_pod_update_with_success(self, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + def test_pod_update_with_success(self): expected_pod = self.mock_pod() expected_pod.uuid = 'test-uuid' expected_pod.name = 'test-name' @@ -653,10 +471,7 @@ class TestK8sConductor(base.TestCase): manifest = {"key": "value"} expected_pod.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: - + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: self.kube_handler.pod_update(self.context, expected_pod) mock_kube_api.return_value.replacePod.assert_called_once_with( body=manifest, name=expected_pod.name, @@ -664,11 +479,8 @@ class TestK8sConductor(base.TestCase): expected_pod.refresh.assert_called_once_with(self.context) expected_pod.save.assert_called_once_with() - @patch('magnum.conductor.handlers.k8s_conductor._retrieve_k8s_master_url') @patch('ast.literal_eval') - def test_pod_update_with_failure(self, mock_literal_eval, - mock_retrieve_k8s_master_url): - expected_master_url = 'api_address' + def test_pod_update_with_failure(self, mock_literal_eval): expected_pod = self.mock_pod() expected_pod.uuid = 'test-uuid' expected_pod.name = 'test-name' @@ -676,9 +488,7 @@ class TestK8sConductor(base.TestCase): manifest = {"key": "value"} expected_pod.manifest = '{"key": "value"}' - mock_retrieve_k8s_master_url.return_value = expected_master_url - with patch('magnum.conductor.handlers.k8s_conductor.Handler.k8s_api', - new_callable=mock.PropertyMock) as mock_kube_api: + with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api: err = error.HTTPError(url='fake', msg='fake', hdrs='fake', fp=mock.MagicMock(), code=404) mock_kube_api.return_value.replacePod.side_effect = err diff --git a/magnum/tests/unit/conductor/test_k8s_api.py b/magnum/tests/unit/conductor/test_k8s_api.py new file mode 100644 index 0000000000..71c3c0a935 --- /dev/null +++ b/magnum/tests/unit/conductor/test_k8s_api.py @@ -0,0 +1,79 @@ +# Copyright 2015 Huawei Technologies Co.,LTD. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from mock import patch +from oslo_config import cfg + +from magnum.conductor import k8s_api +from magnum import objects +from magnum.tests import base + + +class TestK8sAPI(base.TestCase): + + def _test_retrieve_k8s_master_url(self, mock_baymodel_get_by_uuid, + mock_bay_get_by_uuid, + apiserver_port=None): + expected_context = 'context' + expected_api_address = 'api_address' + expected_baymodel_id = 'e74c40e0-d825-11e2-a28f-0800200c9a61' + expected_protocol = cfg.CONF.kubernetes.k8s_protocol + if apiserver_port is None: + expected_apiserver_port = cfg.CONF.kubernetes.k8s_port + else: + expected_apiserver_port = apiserver_port + + resource = objects.Pod({}) + resource.bay_uuid = 'bay_uuid' + bay = objects.Bay({}) + bay.api_address = expected_api_address + bay.baymodel_id = expected_baymodel_id + baymodel = objects.BayModel({}) + baymodel.apiserver_port = apiserver_port + + mock_bay_get_by_uuid.return_value = bay + mock_baymodel_get_by_uuid.return_value = baymodel + + actual_api_address = k8s_api.K8sAPI._retrieve_k8s_master_url( + expected_context, resource) + self.assertEqual("%s://%s:%d" % (expected_protocol, + expected_api_address, + expected_apiserver_port), + actual_api_address) + + @patch('magnum.objects.Bay.get_by_uuid') + @patch('magnum.objects.BayModel.get_by_uuid') + def test_retrieve_k8s_master_url( + self, + mock_baymodel_get_by_uuid, + mock_bay_get_by_uuid): + self._test_retrieve_k8s_master_url(mock_baymodel_get_by_uuid, + mock_bay_get_by_uuid, + apiserver_port=9999) + + @patch('magnum.objects.Bay.get_by_uuid') + @patch('magnum.objects.BayModel.get_by_uuid') + def test_retrieve_k8s_master_url_without_baymodel_apiserver_port( + self, + mock_baymodel_get_by_uuid, + mock_bay_get_by_uuid): + self._test_retrieve_k8s_master_url(mock_baymodel_get_by_uuid, + mock_bay_get_by_uuid) + + @patch('magnum.conductor.k8s_api.K8sAPI') + def test_create_k8s_api(self, mock_k8s_api_cls): + context = 'context' + bay = objects.Bay({}) + k8s_api.create_k8s_api(context, bay) + mock_k8s_api_cls.assert_called_once_with(context, bay) diff --git a/magnum/tests/unit/conductor/test_utils.py b/magnum/tests/unit/conductor/test_utils.py new file mode 100644 index 0000000000..00a9845e70 --- /dev/null +++ b/magnum/tests/unit/conductor/test_utils.py @@ -0,0 +1,66 @@ +# Copyright 2015 Huawei Technologies Co.,LTD. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from mock import patch + +from magnum.conductor import utils +from magnum import objects +from magnum.tests import base + + +class TestConductorUtils(base.TestCase): + + def _test_retrieve_bay(self, obj, mock_bay_get_by_uuid): + expected_context = 'context' + expected_bay_uuid = 'bay_uuid' + + obj.bay_uuid = expected_bay_uuid + utils.retrieve_bay(expected_context, obj) + mock_bay_get_by_uuid.assert_called_once_with(expected_context, + expected_bay_uuid) + + @patch('magnum.objects.Bay.get_by_uuid') + def test_retrieve_bay_from_pod(self, + mock_bay_get_by_uuid): + self._test_retrieve_bay(objects.Pod({}), mock_bay_get_by_uuid) + + @patch('magnum.objects.Bay.get_by_uuid') + def test_retrieve_bay_from_service(self, + mock_bay_get_by_uuid): + self._test_retrieve_bay(objects.Service({}), mock_bay_get_by_uuid) + + @patch('magnum.objects.Bay.get_by_uuid') + def test_retrieve_bay_from_rc(self, + mock_bay_get_by_uuid): + self._test_retrieve_bay(objects.ReplicationController({}), + mock_bay_get_by_uuid) + + @patch('magnum.objects.Bay.get_by_uuid') + def test_retrieve_bay_from_container(self, + mock_bay_get_by_uuid): + self._test_retrieve_bay(objects.Container({}), mock_bay_get_by_uuid) + + @patch('magnum.objects.BayModel.get_by_uuid') + def test_retrieve_baymodel(self, mock_baymodel_get_by_uuid): + expected_context = 'context' + expected_baymodel_uuid = 'baymodel_uuid' + + bay = objects.Bay({}) + bay.baymodel_id = expected_baymodel_uuid + + utils.retrieve_baymodel(expected_context, bay) + + mock_baymodel_get_by_uuid.assert_called_once_with( + expected_context, + expected_baymodel_uuid)