Merge "Migrate to Kubernetes Release 1"

This commit is contained in:
Jenkins 2015-09-22 05:02:45 +00:00 committed by Gerrit Code Review
commit df51585d22
16 changed files with 242 additions and 260 deletions

View File

@ -18,7 +18,7 @@ if is_service_enabled m-api m-cond; then
# add image to glance
if [[ "$ENABLED_SERVICES" =~ 'm-api' ]]; then
MANGUM_GUEST_IMAGE_URL=${MANGUM_GUEST_IMAGE_URL:-"https://fedorapeople.org/groups/magnum/fedora-21-atomic-3.qcow2"}
MANGUM_GUEST_IMAGE_URL=${MANGUM_GUEST_IMAGE_URL:-"https://fedorapeople.org/groups/magnum/fedora-21-atomic-5.qcow2"}
IMAGE_URLS+=",${MANGUM_GUEST_IMAGE_URL}"
fi

View File

@ -7,5 +7,5 @@ user = admin
tenant = admin
pass = secrete
[magnum]
image_id = fedora-21-atomic-3
image_id = fedora-21-atomic-5
nic_id = public

View File

@ -19,6 +19,7 @@ Includes decorator for re-raising Magnum-type exceptions.
"""
import functools
import json
import sys
import uuid
@ -464,8 +465,15 @@ class OSDistroFieldNotFound(ResourceNotFound):
class KubernetesAPIFailed(MagnumException):
def __init__(self, message=None, **kwargs):
self.__class__.code = kwargs.get('code')
def __init__(self, message=None, err=None, **kwargs):
if err:
if err.body:
message = json.loads(err.body)['message']
else:
message = err.reason
self.__class__.code = err.status
else:
self.__class__.code = kwargs.get('code')
super(KubernetesAPIFailed, self).__init__(message, **kwargs)

View File

@ -187,7 +187,7 @@ class ApiClient(object):
"""
if isinstance(obj, type(None)):
return None
elif isinstance(obj, (str, int, float, bool, tuple)):
elif isinstance(obj, (unicode, str, int, float, bool, tuple, file)):
return obj
elif isinstance(obj, list):
return [self.sanitize_for_serialization(sub_obj)

View File

@ -16,12 +16,11 @@ from oslo_log import log as logging
from magnum.common import exception
from magnum.common import k8s_manifest
from magnum.common.pythonk8sclient.swagger_client import rest
from magnum.conductor import k8s_api as k8s
from magnum.conductor import utils as conductor_utils
from magnum import objects
import ast
from six.moves.urllib import error
LOG = logging.getLogger(__name__)
@ -41,11 +40,10 @@ class Handler(object):
self.k8s_api = k8s.create_k8s_api(context, service)
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)
self.k8s_api.create_namespaced_service(body=manifest,
namespace='default')
except rest.ApiException as err:
raise exception.KubernetesAPIFailed(err=err)
# call the service object to persist in db
service.create(context)
return service
@ -55,12 +53,11 @@ class Handler(object):
self.k8s_api = k8s.create_k8s_api(context, service)
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)
self.k8s_api.replace_namespaced_service(name=str(service.name),
body=manifest,
namespace='default')
except rest.ApiException as err:
raise exception.KubernetesAPIFailed(err=err)
# call the service object to persist in db
service.refresh(context)
service.save()
@ -72,15 +69,13 @@ class Handler(object):
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')
except error.HTTPError as err:
if err.code == 404:
self.k8s_api.delete_namespaced_service(name=str(service.name),
namespace='default')
except rest.ApiException as err:
if err.status == 404:
pass
else:
message = ast.literal_eval(err.read())['message']
raise exception.KubernetesAPIFailed(code=err.code,
message=message)
raise exception.KubernetesAPIFailed(err=err)
# call the service object to persist in db
service.destroy(context)
@ -90,15 +85,15 @@ class Handler(object):
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')
except error.HTTPError as err:
resp = self.k8s_api.create_namespaced_pod(body=manifest,
namespace='default')
except rest.ApiException as err:
pod.status = 'failed'
if err.code != 409:
if err.status != 409:
pod.create(context)
message = ast.literal_eval(err.read())['message']
raise exception.KubernetesAPIFailed(code=err.code, message=message)
raise exception.KubernetesAPIFailed(err=err)
pod.status = resp.status.phase
pod.host = resp.spec.host
pod.host = resp.spec.node_name
# call the pod object to persist in db
# TODO(yuanying): parse pod file and,
# - extract pod name and set it
@ -112,11 +107,11 @@ class Handler(object):
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,
namespaces='default')
except error.HTTPError as err:
message = ast.literal_eval(err.read())['message']
raise exception.KubernetesAPIFailed(code=err.code, message=message)
self.k8s_api.replace_namespaced_pod(name=str(pod.name),
body=manifest,
namespace='default')
except rest.ApiException as err:
raise exception.KubernetesAPIFailed(err=err)
# call the pod object to persist in db
pod.refresh(context)
pod.save()
@ -128,15 +123,13 @@ class Handler(object):
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')
except error.HTTPError as err:
if err.code == 404:
self.k8s_api.delete_namespaced_pod(name=str(pod.name), body={},
namespace='default')
except rest.ApiException as err:
if err.status == 404:
pass
else:
message = ast.literal_eval(err.read())['message']
raise exception.KubernetesAPIFailed(code=err.code,
message=message)
raise exception.KubernetesAPIFailed(err=err)
# call the pod object to persist in db
pod.destroy(context)
@ -146,11 +139,10 @@ class Handler(object):
self.k8s_api = k8s.create_k8s_api(context, rc)
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)
self.k8s_api.create_namespaced_replication_controller(
body=manifest, namespace='default')
except rest.ApiException as err:
raise exception.KubernetesAPIFailed(err=err)
# call the rc object to persist in db
rc.create(context)
return rc
@ -160,12 +152,10 @@ class Handler(object):
self.k8s_api = k8s.create_k8s_api(context, rc)
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)
self.k8s_api.replace_namespaced_replication_controller(
name=str(rc.name), body=manifest, namespace='default')
except rest.ApiException as err:
raise exception.KubernetesAPIFailed(err=err)
# call the rc object to persist in db
rc.refresh(context)
rc.save()
@ -177,14 +167,12 @@ class Handler(object):
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')
except error.HTTPError as err:
if err.code == 404:
self.k8s_api.delete_namespaced_replication_controller(
name=str(rc.name), body={}, namespace='default')
except rest.ApiException as err:
if err.status == 404:
pass
else:
message = ast.literal_eval(err.read())['message']
raise exception.KubernetesAPIFailed(code=err.code,
message=message)
raise exception.KubernetesAPIFailed(err=err)
# call the rc object to persist in db
rc.destroy(context)

