Added support of Kubernetes API in magnum.
This patch removes the use of Kubernetes CLI i.e kubectl from magnum and adds the support of Kubernetes API. Change-Id: Ibe7354abba962dde6855225471f468f6a19a41ff Partially-Implements: blueprint python-k8sclient
This commit is contained in:
parent
027a0a3cb9
commit
52c532560a
|
@ -458,3 +458,9 @@ class ImageNotAuthorized(MagnumException):
|
|||
|
||||
class OSDistroFieldNotFound(ResourceNotFound):
|
||||
message = _("Image %(image_id)s doesn't contain os-distro field.")
|
||||
|
||||
|
||||
class KubernetesAPIFailed(MagnumException):
|
||||
def __init__(self, message=None, **kwargs):
|
||||
self.__class__.code = kwargs.get('code')
|
||||
super(KubernetesAPIFailed, self).__init__(message, **kwargs)
|
||||
|
|
|
@ -139,7 +139,7 @@ class ApiClient(object):
|
|||
"""
|
||||
if isinstance(obj, type(None)):
|
||||
return None
|
||||
elif isinstance(obj, (str, int, long, float, bool, file)):
|
||||
elif isinstance(obj, (unicode, str, int, long, float, bool, file)):
|
||||
return obj
|
||||
elif isinstance(obj, list):
|
||||
return [ApiClient.sanitizeForSerialization(subObj) for subObj in obj]
|
||||
|
|
|
@ -16,12 +16,15 @@ from oslo_config import cfg
|
|||
|
||||
from magnum.common import clients
|
||||
from magnum.common import exception
|
||||
from magnum.conductor.handlers.common import kube_utils
|
||||
from magnum.common import k8s_manifest
|
||||
from magnum.common.pythonk8sclient.client import ApivbetaApi
|
||||
from magnum.common.pythonk8sclient.client import swagger
|
||||
from magnum import objects
|
||||
from magnum.openstack.common._i18n import _
|
||||
from magnum.openstack.common._i18n import _LW
|
||||
from magnum.openstack.common import log as logging
|
||||
|
||||
import ast
|
||||
from six.moves.urllib import error
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -89,15 +92,38 @@ class Handler(object):
|
|||
|
||||
def __init__(self):
|
||||
super(Handler, self).__init__()
|
||||
self.kube_cli = kube_utils.KubeClient()
|
||||
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
|
||||
"""
|
||||
if self._k8s_api is None:
|
||||
# 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)
|
||||
# trigger a kubectl command
|
||||
status = self.kube_cli.service_create(k8s_master_url, service)
|
||||
if not status:
|
||||
return None
|
||||
self.k8s_api = k8s_master_url
|
||||
manifest = k8s_manifest.parse(service.manifest)
|
||||
try:
|
||||
self.k8s_api.createService(body=manifest,
|
||||
namespaces='default')
|
||||
except error.HTTPError as err:
|
||||
message = ast.literal_eval(err.read())['message']
|
||||
raise exception.KubernetesAPIFailed(code=err.code, message=message)
|
||||
# call the service object to persist in db
|
||||
service.create(context)
|
||||
return service
|
||||
|
@ -105,10 +131,15 @@ 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)
|
||||
# trigger a kubectl command
|
||||
status = self.kube_cli.service_update(k8s_master_url, service)
|
||||
if not status:
|
||||
return None
|
||||
self.k8s_api = k8s_master_url
|
||||
manifest = k8s_manifest.parse(service.manifest)
|
||||
try:
|
||||
self.k8s_api.replaceService(name=service.name,
|
||||
body=manifest,
|
||||
namespaces='default')
|
||||
except error.HTTPError as err:
|
||||
message = ast.literal_eval(err.read())['message']
|
||||
raise exception.KubernetesAPIFailed(code=err.code, message=message)
|
||||
# call the service object to persist in db
|
||||
service.refresh(context)
|
||||
service.save()
|
||||
|
@ -118,11 +149,18 @@ class Handler(object):
|
|||
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):
|
||||
# trigger a kubectl command
|
||||
status = self.kube_cli.service_delete(k8s_master_url, service.name)
|
||||
if not status:
|
||||
return None
|
||||
try:
|
||||
self.k8s_api.deleteService(name=service.name,
|
||||
namespaces='default')
|
||||
except error.HTTPError as err:
|
||||
if err.code == 404:
|
||||
pass
|
||||
else:
|
||||
message = ast.literal_eval(err.read())['message']
|
||||
raise exception.KubernetesAPIFailed(code=err.code,
|
||||
message=message)
|
||||
# call the service object to persist in db
|
||||
service.destroy(context)
|
||||
|
||||
|
@ -130,13 +168,17 @@ class Handler(object):
|
|||
def pod_create(self, context, pod):
|
||||
LOG.debug("pod_create")
|
||||
k8s_master_url = _retrieve_k8s_master_url(context, pod)
|
||||
# trigger a kubectl command
|
||||
status = self.kube_cli.pod_create(k8s_master_url, pod)
|
||||
# TODO(yuanying): Is this correct location of updating status?
|
||||
if not status:
|
||||
self.k8s_api = k8s_master_url
|
||||
manifest = k8s_manifest.parse(pod.manifest)
|
||||
try:
|
||||
resp = self.k8s_api.createPod(body=manifest, namespaces='default')
|
||||
except error.HTTPError as err:
|
||||
pod.status = 'failed'
|
||||
else:
|
||||
pod.status = 'pending'
|
||||
if err.code != 409:
|
||||
pod.create(context)
|
||||
message = ast.literal_eval(err.read())['message']
|
||||
raise exception.KubernetesAPIFailed(code=err.code, message=message)
|
||||
pod.status = resp['status']['phase']
|
||||
# call the pod object to persist in db
|
||||
# TODO(yuanying): parse pod file and,
|
||||
# - extract pod name and set it
|
||||
|
@ -149,10 +191,14 @@ 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)
|
||||
# trigger a kubectl command
|
||||
status = self.kube_cli.pod_update(k8s_master_url, pod)
|
||||
if not status:
|
||||
return None
|
||||
self.k8s_api = k8s_master_url
|
||||
manifest = k8s_manifest.parse(pod.manifest)
|
||||
try:
|
||||
self.k8s_api.replacePod(name=pod.name, body=manifest,
|
||||
namespaces='default')
|
||||
except error.HTTPError as err:
|
||||
message = ast.literal_eval(err.read())['message']
|
||||
raise exception.KubernetesAPIFailed(code=err.code, message=message)
|
||||
# call the pod object to persist in db
|
||||
pod.refresh(context)
|
||||
pod.save()
|
||||
|
@ -163,16 +209,18 @@ class Handler(object):
|
|||
# trigger a kubectl command
|
||||
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):
|
||||
try:
|
||||
status = self.kube_cli.pod_delete(k8s_master_url, pod.name)
|
||||
|
||||
if not status:
|
||||
return None
|
||||
except exception.PodNotFound:
|
||||
msg = _LW("Pod '%s' not found on bay, "
|
||||
"continuing to delete from database.")
|
||||
LOG.warn(msg, uuid)
|
||||
self.k8s_api.deletePod(name=pod.name,
|
||||
namespaces='default')
|
||||
except error.HTTPError as err:
|
||||
if err.code == 404:
|
||||
pass
|
||||
else:
|
||||
message = ast.literal_eval(err.read())['message']
|
||||
raise exception.KubernetesAPIFailed(code=err.code,
|
||||
message=message)
|
||||
# call the pod object to persist in db
|
||||
pod.destroy(context)
|
||||
|
||||
|
@ -180,10 +228,14 @@ class Handler(object):
|
|||
def rc_create(self, context, rc):
|
||||
LOG.debug("rc_create")
|
||||
k8s_master_url = _retrieve_k8s_master_url(context, rc)
|
||||
# trigger a kubectl command
|
||||
status = self.kube_cli.rc_create(k8s_master_url, rc)
|
||||
if not status:
|
||||
return None
|
||||
self.k8s_api = k8s_master_url
|
||||
manifest = k8s_manifest.parse(rc.manifest)
|
||||
try:
|
||||
self.k8s_api.createReplicationController(body=manifest,
|
||||
namespaces='default')
|
||||
except error.HTTPError as err:
|
||||
message = ast.literal_eval(err.read())['message']
|
||||
raise exception.KubernetesAPIFailed(code=err.code, message=message)
|
||||
# call the rc object to persist in db
|
||||
rc.create(context)
|
||||
return rc
|
||||
|
@ -191,10 +243,15 @@ 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)
|
||||
# trigger a kubectl command
|
||||
status = self.kube_cli.rc_update(k8s_master_url, rc)
|
||||
if not status:
|
||||
return None
|
||||
self.k8s_api = k8s_master_url
|
||||
manifest = k8s_manifest.parse(rc.manifest)
|
||||
try:
|
||||
self.k8s_api.replaceReplicationController(name=rc.name,
|
||||
body=manifest,
|
||||
namespaces='default')
|
||||
except error.HTTPError as err:
|
||||
message = ast.literal_eval(err.read())['message']
|
||||
raise exception.KubernetesAPIFailed(code=err.code, message=message)
|
||||
# call the rc object to persist in db
|
||||
rc.refresh(context)
|
||||
rc.save()
|
||||
|
@ -204,10 +261,17 @@ class Handler(object):
|
|||
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):
|
||||
# trigger a kubectl command
|
||||
status = self.kube_cli.rc_delete(k8s_master_url, rc.name)
|
||||
if not status:
|
||||
return None
|
||||
try:
|
||||
self.k8s_api.deleteReplicationController(name=rc.name,
|
||||
namespaces='default')
|
||||
except error.HTTPError as err:
|
||||
if err.code == 404:
|
||||
pass
|
||||
else:
|
||||
message = ast.literal_eval(err.read())['message']
|
||||
raise exception.KubernetesAPIFailed(code=err.code,
|
||||
message=message)
|
||||
# call the rc object to persist in db
|
||||
rc.destroy(context)
|
||||
|
|
|
@ -21,6 +21,7 @@ from magnum.tests import base
|
|||
|
||||
import mock
|
||||
from mock import patch
|
||||
from six.moves.urllib import error
|
||||
|
||||
|
||||
cfg.CONF.import_opt('k8s_protocol', 'magnum.conductor.handlers.kube',
|
||||
|
@ -125,30 +126,59 @@ class TestKube(base.TestCase):
|
|||
expected_master_url = 'api_address'
|
||||
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.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.pod_create.return_value = True
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
mock_kube_api.createPod.return_value = {'status':
|
||||
{'phase': 'Pending'}}
|
||||
|
||||
self.kube_handler.pod_create(self.context, expected_pod)
|
||||
self.assertEqual('pending', expected_pod.status)
|
||||
self.assertEqual('Pending', expected_pod.status)
|
||||
expected_pod.create.assert_called_once_with(self.context)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
def test_pod_create_with_fail(self,
|
||||
@patch('ast.literal_eval')
|
||||
def test_pod_create_with_fail(self, mock_literal_eval,
|
||||
mock_retrieve_k8s_master_url):
|
||||
expected_master_url = 'api_address'
|
||||
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.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.pod_create.return_value = False
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=500)
|
||||
mock_kube_api.createPod.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.kube_handler.pod_create(self.context, expected_pod)
|
||||
self.assertRaises(exception.KubernetesAPIFailed, self.kube_handler.
|
||||
pod_create, self.context, expected_pod)
|
||||
self.assertEqual('failed', expected_pod.status)
|
||||
expected_pod.create.assert_called_once_with(self.context)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._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'
|
||||
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.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=409)
|
||||
mock_kube_api.createPod.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.assertRaises(exception.KubernetesAPIFailed, self.kube_handler.
|
||||
pod_create, self.context, expected_pod)
|
||||
self.assertEqual('failed', expected_pod.status)
|
||||
self.assertFalse(expected_pod.create.called)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._object_has_stack')
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
@patch('magnum.objects.Pod.get_by_uuid')
|
||||
|
@ -164,19 +194,19 @@ class TestKube(base.TestCase):
|
|||
|
||||
mock_retrieve_k8s_master_url.return_value = expected_master_url
|
||||
mock_object_has_stack.return_value = True
|
||||
with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.pod_delete.return_value = True
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
|
||||
self.kube_handler.pod_delete(self.context, mock_pod.uuid)
|
||||
|
||||
mock_kube_cli.pod_delete.assert_called_once_with(
|
||||
expected_master_url, mock_pod.name)
|
||||
mock_kube_api.deletePod.assert_called_once_with(name=mock_pod.name,
|
||||
namespaces='default')
|
||||
mock_pod.destroy.assert_called_once_with(self.context)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._object_has_stack')
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
@patch('magnum.objects.Pod.get_by_uuid')
|
||||
def test_pod_delete_with_failure(self,
|
||||
@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):
|
||||
|
@ -188,19 +218,24 @@ class TestKube(base.TestCase):
|
|||
|
||||
mock_retrieve_k8s_master_url.return_value = expected_master_url
|
||||
mock_object_has_stack.return_value = True
|
||||
with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.pod_delete.return_value = False
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=500)
|
||||
mock_kube_api.deletePod.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.kube_handler.pod_delete(self.context, mock_pod.uuid)
|
||||
|
||||
mock_kube_cli.pod_delete.assert_called_once_with(
|
||||
expected_master_url, mock_pod.name)
|
||||
self.assertRaises(exception.KubernetesAPIFailed,
|
||||
self.kube_handler.pod_delete,
|
||||
self.context, mock_pod.uuid)
|
||||
mock_kube_api.deletePod.assert_called_once_with(name=mock_pod.name,
|
||||
namespaces='default')
|
||||
self.assertFalse(mock_pod.destroy.called)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._object_has_stack')
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
@patch('magnum.objects.Pod.get_by_uuid')
|
||||
def test_pod_delete_succeeds_when_not_found(self,
|
||||
@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):
|
||||
|
@ -212,13 +247,16 @@ class TestKube(base.TestCase):
|
|||
|
||||
mock_retrieve_k8s_master_url.return_value = expected_master_url
|
||||
mock_object_has_stack.return_value = True
|
||||
with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.pod_delete.side_effect = exception.PodNotFound()
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=404)
|
||||
mock_kube_api.deletePod.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.kube_handler.pod_delete(self.context, mock_pod.uuid)
|
||||
|
||||
mock_kube_cli.pod_delete.assert_called_once_with(
|
||||
expected_master_url, mock_pod.name)
|
||||
mock_kube_api.deletePod.assert_called_once_with(
|
||||
name=mock_pod.name, namespaces='default')
|
||||
mock_pod.destroy.assert_called_once_with(self.context)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
|
@ -227,30 +265,39 @@ class TestKube(base.TestCase):
|
|||
expected_master_url = 'api_address'
|
||||
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.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.service_create.return_value = True
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
|
||||
self.kube_handler.service_create(self.context, expected_service)
|
||||
mock_kube_cli.service_create.assert_called_once_with(
|
||||
expected_master_url, expected_service)
|
||||
mock_kube_api.createService.assert_called_once_with(
|
||||
body=manifest, namespaces='default')
|
||||
expected_service.create.assert_called_once_with(self.context)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
def test_service_create_with_failure(self,
|
||||
@patch('ast.literal_eval')
|
||||
def test_service_create_with_failure(self, mock_literal_eval,
|
||||
mock_retrieve_k8s_master_url):
|
||||
expected_master_url = 'api_address'
|
||||
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.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.service_create.return_value = False
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=404)
|
||||
mock_kube_api.createService.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.kube_handler.service_create(self.context, expected_service)
|
||||
mock_kube_cli.service_create.assert_called_once_with(
|
||||
expected_master_url, expected_service)
|
||||
self.assertRaises(exception.KubernetesAPIFailed,
|
||||
self.kube_handler.service_create,
|
||||
self.context, expected_service)
|
||||
mock_kube_api.createService.assert_called_once_with(
|
||||
body=manifest, namespaces='default')
|
||||
self.assertFalse(expected_service.create.called)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._object_has_stack')
|
||||
|
@ -268,19 +315,19 @@ class TestKube(base.TestCase):
|
|||
|
||||
mock_retrieve_k8s_master_url.return_value = expected_master_url
|
||||
mock_object_has_stack.return_value = True
|
||||
with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.service_delete.return_value = True
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
|
||||
self.kube_handler.service_delete(self.context, mock_service.uuid)
|
||||
|
||||
mock_kube_cli.service_delete.assert_called_once_with(
|
||||
expected_master_url, mock_service.name)
|
||||
mock_kube_api.deleteService.assert_called_once_with(
|
||||
name=mock_service.name, namespaces='default')
|
||||
mock_service.destroy.assert_called_once_with(self.context)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._object_has_stack')
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
@patch('magnum.objects.Service.get_by_uuid')
|
||||
def test_service_delete_with_failure(self,
|
||||
@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):
|
||||
|
@ -292,14 +339,47 @@ class TestKube(base.TestCase):
|
|||
|
||||
mock_retrieve_k8s_master_url.return_value = expected_master_url
|
||||
mock_object_has_stack.return_value = True
|
||||
with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.service_delete.return_value = False
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=500)
|
||||
mock_kube_api.deleteService.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.assertRaises(exception.KubernetesAPIFailed,
|
||||
self.kube_handler.service_delete,
|
||||
self.context, mock_service.uuid)
|
||||
|
||||
mock_kube_api.deleteService.assert_called_once_with(
|
||||
name=mock_service.name, namespaces='default')
|
||||
self.assertFalse(mock_service.destroy.called)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._object_has_stack')
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
@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.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=404)
|
||||
mock_kube_api.deleteService.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.kube_handler.service_delete(self.context, mock_service.uuid)
|
||||
|
||||
mock_kube_cli.service_delete.assert_called_once_with(
|
||||
expected_master_url, mock_service.name)
|
||||
self.assertFalse(mock_service.destroy.called)
|
||||
mock_kube_api.deleteService.assert_called_once_with(
|
||||
name=mock_service.name, namespaces='default')
|
||||
mock_service.destroy.assert_called_once_with(self.context)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
def test_rc_create_with_success(self,
|
||||
|
@ -307,29 +387,38 @@ class TestKube(base.TestCase):
|
|||
expected_master_url = 'api_address'
|
||||
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.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.rc_create.return_value = True
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
|
||||
self.kube_handler.rc_create({}, expected_rc)
|
||||
mock_kube_cli.rc_create.assert_called_once_with(
|
||||
expected_master_url, expected_rc)
|
||||
mock_kube_api.createReplicationController.assert_called_once_with(
|
||||
body=manifest, namespaces='default')
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
def test_rc_create_with_failure(self,
|
||||
@patch('ast.literal_eval')
|
||||
def test_rc_create_with_failure(self, mock_literal_eval,
|
||||
mock_retrieve_k8s_master_url):
|
||||
expected_master_url = 'api_address'
|
||||
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.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.rc_create.return_value = False
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=500)
|
||||
mock_kube_api.createReplicationController.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.kube_handler.rc_create(self.context, expected_rc)
|
||||
mock_kube_cli.rc_create.assert_called_once_with(
|
||||
expected_master_url, expected_rc)
|
||||
self.assertRaises(exception.KubernetesAPIFailed,
|
||||
self.kube_handler.rc_create,
|
||||
self.context, expected_rc)
|
||||
mock_kube_api.createReplicationController.assert_called_once_with(
|
||||
body=manifest, namespaces='default')
|
||||
self.assertFalse(expected_rc.create.called)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._object_has_stack')
|
||||
|
@ -347,19 +436,19 @@ class TestKube(base.TestCase):
|
|||
|
||||
mock_retrieve_k8s_master_url.return_value = expected_master_url
|
||||
mock_object_has_stack.return_value = True
|
||||
with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.rc_delete.return_value = True
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
|
||||
self.kube_handler.rc_delete(self.context, mock_rc.uuid)
|
||||
|
||||
mock_kube_cli.rc_delete.assert_called_once_with(
|
||||
expected_master_url, mock_rc.name)
|
||||
mock_kube_api.deleteReplicationController.assert_called_once_with(
|
||||
name=mock_rc.name, namespaces='default')
|
||||
mock_rc.destroy.assert_called_once_with(self.context)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._object_has_stack')
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
@patch('magnum.objects.ReplicationController.get_by_uuid')
|
||||
def test_rc_delete_with_failure(self,
|
||||
@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):
|
||||
|
@ -371,14 +460,47 @@ class TestKube(base.TestCase):
|
|||
|
||||
mock_retrieve_k8s_master_url.return_value = expected_master_url
|
||||
mock_object_has_stack.return_value = True
|
||||
with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.rc_delete.return_value = False
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=500)
|
||||
mock_kube_api.deleteReplicationController.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.assertRaises(exception.KubernetesAPIFailed,
|
||||
self.kube_handler.rc_delete,
|
||||
self.context, mock_rc.uuid)
|
||||
|
||||
mock_kube_api.deleteReplicationController.assert_called_once_with(
|
||||
name=mock_rc.name, namespaces='default')
|
||||
self.assertFalse(mock_rc.destroy.called)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._object_has_stack')
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
@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.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=404)
|
||||
mock_kube_api.deleteReplicationController.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.kube_handler.rc_delete(self.context, mock_rc.uuid)
|
||||
|
||||
mock_kube_cli.rc_delete.assert_called_once_with(
|
||||
expected_master_url, mock_rc.name)
|
||||
self.assertFalse(mock_rc.destroy.called)
|
||||
mock_kube_api.deleteReplicationController.assert_called_once_with(
|
||||
name=mock_rc.name, namespaces='default')
|
||||
self.assertTrue(mock_rc.destroy.called)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
def test_rc_update_with_success(self,
|
||||
|
@ -386,34 +508,46 @@ class TestKube(base.TestCase):
|
|||
expected_master_url = 'api_address'
|
||||
expected_rc = self.mock_rc()
|
||||
expected_rc.uuid = 'test-uuid'
|
||||
expected_rc.name = 'test-name'
|
||||
expected_rc.refresh = mock.MagicMock()
|
||||
expected_rc.save = mock.MagicMock()
|
||||
manifest = {"key": "value"}
|
||||
expected_rc.manifest = '{"key": "value"}'
|
||||
|
||||
mock_retrieve_k8s_master_url.return_value = expected_master_url
|
||||
with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.rc_update.return_value = True
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
|
||||
self.kube_handler.rc_update(self.context, expected_rc)
|
||||
mock_kube_cli.rc_update.assert_called_once_with(
|
||||
expected_master_url, expected_rc)
|
||||
mock_kube_api.replaceReplicationController.assert_called_once_with(
|
||||
body=manifest, name=expected_rc.name, namespaces='default')
|
||||
expected_rc.refresh.assert_called_once_with(self.context)
|
||||
expected_rc.save.assert_called_once_with()
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
def test_rc_update_with_failure(self,
|
||||
@patch('ast.literal_eval')
|
||||
def test_rc_update_with_failure(self, mock_literal_eval,
|
||||
mock_retrieve_k8s_master_url):
|
||||
expected_master_url = 'api_address'
|
||||
expected_rc = self.mock_rc()
|
||||
expected_rc.uuid = 'test-uuid'
|
||||
expected_rc.name = 'test-name'
|
||||
expected_rc.update = mock.MagicMock()
|
||||
manifest = {"key": "value"}
|
||||
expected_rc.manifest = '{"key": "value"}'
|
||||
|
||||
mock_retrieve_k8s_master_url.return_value = expected_master_url
|
||||
with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.rc_update.return_value = False
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=404)
|
||||
mock_kube_api.replaceReplicationController.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.kube_handler.rc_update(self.context, expected_rc)
|
||||
mock_kube_cli.rc_update.assert_called_once_with(
|
||||
expected_master_url, expected_rc)
|
||||
self.assertRaises(exception.KubernetesAPIFailed,
|
||||
self.kube_handler.rc_update,
|
||||
self.context, expected_rc)
|
||||
mock_kube_api.replaceReplicationController.assert_called_once_with(
|
||||
body=manifest, name=expected_rc.name,
|
||||
namespaces='default')
|
||||
self.assertFalse(expected_rc.update.called)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
|
@ -422,34 +556,46 @@ class TestKube(base.TestCase):
|
|||
expected_master_url = 'api_address'
|
||||
expected_service = self.mock_service()
|
||||
expected_service.uuid = 'test-uuid'
|
||||
expected_service.name = 'test-name'
|
||||
expected_service.refresh = mock.MagicMock()
|
||||
expected_service.save = mock.MagicMock()
|
||||
manifest = {"key": "value"}
|
||||
expected_service.manifest = '{"key": "value"}'
|
||||
|
||||
mock_retrieve_k8s_master_url.return_value = expected_master_url
|
||||
with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.service_update.return_value = True
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
|
||||
self.kube_handler.service_update(self.context, expected_service)
|
||||
mock_kube_cli.service_update.assert_called_once_with(
|
||||
expected_master_url, expected_service)
|
||||
mock_kube_api.replaceService.assert_called_once_with(
|
||||
body=manifest, name=expected_service.name,
|
||||
namespaces='default')
|
||||
expected_service.refresh.assert_called_once_with(self.context)
|
||||
expected_service.save.assert_called_once_with()
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
def test_service_update_with_failure(self,
|
||||
@patch('ast.literal_eval')
|
||||
def test_service_update_with_failure(self, mock_literal_eval,
|
||||
mock_retrieve_k8s_master_url):
|
||||
expected_master_url = 'api_address'
|
||||
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.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.service_update.return_value = False
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=404)
|
||||
mock_kube_api.replaceService.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.kube_handler.service_update(self.context, expected_service)
|
||||
mock_kube_cli.service_update.assert_called_once_with(
|
||||
expected_master_url, expected_service)
|
||||
self.assertRaises(exception.KubernetesAPIFailed,
|
||||
self.kube_handler.service_update,
|
||||
self.context, expected_service)
|
||||
mock_kube_api.replaceService.assert_called_once_with(
|
||||
body=manifest, name=expected_service.name,
|
||||
namespaces='default')
|
||||
self.assertFalse(expected_service.refresh.called)
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
|
@ -458,32 +604,45 @@ class TestKube(base.TestCase):
|
|||
expected_master_url = 'api_address'
|
||||
expected_pod = self.mock_pod()
|
||||
expected_pod.uuid = 'test-uuid'
|
||||
expected_pod.name = 'test-name'
|
||||
expected_pod.refresh = mock.MagicMock()
|
||||
expected_pod.save = mock.MagicMock()
|
||||
manifest = {"key": "value"}
|
||||
expected_pod.manifest = '{"key": "value"}'
|
||||
|
||||
mock_retrieve_k8s_master_url.return_value = expected_master_url
|
||||
with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.pod_update.return_value = True
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
|
||||
self.kube_handler.pod_update(self.context, expected_pod)
|
||||
mock_kube_cli.pod_update.assert_called_once_with(
|
||||
expected_master_url, expected_pod)
|
||||
mock_kube_api.replacePod.assert_called_once_with(
|
||||
body=manifest, name=expected_pod.name,
|
||||
namespaces='default')
|
||||
expected_pod.refresh.assert_called_once_with(self.context)
|
||||
expected_pod.save.assert_called_once_with()
|
||||
|
||||
@patch('magnum.conductor.handlers.kube._retrieve_k8s_master_url')
|
||||
def test_pod_update_with_failure(self,
|
||||
@patch('ast.literal_eval')
|
||||
def test_pod_update_with_failure(self, mock_literal_eval,
|
||||
mock_retrieve_k8s_master_url):
|
||||
expected_master_url = 'api_address'
|
||||
expected_pod = self.mock_pod()
|
||||
expected_pod.uuid = 'test-uuid'
|
||||
expected_pod.name = 'test-name'
|
||||
expected_pod.refresh = mock.MagicMock()
|
||||
manifest = {"key": "value"}
|
||||
expected_pod.manifest = '{"key": "value"}'
|
||||
|
||||
mock_retrieve_k8s_master_url.return_value = expected_master_url
|
||||
with patch.object(self.kube_handler, 'kube_cli') as mock_kube_cli:
|
||||
mock_kube_cli.pod_update.return_value = False
|
||||
with patch.object(self.kube_handler, '_k8s_api') as mock_kube_api:
|
||||
err = error.HTTPError(url='fake', msg='fake', hdrs='fake',
|
||||
fp=mock.MagicMock(), code=404)
|
||||
mock_kube_api.replacePod.side_effect = err
|
||||
mock_literal_eval.return_value = {'message': 'error'}
|
||||
|
||||
self.kube_handler.pod_update(self.context, expected_pod)
|
||||
mock_kube_cli.pod_update.assert_called_once_with(
|
||||
expected_master_url, expected_pod)
|
||||
self.assertRaises(exception.KubernetesAPIFailed,
|
||||
self.kube_handler.pod_update,
|
||||
self.context, expected_pod)
|
||||
mock_kube_api.replacePod.assert_called_once_with(
|
||||
body=manifest, name=expected_pod.name,
|
||||
namespaces='default')
|
||||
self.assertFalse(expected_pod.refresh.called)
|
||||
|
|
Loading…
Reference in New Issue