diff --git a/magnum/api/controllers/v1/pod.py b/magnum/api/controllers/v1/pod.py index 2a41c6042a..478b3c5261 100644 --- a/magnum/api/controllers/v1/pod.py +++ b/magnum/api/controllers/v1/pod.py @@ -91,6 +91,9 @@ class Pod(base.APIBase): pod_definition_url = wtypes.text """URL for pod file to create the pod""" + pod_data = wtypes.text + """Data for pod to create the pod""" + links = wsme.wsattr([link.Link], readonly=True) """A list containing a self link and associated pod links""" @@ -308,6 +311,8 @@ class PodsController(rest.RestController): # ignore pod_definition_url as it was used for create pod if field == 'pod_definition_url': continue + if field == 'pod_data': + continue try: patch_val = getattr(pod, field) except AttributeError: diff --git a/magnum/conductor/handlers/kube.py b/magnum/conductor/handlers/kube.py index e7041b4f27..fe397ab609 100644 --- a/magnum/conductor/handlers/kube.py +++ b/magnum/conductor/handlers/kube.py @@ -12,12 +12,47 @@ """Magnum Kubernetes RPC handler.""" +from oslo.config import cfg + from magnum.conductor.handlers.common import kube_utils +from magnum import objects +from magnum.openstack.common._i18n import _ from magnum.openstack.common import log as logging + 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 _retrive_bay(ctxt, obj): + bay_uuid = obj.bay_uuid + return objects.Bay.get_by_uuid(ctxt, bay_uuid) + + +def _retrive_k8s_master_url(ctxt, obj): + if hasattr(obj, 'bay_uuid'): + obj = _retrive_bay(ctxt, obj) + + params = { + 'k8s_protocol': cfg.CONF.kubernetes.k8s_protocol, + 'k8s_port': cfg.CONF.kubernetes.k8s_port, + 'master_address': obj.master_address + } + return "%(k8s_protocol)s://%(master_address)s:%(k8s_port)s" % params + + 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 @@ -75,12 +110,21 @@ class Handler(object): # Pod Operations def pod_create(self, ctxt, pod): LOG.debug("pod_create") + k8s_master_url = _retrive_k8s_master_url(ctxt, pod) # trigger a kubectl command - status = self.kube_cli.pod_create(pod) + status = self.kube_cli.pod_create(k8s_master_url, pod) + # TODO(yuanying): Is this correct location of updating status? if not status: - return None + pod.status = 'failed' + else: + pod.status = 'pending' # call the pod object to persist in db - pod.create(ctxt) + # TODO(yuanying): parse pod file and, + # - extract pod name and set it + # - extract pod labels and set it + # TODO(yuanying): Should kube_utils support definition_url? + # When do we get pod labels and name? + pod.create() return pod def pod_update(self, ctxt, pod): diff --git a/magnum/objects/pod.py b/magnum/objects/pod.py index e5f2aeb4e9..a93ac20da7 100644 --- a/magnum/objects/pod.py +++ b/magnum/objects/pod.py @@ -36,6 +36,7 @@ class Pod(base.MagnumObject): 'labels': obj_utils.dict_or_none, 'status': obj_utils.str_or_none, 'pod_definition_url': obj_utils.str_or_none, + 'pod_data': obj_utils.str_or_none, } @staticmethod @@ -45,6 +46,8 @@ class Pod(base.MagnumObject): # ignore pod_definition_url as it was used for create pod if field == 'pod_definition_url': continue + if field == 'pod_data': + continue pod[field] = db_pod[field] pod.obj_reset_changes() diff --git a/magnum/tests/conductor/handlers/test_kube.py b/magnum/tests/conductor/handlers/test_kube.py new file mode 100644 index 0000000000..bd775a580d --- /dev/null +++ b/magnum/tests/conductor/handlers/test_kube.py @@ -0,0 +1,91 @@ +# Copyright 2014 NEC Corporation. All rights reserved. +# +# 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.conductor.handlers import kube +from magnum import objects +from magnum.tests import base + +import mock +from mock import patch + + +class TestKube(base.BaseTestCase): + def setUp(self): + super(TestKube, self).setUp() + self.kube_handler = kube.Handler() + + def mock_pod(self): + return objects.Pod({}) + + def mock_bay(self): + return objects.Bay({}) + + @patch('magnum.objects.Bay.get_by_uuid') + def test_retrive_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 + + kube._retrive_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') + def test_retrive_k8s_master_url_from_pod(self, + mock_bay_get_by_uuid): + expected_context = 'context' + expected_master_address = 'master_address' + + pod = self.mock_pod() + pod.bay_uuid = 'bay_uuid' + bay = self.mock_bay() + bay.master_address = expected_master_address + mock_bay_get_by_uuid.return_value = bay + + actual_master_address = kube._retrive_k8s_master_url(expected_context, + pod) + self.assertEqual("http://%s:8080" % expected_master_address, + actual_master_address) + + @patch('magnum.conductor.handlers.kube._retrive_k8s_master_url') + def test_pod_create_with_success(self, + mock_retrive_k8s_master_url): + expected_master_url = 'master_address' + expected_pod = self.mock_pod() + expected_pod.create = mock.MagicMock() + + mock_retrive_k8s_master_url.return_value = expected_master_url + with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli: + mock_kube_cli.pod_create.return_value = True + + self.kube_handler.pod_create({}, expected_pod) + self.assertEqual('pending', expected_pod.status) + + @patch('magnum.conductor.handlers.kube._retrive_k8s_master_url') + def test_pod_create_with_fail(self, + mock_retrive_k8s_master_url): + expected_master_url = 'master_address' + expected_pod = self.mock_pod() + expected_pod.create = mock.MagicMock() + + mock_retrive_k8s_master_url.return_value = expected_master_url + with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli: + mock_kube_cli.pod_create.return_value = False + + self.kube_handler.pod_create({}, expected_pod) + self.assertEqual('failed', expected_pod.status)