View File

@ -15,8 +15,8 @@
from oslo_config import cfg
from magnum.common import config
from magnum.common.pythonk8sclient.client import ApivbetaApi
from magnum.common.pythonk8sclient.client import swagger
from magnum.common.pythonk8sclient.swagger_client import api_client
from magnum.common.pythonk8sclient.swagger_client.apis import apiv_api
from magnum.conductor import utils
from magnum.i18n import _
@ -35,14 +35,14 @@ kubernetes_opts = [
cfg.CONF.register_opts(kubernetes_opts, group='kubernetes')
class K8sAPI(ApivbetaApi.ApivbetaApi):
class K8sAPI(apiv_api.ApivApi):
def __init__(self, context, obj):
# retrieve the URL of the k8s API endpoint
k8s_api_endpoint = self._retrieve_k8s_api_endpoint(context, obj)
# build a connection with Kubernetes master
client = swagger.ApiClient(k8s_api_endpoint)
client = api_client.ApiClient(k8s_api_endpoint)
super(K8sAPI, self).__init__(client)

View File

@ -48,8 +48,8 @@ class ScaleManager(object):
hosts_no_container = list(hosts)
k8s_api = k8s.create_k8s_api(self.context, bay)
for pod in k8s_api.listPod().items:
host = pod.spec.host
for pod in k8s_api.list_namespaced_pod(namespace='default').items:
host = pod.spec.node_name
if host in hosts_no_container:
hosts_no_container.remove(host)

View File

@ -13,9 +13,10 @@ sed -i '
sed -i '
/^KUBE_API_ADDRESS=/ s/=.*/="--address=0.0.0.0"/
/^KUBE_SERVICE_ADDRESSES=/ s|=.*|="--portal_net='"$PORTAL_NETWORK_CIDR"'"|
/^KUBE_API_ARGS=/ s/=.*/="--runtime_config=api\/v1beta3"/
/^KUBE_SERVICE_ADDRESSES=/ s|=.*|="--service-cluster-ip-range='"$PORTAL_NETWORK_CIDR"'"|
/^KUBE_API_ARGS=/ s/=.*/="--runtime_config=api\/all=true"/
/^KUBE_ETCD_SERVERS=/ s/=.*/="--etcd_servers=http:\/\/127.0.0.1:2379"/
/^KUBE_ADMISSION_CONTROL=/ s/=.*/=""/
' /etc/kubernetes/apiserver
sed -i '

View File

@ -37,5 +37,7 @@ cat >> /etc/environment <<EOF
KUBERNETES_MASTER=http://$KUBE_MASTER_IP:8080
EOF
sed -i '/^DOCKER_STORAGE_OPTIONS=/ s/=.*/=--storage-driver devicemapper --storage-opt dm.fs=xfs --storage-opt dm.thinpooldev=\/dev\/mapper\/docker-docker--pool --storage-opt dm.use_deferred_removal=true/' /etc/sysconfig/docker-storage
systemctl enable kube-register

View File

@ -5,28 +5,29 @@ write_files:
owner: "root:root"
permissions: "0644"
content: |
apiVersion: v1
kind: Pod
apiVersion: v1beta1
id: web
labels:
metadata:
labels:
name: web
name: web
desiredState:
manifest:
version: v1beta1
id: web
containers:
- name: web
image: larsks/thttpd
ports:
- containerPort: 80
spec:
containers:
- name: web
image: larsks/thttpd
ports:
- containerPort: 80
- path: /etc/kubernetes/examples/web.service
owner: "root:root"
permissions: "0644"
content: |
apiVersion: v1
kind: Service
apiVersion: v1beta1
id: web
port: 8000
selector:
metadata:
name: web
containerPort: 80
spec:
ports:
- port: 8000
selector:
name: web
containerPort: 80

View File

@ -20,20 +20,24 @@ write_files:
if [ "$1" = "-u" ]; then
echo "unregistering minion $myip"
kubectl -s ${master_url} delete minion/$myip
kubectl -s ${master_url} delete node/$myip
else
echo "registering minion $myip"
cpu=$(($(nproc) * 1000))
memory=$(awk '/MemTotal: /{print $2 * 1024}' /proc/meminfo)
cat <<EOF | kubectl create -s ${master_url} -f-
apiVersion: v1beta1
apiVersion: v1
id: $myip
kind: Minion
kind: Node
resources:
capacity:
cpu: $cpu
memory: $memory
metadata:
name: $myip
spec:
externalID: $myip
EOF
fi
- path: /etc/systemd/system/kube-register.service

View File

@ -60,7 +60,7 @@ popd
# First we test Magnum's command line to see if we can stand up
# a baymodel, bay and a pod
export NIC_ID=$(neutron net-show public | awk '/ id /{print $4}')
export IMAGE_ID=$(glance --os-image-api-version 1 image-show fedora-21-atomic-3 | awk '/ id /{print $4}')
export IMAGE_ID=$(glance --os-image-api-version 1 image-show fedora-21-atomic-5 | awk '/ id /{print $4}')
# pass the appropriate variables via a config file

View File

@ -25,8 +25,8 @@ import time
import fixtures
from magnum.common.pythonk8sclient.client import ApivbetaApi
from magnum.common.pythonk8sclient.client import swagger
from magnum.common.pythonk8sclient.swagger_client import api_client
from magnum.common.pythonk8sclient.swagger_client.apis import apiv_api
from magnum.tests import base
from magnumclient.openstack.common.apiclient import exceptions
from magnumclient.openstack.common import cliutils
@ -215,8 +215,8 @@ class TestKubernetesAPIs(BaseMagnumClient):
cls.bay = cls._create_bay('testk8sAPI', cls.baymodel.uuid)
kube_api_address = cls.cs.bays.get(cls.bay.uuid).api_address
kube_api_url = 'http://%s' % kube_api_address
k8s_client = swagger.ApiClient(kube_api_url)
cls.k8s_api = ApivbetaApi.ApivbetaApi(k8s_client)
k8s_client = api_client.ApiClient(kube_api_url)
cls.k8s_api = apiv_api.ApivApi(k8s_client)
@classmethod
def tearDownClass(cls):
@ -231,53 +231,52 @@ class TestKubernetesAPIs(BaseMagnumClient):
cls._delete_baymodel(cls.baymodel.uuid)
def test_pod_apis(self):
pod_manifest = {'apiVersion': 'v1beta3',
pod_manifest = {'apiVersion': 'v1',
'kind': 'Pod',
'metadata': {'color': 'blue', 'name': 'test'},
'spec': {'containers': [{'image': 'dockerfile/redis',
'name': 'redis'}]}}
resp = self.k8s_api.createPod(body=pod_manifest, namespaces='default')
self.assertEqual(resp.metadata['name'], 'test')
resp = self.k8s_api.create_namespaced_pod(body=pod_manifest,
namespace='default')
self.assertEqual(resp.metadata.name, 'test')
self.assertTrue(resp.status.phase)
resp = self.k8s_api.readPod(name='test', namespaces='default')
self.assertEqual(resp.metadata['name'], 'test')
resp = self.k8s_api.read_namespaced_pod(name='test',
namespace='default')
self.assertEqual(resp.metadata.name, 'test')
self.assertTrue(resp.status.phase)
resp = self.k8s_api.deletePod(name='test', namespaces='default')
self.assertFalse(resp.phase)
resp = self.k8s_api.delete_namespaced_pod(name='test', body={},
namespace='default')
def test_service_apis(self):
service_manifest = {'apiVersion': 'v1beta3',
service_manifest = {'apiVersion': 'v1',
'kind': 'Service',
'metadata': {'labels': {'name': 'frontend'},
'name': 'frontend',
'resourceversion': 'v1beta3'},
'resourceversion': 'v1'},
'spec': {'ports': [{'port': 80,
'protocol': 'TCP',
'targetPort': 80}],
'selector': {'name': 'frontend'}}}
resp = self.k8s_api.createService(body=service_manifest,
namespaces='default')
self.assertEqual(resp.metadata['name'], 'frontend')
resp = self.k8s_api.create_namespaced_service(body=service_manifest,
namespace='default')
self.assertEqual(resp.metadata.name, 'frontend')
self.assertTrue(resp.status)
resp = self.k8s_api.readService(name='frontend', namespaces='default')
self.assertEqual(resp.metadata['name'], 'frontend')
resp = self.k8s_api.read_namespaced_service(name='frontend',
namespace='default')
self.assertEqual(resp.metadata.name, 'frontend')
self.assertTrue(resp.status)
resp = self.k8s_api.deleteService(name='frontend',
namespaces='default')
# TODO(madhuri) Currently the V1beta3_ServiceStatus
# has no attribute defined. Uncomment this assertion
# when the class is redefined to contain 'phase'.
# self.assertTrue(resp.phase)
resp = self.k8s_api.delete_namespaced_service(name='frontend',
namespace='default')
def test_replication_controller_apis(self):
rc_manifest = {
'apiVersion': 'v1beta3',
'apiVersion': 'v1',
'kind': 'ReplicationController',
'metadata': {'labels': {'name': 'frontend'},
'name': 'frontend'},
@ -291,16 +290,15 @@ class TestKubernetesAPIs(BaseMagnumClient):
'ports': [{'containerPort': 80,
'protocol': 'TCP'}]}]}}}}
resp = self.k8s_api.createReplicationController(body=rc_manifest,
namespaces='default')
self.assertEqual(resp.metadata['name'], 'frontend')
resp = self.k8s_api.create_namespaced_replication_controller(
body=rc_manifest, namespace='default')
self.assertEqual(resp.metadata.name, 'frontend')
self.assertEqual(resp.spec.replicas, 2)
resp = self.k8s_api.readReplicationController(name='frontend',
namespaces='default')
self.assertEqual(resp.metadata['name'], 'frontend')
resp = self.k8s_api.read_namespaced_replication_controller(
name='frontend', namespace='default')
self.assertEqual(resp.metadata.name, 'frontend')
self.assertEqual(resp.spec.replicas, 2)
resp = self.k8s_api.deleteReplicationController(name='frontend',
namespaces='default')
self.assertFalse(resp.replicas)
resp = self.k8s_api.delete_namespaced_replication_controller(
name='frontend', body={}, namespace='default')

