From 3e028406289be4afd7248c41d892f81f03e1cb93 Mon Sep 17 00:00:00 2001 From: Tom Cammann Date: Tue, 24 May 2016 14:11:42 +0100 Subject: [PATCH] Remove service object Following on from removing the k8s specific APIs in I1f6f04a35dfbb39f217487fea104ded035b75569 the objects associated with these APIs need removal. Remove the service object, drop the db table and remove references to the service object. Change-Id: I4f06bb779caa0ad369a2b96b4714e1bf2db8acc6 Partially-Implements: blueprint delete-container-endpoint --- etc/magnum/policy.json | 7 - magnum/conductor/api.py | 21 -- magnum/conductor/handlers/k8s_conductor.py | 153 ------------- magnum/db/api.py | 82 ------- .../versions/085e601a39f6_remove_service.py | 28 +++ magnum/db/sqlalchemy/api.py | 104 --------- magnum/db/sqlalchemy/models.py | 20 -- magnum/objects/__init__.py | 3 - magnum/objects/service.py | 137 ------------ magnum/tests/fake_policy.py | 7 - .../tests/unit/api/controllers/v1/test_bay.py | 6 - .../conductor/handlers/test_k8s_conductor.py | 201 ------------------ magnum/tests/unit/conductor/test_rpcapi.py | 27 --- magnum/tests/unit/conductor/test_utils.py | 7 - magnum/tests/unit/db/test_bay.py | 18 -- magnum/tests/unit/db/test_service.py | 178 ---------------- magnum/tests/unit/db/utils.py | 32 --- magnum/tests/unit/objects/test_objects.py | 1 - magnum/tests/unit/objects/test_service.py | 100 --------- magnum/tests/unit/objects/utils.py | 27 --- 20 files changed, 28 insertions(+), 1131 deletions(-) create mode 100644 magnum/db/sqlalchemy/alembic/versions/085e601a39f6_remove_service.py delete mode 100644 magnum/objects/service.py delete mode 100644 magnum/tests/unit/db/test_service.py delete mode 100644 magnum/tests/unit/objects/test_service.py diff --git a/etc/magnum/policy.json b/etc/magnum/policy.json index 43fc95e318..74b3f84b4e 100644 --- a/etc/magnum/policy.json +++ b/etc/magnum/policy.json @@ -27,13 +27,6 @@ "rc:get_all": "rule:default", "rc:update": "rule:default", - "service:create": "rule:default", - "service:delete": "rule:default", - "service:detail": "rule:default", - "service:get": "rule:default", - "service:get_all": "rule:default", - "service:update": "rule:default", - "container:create": "rule:admin_or_user", "container:delete": "rule:admin_or_user", "container:detail": "rule:default", diff --git a/magnum/conductor/api.py b/magnum/conductor/api.py index 838cf329e9..4402b2f488 100644 --- a/magnum/conductor/api.py +++ b/magnum/conductor/api.py @@ -40,27 +40,6 @@ class API(rpc_service.API): def bay_update(self, bay): return self._call('bay_update', bay=bay) - # Service Operations - - def service_create(self, service): - return self._call('service_create', service=service) - - def service_update(self, service_ident, bay_ident, manifest): - return self._call('service_update', service_ident=service_ident, - bay_ident=bay_ident, manifest=manifest) - - def service_list(self, context, bay_ident): - return self._call('service_list', bay_ident=bay_ident) - - def service_delete(self, service_ident, bay_ident): - return self._call('service_delete', - service_ident=service_ident, - bay_ident=bay_ident) - - def service_show(self, context, service_ident, bay_ident): - return self._call('service_show', service_ident=service_ident, - bay_ident=bay_ident) - # ReplicationController Operations def rc_create(self, rc): diff --git a/magnum/conductor/handlers/k8s_conductor.py b/magnum/conductor/handlers/k8s_conductor.py index c077c73105..c5ba548a8e 100644 --- a/magnum/conductor/handlers/k8s_conductor.py +++ b/magnum/conductor/handlers/k8s_conductor.py @@ -38,159 +38,6 @@ class Handler(object): def __init__(self): super(Handler, self).__init__() - def service_create(self, context, service): - LOG.debug("service_create") - bay = conductor_utils.retrieve_bay(context, service.bay_uuid) - self.k8s_api = k8s.create_k8s_api(context, bay) - manifest = k8s_manifest.parse(service.manifest) - try: - resp = self.k8s_api.create_namespaced_service(body=manifest, - namespace='default') - except rest.ApiException as err: - raise exception.KubernetesAPIFailed(err=err) - - if resp is None: - raise exception.ServiceCreationFailed(bay_uuid=service.bay_uuid) - - service['uuid'] = resp.metadata.uid - service['name'] = resp.metadata.name - service['labels'] = ast.literal_eval(resp.metadata.labels) - service['selector'] = ast.literal_eval(resp.spec.selector) - service['ip'] = resp.spec.cluster_ip - service_value = [] - for p in resp.spec.ports: - ports = p.to_dict() - if not ports['name']: - ports['name'] = 'k8s-service' - service_value.append(ports) - - service['ports'] = service_value - - return service - - def service_update(self, context, service_ident, bay_ident, manifest): - LOG.debug("service_update %s", service_ident) - bay = conductor_utils.retrieve_bay(context, bay_ident) - self.k8s_api = k8s.create_k8s_api(context, bay) - if uuidutils.is_uuid_like(service_ident): - service = objects.Service.get_by_uuid(context, - service_ident, - bay.uuid, - self.k8s_api) - else: - service = objects.Service.get_by_name(context, - service_ident, - bay.uuid, - self.k8s_api) - service_ident = service.name - try: - resp = self.k8s_api.replace_namespaced_service( - name=str(service_ident), - body=manifest, - namespace='default') - except rest.ApiException as err: - raise exception.KubernetesAPIFailed(err=err) - - if resp is None: - raise exception.ServiceNotFound(service=service.uuid) - - service['uuid'] = resp.metadata.uid - service['name'] = resp.metadata.name - service['project_id'] = context.project_id - service['user_id'] = context.user_id - service['bay_uuid'] = bay.uuid - service['labels'] = ast.literal_eval(resp.metadata.labels) - if not resp.spec.selector: - service['selector'] = {} - else: - service['selector'] = ast.literal_eval(resp.spec.selector) - service['ip'] = resp.spec.cluster_ip - service_value = [] - for p in resp.spec.ports: - ports = p.to_dict() - if not ports['name']: - ports['name'] = 'k8s-service' - service_value.append(ports) - - service['ports'] = service_value - - return service - - def service_delete(self, context, service_ident, bay_ident): - LOG.debug("service_delete %s", service_ident) - bay = conductor_utils.retrieve_bay(context, bay_ident) - self.k8s_api = k8s.create_k8s_api(context, bay) - if uuidutils.is_uuid_like(service_ident): - service = objects.Service.get_by_uuid(context, service_ident, - bay.uuid, self.k8s_api) - service_name = service.name - else: - service_name = service_ident - if conductor_utils.object_has_stack(context, bay.uuid): - try: - - self.k8s_api.delete_namespaced_service(name=str(service_name), - namespace='default') - except rest.ApiException as err: - if err.status == 404: - pass - else: - raise exception.KubernetesAPIFailed(err=err) - - def service_show(self, context, service_ident, bay_ident): - LOG.debug("service_show %s", service_ident) - bay = conductor_utils.retrieve_bay(context, bay_ident) - self.k8s_api = k8s.create_k8s_api(context, bay) - if uuidutils.is_uuid_like(service_ident): - service = objects.Service.get_by_uuid(context, service_ident, - bay.uuid, self.k8s_api) - else: - service = objects.Service.get_by_name(context, service_ident, - bay.uuid, self.k8s_api) - - return service - - def service_list(self, context, bay_ident): - bay = conductor_utils.retrieve_bay(context, bay_ident) - self.k8s_api = k8s.create_k8s_api(context, bay) - try: - resp = self.k8s_api.list_namespaced_service(namespace='default') - except rest.ApiException as err: - raise exception.KubernetesAPIFailed(err=err) - - if resp is None: - raise exception.ServiceListNotFound(bay_uuid=bay.uuid) - - services = [] - for service_entry in resp.items: - service = {} - service['uuid'] = service_entry.metadata.uid - service['name'] = service_entry.metadata.name - service['project_id'] = context.project_id - service['user_id'] = context.user_id - service['bay_uuid'] = bay.uuid - service['labels'] = ast.literal_eval( - service_entry.metadata.labels) - if not service_entry.spec.selector: - service['selector'] = {} - else: - service['selector'] = ast.literal_eval( - service_entry.spec.selector) - service['ip'] = service_entry.spec.cluster_ip - service_value = [] - for p in service_entry.spec.ports: - ports = p.to_dict() - if not ports['name']: - ports['name'] = 'k8s-service' - service_value.append(ports) - - service['ports'] = service_value - - service_obj = objects.Service(context, **service) - services.append(service_obj) - - return services - # Replication Controller Operations def rc_create(self, context, rc): LOG.debug("rc_create") diff --git a/magnum/db/api.py b/magnum/db/api.py index fb03a6de56..023a18d166 100644 --- a/magnum/db/api.py +++ b/magnum/db/api.py @@ -288,88 +288,6 @@ class Connection(object): :raises: ContainerNotFound """ - @abc.abstractmethod - def get_service_list(self, context, filters=None, limit=None, - marker=None, sort_key=None, sort_dir=None): - """Get matching services. - - Return a list of the specified columns for all services that match the - specified filters. - - :param context: The security context - :param filters: Filters to apply. Defaults to None. - - :param limit: Maximum number of services to return. - :param marker: the last item of the previous page; we return the next - result set. - :param sort_key: Attribute by which results should be sorted. - :param sort_dir: direction in which results should be sorted. - (asc, desc) - :returns: A list of tuples of the specified columns. - """ - - @abc.abstractmethod - def create_service(self, values): - """Create a new service. - - :param values: A dict containing several items used to identify - and track the service, and several dicts which are - passed into the Drivers when managing this service. - For example: - - :: - - { - 'uuid': uuidutils.generate_uuid(), - 'name': 'example', - 'type': 'virt' - } - :returns: A service. - """ - - @abc.abstractmethod - def get_service_by_id(self, context, service_id): - """Return a service. - - :param context: The security context - :param service_id: The id of a service. - :returns: A service. - """ - - @abc.abstractmethod - def get_service_by_uuid(self, context, service_uuid): - """Return a service. - - :param context: The security context - :param service_uuid: The uuid of a service. - :returns: A service. - """ - - @abc.abstractmethod - def get_service_by_name(self, context, service_name): - """Return a service. - - :param context: The security context - :param service_name: The name of a service - :returns: A service. - """ - - @abc.abstractmethod - def destroy_service(self, service_id): - """Destroy a service and all associated interfaces. - - :param service_id: The id or uuid of a service. - """ - - @abc.abstractmethod - def update_service(self, service_id, values): - """Update properties of a service. - - :param service_id: The id or uuid of a service. - :returns: A service. - :raises: ServiceNotFound - """ - @abc.abstractmethod def get_rc_list(self, context, filters=None, limit=None, marker=None, sort_key=None, sort_dir=None): diff --git a/magnum/db/sqlalchemy/alembic/versions/085e601a39f6_remove_service.py b/magnum/db/sqlalchemy/alembic/versions/085e601a39f6_remove_service.py new file mode 100644 index 0000000000..fee6c0c21c --- /dev/null +++ b/magnum/db/sqlalchemy/alembic/versions/085e601a39f6_remove_service.py @@ -0,0 +1,28 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""remove service object + +Revision ID: 085e601a39f6 +Revises: a1136d335540 +Create Date: 2016-05-25 12:05:30.790282 + +""" + +# revision identifiers, used by Alembic. +revision = '085e601a39f6' +down_revision = 'a1136d335540' + +from alembic import op + + +def upgrade(): + op.drop_table('service') diff --git a/magnum/db/sqlalchemy/api.py b/magnum/db/sqlalchemy/api.py index c73bb83bd0..b64e286e5c 100644 --- a/magnum/db/sqlalchemy/api.py +++ b/magnum/db/sqlalchemy/api.py @@ -193,11 +193,6 @@ class Connection(api.Connection): def destroy_bay(self, bay_id): def destroy_bay_resources(session, bay_uuid): """Checks whether the bay does not have resources.""" - query = model_query(models.Service, session=session) - query = self._add_services_filters(query, {'bay_uuid': bay_uuid}) - if query.count() != 0: - query.delete() - query = model_query(models.ReplicationController, session=session) query = self._add_rcs_filters(query, {'bay_uuid': bay_uuid}) if query.count() != 0: @@ -472,105 +467,6 @@ class Connection(api.Connection): ref.update(values) return ref - def _add_services_filters(self, query, filters): - if filters is None: - filters = {} - - if 'bay_uuid' in filters: - query = query.filter_by(bay_uuid=filters['bay_uuid']) - if 'name' in filters: - query = query.filter_by(name=filters['name']) - if 'ip' in filters: - query = query.filter_by(ip=filters['ip']) - if 'ports' in filters: - query = query.filter_by(ports=filters['ports']) - - return query - - def get_service_list(self, context, filters=None, limit=None, marker=None, - sort_key=None, sort_dir=None): - query = model_query(models.Service) - query = self._add_tenant_filters(context, query) - query = self._add_services_filters(query, filters) - return _paginate_query(models.Service, limit, marker, - sort_key, sort_dir, query) - - def create_service(self, values): - # ensure defaults are present for new services - if not values.get('uuid'): - values['uuid'] = uuidutils.generate_uuid() - - service = models.Service() - service.update(values) - try: - service.save() - except db_exc.DBDuplicateEntry: - raise exception.ServiceAlreadyExists(uuid=values['uuid']) - return service - - def get_service_by_id(self, context, service_id): - query = model_query(models.Service) - query = self._add_tenant_filters(context, query) - query = query.filter_by(id=service_id) - try: - return query.one() - except NoResultFound: - raise exception.ServiceNotFound(service=service_id) - - def get_service_by_uuid(self, context, service_uuid): - query = model_query(models.Service) - query = self._add_tenant_filters(context, query) - query = query.filter_by(uuid=service_uuid) - try: - return query.one() - except NoResultFound: - raise exception.ServiceNotFound(service=service_uuid) - - def get_service_by_name(self, context, service_name): - query = model_query(models.Service) - query = self._add_tenant_filters(context, query) - query = query.filter_by(name=service_name) - try: - return query.one() - except MultipleResultsFound: - raise exception.Conflict('Multiple services exist with same name.' - ' Please use the service uuid instead.') - except NoResultFound: - raise exception.ServiceNotFound(service=service_name) - - def destroy_service(self, service_id): - session = get_session() - with session.begin(): - query = model_query(models.Service, session=session) - query = add_identity_filter(query, service_id) - count = query.delete() - if count != 1: - raise exception.ServiceNotFound(service_id) - - def update_service(self, service_id, values): - # NOTE(dtantsur): this can lead to very strange errors - if 'uuid' in values: - msg = _("Cannot overwrite UUID for an existing Service.") - raise exception.InvalidParameterValue(err=msg) - - return self._do_update_service(service_id, values) - - def _do_update_service(self, service_id, values): - session = get_session() - with session.begin(): - query = model_query(models.Service, session=session) - query = add_identity_filter(query, service_id) - try: - ref = query.with_lockmode('update').one() - except NoResultFound: - raise exception.ServiceNotFound(service=service_id) - - if 'provision_state' in values: - values['provision_updated_at'] = timeutils.utcnow() - - ref.update(values) - return ref - def _add_rcs_filters(self, query, filters): if filters is None: filters = {} diff --git a/magnum/db/sqlalchemy/models.py b/magnum/db/sqlalchemy/models.py index 5d8dbab8ce..6eaa0ddd33 100644 --- a/magnum/db/sqlalchemy/models.py +++ b/magnum/db/sqlalchemy/models.py @@ -195,26 +195,6 @@ class Container(Base): environment = Column(JSONEncodedDict) -class Service(Base): - """Represents a software service.""" - - __tablename__ = 'service' - __table_args__ = ( - schema.UniqueConstraint('uuid', name='uniq_service0uuid'), - table_args() - ) - id = Column(Integer, primary_key=True) - uuid = Column(String(36)) - name = Column(String(255)) - bay_uuid = Column(String(36)) - labels = Column(JSONEncodedDict) - selector = Column(JSONEncodedDict) - ip = Column(String(36)) - ports = Column(JSONEncodedList) - project_id = Column(String(255)) - user_id = Column(String(255)) - - class ReplicationController(Base): """Represents a pod replication controller.""" diff --git a/magnum/objects/__init__.py b/magnum/objects/__init__.py index 91a964e52e..621e3b42ab 100644 --- a/magnum/objects/__init__.py +++ b/magnum/objects/__init__.py @@ -18,7 +18,6 @@ from magnum.objects import certificate from magnum.objects import container from magnum.objects import magnum_service from magnum.objects import replicationcontroller as rc -from magnum.objects import service from magnum.objects import x509keypair @@ -27,7 +26,6 @@ Bay = bay.Bay BayModel = baymodel.BayModel MagnumService = magnum_service.MagnumService ReplicationController = rc.ReplicationController -Service = service.Service X509KeyPair = x509keypair.X509KeyPair Certificate = certificate.Certificate __all__ = (Bay, @@ -35,6 +33,5 @@ __all__ = (Bay, Container, MagnumService, ReplicationController, - Service, X509KeyPair, Certificate) diff --git a/magnum/objects/service.py b/magnum/objects/service.py deleted file mode 100644 index 12088a7ad8..0000000000 --- a/magnum/objects/service.py +++ /dev/null @@ -1,137 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import ast - -from k8sclient.client import rest -from oslo_versionedobjects import fields - -from magnum.common import exception -from magnum.db import api as dbapi -from magnum.objects import base -from magnum.objects import fields as magnum_fields - - -@base.MagnumObjectRegistry.register -class Service(base.MagnumPersistentObject, base.MagnumObject, - base.MagnumObjectDictCompat): - # Version 1.0: Initial version - VERSION = '1.0' - - dbapi = dbapi.get_instance() - - fields = { - 'id': fields.IntegerField(), - 'uuid': fields.StringField(nullable=True), - 'name': fields.StringField(nullable=True), - 'project_id': fields.StringField(nullable=True), - 'user_id': fields.StringField(nullable=True), - 'bay_uuid': fields.StringField(nullable=True), - 'labels': fields.DictOfStringsField(nullable=True), - 'selector': fields.DictOfStringsField(nullable=True), - 'ip': fields.StringField(nullable=True), - 'ports': magnum_fields.ListOfDictsField(nullable=True), - 'manifest_url': fields.StringField(nullable=True), - 'manifest': fields.StringField(nullable=True), - } - - @base.remotable_classmethod - def get_by_uuid(cls, context, uuid, bay_uuid, k8s_api): - """Find a service based on service uuid and UUID of the Bay - - :param context: Security context - :param uuid: the uuid of a service. - :param bay_uuid: the UUID of the Bay - :param k8s_api: k8s API object - - :returns: a :class:`Service` object. - """ - try: - resp = k8s_api.list_namespaced_service(namespace='default') - except rest.ApiException as err: - raise exception.KubernetesAPIFailed(err=err) - - if resp is None: - raise exception.ServiceListNotFound(bay_uuid=bay_uuid) - - service = {} - for service_entry in resp.items: - if service_entry.metadata.uid == uuid: - service['uuid'] = service_entry.metadata.uid - service['name'] = service_entry.metadata.name - service['project_id'] = context.project_id - service['user_id'] = context.user_id - service['bay_uuid'] = bay_uuid - service['labels'] = ast.literal_eval( - service_entry.metadata.labels) - if not service_entry.spec.selector: - service['selector'] = {} - else: - service['selector'] = ast.literal_eval( - service_entry.spec.selector) - service['ip'] = service_entry.spec.cluster_ip - service_value = [] - for p in service_entry.spec.ports: - ports = p.to_dict() - if not ports['name']: - ports['name'] = 'k8s-service' - service_value.append(ports) - - service['ports'] = service_value - - service_obj = Service(context, **service) - return service_obj - raise exception.ServiceNotFound(service=uuid) - - @base.remotable_classmethod - def get_by_name(cls, context, name, bay_uuid, k8s_api): - """Find a service based on service name and UUID of the Bay - - :param context: Security context - :param name: the name of a service. - :param bay_uuid: the UUID of the Bay - :param k8s_api: k8s API object - - :returns: a :class:`Service` object. - """ - try: - resp = k8s_api.read_namespaced_service(name=name, - namespace='default') - except rest.ApiException as err: - raise exception.KubernetesAPIFailed(err=err) - - if resp is None: - raise exception.ServiceNotFound(service=name) - - service = {} - service['uuid'] = resp.metadata.uid - service['name'] = resp.metadata.name - service['project_id'] = context.project_id - service['user_id'] = context.user_id - service['bay_uuid'] = bay_uuid - service['labels'] = ast.literal_eval(resp.metadata.labels) - if not resp.spec.selector: - service['selector'] = {} - else: - service['selector'] = ast.literal_eval(resp.spec.selector) - service['ip'] = resp.spec.cluster_ip - service_value = [] - for p in resp.spec.ports: - ports = p.to_dict() - if not ports['name']: - ports['name'] = 'k8s-service' - service_value.append(ports) - - service['ports'] = service_value - - service_obj = Service(context, **service) - return service_obj diff --git a/magnum/tests/fake_policy.py b/magnum/tests/fake_policy.py index a031208c23..87d18f0d37 100644 --- a/magnum/tests/fake_policy.py +++ b/magnum/tests/fake_policy.py @@ -41,13 +41,6 @@ policy_data = """ "rc:get_all": "", "rc:update": "", - "service:create": "", - "service:delete": "", - "service:detail": "", - "service:get": "", - "service:get_all": "", - "service:update": "", - "container:create": "", "container:delete": "", "container:detail": "", diff --git a/magnum/tests/unit/api/controllers/v1/test_bay.py b/magnum/tests/unit/api/controllers/v1/test_bay.py index 03907d41b9..35f4d4b42e 100644 --- a/magnum/tests/unit/api/controllers/v1/test_bay.py +++ b/magnum/tests/unit/api/controllers/v1/test_bay.py @@ -647,12 +647,6 @@ class TestDelete(api_base.FunctionalTest): self.assertEqual('application/json', response.content_type) self.assertTrue(response.json['errors']) - def test_delete_bay_with_services(self): - obj_utils.create_test_service(self.context, bay_uuid=self.bay.uuid) - response = self.delete('/bays/%s' % self.bay.uuid, - expect_errors=True) - self.assertEqual(204, response.status_int) - def test_delete_bay_with_replication_controllers(self): obj_utils.create_test_rc(self.context, bay_uuid=self.bay.uuid) response = self.delete('/bays/%s' % self.bay.uuid, diff --git a/magnum/tests/unit/conductor/handlers/test_k8s_conductor.py b/magnum/tests/unit/conductor/handlers/test_k8s_conductor.py index 77831e9c5b..86fa390e4b 100644 --- a/magnum/tests/unit/conductor/handlers/test_k8s_conductor.py +++ b/magnum/tests/unit/conductor/handlers/test_k8s_conductor.py @@ -27,9 +27,6 @@ class TestK8sConductor(base.TestCase): super(TestK8sConductor, self).setUp() self.kube_handler = k8s_conductor.Handler() - def mock_service(self): - return objects.Service({}) - def mock_rc(self): return objects.ReplicationController({}) @@ -39,137 +36,6 @@ class TestK8sConductor(base.TestCase): def mock_baymodel(self): return objects.BayModel({}) - @patch('magnum.objects.Bay.get_by_name') - @patch('magnum.conductor.k8s_api.create_k8s_api') - @patch('ast.literal_eval') - def test_service_create_with_success(self, - mock_ast, - mock_kube_api, - mock_get_bay): - fake_service = mock.MagicMock() - fake_service.name = 'test-name' - - expected_service = mock.MagicMock() - expected_service.bay_uuid = 'test-bay-uuid' - expected_service.name = 'test-name' - expected_service.uuid = 'test-uuid' - manifest = {"key": "value"} - expected_service.manifest = '{"key": "value"}' - mock_ast.return_value = {} - - with patch('magnum.conductor.k8s_api.create_k8s_api') as \ - mock_kube_api: - self.kube_handler.service_create(self.context, expected_service) - (mock_kube_api.return_value.create_namespaced_service - .assert_called_once_with(body=manifest, namespace='default')) - - @patch('magnum.objects.Bay.get_by_name') - def test_service_create_with_failure(self, mock_get_bay): - expected_service = mock.MagicMock() - expected_service.create = mock.MagicMock() - manifest = {"key": "value"} - expected_service.manifest = '{"key": "value"}' - - with patch('magnum.conductor.k8s_api.create_k8s_api') as \ - mock_kube_api: - err = rest.ApiException(status=404) - (mock_kube_api.return_value.create_namespaced_service - .side_effect) = err - - self.assertRaises(exception.KubernetesAPIFailed, - self.kube_handler.service_create, - self.context, expected_service) - (mock_kube_api.return_value.create_namespaced_service - .assert_called_once_with(body=manifest, namespace='default')) - - @patch('magnum.conductor.utils.object_has_stack') - @patch('magnum.objects.Service.get_by_name') - @patch('magnum.objects.Bay.get_by_name') - def test_service_delete_with_success( - self, mock_bay_get_by_name, - mock_service_get_by_name, - mock_object_has_stack): - mock_bay = mock.MagicMock() - mock_bay_get_by_name.return_value = mock_bay - - mock_service = mock.MagicMock() - mock_service.name = 'test-service' - mock_service.uuid = 'test-uuid' - mock_service.bay_uuid = 'test-bay-uuid' - mock_service_get_by_name.return_value = mock_service - - mock_object_has_stack.return_value = True - with patch('magnum.conductor.k8s_api.create_k8s_api') as \ - mock_kube_api: - self.kube_handler.service_delete(self.context, - mock_service.name, - mock_service.bay_uuid) - (mock_kube_api.return_value.delete_namespaced_service - .assert_called_once_with( - name=mock_service.name, namespace='default')) - - @patch('magnum.conductor.utils.object_has_stack') - @patch('magnum.objects.Service.get_by_uuid') - @patch('magnum.objects.Bay.get_by_name') - def test_service_delete_with_failure( - self, mock_bay_get_by_name, - mock_service_get_by_uuid, - mock_object_has_stack): - mock_bay = mock.MagicMock() - mock_bay_get_by_name.return_value = mock_bay - - mock_service = mock.MagicMock() - mock_service.name = 'test-service' - mock_service.uuid = 'test-uuid' - mock_service.bay_uuid = 'test-bay-uuid' - mock_service_get_by_uuid.return_value = mock_service - - mock_object_has_stack.return_value = True - with patch('magnum.conductor.k8s_api.create_k8s_api') as \ - mock_kube_api: - err = rest.ApiException(status=500) - (mock_kube_api.return_value.delete_namespaced_service - .side_effect) = err - - self.assertRaises(exception.KubernetesAPIFailed, - self.kube_handler.service_delete, - self.context, mock_service.name, - mock_service.bay_uuid) - (mock_kube_api.return_value.delete_namespaced_service - .assert_called_once_with( - name=mock_service.name, namespace='default')) - self.assertFalse(mock_service.destroy.called) - - @patch('magnum.conductor.utils.object_has_stack') - @patch('magnum.objects.Service.get_by_uuid') - @patch('magnum.objects.Bay.get_by_name') - def test_service_delete_succeeds_when_not_found( - self, mock_bay_get_by_name, - mock_service_get_by_uuid, - mock_object_has_stack): - mock_bay = mock.MagicMock() - mock_bay_get_by_name.return_value = mock_bay - - mock_service = mock.MagicMock() - mock_service.name = 'test-service' - mock_service.uuid = 'test-uuid' - mock_service.bay_uuid = 'test-bay-uuid' - mock_service_get_by_uuid.return_value = mock_service - - mock_object_has_stack.return_value = True - with patch('magnum.conductor.k8s_api.create_k8s_api') as \ - mock_kube_api: - err = rest.ApiException(status=404) - (mock_kube_api.return_value.delete_namespaced_service - .side_effect) = err - - self.kube_handler.service_delete(self.context, - mock_service.name, - mock_service.bay_uuid) - (mock_kube_api.return_value.delete_namespaced_service - .assert_called_once_with( - name=mock_service.name, namespace='default')) - @patch('magnum.conductor.utils.retrieve_bay') @patch('ast.literal_eval') def test_rc_create_with_success(self, mock_ast, mock_retrieve): @@ -363,70 +229,3 @@ class TestK8sConductor(base.TestCase): .assert_called_once_with(body=expected_rc.manifest, name=name_rc, namespace='default')) - - @patch('magnum.objects.Service.get_by_name') - @patch('magnum.objects.Service.get_by_uuid') - @patch('magnum.objects.Bay.get_by_name') - @patch('ast.literal_eval') - def test_service_update_with_success(self, mock_ast, - mock_bay_get_by_name, - mock_service_get_by_uuid, - mock_service_get_by_name): - mock_bay = mock.MagicMock() - mock_bay_get_by_name.return_value = mock_bay - - expected_service = mock.MagicMock() - expected_service.uuid = 'test-uuid' - expected_service.name = 'test-name' - expected_service.bay_uuid = 'test-bay-uuid' - expected_service.manifest = '{"key": "value"}' - mock_ast.return_value = {} - - mock_service_get_by_name.return_value = expected_service - mock_service_get_by_uuid.return_value = expected_service - service_name = expected_service.name - - with patch('magnum.conductor.k8s_api.create_k8s_api') as \ - mock_kube_api: - self.kube_handler.service_update(self.context, - expected_service.name, - expected_service.bay_uuid, - expected_service.manifest) - (mock_kube_api.return_value.replace_namespaced_service - .assert_called_once_with(body=expected_service.manifest, - name=service_name, - namespace='default')) - - @patch('magnum.objects.Service.get_by_name') - @patch('magnum.objects.Service.get_by_uuid') - @patch('magnum.objects.Bay.get_by_name') - def test_service_update_with_failure(self, mock_bay_get_by_name, - mock_service_get_by_uuid, - mock_service_get_by_name): - mock_bay = mock.MagicMock() - mock_bay_get_by_name.return_value = mock_bay - - expected_service = mock.MagicMock() - expected_service.uuid = 'test-uuid' - expected_service.name = 'test-name' - expected_service.bay_uuid = 'test-bay-uuid' - expected_service.manifest = '{"key": "value"}' - mock_service_get_by_uuid.return_value = expected_service - mock_service_get_by_name.return_value = expected_service - service_name = expected_service.name - - with patch('magnum.conductor.k8s_api.create_k8s_api') as \ - mock_kube_api: - err = rest.ApiException(status=404) - (mock_kube_api.return_value.replace_namespaced_service - .side_effect) = err - - self.assertRaises(exception.KubernetesAPIFailed, - self.kube_handler.service_update, - self.context, expected_service.name, - expected_service.bay_uuid, - expected_service.manifest) - (mock_kube_api.return_value.replace_namespaced_service - .assert_called_once_with(body=expected_service.manifest, - name=service_name, - namespace='default')) diff --git a/magnum/tests/unit/conductor/test_rpcapi.py b/magnum/tests/unit/conductor/test_rpcapi.py index 51d749ba09..2f25b3b9df 100644 --- a/magnum/tests/unit/conductor/test_rpcapi.py +++ b/magnum/tests/unit/conductor/test_rpcapi.py @@ -30,7 +30,6 @@ class RPCAPITestCase(base.DbTestCase): self.fake_bay = dbutils.get_test_bay(driver='fake-driver') self.fake_container = dbutils.get_test_container(driver='fake-driver') self.fake_rc = dbutils.get_test_rc(driver='fake-driver') - self.fake_service = dbutils.get_test_service(driver='fake-driver') self.fake_certificate = objects.Certificate.from_db_bay(self.fake_bay) self.fake_certificate.csr = 'fake-csr' @@ -99,32 +98,6 @@ class RPCAPITestCase(base.DbTestCase): version='1.1', bay=self.fake_bay['name']) - def test_service_create(self): - self._test_rpcapi('service_create', - 'call', - version='1.0', - service=self.fake_service) - - def test_service_update(self): - self._test_rpcapi('service_update', - 'call', - version='1.0', - service_ident=self.fake_service['uuid'], - bay_ident=self.fake_service['bay_uuid'], - manifest={}) - - def test_service_delete(self): - self._test_rpcapi('service_delete', - 'call', - version='1.0', - service_ident=self.fake_service['uuid'], - bay_ident=self.fake_service['bay_uuid']) - self._test_rpcapi('service_delete', - 'call', - version='1.1', - service_ident=self.fake_service['uuid'], - bay_ident=self.fake_service['bay_uuid']) - def test_rc_create(self): self._test_rpcapi('rc_create', 'call', diff --git a/magnum/tests/unit/conductor/test_utils.py b/magnum/tests/unit/conductor/test_utils.py index 4e5e2d136e..969ab45b02 100644 --- a/magnum/tests/unit/conductor/test_utils.py +++ b/magnum/tests/unit/conductor/test_utils.py @@ -27,13 +27,6 @@ class TestConductorUtils(base.TestCase): mock_bay_get_by_uuid.assert_called_once_with(expected_context, expected_bay_uuid) - @patch('magnum.objects.Bay.get_by_uuid') - def test_retrieve_bay_from_service(self, - 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') def test_retrieve_bay_from_rc(self, mock_bay_get_by_uuid): diff --git a/magnum/tests/unit/db/test_bay.py b/magnum/tests/unit/db/test_bay.py index 96fc8ddc64..5f8644c3ad 100644 --- a/magnum/tests/unit/db/test_bay.py +++ b/magnum/tests/unit/db/test_bay.py @@ -192,24 +192,6 @@ class DbBayTestCase(base.DbTestCase): self.dbapi.destroy_bay, '12345678-9999-0000-aaaa-123456789012') - def test_destroy_bay_that_has_services(self): - bay = utils.create_test_bay() - service = utils.create_test_service(bay_uuid=bay.uuid) - self.assertEqual(bay.uuid, service.bay_uuid) - self.dbapi.destroy_bay(bay.id) - self.assertRaises(exception.ServiceNotFound, - self.dbapi.get_service_by_id, - self.context, service.id) - - def test_destroy_bay_that_has_services_by_uuid(self): - bay = utils.create_test_bay() - service = utils.create_test_service(bay_uuid=bay.uuid) - self.assertEqual(bay.uuid, service.bay_uuid) - self.dbapi.destroy_bay(bay.id) - self.assertRaises(exception.ServiceNotFound, - self.dbapi.get_service_by_id, - self.context, service.id) - def test_destroy_bay_that_has_rc(self): bay = utils.create_test_bay() rc = utils.create_test_rc(bay_uuid=bay.uuid) diff --git a/magnum/tests/unit/db/test_service.py b/magnum/tests/unit/db/test_service.py deleted file mode 100644 index 3365dd5ed2..0000000000 --- a/magnum/tests/unit/db/test_service.py +++ /dev/null @@ -1,178 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Tests for manipulating Services via the DB API""" - -from oslo_utils import uuidutils -import six - -from magnum.common import exception -from magnum.tests.unit.db import base -from magnum.tests.unit.db import utils as utils - - -class DbServiceTestCase(base.DbTestCase): - - def setUp(self): - # This method creates a service for every test and - # replaces a test for creating a service. - super(DbServiceTestCase, self).setUp() - self.bay = utils.create_test_bay() - self.service = utils.create_test_service(bay_uuid=self.bay.uuid) - - def test_create_service_duplicated_uuid(self): - self.assertRaises(exception.ServiceAlreadyExists, - utils.create_test_service, - uuid=self.service.uuid, - bay_uuid=self.bay.uuid) - - def test_get_service_by_id(self): - res = self.dbapi.get_service_by_id(self.context, self.service.id) - self.assertEqual(self.service.id, res.id) - self.assertEqual(self.service.uuid, res.uuid) - - def test_get_service_by_uuid(self): - res = self.dbapi.get_service_by_uuid(self.context, self.service.uuid) - self.assertEqual(self.service.id, res.id) - self.assertEqual(self.service.uuid, res.uuid) - - def test_get_service_by_name(self): - res = self.dbapi.get_service_by_name(self.context, self.service.name) - self.assertEqual(self.service.id, res.id) - self.assertEqual(self.service.uuid, res.uuid) - - def test_get_service_by_name_multiple_service(self): - utils.create_test_service(bay_uuid=self.bay.uuid, - uuid=uuidutils.generate_uuid()) - self.assertRaises(exception.Conflict, self.dbapi.get_service_by_name, - self.context, self.service.name) - - def test_get_service_by_name_not_found(self): - self.assertRaises(exception.ServiceNotFound, - self.dbapi.get_service_by_name, - self.context, 'not_found') - - def test_get_service_that_does_not_exist(self): - self.assertRaises(exception.ServiceNotFound, - self.dbapi.get_service_by_id, self.context, 999) - self.assertRaises(exception.ServiceNotFound, - self.dbapi.get_service_by_uuid, - self.context, - uuidutils.generate_uuid()) - - def test_get_service_list(self): - uuids = [self.service.uuid] - for i in range(1, 6): - service = utils.create_test_service( - bay_uuid=self.bay.uuid, - uuid=uuidutils.generate_uuid()) - uuids.append(six.text_type(service.uuid)) - res = self.dbapi.get_service_list(self.context) - res_uuids = [r.uuid for r in res] - self.assertEqual(sorted(uuids), sorted(res_uuids)) - - def test_get_service_list_sorted(self): - uuids = [self.service.uuid] - for _ in range(5): - service = utils.create_test_service( - uuid=uuidutils.generate_uuid()) - uuids.append(six.text_type(service.uuid)) - res = self.dbapi.get_service_list(self.context, sort_key='uuid') - res_uuids = [r.uuid for r in res] - self.assertEqual(sorted(uuids), res_uuids) - - self.assertRaises(exception.InvalidParameterValue, - self.dbapi.get_service_list, - self.context, - sort_key='foo') - - def test_get_service_list_with_filters(self): - bay1 = utils.get_test_bay(id=11, uuid=uuidutils.generate_uuid()) - bay2 = utils.get_test_bay(id=12, uuid=uuidutils.generate_uuid()) - self.dbapi.create_bay(bay1) - self.dbapi.create_bay(bay2) - - service1 = utils.create_test_service( - name='service-one', - uuid=uuidutils.generate_uuid(), - bay_uuid=bay1['uuid'], - ports=[{'port': 8000}]) - service2 = utils.create_test_service( - name='service-two', - uuid=uuidutils.generate_uuid(), - bay_uuid=bay2['uuid'], - ports=[{'port': 8001}]) - - res = self.dbapi.get_service_list(self.context, - filters={'bay_uuid': bay1['uuid']}) - self.assertEqual([service1.id], [r.id for r in res]) - - res = self.dbapi.get_service_list(self.context, - filters={'bay_uuid': bay2['uuid']}) - self.assertEqual([service2.id], [r.id for r in res]) - - res = self.dbapi.get_service_list(self.context, - filters={'name': 'service-one'}) - self.assertEqual([service1.id], [r.id for r in res]) - - res = self.dbapi.get_service_list(self.context, - filters={'name': 'bad-service'}) - self.assertEqual([], [r.id for r in res]) - - res = self.dbapi.get_service_list(self.context, - filters={'ports': [{'port': 8000}]}) - self.assertEqual([service1.id], [r.id for r in res]) - - res = self.dbapi.get_service_list(self.context, - filters={'ports': [{'port': 8001}]}) - self.assertEqual([service2.id], [r.id for r in res]) - - def test_get_service_list_bay_not_exist(self): - res = self.dbapi.get_service_list(self.context, filters={ - 'bay_uuid': self.bay.uuid}) - self.assertEqual(1, len(res)) - res = self.dbapi.get_service_list(self.context, filters={ - 'bay_uuid': uuidutils.generate_uuid()}) - self.assertEqual(0, len(res)) - - def test_destroy_service_by_uuid(self): - self.assertIsNotNone(self.dbapi.get_service_by_uuid(self.context, - self.service.uuid)) - self.dbapi.destroy_service(self.service.uuid) - self.assertRaises(exception.ServiceNotFound, - self.dbapi.get_service_by_uuid, - self.context, self.service.uuid) - - def test_destroy_service_that_does_not_exist(self): - self.assertRaises(exception.ServiceNotFound, - self.dbapi.destroy_service, - uuidutils.generate_uuid()) - - def test_update_service(self): - old_name = self.service.name - new_name = 'new-service' - self.assertNotEqual(old_name, new_name) - res = self.dbapi.update_service(self.service.id, {'name': new_name}) - self.assertEqual(new_name, res.name) - - def test_update_service_not_found(self): - service_uuid = uuidutils.generate_uuid() - self.assertRaises(exception.ServiceNotFound, self.dbapi.update_service, - service_uuid, {'port': 80}) - - def test_update_service_uuid(self): - self.assertRaises(exception.InvalidParameterValue, - self.dbapi.update_service, self.service.id, - {'uuid': ''}) diff --git a/magnum/tests/unit/db/utils.py b/magnum/tests/unit/db/utils.py index b31b082f08..6b40ef09da 100644 --- a/magnum/tests/unit/db/utils.py +++ b/magnum/tests/unit/db/utils.py @@ -111,38 +111,6 @@ def create_test_bay(**kw): return dbapi.create_bay(bay) -def get_test_service(**kw): - return { - 'id': kw.get('id', 42), - 'uuid': kw.get('uuid', '10a47dd1-4874-4298-91cf-eff046dbdb8d'), - 'name': kw.get('name', 'service1'), - 'project_id': kw.get('project_id', 'fake_project'), - 'user_id': kw.get('user_id', 'fake_user'), - 'bay_uuid': kw.get('bay_uuid', '5d12f6fd-a196-4bf0-ae4c-1f639a523a52'), - 'labels': kw.get('labels', {'name': 'foo'}), - 'selector': kw.get('selector', {'name': 'foo'}), - 'ip': kw.get('ip', '172.17.2.2'), - 'ports': kw.get('ports', [{'port': 80}]), - 'created_at': kw.get('created_at'), - 'updated_at': kw.get('updated_at'), - } - - -def create_test_service(**kw): - """Create test service entry in DB and return Service DB object. - - Function to be used to create test Service objects in the database. - :param kw: kwargs with overriding values for service's attributes. - :returns: Test Service DB object. - """ - service = get_test_service(**kw) - # Let DB generate ID if it isn't specified explicitly - if 'id' not in kw: - del service['id'] - dbapi = db_api.get_instance() - return dbapi.create_service(service) - - def get_test_container(**kw): return { 'id': kw.get('id', 42), diff --git a/magnum/tests/unit/objects/test_objects.py b/magnum/tests/unit/objects/test_objects.py index a628089665..f23dc052c7 100644 --- a/magnum/tests/unit/objects/test_objects.py +++ b/magnum/tests/unit/objects/test_objects.py @@ -363,7 +363,6 @@ object_data = { 'Container': '1.3-e2d9d2e8a8844d421148cd9fde6c6bd6', 'MyObj': '1.0-b43567e512438205e32f4e95ca616697', 'ReplicationController': '1.0-a471c2429c212ed91833cfcf0f934eab', - 'Service': '1.0-f4a1c5a4618708824a553568c1ada0ea', 'X509KeyPair': '1.2-d81950af36c59a71365e33ce539d24f9', 'MagnumService': '1.0-2d397ec59b0046bd5ec35cd3e06efeca', } diff --git a/magnum/tests/unit/objects/test_service.py b/magnum/tests/unit/objects/test_service.py deleted file mode 100644 index 436167003b..0000000000 --- a/magnum/tests/unit/objects/test_service.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock - -from magnum import objects -from magnum.tests.unit.db import base -from magnum.tests.unit.db import utils - - -class TestServiceObject(base.DbTestCase): - - def setUp(self): - super(TestServiceObject, self).setUp() - self.fake_service = utils.get_test_service() - - @mock.patch('magnum.conductor.k8s_api.create_k8s_api') - @mock.patch('ast.literal_eval') - def test_get_by_uuid(self, mock_ast, mock_kube_api): - uuid = self.fake_service['uuid'] - bay_uuid = self.fake_service['bay_uuid'] - mock_ast.return_value = {} - - k8s_api_mock = mock.MagicMock() - mock_kube_api.return_value = k8s_api_mock - - fake_obj = mock.MagicMock() - - items = [ - { - 'metadata': { - 'uid': '10a47dd1-4874-4298-91cf-eff046dbdb8d', - 'name': 'fake-name', - 'labels': {} - }, - 'spec': { - 'selector': {}, - 'cluster_ip': '10.98.100.19', - 'ports': [ - { - 'port': 80 - } - ] - } - } - ] - - 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' - fake_obj.items[0].spec = mock.MagicMock() - fake_obj.items[0].spec.selector = {} - fake_obj.items[0].spec.cluster_ip = '10.98.100.19' - - k8s_api_mock.list_namespaced_service.return_value = fake_obj - - objects.Service.get_by_uuid(self.context, - uuid, bay_uuid, - k8s_api_mock) - - (k8s_api_mock.list_namespaced_service.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_service['name'] - bay_uuid = self.fake_service['bay_uuid'] - mock_ast.return_value = {} - - k8s_api_mock = mock.MagicMock() - mock_kube_api.return_value = k8s_api_mock - fake_service = mock.MagicMock() - fake_service.metadata.uid = 'fake-uuid' - fake_service.metadata.name = 'fake-name' - fake_service.spec.ports.port = ["1234"] - fake_service.spec.selector = {} - fake_service.spec.cluster_ip = '192.10.10.10' - fake_service.metadata.labels = mock_ast.return_value - k8s_api_mock.read_namespaced_service.return_value = fake_service - objects.Service.get_by_name(self.context, - name, bay_uuid, - k8s_api_mock) - (k8s_api_mock.read_namespaced_service.assert_called_once_with( - name=name, - namespace='default')) diff --git a/magnum/tests/unit/objects/utils.py b/magnum/tests/unit/objects/utils.py index c9ebfa8a3b..c428eaaa9f 100644 --- a/magnum/tests/unit/objects/utils.py +++ b/magnum/tests/unit/objects/utils.py @@ -87,33 +87,6 @@ def create_test_bay(context, **kw): return bay -def get_test_service(context, **kw): - """Return a Service object with appropriate attributes. - - NOTE: The object leaves the attributes marked as changed, such - that a create() could be used to commit it to the DB. - """ - db_service = db_utils.get_test_service(**kw) - # Let DB generate ID if it isn't specified explicitly - if 'id' not in kw: - del db_service['id'] - service = objects.Service(context) - for key in db_service: - setattr(service, key, db_service[key]) - return service - - -def create_test_service(context, **kw): - """Create and return a test service object. - - Create a service in the DB and return a Service object with appropriate - attributes. - """ - service = get_test_service(context, **kw) - service.manifest = '{"foo": "bar"}' - return service - - def get_test_rc(context, **kw): """Return a ReplicationController object with appropriate attributes.