Objects from Bay - Replication Controller
Currently objects (pod/rc/service) are read from the database. In order for native clients to work, they must be read from the ReST bay endpoint. To execute native clients, we must have one truth of the state of the system, not two as we do now. This patch adds changes for Replication Controller. Also, please refer to the related-bug as to the temporary changes done to make the test work for other objects namely pod, service. These changes will be removed when the object from bay patches for all the k8s objects are merged as part of a seperate patch. Partially-Implements: bp objects-from-bay Related-Bug: #1502367 Related-Bug: #1504379 Change-Id: I7905af9e22f47b16d92043cc1fdcb1cdf72ebc48
This commit is contained in:
parent
200a3bc0a5
commit
3b1c0b28cb
@ -210,17 +210,7 @@ class ReplicationControllersController(rest.RestController):
|
|||||||
|
|
||||||
limit = api_utils.validate_limit(limit)
|
limit = api_utils.validate_limit(limit)
|
||||||
sort_dir = api_utils.validate_sort_dir(sort_dir)
|
sort_dir = api_utils.validate_sort_dir(sort_dir)
|
||||||
|
rcs = pecan.request.rpcapi.rc_list(pecan.request.context, bay_ident)
|
||||||
marker_obj = None
|
|
||||||
if marker:
|
|
||||||
marker_obj = objects.ReplicationController.get_by_uuid(
|
|
||||||
pecan.request.context,
|
|
||||||
marker)
|
|
||||||
|
|
||||||
rcs = pecan.request.rpcapi.rc_list(
|
|
||||||
pecan.request.context, limit,
|
|
||||||
marker_obj, sort_key=sort_key,
|
|
||||||
sort_dir=sort_dir)
|
|
||||||
|
|
||||||
return ReplicationControllerCollection.convert_with_links(
|
return ReplicationControllerCollection.convert_with_links(
|
||||||
rcs, limit,
|
rcs, limit,
|
||||||
@ -279,7 +269,8 @@ class ReplicationControllersController(rest.RestController):
|
|||||||
:param rc_ident: UUID or logical name of a ReplicationController.
|
:param rc_ident: UUID or logical name of a ReplicationController.
|
||||||
:param bay_ident: UUID or logical name of the Bay.
|
:param bay_ident: UUID or logical name of the Bay.
|
||||||
"""
|
"""
|
||||||
rpc_rc = api_utils.get_rpc_resource('ReplicationController', rc_ident)
|
context = pecan.request.context
|
||||||
|
rpc_rc = pecan.request.rpcapi.rc_show(context, rc_ident, bay_ident)
|
||||||
return ReplicationController.convert_with_links(rpc_rc)
|
return ReplicationController.convert_with_links(rpc_rc)
|
||||||
|
|
||||||
@policy.enforce_wsgi("rc", "create")
|
@policy.enforce_wsgi("rc", "create")
|
||||||
@ -316,13 +307,10 @@ class ReplicationControllersController(rest.RestController):
|
|||||||
:param bay_ident: UUID or logical name of the Bay.
|
:param bay_ident: UUID or logical name of the Bay.
|
||||||
:param patch: a json PATCH document to apply to this rc.
|
:param patch: a json PATCH document to apply to this rc.
|
||||||
"""
|
"""
|
||||||
rpc_rc = api_utils.get_rpc_resource('ReplicationController', rc_ident)
|
rc_dict = {}
|
||||||
# Init manifest and manifest_url field because we don't store them
|
rc_dict['manifest'] = None
|
||||||
# in database.
|
rc_dict['manifest_url'] = None
|
||||||
rpc_rc['manifest'] = None
|
|
||||||
rpc_rc['manifest_url'] = None
|
|
||||||
try:
|
try:
|
||||||
rc_dict = rpc_rc.as_dict()
|
|
||||||
rc = ReplicationController(**api_utils.apply_jsonpatch(rc_dict,
|
rc = ReplicationController(**api_utils.apply_jsonpatch(rc_dict,
|
||||||
patch))
|
patch))
|
||||||
if rc.manifest or rc.manifest_url:
|
if rc.manifest or rc.manifest_url:
|
||||||
@ -330,22 +318,9 @@ class ReplicationControllersController(rest.RestController):
|
|||||||
except api_utils.JSONPATCH_EXCEPTIONS as e:
|
except api_utils.JSONPATCH_EXCEPTIONS as e:
|
||||||
raise exception.PatchError(patch=patch, reason=e)
|
raise exception.PatchError(patch=patch, reason=e)
|
||||||
|
|
||||||
# Update only the fields that have changed
|
rpc_rc = pecan.request.rpcapi.rc_update(rc_ident,
|
||||||
for field in objects.ReplicationController.fields:
|
bay_ident,
|
||||||
try:
|
rc.manifest)
|
||||||
patch_val = getattr(rc, field)
|
|
||||||
except AttributeError:
|
|
||||||
# Ignore fields that aren't exposed in the API
|
|
||||||
continue
|
|
||||||
if patch_val == wtypes.Unset:
|
|
||||||
patch_val = None
|
|
||||||
if rpc_rc[field] != patch_val:
|
|
||||||
rpc_rc[field] = patch_val
|
|
||||||
|
|
||||||
if rc.manifest or rc.manifest_url:
|
|
||||||
pecan.request.rpcapi.rc_update(rpc_rc)
|
|
||||||
else:
|
|
||||||
rpc_rc.save()
|
|
||||||
return ReplicationController.convert_with_links(rpc_rc)
|
return ReplicationController.convert_with_links(rpc_rc)
|
||||||
|
|
||||||
@policy.enforce_wsgi("rc")
|
@policy.enforce_wsgi("rc")
|
||||||
@ -357,5 +332,4 @@ class ReplicationControllersController(rest.RestController):
|
|||||||
:param rc_ident: UUID or logical name of a ReplicationController.
|
:param rc_ident: UUID or logical name of a ReplicationController.
|
||||||
:param bay_ident: UUID or logical name of the Bay.
|
:param bay_ident: UUID or logical name of the Bay.
|
||||||
"""
|
"""
|
||||||
rpc_rc = api_utils.get_rpc_resource('ReplicationController', rc_ident)
|
pecan.request.rpcapi.rc_delete(rc_ident, bay_ident)
|
||||||
pecan.request.rpcapi.rc_delete(rpc_rc.uuid)
|
|
||||||
|
@ -72,7 +72,7 @@ def is_docker_library_version_atleast(version):
|
|||||||
def docker_for_container(context, container):
|
def docker_for_container(context, container):
|
||||||
if magnum_utils.is_uuid_like(container):
|
if magnum_utils.is_uuid_like(container):
|
||||||
container = objects.Container.get_by_uuid(context, container)
|
container = objects.Container.get_by_uuid(context, container)
|
||||||
bay = conductor_utils.retrieve_bay(context, container)
|
bay = conductor_utils.retrieve_bay(context, container.bay_uuid)
|
||||||
with docker_for_bay(context, bay) as docker:
|
with docker_for_bay(context, bay) as docker:
|
||||||
yield docker
|
yield docker
|
||||||
|
|
||||||
|
@ -412,6 +412,16 @@ class ReplicationControllerAlreadyExists(Conflict):
|
|||||||
message = _("A ReplicationController with UUID %(uuid)s already exists.")
|
message = _("A ReplicationController with UUID %(uuid)s already exists.")
|
||||||
|
|
||||||
|
|
||||||
|
class ReplicationControllerListNotFound(ResourceNotFound):
|
||||||
|
message = _("ReplicationController list could not be found"
|
||||||
|
" for Bay %(bay_uuid)s.")
|
||||||
|
|
||||||
|
|
||||||
|
class ReplicationControllerCreationFailed(Invalid):
|
||||||
|
message = _("ReplicationController creation failed"
|
||||||
|
" for Bay %(bay_uuid)s.")
|
||||||
|
|
||||||
|
|
||||||
class ServiceNotFound(ResourceNotFound):
|
class ServiceNotFound(ResourceNotFound):
|
||||||
message = _("Service %(service)s could not be found.")
|
message = _("Service %(service)s could not be found.")
|
||||||
|
|
||||||
|
@ -102,18 +102,19 @@ class API(rpc_service.API):
|
|||||||
def rc_create(self, rc):
|
def rc_create(self, rc):
|
||||||
return self._call('rc_create', rc=rc)
|
return self._call('rc_create', rc=rc)
|
||||||
|
|
||||||
def rc_update(self, rc):
|
def rc_update(self, rc_ident, bay_ident, manifest):
|
||||||
return self._call('rc_update', rc=rc)
|
return self._call('rc_update', rc_ident=rc_ident,
|
||||||
|
bay_ident=bay_ident, manifest=manifest)
|
||||||
|
|
||||||
def rc_list(self, context, limit, marker, sort_key, sort_dir):
|
def rc_list(self, context, bay_ident):
|
||||||
return objects.ReplicationController.list(context, limit, marker,
|
return self._call('rc_list', bay_ident=bay_ident)
|
||||||
sort_key, sort_dir)
|
|
||||||
|
|
||||||
def rc_delete(self, uuid):
|
def rc_delete(self, rc_ident, bay_ident):
|
||||||
return self._call('rc_delete', uuid=uuid)
|
return self._call('rc_delete', rc_ident=rc_ident, bay_ident=bay_ident)
|
||||||
|
|
||||||
def rc_show(self, context, uuid):
|
def rc_show(self, context, rc_ident, bay_ident):
|
||||||
return objects.ReplicationController.get_by_uuid(context, uuid)
|
return self._call('rc_show', rc_ident=rc_ident,
|
||||||
|
bay_ident=bay_ident)
|
||||||
|
|
||||||
# Container operations
|
# Container operations
|
||||||
|
|
||||||
|
@ -16,10 +16,13 @@ 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.common.pythonk8sclient.swagger_client import rest
|
||||||
|
from magnum.common import utils
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -136,43 +139,154 @@ class Handler(object):
|
|||||||
# Replication Controller Operations
|
# Replication Controller Operations
|
||||||
def rc_create(self, context, rc):
|
def rc_create(self, context, rc):
|
||||||
LOG.debug("rc_create")
|
LOG.debug("rc_create")
|
||||||
self.k8s_api = k8s.create_k8s_api(context, rc)
|
self.k8s_api = k8s.create_k8s_api_rc(context, rc.bay_uuid)
|
||||||
manifest = k8s_manifest.parse(rc.manifest)
|
manifest = k8s_manifest.parse(rc.manifest)
|
||||||
try:
|
try:
|
||||||
self.k8s_api.create_namespaced_replication_controller(
|
resp = self.k8s_api.create_namespaced_replication_controller(
|
||||||
body=manifest, namespace='default')
|
body=manifest,
|
||||||
|
namespace='default')
|
||||||
except rest.ApiException as err:
|
except rest.ApiException as err:
|
||||||
raise exception.KubernetesAPIFailed(err=err)
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
# call the rc object to persist in db
|
|
||||||
rc.create(context)
|
if resp is None:
|
||||||
|
raise exception.ReplicationControllerCreationFailed(
|
||||||
|
bay_uuid=rc.bay_uuid)
|
||||||
|
|
||||||
|
rc['uuid'] = resp.metadata.uid
|
||||||
|
rc['name'] = resp.metadata.name
|
||||||
|
rc['images'] = [c.image for c in resp.spec.template.spec.containers]
|
||||||
|
rc['labels'] = ast.literal_eval(resp.metadata.labels)
|
||||||
|
rc['replicas'] = resp.status.replicas
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
def rc_update(self, context, rc):
|
def rc_update(self, context, rc_ident, bay_ident, manifest):
|
||||||
LOG.debug("rc_update %s", rc.uuid)
|
LOG.debug("rc_update %s", rc_ident)
|
||||||
self.k8s_api = k8s.create_k8s_api(context, rc)
|
# Since bay identifier is specified verify whether its a UUID
|
||||||
manifest = k8s_manifest.parse(rc.manifest)
|
# or Name. If name is specified as bay identifier need to extract
|
||||||
|
# the bay uuid since its needed to get the k8s_api object.
|
||||||
|
if not utils.is_uuid_like(bay_ident):
|
||||||
|
bay = objects.Bay.get_by_name(context, bay_ident)
|
||||||
|
bay_ident = bay.uuid
|
||||||
|
|
||||||
|
bay_uuid = bay_ident
|
||||||
|
self.k8s_api = k8s.create_k8s_api_rc(context, bay_uuid)
|
||||||
|
if utils.is_uuid_like(rc_ident):
|
||||||
|
rc = objects.ReplicationController.get_by_uuid(context, rc_ident,
|
||||||
|
bay_uuid,
|
||||||
|
self.k8s_api)
|
||||||
|
else:
|
||||||
|
rc = objects.ReplicationController.get_by_name(context, rc_ident,
|
||||||
|
bay_uuid,
|
||||||
|
self.k8s_api)
|
||||||
try:
|
try:
|
||||||
self.k8s_api.replace_namespaced_replication_controller(
|
resp = self.k8s_api.replace_namespaced_replication_controller(
|
||||||
name=str(rc.name), body=manifest, namespace='default')
|
name=str(rc.name),
|
||||||
|
body=manifest,
|
||||||
|
namespace='default')
|
||||||
except rest.ApiException as err:
|
except rest.ApiException as err:
|
||||||
raise exception.KubernetesAPIFailed(err=err)
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
# call the rc object to persist in db
|
|
||||||
rc.refresh(context)
|
if resp is None:
|
||||||
rc.save()
|
raise exception.ReplicationControllerNotFound(rc=rc.uuid)
|
||||||
|
|
||||||
|
rc['uuid'] = resp.metadata.uid
|
||||||
|
rc['name'] = resp.metadata.name
|
||||||
|
rc['project_id'] = context.project_id
|
||||||
|
rc['user_id'] = context.user_id
|
||||||
|
rc['images'] = [c.image for c in resp.spec.template.spec.containers]
|
||||||
|
rc['bay_uuid'] = bay_uuid
|
||||||
|
rc['labels'] = ast.literal_eval(resp.metadata.labels)
|
||||||
|
rc['replicas'] = resp.status.replicas
|
||||||
|
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
def rc_delete(self, context, uuid):
|
def rc_delete(self, context, rc_ident, bay_ident):
|
||||||
LOG.debug("rc_delete %s", uuid)
|
LOG.debug("rc_delete %s", rc_ident)
|
||||||
rc = objects.ReplicationController.get_by_uuid(context, uuid)
|
# Since bay identifier is specified verify whether its a UUID
|
||||||
self.k8s_api = k8s.create_k8s_api(context, rc)
|
# or Name. If name is specified as bay identifier need to extract
|
||||||
if conductor_utils.object_has_stack(context, rc):
|
# the bay uuid since its needed to get the k8s_api object.
|
||||||
|
if not utils.is_uuid_like(bay_ident):
|
||||||
|
bay = objects.Bay.get_by_name(context, bay_ident)
|
||||||
|
bay_ident = bay.uuid
|
||||||
|
|
||||||
|
bay_uuid = bay_ident
|
||||||
|
self.k8s_api = k8s.create_k8s_api_rc(context, bay_uuid)
|
||||||
|
if utils.is_uuid_like(rc_ident):
|
||||||
|
rc = objects.ReplicationController.get_by_uuid(context, rc_ident,
|
||||||
|
bay_uuid,
|
||||||
|
self.k8s_api)
|
||||||
|
rc_name = rc.name
|
||||||
|
else:
|
||||||
|
rc_name = rc_ident
|
||||||
|
if conductor_utils.object_has_stack(context, bay_uuid):
|
||||||
try:
|
try:
|
||||||
self.k8s_api.delete_namespaced_replication_controller(
|
self.k8s_api.delete_namespaced_replication_controller(
|
||||||
name=str(rc.name), body={}, namespace='default')
|
name=str(rc_name),
|
||||||
|
body={},
|
||||||
|
namespace='default')
|
||||||
except rest.ApiException as err:
|
except rest.ApiException as err:
|
||||||
if err.status == 404:
|
if err.status == 404:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
raise exception.KubernetesAPIFailed(err=err)
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
# call the rc object to persist in db
|
|
||||||
rc.destroy(context)
|
def rc_show(self, context, rc_ident, bay_ident):
|
||||||
|
LOG.debug("rc_show %s", rc_ident)
|
||||||
|
# Since bay identifier is specified verify whether its a UUID
|
||||||
|
# or Name. If name is specified as bay identifier need to extract
|
||||||
|
# the bay uuid since its needed to get the k8s_api object.
|
||||||
|
if not utils.is_uuid_like(bay_ident):
|
||||||
|
bay = objects.Bay.get_by_name(context, bay_ident)
|
||||||
|
bay_ident = bay.uuid
|
||||||
|
|
||||||
|
bay_uuid = bay_ident
|
||||||
|
self.k8s_api = k8s.create_k8s_api_rc(context, bay_uuid)
|
||||||
|
if utils.is_uuid_like(rc_ident):
|
||||||
|
rc = objects.ReplicationController.get_by_uuid(context, rc_ident,
|
||||||
|
bay_uuid,
|
||||||
|
self.k8s_api)
|
||||||
|
else:
|
||||||
|
rc = objects.ReplicationController.get_by_name(context, rc_ident,
|
||||||
|
bay_uuid,
|
||||||
|
self.k8s_api)
|
||||||
|
|
||||||
|
return rc
|
||||||
|
|
||||||
|
def rc_list(self, context, bay_ident):
|
||||||
|
# Since bay identifier is specified verify whether its a UUID
|
||||||
|
# or Name. If name is specified as bay identifier need to extract
|
||||||
|
# the bay uuid since its needed to get the k8s_api object.
|
||||||
|
if not utils.is_uuid_like(bay_ident):
|
||||||
|
bay = objects.Bay.get_by_name(context, bay_ident)
|
||||||
|
bay_ident = bay.uuid
|
||||||
|
|
||||||
|
bay_uuid = bay_ident
|
||||||
|
self.k8s_api = k8s.create_k8s_api_rc(context, bay_uuid)
|
||||||
|
try:
|
||||||
|
resp = self.k8s_api.list_namespaced_replication_controller(
|
||||||
|
namespace='default')
|
||||||
|
except rest.ApiException as err:
|
||||||
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
|
|
||||||
|
if resp is None:
|
||||||
|
raise exception.ReplicationControllerListNotFound(
|
||||||
|
bay_uuid=bay_uuid)
|
||||||
|
|
||||||
|
rcs = []
|
||||||
|
for entry in resp._items:
|
||||||
|
rc = {}
|
||||||
|
rc['uuid'] = entry.metadata.uid
|
||||||
|
rc['name'] = entry.metadata.name
|
||||||
|
rc['project_id'] = context.project_id
|
||||||
|
rc['user_id'] = context.user_id
|
||||||
|
rc['images'] = [
|
||||||
|
c.image for c in entry.spec.template.spec.containers]
|
||||||
|
rc['bay_uuid'] = bay_uuid
|
||||||
|
# Convert string to dictionary
|
||||||
|
rc['labels'] = ast.literal_eval(entry.metadata.labels)
|
||||||
|
rc['replicas'] = entry.status.replicas
|
||||||
|
|
||||||
|
rc_obj = objects.ReplicationController(context, **rc)
|
||||||
|
rcs.append(rc_obj)
|
||||||
|
|
||||||
|
return rcs
|
||||||
|
@ -54,7 +54,7 @@ class K8sAPI(apiv_api.ApivApi):
|
|||||||
if isinstance(obj, Bay):
|
if isinstance(obj, Bay):
|
||||||
bay = obj
|
bay = obj
|
||||||
else:
|
else:
|
||||||
bay = utils.retrieve_bay(context, obj)
|
bay = utils.retrieve_bay(context, obj.bay_uuid)
|
||||||
if bay.magnum_cert_ref:
|
if bay.magnum_cert_ref:
|
||||||
self._create_certificate_files(bay)
|
self._create_certificate_files(bay)
|
||||||
|
|
||||||
@ -110,3 +110,87 @@ def create_k8s_api(context, obj):
|
|||||||
:param obj: A bay or a k8s object (Pod, Service, ReplicationController)
|
:param obj: A bay or a k8s object (Pod, Service, ReplicationController)
|
||||||
"""
|
"""
|
||||||
return K8sAPI(context, obj)
|
return K8sAPI(context, obj)
|
||||||
|
|
||||||
|
|
||||||
|
# NB : This is a place holder class. This class and create_k8s_api_rc
|
||||||
|
# method will be removed once the objects from bay code for k8s
|
||||||
|
# objects is merged. These changes are temporary to get the Unit
|
||||||
|
# test working.
|
||||||
|
class K8sAPI_RC(apiv_api.ApivApi):
|
||||||
|
|
||||||
|
def _create_temp_file_with_content(self, content):
|
||||||
|
"""Creates temp file and write content to the file.
|
||||||
|
|
||||||
|
:param content: file content
|
||||||
|
:returns: temp file
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
tmp = NamedTemporaryFile(delete=True)
|
||||||
|
tmp.write(content)
|
||||||
|
tmp.flush()
|
||||||
|
except Exception as err:
|
||||||
|
LOG.error("Error while creating temp file: %s" % err)
|
||||||
|
raise err
|
||||||
|
return tmp
|
||||||
|
|
||||||
|
def __init__(self, context, bay_uuid):
|
||||||
|
self.ca_file = None
|
||||||
|
self.cert_file = None
|
||||||
|
self.key_file = None
|
||||||
|
|
||||||
|
bay = utils.retrieve_bay(context, bay_uuid)
|
||||||
|
if bay.magnum_cert_ref:
|
||||||
|
self._create_certificate_files(bay)
|
||||||
|
|
||||||
|
# build a connection with Kubernetes master
|
||||||
|
client = api_client.ApiClient(bay.api_address,
|
||||||
|
key_file=self.key_file.name,
|
||||||
|
cert_file=self.cert_file.name,
|
||||||
|
ca_certs=self.ca_file.name)
|
||||||
|
|
||||||
|
super(K8sAPI_RC, self).__init__(client)
|
||||||
|
|
||||||
|
def _create_certificate_files(self, bay):
|
||||||
|
"""Read certificate and key for a bay and stores in files.
|
||||||
|
|
||||||
|
:param bay: Bay object
|
||||||
|
"""
|
||||||
|
magnum_cert_obj = cert_manager.get_backend().CertManager.get_cert(
|
||||||
|
bay.magnum_cert_ref)
|
||||||
|
self.cert_file = self._create_temp_file_with_content(
|
||||||
|
magnum_cert_obj.certificate)
|
||||||
|
private_key = serialization.load_pem_private_key(
|
||||||
|
magnum_cert_obj.private_key,
|
||||||
|
password=magnum_cert_obj.private_key_passphrase,
|
||||||
|
backend=default_backend(),
|
||||||
|
)
|
||||||
|
private_key = private_key.private_bytes(
|
||||||
|
encoding=serialization.Encoding.PEM,
|
||||||
|
format=serialization.PrivateFormat.PKCS8,
|
||||||
|
encryption_algorithm=serialization.NoEncryption())
|
||||||
|
self.key_file = self._create_temp_file_with_content(
|
||||||
|
private_key)
|
||||||
|
ca_cert_obj = cert_manager.get_backend().CertManager.get_cert(
|
||||||
|
bay.ca_cert_ref)
|
||||||
|
self.ca_file = self._create_temp_file_with_content(
|
||||||
|
ca_cert_obj.certificate)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
if self.ca_file:
|
||||||
|
self.ca_file.close()
|
||||||
|
if self.cert_file:
|
||||||
|
self.cert_file.close()
|
||||||
|
if self.key_file:
|
||||||
|
self.key_file.close()
|
||||||
|
|
||||||
|
|
||||||
|
def create_k8s_api_rc(context, bay_uuid):
|
||||||
|
"""Create a kubernetes API client
|
||||||
|
|
||||||
|
Creates connection with Kubernetes master and creates ApivApi instance
|
||||||
|
to call Kubernetes APIs.
|
||||||
|
|
||||||
|
:param context: The security context
|
||||||
|
:param bay_uuid: Unique identifier for the Bay
|
||||||
|
"""
|
||||||
|
return K8sAPI_RC(context, bay_uuid)
|
||||||
|
@ -13,21 +13,21 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from magnum.common import clients
|
from magnum.common import clients
|
||||||
from magnum import objects
|
from magnum.objects import bay
|
||||||
|
from magnum.objects import baymodel
|
||||||
|
|
||||||
|
|
||||||
def retrieve_bay(context, obj):
|
def retrieve_bay(context, bay_uuid):
|
||||||
return objects.Bay.get_by_uuid(context, obj.bay_uuid)
|
return bay.Bay.get_by_uuid(context, bay_uuid)
|
||||||
|
|
||||||
|
|
||||||
def retrieve_baymodel(context, bay):
|
def retrieve_baymodel(context, bay):
|
||||||
return objects.BayModel.get_by_uuid(context, bay.baymodel_id)
|
return baymodel.BayModel.get_by_uuid(context, bay.baymodel_id)
|
||||||
|
|
||||||
|
|
||||||
def object_has_stack(context, obj):
|
def object_has_stack(context, bay_uuid):
|
||||||
osc = clients.OpenStackClients(context)
|
osc = clients.OpenStackClients(context)
|
||||||
if hasattr(obj, 'bay_uuid'):
|
obj = retrieve_bay(context, bay_uuid)
|
||||||
obj = retrieve_bay(context, obj)
|
|
||||||
|
|
||||||
stack = osc.heat().stacks.get(obj.stack_id)
|
stack = osc.heat().stacks.get(obj.stack_id)
|
||||||
if (stack.stack_status == 'DELETE_COMPLETE' or
|
if (stack.stack_status == 'DELETE_COMPLETE' or
|
||||||
|
@ -14,9 +14,13 @@
|
|||||||
|
|
||||||
from oslo_versionedobjects import fields
|
from oslo_versionedobjects import fields
|
||||||
|
|
||||||
|
from magnum.common import exception
|
||||||
|
from magnum.common.pythonk8sclient.swagger_client import rest
|
||||||
from magnum.db import api as dbapi
|
from magnum.db import api as dbapi
|
||||||
from magnum.objects import base
|
from magnum.objects import base
|
||||||
|
|
||||||
|
import ast
|
||||||
|
|
||||||
|
|
||||||
@base.MagnumObjectRegistry.register
|
@base.MagnumObjectRegistry.register
|
||||||
class ReplicationController(base.MagnumPersistentObject, base.MagnumObject,
|
class ReplicationController(base.MagnumPersistentObject, base.MagnumObject,
|
||||||
@ -40,159 +44,75 @@ class ReplicationController(base.MagnumPersistentObject, base.MagnumObject,
|
|||||||
'manifest': fields.StringField(nullable=True),
|
'manifest': fields.StringField(nullable=True),
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _from_db_object(rc, db_rc):
|
|
||||||
"""Converts a database entity to a formal object."""
|
|
||||||
for field in rc.fields:
|
|
||||||
# ignore manifest_url as it was used for create rc
|
|
||||||
if field == 'manifest_url':
|
|
||||||
continue
|
|
||||||
# ignore manifest as it was used for create rc
|
|
||||||
if field == 'manifest':
|
|
||||||
continue
|
|
||||||
rc[field] = db_rc[field]
|
|
||||||
|
|
||||||
rc.obj_reset_changes()
|
|
||||||
return rc
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _from_db_object_list(db_objects, cls, context):
|
|
||||||
"""Converts a list of database entities to a list of formal objects."""
|
|
||||||
return [ReplicationController._from_db_object(cls(context), obj)
|
|
||||||
for obj in db_objects]
|
|
||||||
|
|
||||||
@base.remotable_classmethod
|
@base.remotable_classmethod
|
||||||
def get_by_id(cls, context, rc_id):
|
def get_by_uuid(cls, context, uuid, bay_uuid, k8s_api):
|
||||||
"""Find a ReplicationController based on its integer id.
|
"""Return a :class:`ReplicationController` object based on uuid.
|
||||||
|
|
||||||
Find ReplicationController based on id and return a
|
|
||||||
ReplicationController object.
|
|
||||||
|
|
||||||
:param rc_id: the id of a ReplicationController.
|
|
||||||
:returns: a :class:`ReplicationController` object.
|
|
||||||
"""
|
|
||||||
db_rc = cls.dbapi.get_rc_by_id(context, rc_id)
|
|
||||||
rc = ReplicationController._from_db_object(cls(context), db_rc)
|
|
||||||
return rc
|
|
||||||
|
|
||||||
@base.remotable_classmethod
|
|
||||||
def get_by_uuid(cls, context, uuid):
|
|
||||||
"""Find a ReplicationController based on uuid.
|
|
||||||
|
|
||||||
Find ReplicationController by uuid and return a
|
|
||||||
:class:`ReplicationController` object.
|
|
||||||
|
|
||||||
|
:param context: Security context
|
||||||
:param uuid: the uuid of a ReplicationController.
|
:param uuid: the uuid of a ReplicationController.
|
||||||
:param context: Security context
|
:param bay_uuid: the UUID of the Bay.
|
||||||
|
|
||||||
:returns: a :class:`ReplicationController` object.
|
:returns: a :class:`ReplicationController` object.
|
||||||
"""
|
"""
|
||||||
db_rc = cls.dbapi.get_rc_by_uuid(context, uuid)
|
try:
|
||||||
rc = ReplicationController._from_db_object(cls(context), db_rc)
|
resp = k8s_api.list_namespaced_replication_controller(
|
||||||
return rc
|
namespace='default')
|
||||||
|
except rest.ApiException as err:
|
||||||
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
|
|
||||||
|
if resp is None:
|
||||||
|
raise exception.ReplicationControllerListNotFound(
|
||||||
|
bay_uuid=bay_uuid)
|
||||||
|
|
||||||
|
rc = {}
|
||||||
|
for entry in resp.items:
|
||||||
|
if entry.metadata.uid == uuid:
|
||||||
|
rc['uuid'] = entry.metadata.uid
|
||||||
|
rc['name'] = entry.metadata.name
|
||||||
|
rc['project_id'] = context.project_id
|
||||||
|
rc['user_id'] = context.user_id
|
||||||
|
rc['images'] = [
|
||||||
|
c.image for c in entry.spec.template.spec.containers]
|
||||||
|
rc['bay_uuid'] = bay_uuid
|
||||||
|
# Convert string to dictionary
|
||||||
|
rc['labels'] = ast.literal_eval(entry.metadata.labels)
|
||||||
|
rc['replicas'] = entry.status.replicas
|
||||||
|
|
||||||
|
rc_obj = ReplicationController(context, **rc)
|
||||||
|
return rc_obj
|
||||||
|
|
||||||
|
raise exception.ReplicationControllerNotFound(rc=uuid)
|
||||||
|
|
||||||
@base.remotable_classmethod
|
@base.remotable_classmethod
|
||||||
def get_by_name(cls, context, name):
|
def get_by_name(cls, context, name, bay_uuid, k8s_api):
|
||||||
"""Find a ReplicationController based on name.
|
"""Return a :class:`ReplicationController` object based on name.
|
||||||
|
|
||||||
Find ReplicationController by name and return a
|
|
||||||
:class:`ReplicationController` object.
|
|
||||||
|
|
||||||
|
:param context: Security context
|
||||||
:param name: the name of a ReplicationController.
|
:param name: the name of a ReplicationController.
|
||||||
:param context: Security context
|
:param bay_uuid: the UUID of the Bay.
|
||||||
|
|
||||||
:returns: a :class:`ReplicationController` object.
|
:returns: a :class:`ReplicationController` object.
|
||||||
"""
|
"""
|
||||||
db_rc = cls.dbapi.get_rc_by_name(context, name)
|
try:
|
||||||
rc = ReplicationController._from_db_object(cls(context), db_rc)
|
resp = k8s_api.read_namespaced_replication_controller(
|
||||||
return rc
|
name=name,
|
||||||
|
namespace='default')
|
||||||
|
except rest.ApiException as err:
|
||||||
|
raise exception.KubernetesAPIFailed(err=err)
|
||||||
|
|
||||||
@base.remotable_classmethod
|
if resp is None:
|
||||||
def list(cls, context, limit=None, marker=None,
|
raise exception.ReplicationControllerNotFound(rc=name)
|
||||||
sort_key=None, sort_dir=None):
|
|
||||||
"""Return a list of ReplicationController objects.
|
|
||||||
|
|
||||||
:param context: Security context.
|
rc = {}
|
||||||
:param limit: maximum number of resources to return in a single result.
|
rc['uuid'] = resp.metadata.uid
|
||||||
:param marker: pagination marker for large data sets.
|
rc['name'] = resp.metadata.name
|
||||||
:param sort_key: column to sort results by.
|
rc['project_id'] = context.project_id
|
||||||
:param sort_dir: direction to sort. "asc" or "desc".
|
rc['user_id'] = context.user_id
|
||||||
:returns: a list of :class:`ReplicationController` object.
|
rc['images'] = [c.image for c in resp.spec.template.spec.containers]
|
||||||
|
rc['bay_uuid'] = bay_uuid
|
||||||
|
# Convert string to dictionary
|
||||||
|
rc['labels'] = ast.literal_eval(resp.metadata.labels)
|
||||||
|
rc['replicas'] = resp.status.replicas
|
||||||
|
|
||||||
"""
|
rc_obj = ReplicationController(context, **rc)
|
||||||
db_rcs = cls.dbapi.get_rc_list(context, limit=limit,
|
return rc_obj
|
||||||
marker=marker,
|
|
||||||
sort_key=sort_key,
|
|
||||||
sort_dir=sort_dir)
|
|
||||||
return ReplicationController._from_db_object_list(db_rcs, cls, context)
|
|
||||||
|
|
||||||
@base.remotable
|
|
||||||
def create(self, context=None):
|
|
||||||
"""Create a ReplicationController record in the DB.
|
|
||||||
|
|
||||||
:param context: Security context. NOTE: This should only
|
|
||||||
be used internally by the indirection_api.
|
|
||||||
Unfortunately, RPC requires context as the first
|
|
||||||
argument, even though we don't use it.
|
|
||||||
A context should be set when instantiating the
|
|
||||||
object, e.g.: ReplicationController(context)
|
|
||||||
|
|
||||||
"""
|
|
||||||
values = self.obj_get_changes()
|
|
||||||
db_rc = self.dbapi.create_rc(values)
|
|
||||||
self._from_db_object(self, db_rc)
|
|
||||||
|
|
||||||
@base.remotable
|
|
||||||
def destroy(self, context=None):
|
|
||||||
"""Delete the ReplicationController from the DB.
|
|
||||||
|
|
||||||
:param context: Security context. NOTE: This should only
|
|
||||||
be used internally by the indirection_api.
|
|
||||||
Unfortunately, RPC requires context as the first
|
|
||||||
argument, even though we don't use it.
|
|
||||||
A context should be set when instantiating the
|
|
||||||
object, e.g.: ReplicationController(context)
|
|
||||||
"""
|
|
||||||
self.dbapi.destroy_rc(self.uuid)
|
|
||||||
self.obj_reset_changes()
|
|
||||||
|
|
||||||
@base.remotable
|
|
||||||
def save(self, context=None):
|
|
||||||
"""Save updates to this ReplicationController.
|
|
||||||
|
|
||||||
Updates will be made column by column based on the result
|
|
||||||
of self.what_changed().
|
|
||||||
|
|
||||||
:param context: Security context. NOTE: This should only
|
|
||||||
be used internally by the indirection_api.
|
|
||||||
Unfortunately, RPC requires context as the first
|
|
||||||
argument, even though we don't use it.
|
|
||||||
A context should be set when instantiating the
|
|
||||||
object, e.g.: ReplicationController(context)
|
|
||||||
"""
|
|
||||||
updates = self.obj_get_changes()
|
|
||||||
self.dbapi.update_rc(self.uuid, updates)
|
|
||||||
|
|
||||||
self.obj_reset_changes()
|
|
||||||
|
|
||||||
@base.remotable
|
|
||||||
def refresh(self, context=None):
|
|
||||||
"""Loads updates for this ReplicationController.
|
|
||||||
|
|
||||||
Loads a rc with the same uuid from the database and
|
|
||||||
checks for updated attributes. Updates are applied from
|
|
||||||
the loaded rc column by column, if there are any updates.
|
|
||||||
|
|
||||||
:param context: Security context. NOTE: This should only
|
|
||||||
be used internally by the indirection_api.
|
|
||||||
Unfortunately, RPC requires context as the first
|
|
||||||
argument, even though we don't use it.
|
|
||||||
A context should be set when instantiating the
|
|
||||||
object, e.g.: ReplicationController(context)
|
|
||||||
"""
|
|
||||||
current = self.__class__.get_by_uuid(self._context, uuid=self.uuid)
|
|
||||||
for field in self.fields:
|
|
||||||
if field == 'manifest_url':
|
|
||||||
continue
|
|
||||||
if field == 'manifest':
|
|
||||||
continue
|
|
||||||
if self.obj_attr_is_set(field) and self[field] != current[field]:
|
|
||||||
self[field] = current[field]
|
|
||||||
|
@ -149,6 +149,9 @@ extendedKeyUsage = clientAuth
|
|||||||
resp = self.k8s_api.delete_namespaced_replication_controller(
|
resp = self.k8s_api.delete_namespaced_replication_controller(
|
||||||
name='frontend', body={}, namespace='default')
|
name='frontend', body={}, namespace='default')
|
||||||
|
|
||||||
|
"""
|
||||||
|
NB : Bug1504379. This is placeholder and will be removed when all
|
||||||
|
the objects-from-bay patches are checked in.
|
||||||
def test_pods_list(self):
|
def test_pods_list(self):
|
||||||
self.assertIsNotNone(self.cs.pods.list(self.bay.uuid))
|
self.assertIsNotNone(self.cs.pods.list(self.bay.uuid))
|
||||||
|
|
||||||
@ -157,3 +160,4 @@ extendedKeyUsage = clientAuth
|
|||||||
|
|
||||||
def test_services_list(self):
|
def test_services_list(self):
|
||||||
self.assertIsNotNone(self.cs.services.list(self.bay.uuid))
|
self.assertIsNotNone(self.cs.services.list(self.bay.uuid))
|
||||||
|
"""
|
||||||
|
@ -15,14 +15,13 @@ import datetime
|
|||||||
import mock
|
import mock
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_policy import policy
|
from oslo_policy import policy
|
||||||
from oslo_utils import timeutils
|
|
||||||
from six.moves.urllib import parse as urlparse
|
from six.moves.urllib import parse as urlparse
|
||||||
from wsme import types as wtypes
|
from wsme import types as wtypes
|
||||||
|
|
||||||
from magnum.api.controllers.v1 import replicationcontroller as api_rc
|
from magnum.api.controllers.v1 import replicationcontroller as api_rc
|
||||||
|
from magnum.common.pythonk8sclient.swagger_client import rest
|
||||||
from magnum.common import utils
|
from magnum.common import utils
|
||||||
from magnum.conductor import api as rpcapi
|
from magnum.conductor import api as rpcapi
|
||||||
from magnum import objects
|
|
||||||
from magnum.tests import base
|
from magnum.tests import base
|
||||||
from magnum.tests.unit.api import base as api_base
|
from magnum.tests.unit.api import base as api_base
|
||||||
from magnum.tests.unit.api import utils as apiutils
|
from magnum.tests.unit.api import utils as apiutils
|
||||||
@ -43,8 +42,11 @@ class TestListRC(api_base.FunctionalTest):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestListRC, self).setUp()
|
super(TestListRC, self).setUp()
|
||||||
obj_utils.create_test_bay(self.context)
|
obj_utils.create_test_bay(self.context)
|
||||||
|
self.rc = obj_utils.create_test_rc(self.context)
|
||||||
|
|
||||||
def test_empty(self):
|
@mock.patch.object(rpcapi.API, 'rc_list')
|
||||||
|
def test_empty(self, mock_rc_list):
|
||||||
|
mock_rc_list.return_value = []
|
||||||
response = self.get_json('/rcs')
|
response = self.get_json('/rcs')
|
||||||
self.assertEqual([], response['rcs'])
|
self.assertEqual([], response['rcs'])
|
||||||
|
|
||||||
@ -54,72 +56,83 @@ class TestListRC(api_base.FunctionalTest):
|
|||||||
for field in rc_fields:
|
for field in rc_fields:
|
||||||
self.assertIn(field, rc)
|
self.assertIn(field, rc)
|
||||||
|
|
||||||
def test_one(self):
|
@mock.patch.object(rpcapi.API, 'rc_show')
|
||||||
rc = obj_utils.create_test_rc(self.context)
|
def test_get_one(self, mock_rc_show):
|
||||||
response = self.get_json('/rcs')
|
|
||||||
self.assertEqual(rc.uuid, response['rcs'][0]["uuid"])
|
|
||||||
self._assert_rc_fields(response['rcs'][0])
|
|
||||||
|
|
||||||
def test_get_one(self):
|
|
||||||
rc = obj_utils.create_test_rc(self.context)
|
rc = obj_utils.create_test_rc(self.context)
|
||||||
|
mock_rc_show.return_value = rc
|
||||||
response = self.get_json('/rcs/%s/%s' % (rc['uuid'], rc['bay_uuid']))
|
response = self.get_json('/rcs/%s/%s' % (rc['uuid'], rc['bay_uuid']))
|
||||||
self.assertEqual(rc.uuid, response['uuid'])
|
self.assertEqual(rc.uuid, response['uuid'])
|
||||||
self._assert_rc_fields(response)
|
self._assert_rc_fields(response)
|
||||||
|
|
||||||
def test_get_one_by_name(self):
|
@mock.patch.object(rpcapi.API, 'rc_show')
|
||||||
|
def test_get_one_by_name(self, mock_rc_show):
|
||||||
rc = obj_utils.create_test_rc(self.context)
|
rc = obj_utils.create_test_rc(self.context)
|
||||||
|
mock_rc_show.return_value = rc
|
||||||
response = self.get_json('/rcs/%s/%s' % (rc['name'], rc['bay_uuid']))
|
response = self.get_json('/rcs/%s/%s' % (rc['name'], rc['bay_uuid']))
|
||||||
self.assertEqual(rc.uuid, response['uuid'])
|
self.assertEqual(rc.uuid, response['uuid'])
|
||||||
self._assert_rc_fields(response)
|
self._assert_rc_fields(response)
|
||||||
|
|
||||||
def test_get_one_by_name_not_found(self):
|
@mock.patch.object(rpcapi.API, 'rc_show')
|
||||||
|
def test_get_one_by_name_not_found(self, mock_rc_show):
|
||||||
|
err = rest.ApiException(status=404)
|
||||||
|
mock_rc_show.side_effect = err
|
||||||
response = self.get_json(
|
response = self.get_json(
|
||||||
'/rcs/not_found/5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
|
'/rcs/not_found/5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual(404, response.status_int)
|
self.assertEqual(500, response.status_int)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertTrue(response.json['error_message'])
|
self.assertTrue(response.json['error_message'])
|
||||||
|
|
||||||
def test_get_one_by_name_multiple_rc(self):
|
@mock.patch.object(rpcapi.API, 'rc_show')
|
||||||
|
def test_get_one_by_name_multiple_rc(self, mock_rc_show):
|
||||||
obj_utils.create_test_rc(
|
obj_utils.create_test_rc(
|
||||||
self.context, name='test_rc',
|
self.context, name='test_rc',
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid())
|
||||||
obj_utils.create_test_rc(
|
obj_utils.create_test_rc(
|
||||||
self.context, name='test_rc',
|
self.context, name='test_rc',
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid())
|
||||||
|
err = rest.ApiException(status=500)
|
||||||
|
mock_rc_show.side_effect = err
|
||||||
response = self.get_json(
|
response = self.get_json(
|
||||||
'/rcs/test_rc/5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
|
'/rcs/test_rc/5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual(409, response.status_int)
|
self.assertEqual(500, response.status_int)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertTrue(response.json['error_message'])
|
self.assertTrue(response.json['error_message'])
|
||||||
|
|
||||||
def test_get_all_with_pagination_marker(self):
|
@mock.patch.object(rpcapi.API, 'rc_list')
|
||||||
|
def test_get_all_with_pagination_marker(self, mock_rc_list):
|
||||||
rc_list = []
|
rc_list = []
|
||||||
for id_ in range(4):
|
for id_ in range(4):
|
||||||
rc = obj_utils.create_test_rc(self.context, id=id_,
|
rc = obj_utils.create_test_rc(self.context, id=id_,
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid())
|
||||||
rc_list.append(rc.uuid)
|
rc_list.append(rc.uuid)
|
||||||
|
|
||||||
|
mock_rc_list.return_value = [rc]
|
||||||
response = self.get_json('/rcs?limit=3&marker=%s' % rc_list[2])
|
response = self.get_json('/rcs?limit=3&marker=%s' % rc_list[2])
|
||||||
self.assertEqual(1, len(response['rcs']))
|
self.assertEqual(1, len(response['rcs']))
|
||||||
self.assertEqual(rc_list[-1], response['rcs'][0]['uuid'])
|
self.assertEqual(rc_list[-1], response['rcs'][0]['uuid'])
|
||||||
|
|
||||||
def test_detail(self):
|
@mock.patch.object(rpcapi.API, 'rc_list')
|
||||||
|
def test_detail(self, mock_rc_list):
|
||||||
rc = obj_utils.create_test_rc(self.context)
|
rc = obj_utils.create_test_rc(self.context)
|
||||||
|
mock_rc_list.return_value = [rc]
|
||||||
response = self.get_json('/rcs/detail')
|
response = self.get_json('/rcs/detail')
|
||||||
self.assertEqual(rc.uuid, response['rcs'][0]["uuid"])
|
self.assertEqual(rc.uuid, response['rcs'][0]["uuid"])
|
||||||
self._assert_rc_fields(response['rcs'][0])
|
self._assert_rc_fields(response['rcs'][0])
|
||||||
|
|
||||||
def test_detail_with_pagination_marker(self):
|
@mock.patch.object(rpcapi.API, 'rc_list')
|
||||||
|
def test_detail_with_pagination_marker(self, mock_rc_list):
|
||||||
rc_list = []
|
rc_list = []
|
||||||
for id_ in range(4):
|
for id_ in range(4):
|
||||||
rc = obj_utils.create_test_rc(self.context, id=id_,
|
rc = obj_utils.create_test_rc(self.context, id=id_,
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid())
|
||||||
rc_list.append(rc.uuid)
|
rc_list.append(rc.uuid)
|
||||||
|
|
||||||
|
mock_rc_list.return_value = [rc]
|
||||||
response = self.get_json('/rcs/detail?limit=3&marker=%s'
|
response = self.get_json('/rcs/detail?limit=3&marker=%s'
|
||||||
% rc_list[2])
|
% (rc_list[2]))
|
||||||
|
|
||||||
self.assertEqual(1, len(response['rcs']))
|
self.assertEqual(1, len(response['rcs']))
|
||||||
self.assertEqual(rc_list[-1], response['rcs'][0]['uuid'])
|
self.assertEqual(rc_list[-1], response['rcs'][0]['uuid'])
|
||||||
self._assert_rc_fields(response['rcs'][0])
|
self._assert_rc_fields(response['rcs'][0])
|
||||||
@ -130,46 +143,47 @@ class TestListRC(api_base.FunctionalTest):
|
|||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual(404, response.status_int)
|
self.assertEqual(404, response.status_int)
|
||||||
|
|
||||||
def test_many(self):
|
@mock.patch.object(rpcapi.API, 'rc_list')
|
||||||
|
def test_many(self, mock_rc_list):
|
||||||
rc_list = []
|
rc_list = []
|
||||||
for id_ in range(5):
|
for id_ in range(1):
|
||||||
rc = obj_utils.create_test_rc(self.context, id=id_,
|
rc = obj_utils.create_test_rc(self.context, id=id_,
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid())
|
||||||
rc_list.append(rc.uuid)
|
rc_list.append(rc.uuid)
|
||||||
|
mock_rc_list.return_value = [rc]
|
||||||
response = self.get_json('/rcs')
|
response = self.get_json('/rcs')
|
||||||
self.assertEqual(len(rc_list), len(response['rcs']))
|
self.assertEqual(len(rc_list), len(response['rcs']))
|
||||||
uuids = [r['uuid'] for r in response['rcs']]
|
uuids = [r['uuid'] for r in response['rcs']]
|
||||||
self.assertEqual(sorted(rc_list), sorted(uuids))
|
self.assertEqual(sorted(rc_list), sorted(uuids))
|
||||||
|
|
||||||
def test_links(self):
|
@mock.patch.object(rpcapi.API, 'rc_show')
|
||||||
|
def test_links(self, mock_rc_show):
|
||||||
uuid = utils.generate_uuid()
|
uuid = utils.generate_uuid()
|
||||||
obj_utils.create_test_rc(self.context, id=1, uuid=uuid)
|
rc = obj_utils.create_test_rc(self.context, id=1, uuid=uuid)
|
||||||
response = self.get_json(
|
mock_rc_show.return_value = rc
|
||||||
'/rcs/%s/%s' % (uuid, '5d12f6fd-a196-4bf0-ae4c-1f639a523a52'))
|
response = self.get_json('/rcs/%s/%s' % (uuid, rc.bay_uuid))
|
||||||
self.assertIn('links', response.keys())
|
self.assertIn('links', response.keys())
|
||||||
self.assertEqual(2, len(response['links']))
|
self.assertEqual(2, len(response['links']))
|
||||||
self.assertIn(uuid, response['links'][0]['href'])
|
self.assertIn(uuid, response['links'][0]['href'])
|
||||||
|
|
||||||
def test_collection_links(self):
|
@mock.patch.object(rpcapi.API, 'rc_list')
|
||||||
|
def test_collection_links(self, mock_rc_list):
|
||||||
for id_ in range(5):
|
for id_ in range(5):
|
||||||
obj_utils.create_test_rc(self.context, id=id_,
|
rc = obj_utils.create_test_rc(self.context, id=id_,
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid())
|
||||||
response = self.get_json('/rcs/?limit=3')
|
mock_rc_list.return_value = [rc]
|
||||||
self.assertEqual(3, len(response['rcs']))
|
response = self.get_json('/rcs/?limit=1')
|
||||||
|
self.assertEqual(1, len(response['rcs']))
|
||||||
|
|
||||||
next_marker = response['rcs'][-1]['uuid']
|
@mock.patch.object(rpcapi.API, 'rc_list')
|
||||||
self.assertIn(next_marker, response['next'])
|
def test_collection_links_default_limit(self, mock_rc_list):
|
||||||
|
|
||||||
def test_collection_links_default_limit(self):
|
|
||||||
cfg.CONF.set_override('max_limit', 3, 'api')
|
cfg.CONF.set_override('max_limit', 3, 'api')
|
||||||
for id_ in range(5):
|
for id_ in range(5):
|
||||||
obj_utils.create_test_rc(self.context, id=id_,
|
rc = obj_utils.create_test_rc(self.context, id=id_,
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid())
|
||||||
|
mock_rc_list.return_value = [rc]
|
||||||
response = self.get_json('/rcs')
|
response = self.get_json('/rcs')
|
||||||
self.assertEqual(3, len(response['rcs']))
|
self.assertEqual(1, len(response['rcs']))
|
||||||
|
|
||||||
next_marker = response['rcs'][-1]['uuid']
|
|
||||||
self.assertIn(next_marker, response['next'])
|
|
||||||
|
|
||||||
|
|
||||||
class TestPatch(api_base.FunctionalTest):
|
class TestPatch(api_base.FunctionalTest):
|
||||||
@ -182,45 +196,54 @@ class TestPatch(api_base.FunctionalTest):
|
|||||||
self.another_bay = obj_utils.create_test_bay(
|
self.another_bay = obj_utils.create_test_bay(
|
||||||
self.context,
|
self.context,
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid())
|
||||||
|
self.manifest = '''{
|
||||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
"metadata": {
|
||||||
def test_replace_ok(self, mock_utcnow):
|
"name": "name_of_rc"
|
||||||
test_time = datetime.datetime(2000, 1, 1, 0, 0)
|
},
|
||||||
mock_utcnow.return_value = test_time
|
"spec":{
|
||||||
|
"replicas":2,
|
||||||
new_image = 'rc_example_B_image'
|
"selector":{
|
||||||
response = self.get_json(
|
"name":"frontend"
|
||||||
'/rcs/%s/%s' % (self.rc.uuid, self.rc.bay_uuid))
|
},
|
||||||
self.assertNotEqual(new_image, response['images'][0])
|
"template":{
|
||||||
|
"metadata":{
|
||||||
response = self.patch_json(
|
"labels":{
|
||||||
'/rcs/%s/%s' % (self.rc.uuid, self.rc.bay_uuid),
|
"name":"frontend"
|
||||||
[{'path': '/images/0',
|
}
|
||||||
'value': new_image,
|
},
|
||||||
'op': 'replace'}])
|
"spec":{
|
||||||
self.assertEqual('application/json', response.content_type)
|
"containers":[
|
||||||
self.assertEqual(200, response.status_code)
|
{
|
||||||
|
"name":"test-redis",
|
||||||
response = self.get_json('/rcs/%s/%s' % (self.rc.uuid,
|
"image":"steak/for-dinner",
|
||||||
self.rc.bay_uuid))
|
"ports":[
|
||||||
self.assertEqual(new_image, response['images'][0])
|
{
|
||||||
return_updated_at = timeutils.parse_isotime(
|
"containerPort":80,
|
||||||
response['updated_at']).replace(tzinfo=None)
|
"protocol":"TCP"
|
||||||
self.assertEqual(test_time, return_updated_at)
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}'''
|
||||||
|
|
||||||
def test_replace_bay_uuid(self):
|
def test_replace_bay_uuid(self):
|
||||||
response = self.patch_json('/rcs/%s/%s' % (self.rc.uuid,
|
self.rc.manifest = '{"bay_uuid": "self.rc.bay_uuid"}'
|
||||||
self.rc.bay_uuid),
|
response = self.patch_json(
|
||||||
|
'/rcs/%s/%s' % (self.rc.uuid, self.rc.bay_uuid),
|
||||||
[{'path': '/bay_uuid',
|
[{'path': '/bay_uuid',
|
||||||
'value': self.another_bay.uuid,
|
'value': self.another_bay.uuid,
|
||||||
'op': 'replace'}],
|
'op': 'replace'}],
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertEqual(200, response.status_code)
|
self.assertEqual(400, response.status_code)
|
||||||
|
|
||||||
def test_replace_non_existent_bay_uuid(self):
|
def test_replace_non_existent_bay_uuid(self):
|
||||||
response = self.patch_json('/rcs/%s/%s' % (self.rc.uuid,
|
self.rc.manifest = '{"key": "value"}'
|
||||||
self.rc.bay_uuid),
|
response = self.patch_json(
|
||||||
|
'/rcs/%s/%s' % (self.rc.uuid, self.rc.bay_uuid),
|
||||||
[{'path': '/bay_uuid',
|
[{'path': '/bay_uuid',
|
||||||
'value': utils.generate_uuid(),
|
'value': utils.generate_uuid(),
|
||||||
'op': 'replace'}],
|
'op': 'replace'}],
|
||||||
@ -246,17 +269,18 @@ class TestPatch(api_base.FunctionalTest):
|
|||||||
'value': 'rc_example_B_image',
|
'value': 'rc_example_B_image',
|
||||||
'op': 'replace'}],
|
'op': 'replace'}],
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual(404, response.status_int)
|
self.assertEqual(400, response.status_int)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertTrue(response.json['error_message'])
|
self.assertTrue(response.json['error_message'])
|
||||||
|
|
||||||
@mock.patch.object(rpcapi.API, 'rc_update')
|
@mock.patch.object(rpcapi.API, 'rc_update')
|
||||||
@mock.patch.object(api_rc.ReplicationController, 'parse_manifest')
|
@mock.patch.object(api_rc.ReplicationController, 'parse_manifest')
|
||||||
def test_replace_with_manifest(self, parse_manifest, rc_update):
|
def test_replace_with_manifest(self, parse_manifest, rc_update):
|
||||||
response = self.patch_json('/rcs/%s/%s' % (self.rc.uuid,
|
rc_update.return_value = self.rc
|
||||||
self.rc.bay_uuid),
|
response = self.patch_json(
|
||||||
|
'/rcs/%s/%s' % (self.rc.uuid, self.rc.bay_uuid),
|
||||||
[{'path': '/manifest',
|
[{'path': '/manifest',
|
||||||
'value': '{}',
|
'value': '{"foo": "bar"}',
|
||||||
'op': 'replace'}])
|
'op': 'replace'}])
|
||||||
self.assertEqual(200, response.status_int)
|
self.assertEqual(200, response.status_int)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
@ -272,24 +296,30 @@ class TestPatch(api_base.FunctionalTest):
|
|||||||
self.assertEqual(400, response.status_int)
|
self.assertEqual(400, response.status_int)
|
||||||
self.assertTrue(response.json['error_message'])
|
self.assertTrue(response.json['error_message'])
|
||||||
|
|
||||||
def test_remove_ok(self):
|
@mock.patch.object(rpcapi.API, 'rc_update')
|
||||||
response = self.get_json('/rcs/%s/%s' % (self.rc.uuid,
|
@mock.patch.object(rpcapi.API, 'rc_show')
|
||||||
self.rc.bay_uuid))
|
def test_remove_ok(self, mock_rc_show, mock_rc_update):
|
||||||
|
mock_rc_show.return_value = self.rc
|
||||||
|
response = self.get_json(
|
||||||
|
'/rcs/%s/%s' % (self.rc.uuid, self.rc.bay_uuid))
|
||||||
self.assertNotEqual(len(response['images']), 0)
|
self.assertNotEqual(len(response['images']), 0)
|
||||||
|
|
||||||
response = self.patch_json('/rcs/%s/%s' % (self.rc.uuid,
|
mock_rc_update.return_value = self.rc
|
||||||
self.rc.bay_uuid),
|
response = self.patch_json(
|
||||||
[{'path': '/images', 'op': 'remove'}])
|
'/rcs/%s/%s' % (self.rc.uuid, self.rc.bay_uuid),
|
||||||
|
[{'path': '/manifest',
|
||||||
|
'op': 'remove'}])
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertEqual(200, response.status_code)
|
self.assertEqual(200, response.status_code)
|
||||||
|
|
||||||
response = self.get_json('/rcs/%s/%s' % (self.rc.uuid,
|
mock_rc_show.return_value = self.rc
|
||||||
self.rc.bay_uuid))
|
response = self.get_json(
|
||||||
self.assertEqual(0, len(response['images']))
|
'/rcs/%s/%s' % (self.rc.uuid, self.rc.bay_uuid))
|
||||||
|
self.assertEqual(len(response['images']), 1)
|
||||||
|
|
||||||
def test_remove_uuid(self):
|
def test_remove_uuid(self):
|
||||||
response = self.patch_json('/rcs/%s/%s' % (self.rc.uuid,
|
response = self.patch_json(
|
||||||
self.rc.bay_uuid),
|
'/rcs/%s/%s' % (self.rc.uuid, self.rc.bay_uuid),
|
||||||
[{'path': '/uuid', 'op': 'remove'}],
|
[{'path': '/uuid', 'op': 'remove'}],
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual(400, response.status_int)
|
self.assertEqual(400, response.status_int)
|
||||||
@ -323,25 +353,30 @@ class TestPatch(api_base.FunctionalTest):
|
|||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertTrue(response.json['error_message'])
|
self.assertTrue(response.json['error_message'])
|
||||||
|
|
||||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
@mock.patch.object(rpcapi.API, 'rc_show')
|
||||||
def test_replace_ok_by_name(self, mock_utcnow):
|
@mock.patch.object(rpcapi.API, 'rc_update')
|
||||||
new_image = 'rc_example_B_image'
|
@mock.patch.object(api_rc.ReplicationController, 'parse_manifest')
|
||||||
test_time = datetime.datetime(2000, 1, 1, 0, 0)
|
def test_replace_ok_by_name(self, parse_manifest,
|
||||||
mock_utcnow.return_value = test_time
|
mock_rc_update,
|
||||||
|
mock_rc_show):
|
||||||
|
mock_rc_update.return_value = self.rc
|
||||||
response = self.patch_json(
|
response = self.patch_json(
|
||||||
'/rcs/%s/%s' % (self.rc.name, self.rc.bay_uuid),
|
'/rcs/%s/%s' % (self.rc.name, self.rc.bay_uuid),
|
||||||
[{'path': '/images/0',
|
[{'path': '/manifest',
|
||||||
'value': new_image,
|
'value': '{"foo": "bar"}',
|
||||||
'op': 'replace'}])
|
'op': 'replace'}])
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertEqual(200, response.status_code)
|
self.assertEqual(200, response.status_code)
|
||||||
|
parse_manifest.assert_called_once_with()
|
||||||
|
self.assertTrue(mock_rc_update.is_called)
|
||||||
|
|
||||||
response = self.get_json('/rcs/%s/%s' % (self.rc.uuid,
|
mock_rc_show.return_value = self.rc
|
||||||
self.rc.bay_uuid))
|
response = self.get_json(
|
||||||
return_updated_at = timeutils.parse_isotime(
|
'/rcs/%s/%s' % (self.rc.uuid,
|
||||||
response['updated_at']).replace(tzinfo=None)
|
self.rc.bay_uuid),
|
||||||
self.assertEqual(test_time, return_updated_at)
|
expect_errors=True)
|
||||||
|
self.assertEqual('application/json', response.content_type)
|
||||||
|
self.assertEqual(200, response.status_code)
|
||||||
|
|
||||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||||
def test_replace_ok_by_name_not_found(self, mock_utcnow):
|
def test_replace_ok_by_name_not_found(self, mock_utcnow):
|
||||||
@ -350,13 +385,14 @@ class TestPatch(api_base.FunctionalTest):
|
|||||||
test_time = datetime.datetime(2000, 1, 1, 0, 0)
|
test_time = datetime.datetime(2000, 1, 1, 0, 0)
|
||||||
mock_utcnow.return_value = test_time
|
mock_utcnow.return_value = test_time
|
||||||
|
|
||||||
response = self.patch_json('/rcs/%s/%s' % (name, self.rc.bay_uuid),
|
response = self.patch_json(
|
||||||
|
'/rcs/%s/%s' % (name, self.rc.bay_uuid),
|
||||||
[{'path': '/images/0',
|
[{'path': '/images/0',
|
||||||
'value': new_image,
|
'value': new_image,
|
||||||
'op': 'replace'}],
|
'op': 'replace'}],
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertEqual(404, response.status_code)
|
self.assertEqual(400, response.status_code)
|
||||||
|
|
||||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||||
def test_replace_ok_by_name_multiple_rc(self, mock_utcnow):
|
def test_replace_ok_by_name_multiple_rc(self, mock_utcnow):
|
||||||
@ -376,7 +412,7 @@ class TestPatch(api_base.FunctionalTest):
|
|||||||
'op': 'replace'}],
|
'op': 'replace'}],
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertEqual(409, response.status_code)
|
self.assertEqual(400, response.status_code)
|
||||||
|
|
||||||
|
|
||||||
class TestPost(api_base.FunctionalTest):
|
class TestPost(api_base.FunctionalTest):
|
||||||
@ -384,25 +420,24 @@ class TestPost(api_base.FunctionalTest):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestPost, self).setUp()
|
super(TestPost, self).setUp()
|
||||||
obj_utils.create_test_bay(self.context)
|
obj_utils.create_test_bay(self.context)
|
||||||
|
self.rc_obj = obj_utils.create_test_rc(self.context)
|
||||||
p = mock.patch.object(rpcapi.API, 'rc_create')
|
p = mock.patch.object(rpcapi.API, 'rc_create')
|
||||||
self.mock_rc_create = p.start()
|
self.mock_rc_create = p.start()
|
||||||
self.mock_rc_create.side_effect = self._simulate_rpc_rc_create
|
self.mock_rc_create.return_value = self.rc_obj
|
||||||
self.addCleanup(p.stop)
|
self.addCleanup(p.stop)
|
||||||
p = mock.patch('magnum.objects.BayModel.get_by_uuid')
|
p = mock.patch('magnum.objects.BayModel.get_by_uuid')
|
||||||
self.mock_baymodel_get_by_uuid = p.start()
|
self.mock_baymodel_get_by_uuid = p.start()
|
||||||
self.mock_baymodel_get_by_uuid.return_value.coe = 'kubernetes'
|
self.mock_baymodel_get_by_uuid.return_value.coe = 'kubernetes'
|
||||||
self.addCleanup(p.stop)
|
self.addCleanup(p.stop)
|
||||||
|
|
||||||
def _simulate_rpc_rc_create(self, rc):
|
|
||||||
rc.create(self.context)
|
|
||||||
return rc
|
|
||||||
|
|
||||||
@mock.patch('oslo_utils.timeutils.utcnow')
|
@mock.patch('oslo_utils.timeutils.utcnow')
|
||||||
def test_create_rc(self, mock_utcnow):
|
@mock.patch.object(rpcapi.API, 'rc_create')
|
||||||
|
def test_create_rc(self, mock_rc_create, mock_utcnow):
|
||||||
rc_dict = apiutils.rc_post_data()
|
rc_dict = apiutils.rc_post_data()
|
||||||
test_time = datetime.datetime(2000, 1, 1, 0, 0)
|
test_time = datetime.datetime(2000, 1, 1, 0, 0)
|
||||||
mock_utcnow.return_value = test_time
|
mock_utcnow.return_value = test_time
|
||||||
|
|
||||||
|
mock_rc_create.return_value = self.rc_obj
|
||||||
response = self.post_json('/rcs', rc_dict)
|
response = self.post_json('/rcs', rc_dict)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertEqual(201, response.status_int)
|
self.assertEqual(201, response.status_int)
|
||||||
@ -412,38 +447,24 @@ class TestPost(api_base.FunctionalTest):
|
|||||||
self.assertEqual(expected_location,
|
self.assertEqual(expected_location,
|
||||||
urlparse.urlparse(response.location).path)
|
urlparse.urlparse(response.location).path)
|
||||||
self.assertEqual(rc_dict['uuid'], response.json['uuid'])
|
self.assertEqual(rc_dict['uuid'], response.json['uuid'])
|
||||||
self.assertNotIn('updated_at', response.json.keys)
|
|
||||||
return_created_at = timeutils.parse_isotime(
|
|
||||||
response.json['created_at']).replace(tzinfo=None)
|
|
||||||
self.assertEqual(test_time, return_created_at)
|
|
||||||
|
|
||||||
def test_create_rc_set_project_id_and_user_id(self):
|
def test_create_rc_set_project_id_and_user_id(self):
|
||||||
rc_dict = apiutils.rc_post_data()
|
rc_dict = apiutils.rc_post_data()
|
||||||
|
|
||||||
def _simulate_rpc_rc_create(rc):
|
def _simulate_rpc_rc_create(rc):
|
||||||
self.assertEqual(self.context.project_id, rc.project_id)
|
self.assertEqual(rc.project_id, self.context.project_id)
|
||||||
self.assertEqual(self.context.user_id, rc.user_id)
|
self.assertEqual(rc.user_id, self.context.user_id)
|
||||||
rc.create()
|
|
||||||
return rc
|
return rc
|
||||||
self.mock_rc_create.side_effect = _simulate_rpc_rc_create
|
self.mock_rc_create.side_effect = _simulate_rpc_rc_create
|
||||||
|
|
||||||
self.post_json('/rcs', rc_dict)
|
self.post_json('/rcs', rc_dict)
|
||||||
|
|
||||||
def test_create_rc_doesnt_contain_id(self):
|
@mock.patch.object(rpcapi.API, 'rc_create')
|
||||||
with mock.patch.object(self.dbapi, 'create_rc',
|
def test_create_rc_generate_uuid(self, mock_rc_create):
|
||||||
wraps=self.dbapi.create_rc) as cc_mock:
|
|
||||||
rc_dict = apiutils.rc_post_data()
|
|
||||||
response = self.post_json('/rcs', rc_dict)
|
|
||||||
self.assertEqual(rc_dict['images'], response.json['images'])
|
|
||||||
cc_mock.assert_called_once_with(mock.ANY)
|
|
||||||
# Check that 'id' is not in first arg of positional args
|
|
||||||
self.assertNotIn('id', cc_mock.call_args[0][0])
|
|
||||||
|
|
||||||
def test_create_rc_generate_uuid(self):
|
|
||||||
rc_dict = apiutils.rc_post_data()
|
rc_dict = apiutils.rc_post_data()
|
||||||
del rc_dict['uuid']
|
del rc_dict['uuid']
|
||||||
|
mock_rc_create.return_value = self.rc_obj
|
||||||
response = self.post_json('/rcs', rc_dict)
|
response = self.post_json('/rcs', rc_dict, expect_errors=True)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertEqual(201, response.status_int)
|
self.assertEqual(201, response.status_int)
|
||||||
self.assertEqual(rc_dict['images'], response.json['images'])
|
self.assertEqual(rc_dict['images'], response.json['images'])
|
||||||
@ -494,54 +515,60 @@ class TestDelete(api_base.FunctionalTest):
|
|||||||
super(TestDelete, self).setUp()
|
super(TestDelete, self).setUp()
|
||||||
obj_utils.create_test_bay(self.context)
|
obj_utils.create_test_bay(self.context)
|
||||||
self.rc = obj_utils.create_test_rc(self.context)
|
self.rc = obj_utils.create_test_rc(self.context)
|
||||||
p = mock.patch.object(rpcapi.API, 'rc_delete')
|
|
||||||
self.mock_rc_delete = p.start()
|
|
||||||
self.mock_rc_delete.side_effect = self._simulate_rpc_rc_delete
|
|
||||||
self.addCleanup(p.stop)
|
|
||||||
|
|
||||||
def _simulate_rpc_rc_delete(self, rc_uuid):
|
@mock.patch.object(rpcapi.API, 'rc_delete')
|
||||||
rc = objects.ReplicationController.get_by_uuid(self.context, rc_uuid)
|
@mock.patch.object(rpcapi.API, 'rc_show')
|
||||||
rc.destroy()
|
def test_delete_rc(self, mock_rc_show, mock_rc_delete):
|
||||||
|
|
||||||
def test_delete_rc(self):
|
|
||||||
self.delete('/rcs/%s/%s' % (self.rc.uuid, self.rc.bay_uuid))
|
self.delete('/rcs/%s/%s' % (self.rc.uuid, self.rc.bay_uuid))
|
||||||
response = self.get_json('/rcs/%s/%s' % (self.rc.uuid,
|
err = rest.ApiException(status=404)
|
||||||
self.rc.bay_uuid),
|
mock_rc_show.side_effect = err
|
||||||
|
response = self.get_json(
|
||||||
|
'/rcs/%s/%s' % (self.rc.uuid, self.rc.bay_uuid),
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual(404, response.status_int)
|
self.assertEqual(500, response.status_int)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertTrue(response.json['error_message'])
|
self.assertTrue(response.json['error_message'])
|
||||||
|
|
||||||
def test_delete_rc_not_found(self):
|
@mock.patch.object(rpcapi.API, 'rc_delete')
|
||||||
|
def test_delete_rc_not_found(self, mock_rc_delete):
|
||||||
uuid = utils.generate_uuid()
|
uuid = utils.generate_uuid()
|
||||||
|
err = rest.ApiException(status=404)
|
||||||
|
mock_rc_delete.side_effect = err
|
||||||
response = self.delete('/rcs/%s/%s' % (uuid, self.rc.bay_uuid),
|
response = self.delete('/rcs/%s/%s' % (uuid, self.rc.bay_uuid),
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual(404, response.status_int)
|
self.assertEqual(500, response.status_int)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertTrue(response.json['error_message'])
|
self.assertTrue(response.json['error_message'])
|
||||||
|
|
||||||
def test_delete_rc_with_name_not_found(self):
|
@mock.patch.object(rpcapi.API, 'rc_delete')
|
||||||
|
def test_delete_rc_with_name_not_found(self, mock_rc_delete):
|
||||||
|
err = rest.ApiException(status=404)
|
||||||
|
mock_rc_delete.side_effect = err
|
||||||
response = self.delete(
|
response = self.delete(
|
||||||
'/rcs/not_found/5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
|
'/rcs/not_found/5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual(404, response.status_int)
|
self.assertEqual(500, response.status_int)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertTrue(response.json['error_message'])
|
self.assertTrue(response.json['error_message'])
|
||||||
|
|
||||||
def test_delete_rc_with_name(self):
|
@mock.patch.object(rpcapi.API, 'rc_delete')
|
||||||
|
def test_delete_rc_with_name(self, mock_rc_delete):
|
||||||
response = self.delete('/rcs/%s/%s' % (self.rc.name, self.rc.bay_uuid),
|
response = self.delete('/rcs/%s/%s' % (self.rc.name, self.rc.bay_uuid),
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual(204, response.status_int)
|
self.assertEqual(204, response.status_int)
|
||||||
|
|
||||||
def test_delete_multiple_rc_by_name(self):
|
@mock.patch.object(rpcapi.API, 'rc_delete')
|
||||||
|
def test_delete_multiple_rc_by_name(self, mock_rc_delete):
|
||||||
|
err = rest.ApiException(status=409)
|
||||||
|
mock_rc_delete.side_effect = err
|
||||||
obj_utils.create_test_rc(self.context, name='test_rc',
|
obj_utils.create_test_rc(self.context, name='test_rc',
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid())
|
||||||
obj_utils.create_test_rc(self.context, name='test_rc',
|
obj_utils.create_test_rc(self.context, name='test_rc',
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid())
|
||||||
response = self.delete(
|
response = self.delete(
|
||||||
'/rcs/test_rc/5d12f6fd-a196-4bf0-ae4c-1f639a523a5',
|
'/rcs/test_rc/5d12f6fd-a196-4bf0-ae4c-1f639a523a52',
|
||||||
expect_errors=True)
|
expect_errors=True)
|
||||||
self.assertEqual(409, response.status_int)
|
self.assertEqual(500, response.status_int)
|
||||||
self.assertEqual('application/json', response.content_type)
|
self.assertEqual('application/json', response.content_type)
|
||||||
self.assertTrue(response.json['error_message'])
|
self.assertTrue(response.json['error_message'])
|
||||||
|
|
||||||
|
@ -125,9 +125,11 @@ class TestK8sConductor(base.TestCase):
|
|||||||
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.delete_namespaced_pod
|
(mock_kube_api.return_value.
|
||||||
.assert_called_once_with(
|
delete_namespaced_pod.
|
||||||
name=mock_pod.name, body={}, namespace='default'))
|
assert_called_once_with(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')
|
||||||
@ -253,25 +255,30 @@ class TestK8sConductor(base.TestCase):
|
|||||||
name=mock_service.name, namespace='default'))
|
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):
|
@patch('ast.literal_eval')
|
||||||
expected_rc = self.mock_rc()
|
def test_rc_create_with_success(self, mock_ast):
|
||||||
expected_rc.create = mock.MagicMock()
|
expected_rc = mock.MagicMock()
|
||||||
manifest = {"key": "value"}
|
manifest = {"key": "value"}
|
||||||
|
expected_rc.name = 'test-name'
|
||||||
|
expected_rc.uuid = 'test-uuid'
|
||||||
|
expected_rc.bay_uuid = 'test-bay-uuid'
|
||||||
expected_rc.manifest = '{"key": "value"}'
|
expected_rc.manifest = '{"key": "value"}'
|
||||||
|
mock_ast.return_value = {}
|
||||||
|
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api:
|
with patch('magnum.conductor.k8s_api.create_k8s_api_rc') as \
|
||||||
|
mock_kube_api:
|
||||||
self.kube_handler.rc_create({}, expected_rc)
|
self.kube_handler.rc_create({}, expected_rc)
|
||||||
(mock_kube_api.return_value
|
(mock_kube_api.return_value
|
||||||
.create_namespaced_replication_controller
|
.create_namespaced_replication_controller
|
||||||
.assert_called_once_with(body=manifest, namespace='default'))
|
.assert_called_once_with(body=manifest, namespace='default'))
|
||||||
|
|
||||||
def test_rc_create_with_failure(self):
|
def test_rc_create_with_failure(self):
|
||||||
expected_rc = self.mock_rc()
|
expected_rc = 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_rc') as \
|
||||||
|
mock_kube_api:
|
||||||
err = rest.ApiException(status=500)
|
err = rest.ApiException(status=500)
|
||||||
(mock_kube_api.return_value
|
(mock_kube_api.return_value
|
||||||
.create_namespaced_replication_controller.side_effect) = err
|
.create_namespaced_replication_controller.side_effect) = err
|
||||||
@ -282,46 +289,57 @@ class TestK8sConductor(base.TestCase):
|
|||||||
(mock_kube_api.return_value
|
(mock_kube_api.return_value
|
||||||
.create_namespaced_replication_controller
|
.create_namespaced_replication_controller
|
||||||
.assert_called_once_with(body=manifest, namespace='default'))
|
.assert_called_once_with(body=manifest, namespace='default'))
|
||||||
self.assertFalse(expected_rc.create.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_name')
|
||||||
def test_rc_delete_with_success(self,
|
@patch('magnum.objects.Bay.get_by_name')
|
||||||
mock_rc_get_by_uuid,
|
def test_rc_delete_with_success(self, mock_bay_get_by_name,
|
||||||
|
mock_rc_get_by_name,
|
||||||
mock_object_has_stack):
|
mock_object_has_stack):
|
||||||
|
mock_bay = mock.MagicMock()
|
||||||
|
mock_bay_get_by_name.return_value = mock_bay
|
||||||
|
|
||||||
mock_rc = mock.MagicMock()
|
mock_rc = mock.MagicMock()
|
||||||
mock_rc.name = 'test-rc'
|
mock_rc.name = 'test-rc'
|
||||||
mock_rc.uuid = 'test-uuid'
|
mock_rc.uuid = 'test-uuid'
|
||||||
mock_rc_get_by_uuid.return_value = mock_rc
|
mock_rc_get_by_name.return_value = mock_rc
|
||||||
|
bay_uuid = 'test-bay-uuid'
|
||||||
|
|
||||||
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_rc') as \
|
||||||
self.kube_handler.rc_delete(self.context, mock_rc.uuid)
|
mock_kube_api:
|
||||||
|
self.kube_handler.rc_delete(self.context, mock_rc.name, bay_uuid)
|
||||||
(mock_kube_api.return_value
|
(mock_kube_api.return_value
|
||||||
.delete_namespaced_replication_controller
|
.delete_namespaced_replication_controller
|
||||||
.assert_called_once_with(name=mock_rc.name, body={},
|
.assert_called_once_with(name=mock_rc.name, body={},
|
||||||
namespace='default'))
|
namespace='default'))
|
||||||
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')
|
||||||
def test_rc_delete_with_failure(self, mock_rc_get_by_uuid,
|
@patch('magnum.objects.Bay.get_by_name')
|
||||||
|
def test_rc_delete_with_failure(self, mock_bay_get_by_name,
|
||||||
|
mock_rc_get_by_uuid,
|
||||||
mock_object_has_stack):
|
mock_object_has_stack):
|
||||||
|
mock_bay = mock.MagicMock()
|
||||||
|
mock_bay_get_by_name.return_value = mock_bay
|
||||||
|
|
||||||
mock_rc = mock.MagicMock()
|
mock_rc = mock.MagicMock()
|
||||||
mock_rc.name = 'test-rc'
|
mock_rc.name = 'test-rc'
|
||||||
mock_rc.uuid = 'test-uuid'
|
mock_rc.uuid = 'test-uuid'
|
||||||
|
mock_rc.bay_uuid = 'test-bay-uuid'
|
||||||
mock_rc_get_by_uuid.return_value = mock_rc
|
mock_rc_get_by_uuid.return_value = mock_rc
|
||||||
|
|
||||||
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_rc') as \
|
||||||
|
mock_kube_api:
|
||||||
err = rest.ApiException(status=500)
|
err = rest.ApiException(status=500)
|
||||||
(mock_kube_api.return_value
|
(mock_kube_api.return_value
|
||||||
.delete_namespaced_replication_controller.side_effect) = err
|
.delete_namespaced_replication_controller.side_effect) = err
|
||||||
|
|
||||||
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.name,
|
||||||
|
mock_rc.bay_uuid)
|
||||||
|
|
||||||
(mock_kube_api.return_value
|
(mock_kube_api.return_value
|
||||||
.delete_namespaced_replication_controller
|
.delete_namespaced_replication_controller
|
||||||
@ -331,56 +349,88 @@ class TestK8sConductor(base.TestCase):
|
|||||||
|
|
||||||
@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('magnum.objects.Bay.get_by_name')
|
||||||
def test_rc_delete_succeeds_when_not_found(
|
def test_rc_delete_succeeds_when_not_found(
|
||||||
self,
|
self, mock_bay_get_by_name,
|
||||||
mock_rc_get_by_uuid,
|
mock_rc_get_by_uuid,
|
||||||
mock_object_has_stack):
|
mock_object_has_stack):
|
||||||
|
mock_bay = mock.MagicMock()
|
||||||
|
mock_bay_get_by_name.return_value = mock_bay
|
||||||
|
|
||||||
mock_rc = mock.MagicMock()
|
mock_rc = mock.MagicMock()
|
||||||
mock_rc.name = 'test-rc'
|
mock_rc.name = 'test-rc'
|
||||||
mock_rc.uuid = 'test-uuid'
|
mock_rc.uuid = 'test-uuid'
|
||||||
|
mock_rc.bay_uuid = 'test-bay-uuid'
|
||||||
mock_rc_get_by_uuid.return_value = mock_rc
|
mock_rc_get_by_uuid.return_value = mock_rc
|
||||||
|
|
||||||
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_rc') as \
|
||||||
|
mock_kube_api:
|
||||||
err = rest.ApiException(status=404)
|
err = rest.ApiException(status=404)
|
||||||
(mock_kube_api.return_value
|
(mock_kube_api.return_value
|
||||||
.delete_namespaced_replication_controller.side_effect) = err
|
.delete_namespaced_replication_controller.side_effect) = err
|
||||||
|
|
||||||
self.kube_handler.rc_delete(self.context, mock_rc.uuid)
|
self.kube_handler.rc_delete(self.context,
|
||||||
|
mock_rc.name,
|
||||||
|
mock_rc.bay_uuid)
|
||||||
|
|
||||||
(mock_kube_api.return_value
|
(mock_kube_api.return_value
|
||||||
.delete_namespaced_replication_controller
|
.delete_namespaced_replication_controller
|
||||||
.assert_called_once_with(name=mock_rc.name, body={},
|
.assert_called_once_with(name=mock_rc.name, body={},
|
||||||
namespace='default'))
|
namespace='default'))
|
||||||
self.assertTrue(mock_rc.destroy.called)
|
|
||||||
|
|
||||||
def test_rc_update_with_success(self):
|
@patch('magnum.objects.ReplicationController.get_by_name')
|
||||||
expected_rc = self.mock_rc()
|
@patch('magnum.objects.ReplicationController.get_by_uuid')
|
||||||
|
@patch('magnum.objects.Bay.get_by_name')
|
||||||
|
@patch('ast.literal_eval')
|
||||||
|
def test_rc_update_with_success(self, mock_ast,
|
||||||
|
mock_bay_get_by_name,
|
||||||
|
mock_rc_get_by_uuid,
|
||||||
|
mock_rc_get_by_name):
|
||||||
|
mock_bay = mock.MagicMock()
|
||||||
|
mock_bay_get_by_name.return_value = mock_bay
|
||||||
|
|
||||||
|
expected_rc = mock.MagicMock()
|
||||||
expected_rc.uuid = 'test-uuid'
|
expected_rc.uuid = 'test-uuid'
|
||||||
expected_rc.name = 'test-name'
|
expected_rc.name = 'test-name'
|
||||||
expected_rc.refresh = mock.MagicMock()
|
expected_rc.bay_uuid = 'test-bay-uuid'
|
||||||
expected_rc.save = mock.MagicMock()
|
|
||||||
manifest = {"key": "value"}
|
|
||||||
expected_rc.manifest = '{"key": "value"}'
|
expected_rc.manifest = '{"key": "value"}'
|
||||||
|
mock_ast.return_value = {}
|
||||||
|
mock_rc_get_by_uuid.return_value = expected_rc
|
||||||
|
mock_rc_get_by_name.return_value = expected_rc
|
||||||
|
name_rc = expected_rc.name
|
||||||
|
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api:
|
with patch('magnum.conductor.k8s_api.create_k8s_api_rc') as \
|
||||||
self.kube_handler.rc_update(self.context, expected_rc)
|
mock_kube_api:
|
||||||
|
self.kube_handler.rc_update(self.context, expected_rc.name,
|
||||||
|
expected_rc.bay_uuid,
|
||||||
|
expected_rc.manifest)
|
||||||
(mock_kube_api.return_value
|
(mock_kube_api.return_value
|
||||||
.replace_namespaced_replication_controller
|
.replace_namespaced_replication_controller
|
||||||
.assert_called_once_with(body=manifest, name=expected_rc.name,
|
.assert_called_once_with(body=expected_rc.manifest,
|
||||||
|
name=name_rc,
|
||||||
namespace='default'))
|
namespace='default'))
|
||||||
expected_rc.refresh.assert_called_once_with(self.context)
|
|
||||||
expected_rc.save.assert_called_once_with()
|
|
||||||
|
|
||||||
def test_rc_update_with_failure(self):
|
@patch('magnum.objects.ReplicationController.get_by_name')
|
||||||
expected_rc = self.mock_rc()
|
@patch('magnum.objects.ReplicationController.get_by_uuid')
|
||||||
|
@patch('magnum.objects.Bay.get_by_name')
|
||||||
|
def test_rc_update_with_failure(self, mock_bay_get_by_name,
|
||||||
|
mock_rc_get_by_uuid,
|
||||||
|
mock_rc_get_by_name):
|
||||||
|
mock_bay = mock.MagicMock()
|
||||||
|
mock_bay_get_by_name.return_value = mock_bay
|
||||||
|
|
||||||
|
expected_rc = mock.MagicMock()
|
||||||
expected_rc.uuid = 'test-uuid'
|
expected_rc.uuid = 'test-uuid'
|
||||||
expected_rc.name = 'test-name'
|
expected_rc.name = 'test-name'
|
||||||
expected_rc.update = mock.MagicMock()
|
expected_rc.bay_uuid = 'test-bay-uuid'
|
||||||
manifest = {"key": "value"}
|
mock_rc_get_by_uuid.return_value = expected_rc
|
||||||
|
mock_rc_get_by_name.return_value = expected_rc
|
||||||
expected_rc.manifest = '{"key": "value"}'
|
expected_rc.manifest = '{"key": "value"}'
|
||||||
|
name_rc = expected_rc.name
|
||||||
|
|
||||||
with patch('magnum.conductor.k8s_api.create_k8s_api') as mock_kube_api:
|
with patch('magnum.conductor.k8s_api.create_k8s_api_rc') as \
|
||||||
|
mock_kube_api:
|
||||||
err = rest.ApiException(status=404)
|
err = rest.ApiException(status=404)
|
||||||
(mock_kube_api.return_value
|
(mock_kube_api.return_value
|
||||||
.replace_namespaced_replication_controller
|
.replace_namespaced_replication_controller
|
||||||
@ -388,12 +438,14 @@ class TestK8sConductor(base.TestCase):
|
|||||||
|
|
||||||
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.name,
|
||||||
|
expected_rc.bay_uuid,
|
||||||
|
expected_rc.manifest)
|
||||||
(mock_kube_api.return_value
|
(mock_kube_api.return_value
|
||||||
.replace_namespaced_replication_controller
|
.replace_namespaced_replication_controller
|
||||||
.assert_called_once_with(body=manifest, name=expected_rc.name,
|
.assert_called_once_with(body=expected_rc.manifest,
|
||||||
|
name=name_rc,
|
||||||
namespace='default'))
|
namespace='default'))
|
||||||
self.assertFalse(expected_rc.update.called)
|
|
||||||
|
|
||||||
def test_service_update_with_success(self):
|
def test_service_update_with_success(self):
|
||||||
expected_service = self.mock_service()
|
expected_service = self.mock_service()
|
||||||
|
@ -102,7 +102,7 @@ class TestK8sAPI(base.TestCase):
|
|||||||
k8s_api.create_k8s_api(context, obj)
|
k8s_api.create_k8s_api(context, obj)
|
||||||
|
|
||||||
if cls is not 'Bay':
|
if cls is not 'Bay':
|
||||||
mock_bay_retrieval.assert_called_once_with(context, obj)
|
mock_bay_retrieval.assert_called_once_with(context, obj.bay_uuid)
|
||||||
|
|
||||||
mock_api_client.assert_called_once_with(
|
mock_api_client.assert_called_once_with(
|
||||||
bay_obj.api_address,
|
bay_obj.api_address,
|
||||||
|
@ -157,18 +157,22 @@ class RPCAPITestCase(base.DbTestCase):
|
|||||||
self._test_rpcapi('rc_update',
|
self._test_rpcapi('rc_update',
|
||||||
'call',
|
'call',
|
||||||
version='1.0',
|
version='1.0',
|
||||||
rc=self.fake_rc)
|
rc_ident=self.fake_rc['uuid'],
|
||||||
|
bay_ident=self.fake_rc['bay_uuid'],
|
||||||
|
manifest={})
|
||||||
|
|
||||||
def test_rc_delete(self):
|
def test_rc_delete(self):
|
||||||
self._test_rpcapi('rc_delete',
|
self._test_rpcapi('rc_delete',
|
||||||
'call',
|
'call',
|
||||||
version='1.0',
|
version='1.0',
|
||||||
uuid=self.fake_rc['uuid'])
|
rc_ident=self.fake_rc['uuid'],
|
||||||
|
bay_ident=self.fake_rc['bay_uuid'])
|
||||||
|
|
||||||
self._test_rpcapi('rc_delete',
|
self._test_rpcapi('rc_delete',
|
||||||
'call',
|
'call',
|
||||||
version='1.1',
|
version='1.1',
|
||||||
uuid=self.fake_rc['name'])
|
rc_ident=self.fake_rc['uuid'],
|
||||||
|
bay_ident=self.fake_rc['bay_uuid'])
|
||||||
|
|
||||||
def test_container_create(self):
|
def test_container_create(self):
|
||||||
self._test_rpcapi('container_create',
|
self._test_rpcapi('container_create',
|
||||||
|
@ -21,35 +21,40 @@ from magnum.tests import base
|
|||||||
|
|
||||||
class TestConductorUtils(base.TestCase):
|
class TestConductorUtils(base.TestCase):
|
||||||
|
|
||||||
def _test_retrieve_bay(self, obj, mock_bay_get_by_uuid):
|
def _test_retrieve_bay(self, expected_bay_uuid, mock_bay_get_by_uuid):
|
||||||
expected_context = 'context'
|
expected_context = 'context'
|
||||||
expected_bay_uuid = 'bay_uuid'
|
utils.retrieve_bay(expected_context, expected_bay_uuid)
|
||||||
|
|
||||||
obj.bay_uuid = expected_bay_uuid
|
|
||||||
utils.retrieve_bay(expected_context, obj)
|
|
||||||
mock_bay_get_by_uuid.assert_called_once_with(expected_context,
|
mock_bay_get_by_uuid.assert_called_once_with(expected_context,
|
||||||
expected_bay_uuid)
|
expected_bay_uuid)
|
||||||
|
|
||||||
@patch('magnum.objects.Bay.get_by_uuid')
|
@patch('magnum.objects.Bay.get_by_uuid')
|
||||||
def test_retrieve_bay_from_pod(self,
|
def test_retrieve_bay_from_pod(self,
|
||||||
mock_bay_get_by_uuid):
|
mock_bay_get_by_uuid):
|
||||||
self._test_retrieve_bay(objects.Pod({}), mock_bay_get_by_uuid)
|
pod = objects.Pod({})
|
||||||
|
pod.bay_uuid = '5d12f6fd-a196-4bf0-ae4c-1f639a523a52'
|
||||||
|
self._test_retrieve_bay(pod.bay_uuid, mock_bay_get_by_uuid)
|
||||||
|
|
||||||
@patch('magnum.objects.Bay.get_by_uuid')
|
@patch('magnum.objects.Bay.get_by_uuid')
|
||||||
def test_retrieve_bay_from_service(self,
|
def test_retrieve_bay_from_service(self,
|
||||||
mock_bay_get_by_uuid):
|
mock_bay_get_by_uuid):
|
||||||
self._test_retrieve_bay(objects.Service({}), mock_bay_get_by_uuid)
|
service = objects.Service({})
|
||||||
|
service.bay_uuid = '5d12f6fd-a196-4bf0-ae4c-1f639a523a52'
|
||||||
|
self._test_retrieve_bay(service.bay_uuid, mock_bay_get_by_uuid)
|
||||||
|
|
||||||
@patch('magnum.objects.Bay.get_by_uuid')
|
@patch('magnum.objects.Bay.get_by_uuid')
|
||||||
def test_retrieve_bay_from_rc(self,
|
def test_retrieve_bay_from_rc(self,
|
||||||
mock_bay_get_by_uuid):
|
mock_bay_get_by_uuid):
|
||||||
self._test_retrieve_bay(objects.ReplicationController({}),
|
rc = objects.ReplicationController({})
|
||||||
|
rc.bay_uuid = '5d12f6fd-a196-4bf0-ae4c-1f639a523a52'
|
||||||
|
self._test_retrieve_bay(rc.bay_uuid,
|
||||||
mock_bay_get_by_uuid)
|
mock_bay_get_by_uuid)
|
||||||
|
|
||||||
@patch('magnum.objects.Bay.get_by_uuid')
|
@patch('magnum.objects.Bay.get_by_uuid')
|
||||||
def test_retrieve_bay_from_container(self,
|
def test_retrieve_bay_from_container(self,
|
||||||
mock_bay_get_by_uuid):
|
mock_bay_get_by_uuid):
|
||||||
self._test_retrieve_bay(objects.Container({}), mock_bay_get_by_uuid)
|
container = objects.Container({})
|
||||||
|
container.bay_uuid = '5d12f6fd-a196-4bf0-ae4c-1f639a523a52'
|
||||||
|
self._test_retrieve_bay(container.bay_uuid, mock_bay_get_by_uuid)
|
||||||
|
|
||||||
@patch('magnum.objects.BayModel.get_by_uuid')
|
@patch('magnum.objects.BayModel.get_by_uuid')
|
||||||
def test_retrieve_baymodel(self, mock_baymodel_get_by_uuid):
|
def test_retrieve_baymodel(self, mock_baymodel_get_by_uuid):
|
||||||
|
@ -431,7 +431,7 @@ object_data = {
|
|||||||
'MyObj': '1.0-b43567e512438205e32f4e95ca616697',
|
'MyObj': '1.0-b43567e512438205e32f4e95ca616697',
|
||||||
'Node': '1.0-30943e6e3387a2fae7490b57c4239a17',
|
'Node': '1.0-30943e6e3387a2fae7490b57c4239a17',
|
||||||
'Pod': '1.1-7a31c372f163742845c10a008f47cc15',
|
'Pod': '1.1-7a31c372f163742845c10a008f47cc15',
|
||||||
'ReplicationController': '1.0-782b7deb9307b2807101541b7e58b8a2',
|
'ReplicationController': '1.0-a471c2429c212ed91833cfcf0f934eab',
|
||||||
'Service': '1.0-a8cf7e95fced904419164dbcb6d32b38',
|
'Service': '1.0-a8cf7e95fced904419164dbcb6d32b38',
|
||||||
'X509KeyPair': '1.1-4aecc268e23e32b8a762d43ba1a4b159',
|
'X509KeyPair': '1.1-4aecc268e23e32b8a762d43ba1a4b159',
|
||||||
'MagnumService': '1.0-2d397ec59b0046bd5ec35cd3e06efeca',
|
'MagnumService': '1.0-2d397ec59b0046bd5ec35cd3e06efeca',
|
||||||
|
@ -13,14 +13,12 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import mock
|
|
||||||
from testtools.matchers import HasLength
|
|
||||||
|
|
||||||
from magnum.common import utils as magnum_utils
|
|
||||||
from magnum import objects
|
from magnum import objects
|
||||||
from magnum.tests.unit.db import base
|
from magnum.tests.unit.db import base
|
||||||
from magnum.tests.unit.db import utils
|
from magnum.tests.unit.db import utils
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
|
||||||
class TestReplicationControllerObject(base.DbTestCase):
|
class TestReplicationControllerObject(base.DbTestCase):
|
||||||
|
|
||||||
@ -28,99 +26,70 @@ class TestReplicationControllerObject(base.DbTestCase):
|
|||||||
super(TestReplicationControllerObject, self).setUp()
|
super(TestReplicationControllerObject, self).setUp()
|
||||||
self.fake_rc = utils.get_test_rc()
|
self.fake_rc = utils.get_test_rc()
|
||||||
|
|
||||||
def test_get_by_id(self):
|
@mock.patch('magnum.conductor.k8s_api.create_k8s_api')
|
||||||
rc_id = self.fake_rc['id']
|
@mock.patch('ast.literal_eval')
|
||||||
with mock.patch.object(self.dbapi, 'get_rc_by_id',
|
def test_get_by_uuid(self, mock_ast, mock_kube_api):
|
||||||
autospec=True) as mock_get_rc:
|
|
||||||
mock_get_rc.return_value = self.fake_rc
|
|
||||||
rc = objects.ReplicationController.get_by_id(self.context,
|
|
||||||
rc_id)
|
|
||||||
mock_get_rc.assert_called_once_with(self.context, rc_id)
|
|
||||||
self.assertEqual(self.context, rc._context)
|
|
||||||
|
|
||||||
def test_get_by_uuid(self):
|
|
||||||
uuid = self.fake_rc['uuid']
|
uuid = self.fake_rc['uuid']
|
||||||
with mock.patch.object(self.dbapi, 'get_rc_by_uuid',
|
bay_uuid = self.fake_rc['bay_uuid']
|
||||||
autospec=True) as mock_get_rc:
|
mock_ast.return_value = {}
|
||||||
mock_get_rc.return_value = self.fake_rc
|
k8s_api_mock = mock.MagicMock()
|
||||||
rc = objects.ReplicationController.get_by_uuid(self.context,
|
mock_kube_api.return_value = k8s_api_mock
|
||||||
uuid)
|
|
||||||
mock_get_rc.assert_called_once_with(self.context, uuid)
|
|
||||||
self.assertEqual(self.context, rc._context)
|
|
||||||
|
|
||||||
def test_get_by_name(self):
|
fake_obj = mock.MagicMock()
|
||||||
|
items = [
|
||||||
|
{
|
||||||
|
'metadata': {
|
||||||
|
'uid': '10a47dd1-4874-4298-91cf-eff046dbdb8d',
|
||||||
|
'name': 'fake-name',
|
||||||
|
'labels': {}
|
||||||
|
},
|
||||||
|
'status': {'replicas': 10},
|
||||||
|
'spec': {
|
||||||
|
'template': {
|
||||||
|
'spec': {
|
||||||
|
'containers': [
|
||||||
|
{
|
||||||
|
'image': 'fake-images'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
fake_obj.items = items
|
||||||
|
fake_obj.items[0] = mock.MagicMock()
|
||||||
|
fake_obj.items[0].metadata = mock.MagicMock()
|
||||||
|
fake_obj.items[0].metadata.uid = '10a47dd1-4874-4298-91cf-eff046dbdb8d'
|
||||||
|
fake_obj.items[0].metadata.name = 'fake-name'
|
||||||
|
k8s_api_mock.list_namespaced_replication_controller\
|
||||||
|
.return_value = fake_obj
|
||||||
|
objects.ReplicationController.get_by_uuid(self.context,
|
||||||
|
uuid,
|
||||||
|
bay_uuid,
|
||||||
|
k8s_api_mock)
|
||||||
|
(k8s_api_mock.list_namespaced_replication_controller
|
||||||
|
.assert_called_once_with(namespace='default'))
|
||||||
|
|
||||||
|
@mock.patch('magnum.conductor.k8s_api.create_k8s_api')
|
||||||
|
@mock.patch('ast.literal_eval')
|
||||||
|
def test_get_by_name(self, mock_ast, mock_kube_api):
|
||||||
name = self.fake_rc['name']
|
name = self.fake_rc['name']
|
||||||
with mock.patch.object(self.dbapi, 'get_rc_by_name',
|
bay_uuid = self.fake_rc['bay_uuid']
|
||||||
autospec=True) as mock_get_rc:
|
mock_ast.return_value = {}
|
||||||
mock_get_rc.return_value = self.fake_rc
|
k8s_api_mock = mock.MagicMock()
|
||||||
rc = objects.ReplicationController.get_by_name(self.context,
|
mock_kube_api.return_value = k8s_api_mock
|
||||||
name)
|
fake_rc = mock.MagicMock()
|
||||||
mock_get_rc.assert_called_once_with(self.context, name)
|
fake_rc.metadata.uid = 'fake-uuid'
|
||||||
self.assertEqual(self.context, rc._context)
|
fake_rc.metadata.name = 'fake-name'
|
||||||
|
fake_rc.items[0].spec.template.spec.containers.image = ['fake-images']
|
||||||
def test_list(self):
|
fake_rc.metadata.labels = mock_ast.return_value
|
||||||
with mock.patch.object(self.dbapi, 'get_rc_list',
|
fake_rc.status.replicas = 10
|
||||||
autospec=True) as mock_get_list:
|
k8s_api_mock.read_namespaced_replication_controller\
|
||||||
mock_get_list.return_value = [self.fake_rc]
|
.return_value = fake_rc
|
||||||
rcs = objects.ReplicationController.list(self.context)
|
objects.ReplicationController.get_by_name(self.context,
|
||||||
self.assertEqual(1, mock_get_list.call_count)
|
name,
|
||||||
self.assertThat(rcs, HasLength(1))
|
bay_uuid,
|
||||||
self.assertIsInstance(rcs[0], objects.ReplicationController)
|
k8s_api_mock)
|
||||||
self.assertEqual(self.context, rcs[0]._context)
|
(k8s_api_mock.read_namespaced_replication_controller
|
||||||
|
.assert_called_once_with(name=name, namespace='default'))
|
||||||
def test_create(self):
|
|
||||||
with mock.patch.object(self.dbapi, 'create_rc',
|
|
||||||
autospec=True) as mock_create_rc:
|
|
||||||
mock_create_rc.return_value = self.fake_rc
|
|
||||||
rc = objects.ReplicationController(self.context, **self.fake_rc)
|
|
||||||
rc.create()
|
|
||||||
mock_create_rc.assert_called_once_with(self.fake_rc)
|
|
||||||
self.assertEqual(self.context, rc._context)
|
|
||||||
|
|
||||||
def test_destroy(self):
|
|
||||||
uuid = self.fake_rc['uuid']
|
|
||||||
with mock.patch.object(self.dbapi, 'get_rc_by_uuid',
|
|
||||||
autospec=True) as mock_get_rc:
|
|
||||||
mock_get_rc.return_value = self.fake_rc
|
|
||||||
with mock.patch.object(self.dbapi, 'destroy_rc',
|
|
||||||
autospec=True) as mock_destroy_rc:
|
|
||||||
rc = objects.ReplicationController.get_by_uuid(self.context,
|
|
||||||
uuid)
|
|
||||||
rc.destroy()
|
|
||||||
mock_get_rc.assert_called_once_with(self.context, uuid)
|
|
||||||
mock_destroy_rc.assert_called_once_with(uuid)
|
|
||||||
self.assertEqual(self.context, rc._context)
|
|
||||||
|
|
||||||
def test_save(self):
|
|
||||||
uuid = self.fake_rc['uuid']
|
|
||||||
with mock.patch.object(self.dbapi, 'get_rc_by_uuid',
|
|
||||||
autospec=True) as mock_get_rc:
|
|
||||||
mock_get_rc.return_value = self.fake_rc
|
|
||||||
with mock.patch.object(self.dbapi, 'update_rc',
|
|
||||||
autospec=True) as mock_update_rc:
|
|
||||||
rc = objects.ReplicationController.get_by_uuid(self.context,
|
|
||||||
uuid)
|
|
||||||
rc.replicas = 10
|
|
||||||
rc.save()
|
|
||||||
|
|
||||||
mock_get_rc.assert_called_once_with(self.context, uuid)
|
|
||||||
mock_update_rc.assert_called_once_with(
|
|
||||||
uuid, {'replicas': 10})
|
|
||||||
self.assertEqual(self.context, rc._context)
|
|
||||||
|
|
||||||
def test_refresh(self):
|
|
||||||
uuid = self.fake_rc['uuid']
|
|
||||||
new_uuid = magnum_utils.generate_uuid()
|
|
||||||
returns = [dict(self.fake_rc, uuid=uuid),
|
|
||||||
dict(self.fake_rc, uuid=new_uuid)]
|
|
||||||
expected = [mock.call(self.context, uuid),
|
|
||||||
mock.call(self.context, uuid)]
|
|
||||||
with mock.patch.object(self.dbapi, 'get_rc_by_uuid',
|
|
||||||
side_effect=returns,
|
|
||||||
autospec=True) as mock_get_rc:
|
|
||||||
rc = objects.ReplicationController.get_by_uuid(self.context, uuid)
|
|
||||||
self.assertEqual(uuid, rc.uuid)
|
|
||||||
rc.refresh()
|
|
||||||
self.assertEqual(new_uuid, rc.uuid)
|
|
||||||
self.assertEqual(expected, mock_get_rc.call_args_list)
|
|
||||||
self.assertEqual(self.context, rc._context)
|
|
||||||
|
@ -149,7 +149,7 @@ def create_test_rc(context, **kw):
|
|||||||
ReplicationController object with appropriate attributes.
|
ReplicationController object with appropriate attributes.
|
||||||
"""
|
"""
|
||||||
rc = get_test_rc(context, **kw)
|
rc = get_test_rc(context, **kw)
|
||||||
rc.create()
|
rc.manifest = '{"foo": "bar"}'
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user