View File

@ -15,13 +15,13 @@
from oslo_config import cfg
from magnum.common import exception
from magnum.common.pythonk8sclient.swagger_client import rest
from magnum.conductor.handlers import k8s_conductor
from magnum import objects
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.k8s_conductor',
@ -60,43 +60,37 @@ class TestK8sConductor(base.TestCase):
return_value.status = mock.MagicMock()
return_value.status.phase = 'Pending'
return_value.spec = mock.MagicMock()
return_value.spec.host = '10.0.0.3'
mock_kube_api.return_value.createPod.return_value = return_value
return_value.spec.node_name = '10.0.0.3'
mock_kube_api.return_value.create_namespaced_pod.return_value = (
return_value)
self.kube_handler.pod_create(self.context, expected_pod)
self.assertEqual('Pending', expected_pod.status)
self.assertEqual('10.0.0.3', expected_pod.host)
expected_pod.create.assert_called_once_with(self.context)
@patch('ast.literal_eval')
def test_pod_create_with_fail(self, mock_literal_eval):
def test_pod_create_with_fail(self):
expected_pod = self.mock_pod()
expected_pod.create = mock.MagicMock()
expected_pod.manifest = '{"key": "value"}'
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
mock_literal_eval.return_value = {'message': 'error'}
err = rest.ApiException(status=500)
mock_kube_api.return_value.create_namespaced_pod.side_effect = err
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('ast.literal_eval')
def test_pod_create_fail_on_existing_pod(
self, mock_literal_eval):
def test_pod_create_fail_on_existing_pod(self):
expected_pod = self.mock_pod()
expected_pod.create = mock.MagicMock()
expected_pod.manifest = '{"key": "value"}'
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
mock_literal_eval.return_value = {'message': 'error'}
err = rest.ApiException(status=409)
mock_kube_api.return_value.create_namespaced_pod.side_effect = err
self.assertRaises(exception.KubernetesAPIFailed, self.kube_handler.
pod_create, self.context, expected_pod)
@ -117,16 +111,14 @@ class TestK8sConductor(base.TestCase):
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(
name=mock_pod.name,
namespaces='default')
(mock_kube_api.return_value.delete_namespaced_pod
.assert_called_once_with(
name=mock_pod.name, body={}, namespace='default'))
mock_pod.destroy.assert_called_once_with(self.context)
@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,
def test_pod_delete_with_failure(self, mock_pod_get_by_uuid,
mock_object_has_stack):
mock_pod = mock.MagicMock()
mock_pod.name = 'test-pod'
@ -135,24 +127,21 @@ class TestK8sConductor(base.TestCase):
mock_object_has_stack.return_value = True
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
mock_literal_eval.return_value = {'message': 'error'}
err = rest.ApiException(status=500)
mock_kube_api.return_value.delete_namespaced_pod.side_effect = err
self.assertRaises(exception.KubernetesAPIFailed,
self.kube_handler.pod_delete,
self.context, mock_pod.uuid)
mock_kube_api.return_value.deletePod.assert_called_once_with(
name=mock_pod.name,
namespaces='default')
(mock_kube_api.return_value.delete_namespaced_pod
.assert_called_once_with(
name=mock_pod.name, body={}, namespace='default'))
self.assertFalse(mock_pod.destroy.called)
@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,
self,
mock_pod_get_by_uuid,
mock_object_has_stack):
mock_pod = mock.MagicMock()
@ -162,15 +151,14 @@ class TestK8sConductor(base.TestCase):
mock_object_has_stack.return_value = True
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
mock_literal_eval.return_value = {'message': 'error'}
err = rest.ApiException(status=404)
mock_kube_api.return_value.delete_namespaced_pod.side_effect = err
self.kube_handler.pod_delete(self.context, mock_pod.uuid)
mock_kube_api.return_value.deletePod.assert_called_once_with(
name=mock_pod.name, namespaces='default')
(mock_kube_api.return_value.delete_namespaced_pod
.assert_called_once_with(
name=mock_pod.name, body={}, namespace='default'))
mock_pod.destroy.assert_called_once_with(self.context)
def test_service_create_with_success(self):
@ -181,28 +169,26 @@ class TestK8sConductor(base.TestCase):
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')
(mock_kube_api.return_value.create_namespaced_service
.assert_called_once_with(body=manifest, namespace='default'))
expected_service.create.assert_called_once_with(self.context)
@patch('ast.literal_eval')
def test_service_create_with_failure(self, mock_literal_eval):
def test_service_create_with_failure(self):
expected_service = self.mock_service()
expected_service.create = mock.MagicMock()
manifest = {"key": "value"}
expected_service.manifest = '{"key": "value"}'
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
mock_literal_eval.return_value = {'message': 'error'}
err = rest.ApiException(status=404)
(mock_kube_api.return_value.create_namespaced_service
.side_effect) = err
self.assertRaises(exception.KubernetesAPIFailed,
self.kube_handler.service_create,
self.context, expected_service)
mock_kube_api.return_value.createService.assert_called_once_with(
body=manifest, namespaces='default')
(mock_kube_api.return_value.create_namespaced_service
.assert_called_once_with(body=manifest, namespace='default'))
self.assertFalse(expected_service.create.called)
@patch('magnum.conductor.utils.object_has_stack')
@ -220,15 +206,15 @@ class TestK8sConductor(base.TestCase):
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_kube_api.return_value.delete_namespaced_service
.assert_called_once_with(
name=mock_service.name, namespace='default'))
mock_service.destroy.assert_called_once_with(self.context)
@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,
self,
mock_service_get_by_uuid,
mock_object_has_stack):
mock_service = mock.MagicMock()
@ -238,24 +224,23 @@ class TestK8sConductor(base.TestCase):
mock_object_has_stack.return_value = True
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
mock_literal_eval.return_value = {'message': 'error'}
err = rest.ApiException(status=500)
(mock_kube_api.return_value.delete_namespaced_service
.side_effect) = err
self.assertRaises(exception.KubernetesAPIFailed,
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_kube_api.return_value.delete_namespaced_service
.assert_called_once_with(
name=mock_service.name, namespace='default'))
self.assertFalse(mock_service.destroy.called)
@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,
self,
mock_service_get_by_uuid,
mock_object_has_stack):
mock_service = mock.MagicMock()
@ -265,15 +250,15 @@ class TestK8sConductor(base.TestCase):
mock_object_has_stack.return_value = True
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
mock_literal_eval.return_value = {'message': 'error'}
err = rest.ApiException(status=404)
(mock_kube_api.return_value.delete_namespaced_service
.side_effect) = err
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_kube_api.return_value.delete_namespaced_service
.assert_called_once_with(
name=mock_service.name, namespace='default'))
mock_service.destroy.assert_called_once_with(self.context)
def test_rc_create_with_success(self):
@ -284,28 +269,27 @@ class TestK8sConductor(base.TestCase):
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'))
(mock_kube_api.return_value
.create_namespaced_replication_controller
.assert_called_once_with(body=manifest, namespace='default'))
@patch('ast.literal_eval')
def test_rc_create_with_failure(self, mock_literal_eval):
def test_rc_create_with_failure(self):
expected_rc = self.mock_rc()
expected_rc.create = mock.MagicMock()
manifest = {"key": "value"}
expected_rc.manifest = '{"key": "value"}'
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
) = err
mock_literal_eval.return_value = {'message': 'error'}
err = rest.ApiException(status=500)
(mock_kube_api.return_value
.create_namespaced_replication_controller.side_effect) = err
self.assertRaises(exception.KubernetesAPIFailed,
self.kube_handler.rc_create,
self.context, expected_rc)
(mock_kube_api.return_value.createReplicationController
.assert_called_once_with(body=manifest, namespaces='default'))
(mock_kube_api.return_value
.create_namespaced_replication_controller
.assert_called_once_with(body=manifest, namespace='default'))
self.assertFalse(expected_rc.create.called)
@patch('magnum.conductor.utils.object_has_stack')
@ -322,16 +306,15 @@ class TestK8sConductor(base.TestCase):
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
.assert_called_once_with(name=mock_rc.name,
namespaces='default'))
(mock_kube_api.return_value
.delete_namespaced_replication_controller
.assert_called_once_with(name=mock_rc.name, body={},
namespace='default'))
mock_rc.destroy.assert_called_once_with(self.context)
@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,
def test_rc_delete_with_failure(self, mock_rc_get_by_uuid,
mock_object_has_stack):
mock_rc = mock.MagicMock()
mock_rc.name = 'test-rc'
@ -340,26 +323,24 @@ class TestK8sConductor(base.TestCase):
mock_object_has_stack.return_value = True
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
) = err
mock_literal_eval.return_value = {'message': 'error'}
err = rest.ApiException(status=500)
(mock_kube_api.return_value
.delete_namespaced_replication_controller.side_effect) = err
self.assertRaises(exception.KubernetesAPIFailed,
self.kube_handler.rc_delete,
self.context, mock_rc.uuid)
(mock_kube_api.return_value.deleteReplicationController
.assert_called_once_with(name=mock_rc.name,
namespaces='default'))
(mock_kube_api.return_value
.delete_namespaced_replication_controller
.assert_called_once_with(name=mock_rc.name, body={},
namespace='default'))
self.assertFalse(mock_rc.destroy.called)
@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,
self,
mock_rc_get_by_uuid,
mock_object_has_stack):
mock_rc = mock.MagicMock()
@ -369,17 +350,16 @@ class TestK8sConductor(base.TestCase):
mock_object_has_stack.return_value = True
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
) = err
mock_literal_eval.return_value = {'message': 'error'}
err = rest.ApiException(status=404)
(mock_kube_api.return_value
.delete_namespaced_replication_controller.side_effect) = err
self.kube_handler.rc_delete(self.context, mock_rc.uuid)
(mock_kube_api.return_value.deleteReplicationController
.assert_called_once_with(name=mock_rc.name,
namespaces='default'))
(mock_kube_api.return_value
.delete_namespaced_replication_controller
.assert_called_once_with(name=mock_rc.name, body={},
namespace='default'))
self.assertTrue(mock_rc.destroy.called)
def test_rc_update_with_success(self):
@ -393,14 +373,14 @@ class TestK8sConductor(base.TestCase):
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
(mock_kube_api.return_value
.replace_namespaced_replication_controller
.assert_called_once_with(body=manifest, name=expected_rc.name,
namespaces='default'))
namespace='default'))
expected_rc.refresh.assert_called_once_with(self.context)
expected_rc.save.assert_called_once_with()
@patch('ast.literal_eval')
def test_rc_update_with_failure(self, mock_literal_eval):
def test_rc_update_with_failure(self):
expected_rc = self.mock_rc()
expected_rc.uuid = 'test-uuid'
expected_rc.name = 'test-name'
@ -409,18 +389,18 @@ class TestK8sConductor(base.TestCase):
expected_rc.manifest = '{"key": "value"}'
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
err = rest.ApiException(status=404)
(mock_kube_api.return_value
.replace_namespaced_replication_controller
.side_effect) = err
mock_literal_eval.return_value = {'message': 'error'}
self.assertRaises(exception.KubernetesAPIFailed,
self.kube_handler.rc_update,
self.context, expected_rc)
(mock_kube_api.return_value.replaceReplicationController
(mock_kube_api.return_value
.replace_namespaced_replication_controller
.assert_called_once_with(body=manifest, name=expected_rc.name,
namespaces='default'))
namespace='default'))
self.assertFalse(expected_rc.update.called)
def test_service_update_with_success(self):
@ -434,14 +414,14 @@ class TestK8sConductor(base.TestCase):
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,
namespaces='default')
(mock_kube_api.return_value.replace_namespaced_service
.assert_called_once_with(
body=manifest, name=expected_service.name,
namespace='default'))
expected_service.refresh.assert_called_once_with(self.context)
expected_service.save.assert_called_once_with()
@patch('ast.literal_eval')
def test_service_update_with_failure(self, mock_literal_eval):
def test_service_update_with_failure(self):
expected_service = self.mock_service()
expected_service.uuid = 'test-uuid'
expected_service.name = 'test-name'
@ -449,17 +429,17 @@ class TestK8sConductor(base.TestCase):
manifest = {"key": "value"}
expected_service.manifest = '{"key": "value"}'
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
mock_literal_eval.return_value = {'message': 'error'}
err = rest.ApiException(status=404)
(mock_kube_api.return_value.replace_namespaced_service
.side_effect) = err
self.assertRaises(exception.KubernetesAPIFailed,
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,
namespaces='default')
(mock_kube_api.return_value.replace_namespaced_service
.assert_called_once_with(
body=manifest, name=expected_service.name,
namespace='default'))
self.assertFalse(expected_service.refresh.called)
def test_pod_update_with_success(self):
@ -473,14 +453,14 @@ class TestK8sConductor(base.TestCase):
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,
namespaces='default')
(mock_kube_api.return_value.replace_namespaced_pod
.assert_called_once_with(
body=manifest, name=expected_pod.name,
namespace='default'))
expected_pod.refresh.assert_called_once_with(self.context)
expected_pod.save.assert_called_once_with()
@patch('ast.literal_eval')
def test_pod_update_with_failure(self, mock_literal_eval):
def test_pod_update_with_failure(self):
expected_pod = self.mock_pod()
expected_pod.uuid = 'test-uuid'
expected_pod.name = 'test-name'
@ -489,15 +469,14 @@ class TestK8sConductor(base.TestCase):
expected_pod.manifest = '{"key": "value"}'
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
mock_literal_eval.return_value = {'message': 'error'}
err = rest.ApiException(status=404)
mock_kube_api.return_value.replace_namespaced_pod.side_effect = err
self.assertRaises(exception.KubernetesAPIFailed,
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,
namespaces='default')
(mock_kube_api.return_value.replace_namespaced_pod
.assert_called_once_with(
body=manifest, name=expected_pod.name,
namespace='default'))
self.assertFalse(expected_pod.refresh.called)

View File

@ -32,11 +32,11 @@ class TestScaleManager(base.TestCase):
pods = list()
for h in pod_hosts:
pod = mock.MagicMock()
pod.spec.host = h
pod.spec.node_name = h
pods.append(pod)
mock_k8s_api = mock.MagicMock()
mock_k8s_api.listPod.return_value.items = pods
mock_k8s_api.list_namespaced_pod.return_value.items = pods
mock_create_k8s_api.return_value = mock_k8s_api
mock_heat_output = mock.MagicMock()

View File

@ -46,3 +46,4 @@ six>=1.9.0
stevedore>=1.5.0 # Apache-2.0
taskflow>=1.16.0
cryptography>=1.0 # Apache-2.0
urllib3>=1.8.3