Migrate to Kubernetes Release 1
Kubernetes Release 1.0 was announced at OSCON A new Fedora Atomic image has been built with version 1.0.4 and this series of patches will update the templates, scripts, documents to work with the new image. The api has also been changed from v1beta3 to v1 and the beta api is no longer available, so the interface between Magnum and Kubernetes master are updated as well in this series of patches. This particular patch will bring up a V1 cluster with the bay-create command. Because the switch to the V1 API requires all the code changes to be applied at once, this patch pulls in portion of 3 patches together. The changes include: 1. devstack plugin downloads the new image. 2. k8s conductor and other code calls the new V1 client and k8s methods. 3. Configuration for k8s services and docker updated with new parameters. 4. Minion registration and example code updated to V1. 5. Functional tests updated to V1. 6. Gate test setup points to the new image. Co-Authored-By: Hongbin Lu <hongbin.lu@huawei.com> Change-Id: I046931ad491e8b7ee45943852901eac5c3df913e Partially-Implements: blueprint kubernetes-v1
This commit is contained in:
parent
27db916c5e
commit
4bfed61fe3
|
@ -18,7 +18,7 @@ if is_service_enabled m-api m-cond; then
|
||||||
|
|
||||||
# add image to glance
|
# add image to glance
|
||||||
if [[ "$ENABLED_SERVICES" =~ 'm-api' ]]; then
|
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}"
|
IMAGE_URLS+=",${MANGUM_GUEST_IMAGE_URL}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -7,5 +7,5 @@ user = admin
|
||||||
tenant = admin
|
tenant = admin
|
||||||
pass = secrete
|
pass = secrete
|
||||||
[magnum]
|
[magnum]
|
||||||
image_id = fedora-21-atomic-3
|
image_id = fedora-21-atomic-5
|
||||||
nic_id = public
|
nic_id = public
|
||||||
|
|
|
@ -19,6 +19,7 @@ Includes decorator for re-raising Magnum-type exceptions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
import json
|
||||||
import sys
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
@ -464,8 +465,15 @@ class OSDistroFieldNotFound(ResourceNotFound):
|
||||||
|
|
||||||
|
|
||||||
class KubernetesAPIFailed(MagnumException):
|
class KubernetesAPIFailed(MagnumException):
|
||||||
def __init__(self, message=None, **kwargs):
|
def __init__(self, message=None, err=None, **kwargs):
|
||||||
self.__class__.code = kwargs.get('code')
|
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)
|
super(KubernetesAPIFailed, self).__init__(message, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -187,7 +187,7 @@ class ApiClient(object):
|
||||||
"""
|
"""
|
||||||
if isinstance(obj, type(None)):
|
if isinstance(obj, type(None)):
|
||||||
return None
|
return None
|
||||||
elif isinstance(obj, (str, int, float, bool, tuple)):
|
elif isinstance(obj, (unicode, str, int, float, bool, tuple, file)):
|
||||||
return obj
|
return obj
|
||||||
elif isinstance(obj, list):
|
elif isinstance(obj, list):
|
||||||
return [self.sanitize_for_serialization(sub_obj)
|
return [self.sanitize_for_serialization(sub_obj)
|
||||||
|
|
|
@ -16,12 +16,11 @@ from oslo_log import log as logging
|
||||||
|
|
||||||
from magnum.common import exception
|
from magnum.common import exception
|
||||||
from magnum.common import k8s_manifest
|
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 k8s_api as k8s
|
||||||
from magnum.conductor import utils as conductor_utils
|
from magnum.conductor import utils as conductor_utils
|
||||||
from magnum import objects
|
from magnum import objects
|
||||||
|
|
||||||
import ast
|
|
||||||
from six.moves.urllib import error
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -41,11 +40,10 @@ class Handler(object):
|
||||||
self.k8s_api = k8s.create_k8s_api(context, service)
|
self.k8s_api = k8s.create_k8s_api(context, service)
|
||||||
manifest = k8s_manifest.parse(service.manifest)
|
manifest = k8s_manifest.parse(service.manifest)
|
||||||
try:
|
try:
|
||||||
self.k8s_api.createService(body=manifest,
|
self.k8s_api.create_namespaced_service(body=manifest,
|
||||||
namespaces='default')
|
namespace='default')
|
||||||
except error.HTTPError as err:
|
except rest.ApiException as err:
|
||||||
message = ast.literal_eval(err.read())['message']
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
raise exception.KubernetesAPIFailed(code=err.code, message=message)
|
|
||||||
# call the service object to persist in db
|
# call the service object to persist in db
|
||||||
service.create(context)
|
service.create(context)
|
||||||
return service
|
return service
|
||||||
|
@ -55,12 +53,11 @@ class Handler(object):
|
||||||
self.k8s_api = k8s.create_k8s_api(context, service)
|
self.k8s_api = k8s.create_k8s_api(context, service)
|
||||||
manifest = k8s_manifest.parse(service.manifest)
|
manifest = k8s_manifest.parse(service.manifest)
|
||||||
try:
|
try:
|
||||||
self.k8s_api.replaceService(name=service.name,
|
self.k8s_api.replace_namespaced_service(name=str(service.name),
|
||||||
body=manifest,
|
body=manifest,
|
||||||
namespaces='default')
|
namespace='default')
|
||||||
except error.HTTPError as err:
|
except rest.ApiException as err:
|
||||||
message = ast.literal_eval(err.read())['message']
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
raise exception.KubernetesAPIFailed(code=err.code, message=message)
|
|
||||||
# call the service object to persist in db
|
# call the service object to persist in db
|
||||||
service.refresh(context)
|
service.refresh(context)
|
||||||
service.save()
|
service.save()
|
||||||
|
@ -72,15 +69,13 @@ class Handler(object):
|
||||||
self.k8s_api = k8s.create_k8s_api(context, service)
|
self.k8s_api = k8s.create_k8s_api(context, service)
|
||||||
if conductor_utils.object_has_stack(context, service):
|
if conductor_utils.object_has_stack(context, service):
|
||||||
try:
|
try:
|
||||||
self.k8s_api.deleteService(name=service.name,
|
self.k8s_api.delete_namespaced_service(name=str(service.name),
|
||||||
namespaces='default')
|
namespace='default')
|
||||||
except error.HTTPError as err:
|
except rest.ApiException as err:
|
||||||
if err.code == 404:
|
if err.status == 404:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
message = ast.literal_eval(err.read())['message']
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
raise exception.KubernetesAPIFailed(code=err.code,
|
|
||||||
message=message)
|
|
||||||
# call the service object to persist in db
|
# call the service object to persist in db
|
||||||
service.destroy(context)
|
service.destroy(context)
|
||||||
|
|
||||||
|
@ -90,15 +85,15 @@ class Handler(object):
|
||||||
self.k8s_api = k8s.create_k8s_api(context, pod)
|
self.k8s_api = k8s.create_k8s_api(context, pod)
|
||||||
manifest = k8s_manifest.parse(pod.manifest)
|
manifest = k8s_manifest.parse(pod.manifest)
|
||||||
try:
|
try:
|
||||||
resp = self.k8s_api.createPod(body=manifest, namespaces='default')
|
resp = self.k8s_api.create_namespaced_pod(body=manifest,
|
||||||
except error.HTTPError as err:
|
namespace='default')
|
||||||
|
except rest.ApiException as err:
|
||||||
pod.status = 'failed'
|
pod.status = 'failed'
|
||||||
if err.code != 409:
|
if err.status != 409:
|
||||||
pod.create(context)
|
pod.create(context)
|
||||||
message = ast.literal_eval(err.read())['message']
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
raise exception.KubernetesAPIFailed(code=err.code, message=message)
|
|
||||||
pod.status = resp.status.phase
|
pod.status = resp.status.phase
|
||||||
pod.host = resp.spec.host
|
pod.host = resp.spec.node_name
|
||||||
# call the pod object to persist in db
|
# call the pod object to persist in db
|
||||||
# TODO(yuanying): parse pod file and,
|
# TODO(yuanying): parse pod file and,
|
||||||
# - extract pod name and set it
|
# - extract pod name and set it
|
||||||
|
@ -112,11 +107,11 @@ class Handler(object):
|
||||||
self.k8s_api = k8s.create_k8s_api(context, pod)
|
self.k8s_api = k8s.create_k8s_api(context, pod)
|
||||||
manifest = k8s_manifest.parse(pod.manifest)
|
manifest = k8s_manifest.parse(pod.manifest)
|
||||||
try:
|
try:
|
||||||
self.k8s_api.replacePod(name=pod.name, body=manifest,
|
self.k8s_api.replace_namespaced_pod(name=str(pod.name),
|
||||||
namespaces='default')
|
body=manifest,
|
||||||
except error.HTTPError as err:
|
namespace='default')
|
||||||
message = ast.literal_eval(err.read())['message']
|
except rest.ApiException as err:
|
||||||
raise exception.KubernetesAPIFailed(code=err.code, message=message)
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
# call the pod object to persist in db
|
# call the pod object to persist in db
|
||||||
pod.refresh(context)
|
pod.refresh(context)
|
||||||
pod.save()
|
pod.save()
|
||||||
|
@ -128,15 +123,13 @@ class Handler(object):
|
||||||
self.k8s_api = k8s.create_k8s_api(context, pod)
|
self.k8s_api = k8s.create_k8s_api(context, pod)
|
||||||
if conductor_utils.object_has_stack(context, pod):
|
if conductor_utils.object_has_stack(context, pod):
|
||||||
try:
|
try:
|
||||||
self.k8s_api.deletePod(name=pod.name,
|
self.k8s_api.delete_namespaced_pod(name=str(pod.name), body={},
|
||||||
namespaces='default')
|
namespace='default')
|
||||||
except error.HTTPError as err:
|
except rest.ApiException as err:
|
||||||
if err.code == 404:
|
if err.status == 404:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
message = ast.literal_eval(err.read())['message']
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
raise exception.KubernetesAPIFailed(code=err.code,
|
|
||||||
message=message)
|
|
||||||
# call the pod object to persist in db
|
# call the pod object to persist in db
|
||||||
pod.destroy(context)
|
pod.destroy(context)
|
||||||
|
|
||||||
|
@ -146,11 +139,10 @@ class Handler(object):
|
||||||
self.k8s_api = k8s.create_k8s_api(context, rc)
|
self.k8s_api = k8s.create_k8s_api(context, rc)
|
||||||
manifest = k8s_manifest.parse(rc.manifest)
|
manifest = k8s_manifest.parse(rc.manifest)
|
||||||
try:
|
try:
|
||||||
self.k8s_api.createReplicationController(body=manifest,
|
self.k8s_api.create_namespaced_replication_controller(
|
||||||
namespaces='default')
|
body=manifest, namespace='default')
|
||||||
except error.HTTPError as err:
|
except rest.ApiException as err:
|
||||||
message = ast.literal_eval(err.read())['message']
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
raise exception.KubernetesAPIFailed(code=err.code, message=message)
|
|
||||||
# call the rc object to persist in db
|
# call the rc object to persist in db
|
||||||
rc.create(context)
|
rc.create(context)
|
||||||
return rc
|
return rc
|
||||||
|
@ -160,12 +152,10 @@ class Handler(object):
|
||||||
self.k8s_api = k8s.create_k8s_api(context, rc)
|
self.k8s_api = k8s.create_k8s_api(context, rc)
|
||||||
manifest = k8s_manifest.parse(rc.manifest)
|
manifest = k8s_manifest.parse(rc.manifest)
|
||||||
try:
|
try:
|
||||||
self.k8s_api.replaceReplicationController(name=rc.name,
|
self.k8s_api.replace_namespaced_replication_controller(
|
||||||
body=manifest,
|
name=str(rc.name), body=manifest, namespace='default')
|
||||||
namespaces='default')
|
except rest.ApiException as err:
|
||||||
except error.HTTPError as err:
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
message = ast.literal_eval(err.read())['message']
|
|
||||||
raise exception.KubernetesAPIFailed(code=err.code, message=message)
|
|
||||||
# call the rc object to persist in db
|
# call the rc object to persist in db
|
||||||
rc.refresh(context)
|
rc.refresh(context)
|
||||||
rc.save()
|
rc.save()
|
||||||
|
@ -177,14 +167,12 @@ class Handler(object):
|
||||||
self.k8s_api = k8s.create_k8s_api(context, rc)
|
self.k8s_api = k8s.create_k8s_api(context, rc)
|
||||||
if conductor_utils.object_has_stack(context, rc):
|
if conductor_utils.object_has_stack(context, rc):
|
||||||
try:
|
try:
|
||||||
self.k8s_api.deleteReplicationController(name=rc.name,
|
self.k8s_api.delete_namespaced_replication_controller(
|
||||||
namespaces='default')
|
name=str(rc.name), body={}, namespace='default')
|
||||||
except error.HTTPError as err:
|
except rest.ApiException as err:
|
||||||
if err.code == 404:
|
if err.status == 404:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
message = ast.literal_eval(err.read())['message']
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
raise exception.KubernetesAPIFailed(code=err.code,
|
|
||||||
message=message)
|
|
||||||
# call the rc object to persist in db
|
# call the rc object to persist in db
|
||||||
rc.destroy(context)
|
rc.destroy(context)
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
from magnum.common import config
|
from magnum.common import config
|
||||||
from magnum.common.pythonk8sclient.client import ApivbetaApi
|
from magnum.common.pythonk8sclient.swagger_client import api_client
|
||||||
from magnum.common.pythonk8sclient.client import swagger
|
from magnum.common.pythonk8sclient.swagger_client.apis import apiv_api
|
||||||
from magnum.conductor import utils
|
from magnum.conductor import utils
|
||||||
from magnum.i18n import _
|
from magnum.i18n import _
|
||||||
|
|
||||||
|
@ -35,14 +35,14 @@ kubernetes_opts = [
|
||||||
cfg.CONF.register_opts(kubernetes_opts, group='kubernetes')
|
cfg.CONF.register_opts(kubernetes_opts, group='kubernetes')
|
||||||
|
|
||||||
|
|
||||||
class K8sAPI(ApivbetaApi.ApivbetaApi):
|
class K8sAPI(apiv_api.ApivApi):
|
||||||
|
|
||||||
def __init__(self, context, obj):
|
def __init__(self, context, obj):
|
||||||
# retrieve the URL of the k8s API endpoint
|
# retrieve the URL of the k8s API endpoint
|
||||||
k8s_api_endpoint = self._retrieve_k8s_api_endpoint(context, obj)
|
k8s_api_endpoint = self._retrieve_k8s_api_endpoint(context, obj)
|
||||||
|
|
||||||
# build a connection with Kubernetes master
|
# build a connection with Kubernetes master
|
||||||
client = swagger.ApiClient(k8s_api_endpoint)
|
client = api_client.ApiClient(k8s_api_endpoint)
|
||||||
|
|
||||||
super(K8sAPI, self).__init__(client)
|
super(K8sAPI, self).__init__(client)
|
||||||
|
|
||||||
|
|
|
@ -48,8 +48,8 @@ class ScaleManager(object):
|
||||||
|
|
||||||
hosts_no_container = list(hosts)
|
hosts_no_container = list(hosts)
|
||||||
k8s_api = k8s.create_k8s_api(self.context, bay)
|
k8s_api = k8s.create_k8s_api(self.context, bay)
|
||||||
for pod in k8s_api.listPod().items:
|
for pod in k8s_api.list_namespaced_pod(namespace='default').items:
|
||||||
host = pod.spec.host
|
host = pod.spec.node_name
|
||||||
if host in hosts_no_container:
|
if host in hosts_no_container:
|
||||||
hosts_no_container.remove(host)
|
hosts_no_container.remove(host)
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,10 @@ sed -i '
|
||||||
|
|
||||||
sed -i '
|
sed -i '
|
||||||
/^KUBE_API_ADDRESS=/ s/=.*/="--address=0.0.0.0"/
|
/^KUBE_API_ADDRESS=/ s/=.*/="--address=0.0.0.0"/
|
||||||
/^KUBE_SERVICE_ADDRESSES=/ s|=.*|="--portal_net='"$PORTAL_NETWORK_CIDR"'"|
|
/^KUBE_SERVICE_ADDRESSES=/ s|=.*|="--service-cluster-ip-range='"$PORTAL_NETWORK_CIDR"'"|
|
||||||
/^KUBE_API_ARGS=/ s/=.*/="--runtime_config=api\/v1beta3"/
|
/^KUBE_API_ARGS=/ s/=.*/="--runtime_config=api\/all=true"/
|
||||||
/^KUBE_ETCD_SERVERS=/ s/=.*/="--etcd_servers=http:\/\/127.0.0.1:2379"/
|
/^KUBE_ETCD_SERVERS=/ s/=.*/="--etcd_servers=http:\/\/127.0.0.1:2379"/
|
||||||
|
/^KUBE_ADMISSION_CONTROL=/ s/=.*/=""/
|
||||||
' /etc/kubernetes/apiserver
|
' /etc/kubernetes/apiserver
|
||||||
|
|
||||||
sed -i '
|
sed -i '
|
||||||
|
|
|
@ -37,5 +37,7 @@ cat >> /etc/environment <<EOF
|
||||||
KUBERNETES_MASTER=http://$KUBE_MASTER_IP:8080
|
KUBERNETES_MASTER=http://$KUBE_MASTER_IP:8080
|
||||||
EOF
|
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
|
systemctl enable kube-register
|
||||||
|
|
||||||
|
|
|
@ -5,28 +5,29 @@ write_files:
|
||||||
owner: "root:root"
|
owner: "root:root"
|
||||||
permissions: "0644"
|
permissions: "0644"
|
||||||
content: |
|
content: |
|
||||||
|
apiVersion: v1
|
||||||
kind: Pod
|
kind: Pod
|
||||||
apiVersion: v1beta1
|
metadata:
|
||||||
id: web
|
labels:
|
||||||
labels:
|
name: web
|
||||||
name: web
|
name: web
|
||||||
desiredState:
|
spec:
|
||||||
manifest:
|
containers:
|
||||||
version: v1beta1
|
- name: web
|
||||||
id: web
|
image: larsks/thttpd
|
||||||
containers:
|
ports:
|
||||||
- name: web
|
- containerPort: 80
|
||||||
image: larsks/thttpd
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
- path: /etc/kubernetes/examples/web.service
|
- path: /etc/kubernetes/examples/web.service
|
||||||
owner: "root:root"
|
owner: "root:root"
|
||||||
permissions: "0644"
|
permissions: "0644"
|
||||||
content: |
|
content: |
|
||||||
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
apiVersion: v1beta1
|
metadata:
|
||||||
id: web
|
|
||||||
port: 8000
|
|
||||||
selector:
|
|
||||||
name: web
|
name: web
|
||||||
containerPort: 80
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 8000
|
||||||
|
selector:
|
||||||
|
name: web
|
||||||
|
containerPort: 80
|
||||||
|
|
|
@ -20,20 +20,24 @@ write_files:
|
||||||
|
|
||||||
if [ "$1" = "-u" ]; then
|
if [ "$1" = "-u" ]; then
|
||||||
echo "unregistering minion $myip"
|
echo "unregistering minion $myip"
|
||||||
kubectl -s ${master_url} delete minion/$myip
|
kubectl -s ${master_url} delete node/$myip
|
||||||
else
|
else
|
||||||
echo "registering minion $myip"
|
echo "registering minion $myip"
|
||||||
cpu=$(($(nproc) * 1000))
|
cpu=$(($(nproc) * 1000))
|
||||||
memory=$(awk '/MemTotal: /{print $2 * 1024}' /proc/meminfo)
|
memory=$(awk '/MemTotal: /{print $2 * 1024}' /proc/meminfo)
|
||||||
|
|
||||||
cat <<EOF | kubectl create -s ${master_url} -f-
|
cat <<EOF | kubectl create -s ${master_url} -f-
|
||||||
apiVersion: v1beta1
|
apiVersion: v1
|
||||||
id: $myip
|
id: $myip
|
||||||
kind: Minion
|
kind: Node
|
||||||
resources:
|
resources:
|
||||||
capacity:
|
capacity:
|
||||||
cpu: $cpu
|
cpu: $cpu
|
||||||
memory: $memory
|
memory: $memory
|
||||||
|
metadata:
|
||||||
|
name: $myip
|
||||||
|
spec:
|
||||||
|
externalID: $myip
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
- path: /etc/systemd/system/kube-register.service
|
- path: /etc/systemd/system/kube-register.service
|
||||||
|
|
|
@ -60,7 +60,7 @@ popd
|
||||||
# First we test Magnum's command line to see if we can stand up
|
# First we test Magnum's command line to see if we can stand up
|
||||||
# a baymodel, bay and a pod
|
# a baymodel, bay and a pod
|
||||||
export NIC_ID=$(neutron net-show public | awk '/ id /{print $4}')
|
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
|
# pass the appropriate variables via a config file
|
||||||
|
|
|
@ -25,8 +25,8 @@ import time
|
||||||
|
|
||||||
import fixtures
|
import fixtures
|
||||||
|
|
||||||
from magnum.common.pythonk8sclient.client import ApivbetaApi
|
from magnum.common.pythonk8sclient.swagger_client import api_client
|
||||||
from magnum.common.pythonk8sclient.client import swagger
|
from magnum.common.pythonk8sclient.swagger_client.apis import apiv_api
|
||||||
from magnum.tests import base
|
from magnum.tests import base
|
||||||
from magnumclient.openstack.common.apiclient import exceptions
|
from magnumclient.openstack.common.apiclient import exceptions
|
||||||
from magnumclient.openstack.common import cliutils
|
from magnumclient.openstack.common import cliutils
|
||||||
|
@ -214,8 +214,8 @@ class TestKubernetesAPIs(BaseMagnumClient):
|
||||||
cls.bay = cls._create_bay('testk8sAPI', cls.baymodel.uuid)
|
cls.bay = cls._create_bay('testk8sAPI', cls.baymodel.uuid)
|
||||||
kube_api_address = cls.cs.bays.get(cls.bay.uuid).api_address
|
kube_api_address = cls.cs.bays.get(cls.bay.uuid).api_address
|
||||||
kube_api_url = 'http://%s' % kube_api_address
|
kube_api_url = 'http://%s' % kube_api_address
|
||||||
k8s_client = swagger.ApiClient(kube_api_url)
|
k8s_client = api_client.ApiClient(kube_api_url)
|
||||||
cls.k8s_api = ApivbetaApi.ApivbetaApi(k8s_client)
|
cls.k8s_api = apiv_api.ApivApi(k8s_client)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tearDownClass(cls):
|
def tearDownClass(cls):
|
||||||
|
@ -230,53 +230,52 @@ class TestKubernetesAPIs(BaseMagnumClient):
|
||||||
cls._delete_baymodel(cls.baymodel.uuid)
|
cls._delete_baymodel(cls.baymodel.uuid)
|
||||||
|
|
||||||
def test_pod_apis(self):
|
def test_pod_apis(self):
|
||||||
pod_manifest = {'apiVersion': 'v1beta3',
|
pod_manifest = {'apiVersion': 'v1',
|
||||||
'kind': 'Pod',
|
'kind': 'Pod',
|
||||||
'metadata': {'color': 'blue', 'name': 'test'},
|
'metadata': {'color': 'blue', 'name': 'test'},
|
||||||
'spec': {'containers': [{'image': 'dockerfile/redis',
|
'spec': {'containers': [{'image': 'dockerfile/redis',
|
||||||
'name': 'redis'}]}}
|
'name': 'redis'}]}}
|
||||||
|
|
||||||
resp = self.k8s_api.createPod(body=pod_manifest, namespaces='default')
|
resp = self.k8s_api.create_namespaced_pod(body=pod_manifest,
|
||||||
self.assertEqual(resp.metadata['name'], 'test')
|
namespace='default')
|
||||||
|
self.assertEqual(resp.metadata.name, 'test')
|
||||||
self.assertTrue(resp.status.phase)
|
self.assertTrue(resp.status.phase)
|
||||||
|
|
||||||
resp = self.k8s_api.readPod(name='test', namespaces='default')
|
resp = self.k8s_api.read_namespaced_pod(name='test',
|
||||||
self.assertEqual(resp.metadata['name'], 'test')
|
namespace='default')
|
||||||
|
self.assertEqual(resp.metadata.name, 'test')
|
||||||
self.assertTrue(resp.status.phase)
|
self.assertTrue(resp.status.phase)
|
||||||
|
|
||||||
resp = self.k8s_api.deletePod(name='test', namespaces='default')
|
resp = self.k8s_api.delete_namespaced_pod(name='test', body={},
|
||||||
self.assertFalse(resp.phase)
|
namespace='default')
|
||||||
|
|
||||||
def test_service_apis(self):
|
def test_service_apis(self):
|
||||||
service_manifest = {'apiVersion': 'v1beta3',
|
service_manifest = {'apiVersion': 'v1',
|
||||||
'kind': 'Service',
|
'kind': 'Service',
|
||||||
'metadata': {'labels': {'name': 'frontend'},
|
'metadata': {'labels': {'name': 'frontend'},
|
||||||
'name': 'frontend',
|
'name': 'frontend',
|
||||||
'resourceversion': 'v1beta3'},
|
'resourceversion': 'v1'},
|
||||||
'spec': {'ports': [{'port': 80,
|
'spec': {'ports': [{'port': 80,
|
||||||
'protocol': 'TCP',
|
'protocol': 'TCP',
|
||||||
'targetPort': 80}],
|
'targetPort': 80}],
|
||||||
'selector': {'name': 'frontend'}}}
|
'selector': {'name': 'frontend'}}}
|
||||||
|
|
||||||
resp = self.k8s_api.createService(body=service_manifest,
|
resp = self.k8s_api.create_namespaced_service(body=service_manifest,
|
||||||
namespaces='default')
|
namespace='default')
|
||||||
self.assertEqual(resp.metadata['name'], 'frontend')
|
self.assertEqual(resp.metadata.name, 'frontend')
|
||||||
self.assertTrue(resp.status)
|
self.assertTrue(resp.status)
|
||||||
|
|
||||||
resp = self.k8s_api.readService(name='frontend', namespaces='default')
|
resp = self.k8s_api.read_namespaced_service(name='frontend',
|
||||||
self.assertEqual(resp.metadata['name'], 'frontend')
|
namespace='default')
|
||||||
|
self.assertEqual(resp.metadata.name, 'frontend')
|
||||||
self.assertTrue(resp.status)
|
self.assertTrue(resp.status)
|
||||||
|
|
||||||
resp = self.k8s_api.deleteService(name='frontend',
|
resp = self.k8s_api.delete_namespaced_service(name='frontend',
|
||||||
namespaces='default')
|
namespace='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)
|
|
||||||
|
|
||||||
def test_replication_controller_apis(self):
|
def test_replication_controller_apis(self):
|
||||||
rc_manifest = {
|
rc_manifest = {
|
||||||
'apiVersion': 'v1beta3',
|
'apiVersion': 'v1',
|
||||||
'kind': 'ReplicationController',
|
'kind': 'ReplicationController',
|
||||||
'metadata': {'labels': {'name': 'frontend'},
|
'metadata': {'labels': {'name': 'frontend'},
|
||||||
'name': 'frontend'},
|
'name': 'frontend'},
|
||||||
|
@ -290,16 +289,15 @@ class TestKubernetesAPIs(BaseMagnumClient):
|
||||||
'ports': [{'containerPort': 80,
|
'ports': [{'containerPort': 80,
|
||||||
'protocol': 'TCP'}]}]}}}}
|
'protocol': 'TCP'}]}]}}}}
|
||||||
|
|
||||||
resp = self.k8s_api.createReplicationController(body=rc_manifest,
|
resp = self.k8s_api.create_namespaced_replication_controller(
|
||||||
namespaces='default')
|
body=rc_manifest, namespace='default')
|
||||||
self.assertEqual(resp.metadata['name'], 'frontend')
|
self.assertEqual(resp.metadata.name, 'frontend')
|
||||||
self.assertEqual(resp.spec.replicas, 2)
|
self.assertEqual(resp.spec.replicas, 2)
|
||||||
|
|
||||||
resp = self.k8s_api.readReplicationController(name='frontend',
|
resp = self.k8s_api.read_namespaced_replication_controller(
|
||||||
namespaces='default')
|
name='frontend', namespace='default')
|
||||||
self.assertEqual(resp.metadata['name'], 'frontend')
|
self.assertEqual(resp.metadata.name, 'frontend')
|
||||||
self.assertEqual(resp.spec.replicas, 2)
|
self.assertEqual(resp.spec.replicas, 2)
|
||||||
|
|
||||||
resp = self.k8s_api.deleteReplicationController(name='frontend',
|
resp = self.k8s_api.delete_namespaced_replication_controller(
|
||||||
namespaces='default')
|
name='frontend', body={}, namespace='default')
|
||||||
self.assertFalse(resp.replicas)
|
|
||||||
|
|
|
@ -15,13 +15,13 @@
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
|
||||||
from magnum.common import exception
|
from magnum.common import exception
|
||||||
|
from magnum.common.pythonk8sclient.swagger_client import rest
|
||||||
from magnum.conductor.handlers import k8s_conductor
|
from magnum.conductor.handlers import k8s_conductor
|
||||||
from magnum import objects
|
from magnum import objects
|
||||||
from magnum.tests import base
|
from magnum.tests import base
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
from mock import patch
|
from mock import patch
|
||||||
from six.moves.urllib import error
|
|
||||||
|
|
||||||
|
|
||||||
cfg.CONF.import_opt('k8s_protocol', 'magnum.conductor.handlers.k8s_conductor',
|
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 = mock.MagicMock()
|
||||||
return_value.status.phase = 'Pending'
|
return_value.status.phase = 'Pending'
|
||||||
return_value.spec = mock.MagicMock()
|
return_value.spec = mock.MagicMock()
|
||||||
return_value.spec.host = '10.0.0.3'
|
return_value.spec.node_name = '10.0.0.3'
|
||||||
mock_kube_api.return_value.createPod.return_value = return_value
|
mock_kube_api.return_value.create_namespaced_pod.return_value = (
|
||||||
|
return_value)
|
||||||
|
|
||||||
self.kube_handler.pod_create(self.context, expected_pod)
|
self.kube_handler.pod_create(self.context, expected_pod)
|
||||||
self.assertEqual('Pending', expected_pod.status)
|
self.assertEqual('Pending', expected_pod.status)
|
||||||
self.assertEqual('10.0.0.3', expected_pod.host)
|
self.assertEqual('10.0.0.3', expected_pod.host)
|
||||||
expected_pod.create.assert_called_once_with(self.context)
|
expected_pod.create.assert_called_once_with(self.context)
|
||||||
|
|
||||||
@patch('ast.literal_eval')
|
def test_pod_create_with_fail(self):
|
||||||
def test_pod_create_with_fail(self, mock_literal_eval):
|
|
||||||
expected_pod = self.mock_pod()
|
expected_pod = self.mock_pod()
|
||||||
expected_pod.create = mock.MagicMock()
|
expected_pod.create = mock.MagicMock()
|
||||||
expected_pod.manifest = '{"key": "value"}'
|
expected_pod.manifest = '{"key": "value"}'
|
||||||
|
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=500)
|
||||||
fp=mock.MagicMock(), code=500)
|
mock_kube_api.return_value.create_namespaced_pod.side_effect = err
|
||||||
mock_kube_api.return_value.createPod.side_effect = err
|
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.assertRaises(exception.KubernetesAPIFailed, self.kube_handler.
|
self.assertRaises(exception.KubernetesAPIFailed, self.kube_handler.
|
||||||
pod_create, self.context, expected_pod)
|
pod_create, self.context, expected_pod)
|
||||||
self.assertEqual('failed', expected_pod.status)
|
self.assertEqual('failed', expected_pod.status)
|
||||||
expected_pod.create.assert_called_once_with(self.context)
|
expected_pod.create.assert_called_once_with(self.context)
|
||||||
|
|
||||||
@patch('ast.literal_eval')
|
def test_pod_create_fail_on_existing_pod(self):
|
||||||
def test_pod_create_fail_on_existing_pod(
|
|
||||||
self, mock_literal_eval):
|
|
||||||
expected_pod = self.mock_pod()
|
expected_pod = self.mock_pod()
|
||||||
expected_pod.create = mock.MagicMock()
|
expected_pod.create = mock.MagicMock()
|
||||||
expected_pod.manifest = '{"key": "value"}'
|
expected_pod.manifest = '{"key": "value"}'
|
||||||
|
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=409)
|
||||||
fp=mock.MagicMock(), code=409)
|
mock_kube_api.return_value.create_namespaced_pod.side_effect = err
|
||||||
mock_kube_api.return_value.createPod.side_effect = err
|
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.assertRaises(exception.KubernetesAPIFailed, self.kube_handler.
|
self.assertRaises(exception.KubernetesAPIFailed, self.kube_handler.
|
||||||
pod_create, self.context, expected_pod)
|
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:
|
with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api:
|
||||||
self.kube_handler.pod_delete(self.context, mock_pod.uuid)
|
self.kube_handler.pod_delete(self.context, mock_pod.uuid)
|
||||||
|
|
||||||
mock_kube_api.return_value.deletePod.assert_called_once_with(
|
(mock_kube_api.return_value.delete_namespaced_pod
|
||||||
name=mock_pod.name,
|
.assert_called_once_with(
|
||||||
namespaces='default')
|
name=mock_pod.name, body={}, namespace='default'))
|
||||||
mock_pod.destroy.assert_called_once_with(self.context)
|
mock_pod.destroy.assert_called_once_with(self.context)
|
||||||
|
|
||||||
@patch('magnum.conductor.utils.object_has_stack')
|
@patch('magnum.conductor.utils.object_has_stack')
|
||||||
@patch('magnum.objects.Pod.get_by_uuid')
|
@patch('magnum.objects.Pod.get_by_uuid')
|
||||||
@patch('ast.literal_eval')
|
def test_pod_delete_with_failure(self, mock_pod_get_by_uuid,
|
||||||
def test_pod_delete_with_failure(self, mock_literal_eval,
|
|
||||||
mock_pod_get_by_uuid,
|
|
||||||
mock_object_has_stack):
|
mock_object_has_stack):
|
||||||
mock_pod = mock.MagicMock()
|
mock_pod = mock.MagicMock()
|
||||||
mock_pod.name = 'test-pod'
|
mock_pod.name = 'test-pod'
|
||||||
|
@ -135,24 +127,21 @@ class TestK8sConductor(base.TestCase):
|
||||||
|
|
||||||
mock_object_has_stack.return_value = True
|
mock_object_has_stack.return_value = True
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=500)
|
||||||
fp=mock.MagicMock(), code=500)
|
mock_kube_api.return_value.delete_namespaced_pod.side_effect = err
|
||||||
mock_kube_api.return_value.deletePod.side_effect = err
|
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.assertRaises(exception.KubernetesAPIFailed,
|
self.assertRaises(exception.KubernetesAPIFailed,
|
||||||
self.kube_handler.pod_delete,
|
self.kube_handler.pod_delete,
|
||||||
self.context, mock_pod.uuid)
|
self.context, mock_pod.uuid)
|
||||||
mock_kube_api.return_value.deletePod.assert_called_once_with(
|
(mock_kube_api.return_value.delete_namespaced_pod
|
||||||
name=mock_pod.name,
|
.assert_called_once_with(
|
||||||
namespaces='default')
|
name=mock_pod.name, body={}, namespace='default'))
|
||||||
self.assertFalse(mock_pod.destroy.called)
|
self.assertFalse(mock_pod.destroy.called)
|
||||||
|
|
||||||
@patch('magnum.conductor.utils.object_has_stack')
|
@patch('magnum.conductor.utils.object_has_stack')
|
||||||
@patch('magnum.objects.Pod.get_by_uuid')
|
@patch('magnum.objects.Pod.get_by_uuid')
|
||||||
@patch('ast.literal_eval')
|
|
||||||
def test_pod_delete_succeeds_when_not_found(
|
def test_pod_delete_succeeds_when_not_found(
|
||||||
self, mock_literal_eval,
|
self,
|
||||||
mock_pod_get_by_uuid,
|
mock_pod_get_by_uuid,
|
||||||
mock_object_has_stack):
|
mock_object_has_stack):
|
||||||
mock_pod = mock.MagicMock()
|
mock_pod = mock.MagicMock()
|
||||||
|
@ -162,15 +151,14 @@ class TestK8sConductor(base.TestCase):
|
||||||
|
|
||||||
mock_object_has_stack.return_value = True
|
mock_object_has_stack.return_value = True
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=404)
|
||||||
fp=mock.MagicMock(), code=404)
|
mock_kube_api.return_value.delete_namespaced_pod.side_effect = err
|
||||||
mock_kube_api.return_value.deletePod.side_effect = err
|
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.kube_handler.pod_delete(self.context, mock_pod.uuid)
|
self.kube_handler.pod_delete(self.context, mock_pod.uuid)
|
||||||
|
|
||||||
mock_kube_api.return_value.deletePod.assert_called_once_with(
|
(mock_kube_api.return_value.delete_namespaced_pod
|
||||||
name=mock_pod.name, namespaces='default')
|
.assert_called_once_with(
|
||||||
|
name=mock_pod.name, body={}, namespace='default'))
|
||||||
mock_pod.destroy.assert_called_once_with(self.context)
|
mock_pod.destroy.assert_called_once_with(self.context)
|
||||||
|
|
||||||
def test_service_create_with_success(self):
|
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:
|
with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api:
|
||||||
self.kube_handler.service_create(self.context, expected_service)
|
self.kube_handler.service_create(self.context, expected_service)
|
||||||
mock_kube_api.return_value.createService.assert_called_once_with(
|
(mock_kube_api.return_value.create_namespaced_service
|
||||||
body=manifest, namespaces='default')
|
.assert_called_once_with(body=manifest, namespace='default'))
|
||||||
expected_service.create.assert_called_once_with(self.context)
|
expected_service.create.assert_called_once_with(self.context)
|
||||||
|
|
||||||
@patch('ast.literal_eval')
|
def test_service_create_with_failure(self):
|
||||||
def test_service_create_with_failure(self, mock_literal_eval):
|
|
||||||
expected_service = self.mock_service()
|
expected_service = self.mock_service()
|
||||||
expected_service.create = mock.MagicMock()
|
expected_service.create = mock.MagicMock()
|
||||||
manifest = {"key": "value"}
|
manifest = {"key": "value"}
|
||||||
expected_service.manifest = '{"key": "value"}'
|
expected_service.manifest = '{"key": "value"}'
|
||||||
|
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=404)
|
||||||
fp=mock.MagicMock(), code=404)
|
(mock_kube_api.return_value.create_namespaced_service
|
||||||
mock_kube_api.return_value.createService.side_effect = err
|
.side_effect) = err
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.assertRaises(exception.KubernetesAPIFailed,
|
self.assertRaises(exception.KubernetesAPIFailed,
|
||||||
self.kube_handler.service_create,
|
self.kube_handler.service_create,
|
||||||
self.context, expected_service)
|
self.context, expected_service)
|
||||||
mock_kube_api.return_value.createService.assert_called_once_with(
|
(mock_kube_api.return_value.create_namespaced_service
|
||||||
body=manifest, namespaces='default')
|
.assert_called_once_with(body=manifest, namespace='default'))
|
||||||
self.assertFalse(expected_service.create.called)
|
self.assertFalse(expected_service.create.called)
|
||||||
|
|
||||||
@patch('magnum.conductor.utils.object_has_stack')
|
@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:
|
with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api:
|
||||||
self.kube_handler.service_delete(self.context, mock_service.uuid)
|
self.kube_handler.service_delete(self.context, mock_service.uuid)
|
||||||
|
|
||||||
mock_kube_api.return_value.deleteService.assert_called_once_with(
|
(mock_kube_api.return_value.delete_namespaced_service
|
||||||
name=mock_service.name, namespaces='default')
|
.assert_called_once_with(
|
||||||
|
name=mock_service.name, namespace='default'))
|
||||||
mock_service.destroy.assert_called_once_with(self.context)
|
mock_service.destroy.assert_called_once_with(self.context)
|
||||||
|
|
||||||
@patch('magnum.conductor.utils.object_has_stack')
|
@patch('magnum.conductor.utils.object_has_stack')
|
||||||
@patch('magnum.objects.Service.get_by_uuid')
|
@patch('magnum.objects.Service.get_by_uuid')
|
||||||
@patch('ast.literal_eval')
|
|
||||||
def test_service_delete_with_failure(
|
def test_service_delete_with_failure(
|
||||||
self, mock_literal_eval,
|
self,
|
||||||
mock_service_get_by_uuid,
|
mock_service_get_by_uuid,
|
||||||
mock_object_has_stack):
|
mock_object_has_stack):
|
||||||
mock_service = mock.MagicMock()
|
mock_service = mock.MagicMock()
|
||||||
|
@ -238,24 +224,23 @@ class TestK8sConductor(base.TestCase):
|
||||||
|
|
||||||
mock_object_has_stack.return_value = True
|
mock_object_has_stack.return_value = True
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=500)
|
||||||
fp=mock.MagicMock(), code=500)
|
(mock_kube_api.return_value.delete_namespaced_service
|
||||||
mock_kube_api.return_value.deleteService.side_effect = err
|
.side_effect) = err
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.assertRaises(exception.KubernetesAPIFailed,
|
self.assertRaises(exception.KubernetesAPIFailed,
|
||||||
self.kube_handler.service_delete,
|
self.kube_handler.service_delete,
|
||||||
self.context, mock_service.uuid)
|
self.context, mock_service.uuid)
|
||||||
|
|
||||||
mock_kube_api.return_value.deleteService.assert_called_once_with(
|
(mock_kube_api.return_value.delete_namespaced_service
|
||||||
name=mock_service.name, namespaces='default')
|
.assert_called_once_with(
|
||||||
|
name=mock_service.name, namespace='default'))
|
||||||
self.assertFalse(mock_service.destroy.called)
|
self.assertFalse(mock_service.destroy.called)
|
||||||
|
|
||||||
@patch('magnum.conductor.utils.object_has_stack')
|
@patch('magnum.conductor.utils.object_has_stack')
|
||||||
@patch('magnum.objects.Service.get_by_uuid')
|
@patch('magnum.objects.Service.get_by_uuid')
|
||||||
@patch('ast.literal_eval')
|
|
||||||
def test_service_delete_succeeds_when_not_found(
|
def test_service_delete_succeeds_when_not_found(
|
||||||
self, mock_literal_eval,
|
self,
|
||||||
mock_service_get_by_uuid,
|
mock_service_get_by_uuid,
|
||||||
mock_object_has_stack):
|
mock_object_has_stack):
|
||||||
mock_service = mock.MagicMock()
|
mock_service = mock.MagicMock()
|
||||||
|
@ -265,15 +250,15 @@ class TestK8sConductor(base.TestCase):
|
||||||
|
|
||||||
mock_object_has_stack.return_value = True
|
mock_object_has_stack.return_value = True
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=404)
|
||||||
fp=mock.MagicMock(), code=404)
|
(mock_kube_api.return_value.delete_namespaced_service
|
||||||
mock_kube_api.return_value.deleteService.side_effect = err
|
.side_effect) = err
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.kube_handler.service_delete(self.context, mock_service.uuid)
|
self.kube_handler.service_delete(self.context, mock_service.uuid)
|
||||||
|
|
||||||
mock_kube_api.return_value.deleteService.assert_called_once_with(
|
(mock_kube_api.return_value.delete_namespaced_service
|
||||||
name=mock_service.name, namespaces='default')
|
.assert_called_once_with(
|
||||||
|
name=mock_service.name, namespace='default'))
|
||||||
mock_service.destroy.assert_called_once_with(self.context)
|
mock_service.destroy.assert_called_once_with(self.context)
|
||||||
|
|
||||||
def test_rc_create_with_success(self):
|
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:
|
with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api:
|
||||||
self.kube_handler.rc_create({}, expected_rc)
|
self.kube_handler.rc_create({}, expected_rc)
|
||||||
(mock_kube_api.return_value.createReplicationController
|
(mock_kube_api.return_value
|
||||||
.assert_called_once_with(body=manifest, namespaces='default'))
|
.create_namespaced_replication_controller
|
||||||
|
.assert_called_once_with(body=manifest, namespace='default'))
|
||||||
|
|
||||||
@patch('ast.literal_eval')
|
def test_rc_create_with_failure(self):
|
||||||
def test_rc_create_with_failure(self, mock_literal_eval):
|
|
||||||
expected_rc = self.mock_rc()
|
expected_rc = self.mock_rc()
|
||||||
expected_rc.create = mock.MagicMock()
|
expected_rc.create = mock.MagicMock()
|
||||||
manifest = {"key": "value"}
|
manifest = {"key": "value"}
|
||||||
expected_rc.manifest = '{"key": "value"}'
|
expected_rc.manifest = '{"key": "value"}'
|
||||||
|
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=500)
|
||||||
fp=mock.MagicMock(), code=500)
|
(mock_kube_api.return_value
|
||||||
(mock_kube_api.return_value.createReplicationController.side_effect
|
.create_namespaced_replication_controller.side_effect) = err
|
||||||
) = err
|
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.assertRaises(exception.KubernetesAPIFailed,
|
self.assertRaises(exception.KubernetesAPIFailed,
|
||||||
self.kube_handler.rc_create,
|
self.kube_handler.rc_create,
|
||||||
self.context, expected_rc)
|
self.context, expected_rc)
|
||||||
(mock_kube_api.return_value.createReplicationController
|
(mock_kube_api.return_value
|
||||||
.assert_called_once_with(body=manifest, namespaces='default'))
|
.create_namespaced_replication_controller
|
||||||
|
.assert_called_once_with(body=manifest, namespace='default'))
|
||||||
self.assertFalse(expected_rc.create.called)
|
self.assertFalse(expected_rc.create.called)
|
||||||
|
|
||||||
@patch('magnum.conductor.utils.object_has_stack')
|
@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:
|
with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api:
|
||||||
self.kube_handler.rc_delete(self.context, mock_rc.uuid)
|
self.kube_handler.rc_delete(self.context, mock_rc.uuid)
|
||||||
|
|
||||||
(mock_kube_api.return_value.deleteReplicationController
|
(mock_kube_api.return_value
|
||||||
.assert_called_once_with(name=mock_rc.name,
|
.delete_namespaced_replication_controller
|
||||||
namespaces='default'))
|
.assert_called_once_with(name=mock_rc.name, body={},
|
||||||
|
namespace='default'))
|
||||||
mock_rc.destroy.assert_called_once_with(self.context)
|
mock_rc.destroy.assert_called_once_with(self.context)
|
||||||
|
|
||||||
@patch('magnum.conductor.utils.object_has_stack')
|
@patch('magnum.conductor.utils.object_has_stack')
|
||||||
@patch('magnum.objects.ReplicationController.get_by_uuid')
|
@patch('magnum.objects.ReplicationController.get_by_uuid')
|
||||||
@patch('ast.literal_eval')
|
def test_rc_delete_with_failure(self, mock_rc_get_by_uuid,
|
||||||
def test_rc_delete_with_failure(self, mock_literal_eval,
|
|
||||||
mock_rc_get_by_uuid,
|
|
||||||
mock_object_has_stack):
|
mock_object_has_stack):
|
||||||
mock_rc = mock.MagicMock()
|
mock_rc = mock.MagicMock()
|
||||||
mock_rc.name = 'test-rc'
|
mock_rc.name = 'test-rc'
|
||||||
|
@ -340,26 +323,24 @@ class TestK8sConductor(base.TestCase):
|
||||||
|
|
||||||
mock_object_has_stack.return_value = True
|
mock_object_has_stack.return_value = True
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=500)
|
||||||
fp=mock.MagicMock(), code=500)
|
(mock_kube_api.return_value
|
||||||
(mock_kube_api.return_value.deleteReplicationController.side_effect
|
.delete_namespaced_replication_controller.side_effect) = err
|
||||||
) = err
|
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.assertRaises(exception.KubernetesAPIFailed,
|
self.assertRaises(exception.KubernetesAPIFailed,
|
||||||
self.kube_handler.rc_delete,
|
self.kube_handler.rc_delete,
|
||||||
self.context, mock_rc.uuid)
|
self.context, mock_rc.uuid)
|
||||||
|
|
||||||
(mock_kube_api.return_value.deleteReplicationController
|
(mock_kube_api.return_value
|
||||||
.assert_called_once_with(name=mock_rc.name,
|
.delete_namespaced_replication_controller
|
||||||
namespaces='default'))
|
.assert_called_once_with(name=mock_rc.name, body={},
|
||||||
|
namespace='default'))
|
||||||
self.assertFalse(mock_rc.destroy.called)
|
self.assertFalse(mock_rc.destroy.called)
|
||||||
|
|
||||||
@patch('magnum.conductor.utils.object_has_stack')
|
@patch('magnum.conductor.utils.object_has_stack')
|
||||||
@patch('magnum.objects.ReplicationController.get_by_uuid')
|
@patch('magnum.objects.ReplicationController.get_by_uuid')
|
||||||
@patch('ast.literal_eval')
|
|
||||||
def test_rc_delete_succeeds_when_not_found(
|
def test_rc_delete_succeeds_when_not_found(
|
||||||
self, mock_literal_eval,
|
self,
|
||||||
mock_rc_get_by_uuid,
|
mock_rc_get_by_uuid,
|
||||||
mock_object_has_stack):
|
mock_object_has_stack):
|
||||||
mock_rc = mock.MagicMock()
|
mock_rc = mock.MagicMock()
|
||||||
|
@ -369,17 +350,16 @@ class TestK8sConductor(base.TestCase):
|
||||||
|
|
||||||
mock_object_has_stack.return_value = True
|
mock_object_has_stack.return_value = True
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=404)
|
||||||
fp=mock.MagicMock(), code=404)
|
(mock_kube_api.return_value
|
||||||
(mock_kube_api.return_value.deleteReplicationController.side_effect
|
.delete_namespaced_replication_controller.side_effect) = err
|
||||||
) = err
|
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.kube_handler.rc_delete(self.context, mock_rc.uuid)
|
self.kube_handler.rc_delete(self.context, mock_rc.uuid)
|
||||||
|
|
||||||
(mock_kube_api.return_value.deleteReplicationController
|
(mock_kube_api.return_value
|
||||||
.assert_called_once_with(name=mock_rc.name,
|
.delete_namespaced_replication_controller
|
||||||
namespaces='default'))
|
.assert_called_once_with(name=mock_rc.name, body={},
|
||||||
|
namespace='default'))
|
||||||
self.assertTrue(mock_rc.destroy.called)
|
self.assertTrue(mock_rc.destroy.called)
|
||||||
|
|
||||||
def test_rc_update_with_success(self):
|
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:
|
with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api:
|
||||||
self.kube_handler.rc_update(self.context, expected_rc)
|
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,
|
.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.refresh.assert_called_once_with(self.context)
|
||||||
expected_rc.save.assert_called_once_with()
|
expected_rc.save.assert_called_once_with()
|
||||||
|
|
||||||
@patch('ast.literal_eval')
|
def test_rc_update_with_failure(self):
|
||||||
def test_rc_update_with_failure(self, mock_literal_eval):
|
|
||||||
expected_rc = self.mock_rc()
|
expected_rc = self.mock_rc()
|
||||||
expected_rc.uuid = 'test-uuid'
|
expected_rc.uuid = 'test-uuid'
|
||||||
expected_rc.name = 'test-name'
|
expected_rc.name = 'test-name'
|
||||||
|
@ -409,18 +389,18 @@ class TestK8sConductor(base.TestCase):
|
||||||
expected_rc.manifest = '{"key": "value"}'
|
expected_rc.manifest = '{"key": "value"}'
|
||||||
|
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=404)
|
||||||
fp=mock.MagicMock(), code=404)
|
(mock_kube_api.return_value
|
||||||
(mock_kube_api.return_value.replaceReplicationController
|
.replace_namespaced_replication_controller
|
||||||
.side_effect) = err
|
.side_effect) = err
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.assertRaises(exception.KubernetesAPIFailed,
|
self.assertRaises(exception.KubernetesAPIFailed,
|
||||||
self.kube_handler.rc_update,
|
self.kube_handler.rc_update,
|
||||||
self.context, expected_rc)
|
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,
|
.assert_called_once_with(body=manifest, name=expected_rc.name,
|
||||||
namespaces='default'))
|
namespace='default'))
|
||||||
self.assertFalse(expected_rc.update.called)
|
self.assertFalse(expected_rc.update.called)
|
||||||
|
|
||||||
def test_service_update_with_success(self):
|
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:
|
with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api:
|
||||||
self.kube_handler.service_update(self.context, expected_service)
|
self.kube_handler.service_update(self.context, expected_service)
|
||||||
mock_kube_api.return_value.replaceService.assert_called_once_with(
|
(mock_kube_api.return_value.replace_namespaced_service
|
||||||
body=manifest, name=expected_service.name,
|
.assert_called_once_with(
|
||||||
namespaces='default')
|
body=manifest, name=expected_service.name,
|
||||||
|
namespace='default'))
|
||||||
expected_service.refresh.assert_called_once_with(self.context)
|
expected_service.refresh.assert_called_once_with(self.context)
|
||||||
expected_service.save.assert_called_once_with()
|
expected_service.save.assert_called_once_with()
|
||||||
|
|
||||||
@patch('ast.literal_eval')
|
def test_service_update_with_failure(self):
|
||||||
def test_service_update_with_failure(self, mock_literal_eval):
|
|
||||||
expected_service = self.mock_service()
|
expected_service = self.mock_service()
|
||||||
expected_service.uuid = 'test-uuid'
|
expected_service.uuid = 'test-uuid'
|
||||||
expected_service.name = 'test-name'
|
expected_service.name = 'test-name'
|
||||||
|
@ -449,17 +429,17 @@ class TestK8sConductor(base.TestCase):
|
||||||
manifest = {"key": "value"}
|
manifest = {"key": "value"}
|
||||||
expected_service.manifest = '{"key": "value"}'
|
expected_service.manifest = '{"key": "value"}'
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=404)
|
||||||
fp=mock.MagicMock(), code=404)
|
(mock_kube_api.return_value.replace_namespaced_service
|
||||||
mock_kube_api.return_value.replaceService.side_effect = err
|
.side_effect) = err
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.assertRaises(exception.KubernetesAPIFailed,
|
self.assertRaises(exception.KubernetesAPIFailed,
|
||||||
self.kube_handler.service_update,
|
self.kube_handler.service_update,
|
||||||
self.context, expected_service)
|
self.context, expected_service)
|
||||||
mock_kube_api.return_value.replaceService.assert_called_once_with(
|
(mock_kube_api.return_value.replace_namespaced_service
|
||||||
body=manifest, name=expected_service.name,
|
.assert_called_once_with(
|
||||||
namespaces='default')
|
body=manifest, name=expected_service.name,
|
||||||
|
namespace='default'))
|
||||||
self.assertFalse(expected_service.refresh.called)
|
self.assertFalse(expected_service.refresh.called)
|
||||||
|
|
||||||
def test_pod_update_with_success(self):
|
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:
|
with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api:
|
||||||
self.kube_handler.pod_update(self.context, expected_pod)
|
self.kube_handler.pod_update(self.context, expected_pod)
|
||||||
mock_kube_api.return_value.replacePod.assert_called_once_with(
|
(mock_kube_api.return_value.replace_namespaced_pod
|
||||||
body=manifest, name=expected_pod.name,
|
.assert_called_once_with(
|
||||||
namespaces='default')
|
body=manifest, name=expected_pod.name,
|
||||||
|
namespace='default'))
|
||||||
expected_pod.refresh.assert_called_once_with(self.context)
|
expected_pod.refresh.assert_called_once_with(self.context)
|
||||||
expected_pod.save.assert_called_once_with()
|
expected_pod.save.assert_called_once_with()
|
||||||
|
|
||||||
@patch('ast.literal_eval')
|
def test_pod_update_with_failure(self):
|
||||||
def test_pod_update_with_failure(self, mock_literal_eval):
|
|
||||||
expected_pod = self.mock_pod()
|
expected_pod = self.mock_pod()
|
||||||
expected_pod.uuid = 'test-uuid'
|
expected_pod.uuid = 'test-uuid'
|
||||||
expected_pod.name = 'test-name'
|
expected_pod.name = 'test-name'
|
||||||
|
@ -489,15 +469,14 @@ class TestK8sConductor(base.TestCase):
|
||||||
expected_pod.manifest = '{"key": "value"}'
|
expected_pod.manifest = '{"key": "value"}'
|
||||||
|
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') 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',
|
err = rest.ApiException(status=404)
|
||||||
fp=mock.MagicMock(), code=404)
|
mock_kube_api.return_value.replace_namespaced_pod.side_effect = err
|
||||||
mock_kube_api.return_value.replacePod.side_effect = err
|
|
||||||
mock_literal_eval.return_value = {'message': 'error'}
|
|
||||||
|
|
||||||
self.assertRaises(exception.KubernetesAPIFailed,
|
self.assertRaises(exception.KubernetesAPIFailed,
|
||||||
self.kube_handler.pod_update,
|
self.kube_handler.pod_update,
|
||||||
self.context, expected_pod)
|
self.context, expected_pod)
|
||||||
mock_kube_api.return_value.replacePod.assert_called_once_with(
|
(mock_kube_api.return_value.replace_namespaced_pod
|
||||||
body=manifest, name=expected_pod.name,
|
.assert_called_once_with(
|
||||||
namespaces='default')
|
body=manifest, name=expected_pod.name,
|
||||||
|
namespace='default'))
|
||||||
self.assertFalse(expected_pod.refresh.called)
|
self.assertFalse(expected_pod.refresh.called)
|
||||||
|
|
|
@ -32,11 +32,11 @@ class TestScaleManager(base.TestCase):
|
||||||
pods = list()
|
pods = list()
|
||||||
for h in pod_hosts:
|
for h in pod_hosts:
|
||||||
pod = mock.MagicMock()
|
pod = mock.MagicMock()
|
||||||
pod.spec.host = h
|
pod.spec.node_name = h
|
||||||
pods.append(pod)
|
pods.append(pod)
|
||||||
|
|
||||||
mock_k8s_api = mock.MagicMock()
|
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_create_k8s_api.return_value = mock_k8s_api
|
||||||
|
|
||||||
mock_heat_output = mock.MagicMock()
|
mock_heat_output = mock.MagicMock()
|
||||||
|
|
|
@ -46,3 +46,4 @@ six>=1.9.0
|
||||||
stevedore>=1.5.0 # Apache-2.0
|
stevedore>=1.5.0 # Apache-2.0
|
||||||
taskflow>=1.16.0
|
taskflow>=1.16.0
|
||||||
cryptography>=1.0 # Apache-2.0
|
cryptography>=1.0 # Apache-2.0
|
||||||
|
urllib3>=1.8.3
|
||||||
|
|
Loading…
Reference in New Issue