Merge "Remove ReplicationController object"

This commit is contained in:
Jenkins 2016-08-11 02:38:28 +00:00 committed by Gerrit Code Review
commit b4ef63965e
25 changed files with 60 additions and 1160 deletions

View File

@ -39,8 +39,6 @@ There are several different types of objects in the magnum system:
machine
* **Service:** An abstraction which defines a logical set of pods and a policy
by which to access them
* **ReplicationController:** An abstraction for managing a group of pods to
ensure a specified number of resources are running
* **Container:** A Docker container
Two binaries work together to compose the magnum system. The first binary

View File

@ -87,7 +87,6 @@ magnum/tests/unit/objects/test_objects.py::
'Container': '1.1-22b40e8eed0414561ca921906b189820',
'MyObj': '1.0-b43567e512438205e32f4e95ca616697',
'Pod': '1.0-69b579203c6d726be7878c606626e438',
'ReplicationController': '1.0-782b7deb9307b2807101541b7e58b8a2',
'Service': '1.0-d4b8c0f3a234aec35d273196e18f7ed1',
'X509KeyPair': '1.0-fd008eba0fbc390e0e5da247bba4eedd',
}

View File

@ -29,7 +29,6 @@ from magnum.conductor.handlers import bay_conductor
from magnum.conductor.handlers import ca_conductor
from magnum.conductor.handlers import conductor_listener
from magnum.conductor.handlers import indirection_api
from magnum.conductor.handlers import k8s_conductor
from magnum.i18n import _LI
from magnum import version
@ -50,7 +49,6 @@ def main():
conductor_id = short_id.generate_id()
endpoints = [
indirection_api.Handler(),
k8s_conductor.Handler(),
bay_conductor.Handler(),
conductor_listener.Handler(),
ca_conductor.Handler(),

View File

@ -273,24 +273,6 @@ class PodCreationFailed(Invalid):
message = _("Pod creation failed in Bay %(bay_uuid)s.")
class ReplicationControllerNotFound(ResourceNotFound):
message = _("ReplicationController %(rc)s could not be found.")
class ReplicationControllerAlreadyExists(Conflict):
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):
message = _("Service %(service)s could not be found.")

View File

@ -40,25 +40,6 @@ class API(rpc_service.API):
def bay_update(self, bay):
return self._call('bay_update', bay=bay)
# ReplicationController Operations
def rc_create(self, rc):
return self._call('rc_create', rc=rc)
def rc_update(self, rc_ident, bay_ident, manifest):
return self._call('rc_update', rc_ident=rc_ident,
bay_ident=bay_ident, manifest=manifest)
def rc_list(self, context, bay_ident):
return self._call('rc_list', bay_ident=bay_ident)
def rc_delete(self, rc_ident, bay_ident):
return self._call('rc_delete', rc_ident=rc_ident, bay_ident=bay_ident)
def rc_show(self, context, rc_ident, bay_ident):
return self._call('rc_show', rc_ident=rc_ident,
bay_ident=bay_ident)
# CA operations
def sign_certificate(self, bay, certificate):

View File

@ -1,167 +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.
from k8sclient.client import rest
from oslo_log import log as logging
from oslo_utils import uuidutils
from magnum.common import exception
from magnum.common import k8s_manifest
from magnum.conductor import k8s_api as k8s
from magnum.conductor import utils as conductor_utils
from magnum import objects
import ast
LOG = logging.getLogger(__name__)
class Handler(object):
"""Magnum Kubernetes RPC handler.
These are the backend operations. They are executed by the backend service.
API calls via AMQP (within the ReST API) trigger the handlers to be called.
"""
def __init__(self):
super(Handler, self).__init__()
# Replication Controller Operations
def rc_create(self, context, rc):
LOG.debug("rc_create")
bay = conductor_utils.retrieve_bay(context, rc.bay_uuid)
self.k8s_api = k8s.create_k8s_api(context, bay)
manifest = k8s_manifest.parse(rc.manifest)
try:
resp = self.k8s_api.create_namespaced_replication_controller(
body=manifest,
namespace='default')
except rest.ApiException as err:
raise exception.KubernetesAPIFailed(err=err)
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
def rc_update(self, context, rc_ident, bay_ident, manifest):
LOG.debug("rc_update %s", rc_ident)
bay = conductor_utils.retrieve_bay(context, bay_ident)
self.k8s_api = k8s.create_k8s_api(context, bay)
if uuidutils.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:
resp = self.k8s_api.replace_namespaced_replication_controller(
name=str(rc.name),
body=manifest,
namespace='default')
except rest.ApiException as err:
raise exception.KubernetesAPIFailed(err=err)
if resp is None:
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
def rc_delete(self, context, rc_ident, bay_ident):
LOG.debug("rc_delete %s", rc_ident)
bay = conductor_utils.retrieve_bay(context, bay_ident)
self.k8s_api = k8s.create_k8s_api(context, bay)
if uuidutils.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:
self.k8s_api.delete_namespaced_replication_controller(
name=str(rc_name),
body={},
namespace='default')
except rest.ApiException as err:
if err.status == 404:
pass
else:
raise exception.KubernetesAPIFailed(err=err)
def rc_show(self, context, rc_ident, bay_ident):
LOG.debug("rc_show %s", rc_ident)
bay = conductor_utils.retrieve_bay(context, bay_ident)
self.k8s_api = k8s.create_k8s_api(context, bay)
if uuidutils.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):
bay = conductor_utils.retrieve_bay(context, bay_ident)
self.k8s_api = k8s.create_k8s_api(context, bay)
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

View File

@ -204,86 +204,6 @@ class Connection(object):
:raises: BayModelNotFound
"""
@abc.abstractmethod
def get_rc_list(self, context, filters=None, limit=None,
marker=None, sort_key=None, sort_dir=None):
"""Get matching ReplicationControllers.
Return a list of the specified columns for all rcs that match the
specified filters.
:param context: The security context
:param filters: Filters to apply. Defaults to None.
:param limit: Maximum number of pods 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_rc(self, values):
"""Create a new ReplicationController.
:param values: A dict containing several items used to identify
and track the rc, and several dicts which are passed
into the Drivers when managing this pod. For example:
::
{
'uuid': uuidutils.generate_uuid(),
'name': 'example',
'images': '["myimage"]'
}
:returns: A ReplicationController.
"""
@abc.abstractmethod
def get_rc_by_id(self, context, rc_id):
"""Return a ReplicationController.
:param context: The security context
:param rc_id: The id of a rc.
:returns: A ReplicationController.
"""
@abc.abstractmethod
def get_rc_by_uuid(self, context, rc_uuid):
"""Return a ReplicationController.
:param context: The security context
:param rc_uuid: The uuid of a ReplicationController.
:returns: A ReplicationController.
"""
@abc.abstractmethod
def get_rc_by_name(self, context, rc_name):
"""Return a ReplicationController.
:param context: The security context
:param rc_name: The name of a ReplicationController.
:returns: A ReplicationController.
"""
@abc.abstractmethod
def destroy_rc(self, rc_id):
"""Destroy a ReplicationController and all associated interfaces.
:param rc_id: The id or uuid of a ReplicationController.
"""
@abc.abstractmethod
def update_rc(self, rc_id, values):
"""Update properties of a ReplicationController.
:param rc_id: The id or uuid of a ReplicationController.
:returns: A ReplicationController.
"""
@abc.abstractmethod
def create_x509keypair(self, values):
"""Create a new x509keypair.

View File

@ -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 replication controller
Revision ID: 859fb45df249
Revises: 1f196a3dabae
Create Date: 2016-08-09 13:46:24.052528
"""
# revision identifiers, used by Alembic.
revision = '859fb45df249'
down_revision = '1f196a3dabae'
from alembic import op
def upgrade():
op.drop_table('replicationcontroller')

View File

@ -191,24 +191,16 @@ class Connection(api.Connection):
raise exception.BayNotFound(bay=bay_uuid)
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.ReplicationController, session=session)
query = self._add_rcs_filters(query, {'bay_uuid': bay_uuid})
if query.count() != 0:
query.delete()
session = get_session()
with session.begin():
query = model_query(models.Bay, session=session)
query = add_identity_filter(query, bay_id)
try:
bay_ref = query.one()
query.one()
except NoResultFound:
raise exception.BayNotFound(bay=bay_id)
destroy_bay_resources(session, bay_ref['uuid'])
query.delete()
def update_bay(self, bay_id, values):
@ -365,100 +357,6 @@ class Connection(api.Connection):
ref.update(values)
return ref
def _add_rcs_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 'replicas' in filters:
query = query.filter_by(replicas=filters['replicas'])
return query
def get_rc_list(self, context, filters=None, limit=None, marker=None,
sort_key=None, sort_dir=None):
query = model_query(models.ReplicationController)
query = self._add_tenant_filters(context, query)
query = self._add_rcs_filters(query, filters)
return _paginate_query(models.ReplicationController, limit, marker,
sort_key, sort_dir, query)
def create_rc(self, values):
# ensure defaults are present for new ReplicationController
if not values.get('uuid'):
values['uuid'] = uuidutils.generate_uuid()
rc = models.ReplicationController()
rc.update(values)
try:
rc.save()
except db_exc.DBDuplicateEntry:
raise exception.ReplicationControllerAlreadyExists(
uuid=values['uuid'])
return rc
def get_rc_by_id(self, context, rc_id):
query = model_query(models.ReplicationController)
query = self._add_tenant_filters(context, query)
query = query.filter_by(id=rc_id)
try:
return query.one()
except NoResultFound:
raise exception.ReplicationControllerNotFound(rc=rc_id)
def get_rc_by_uuid(self, context, rc_uuid):
query = model_query(models.ReplicationController)
query = self._add_tenant_filters(context, query)
query = query.filter_by(uuid=rc_uuid)
try:
return query.one()
except NoResultFound:
raise exception.ReplicationControllerNotFound(rc=rc_uuid)
def get_rc_by_name(self, context, rc_name):
query = model_query(models.ReplicationController)
query = self._add_tenant_filters(context, query)
query = query.filter_by(name=rc_name)
try:
return query.one()
except MultipleResultsFound:
raise exception.Conflict('Multiple rcs exist with same name.'
' Please use the rc uuid instead.')
except NoResultFound:
raise exception.ReplicationControllerNotFound(rc=rc_name)
def destroy_rc(self, rc_id):
session = get_session()
with session.begin():
query = model_query(models.ReplicationController, session=session)
query = add_identity_filter(query, rc_id)
count = query.delete()
if count != 1:
raise exception.ReplicationControllerNotFound(rc_id)
def update_rc(self, rc_id, values):
if 'uuid' in values:
msg = _("Cannot overwrite UUID for an existing rc.")
raise exception.InvalidParameterValue(err=msg)
return self._do_update_rc(rc_id, values)
def _do_update_rc(self, rc_id, values):
session = get_session()
with session.begin():
query = model_query(models.ReplicationController, session=session)
query = add_identity_filter(query, rc_id)
try:
ref = query.with_lockmode('update').one()
except NoResultFound:
raise exception.ReplicationControllerNotFound(rc=rc_id)
ref.update(values)
return ref
def create_x509keypair(self, values):
# ensure defaults are present for new x509keypairs
if not values.get('uuid'):

View File

@ -179,26 +179,6 @@ class BayModel(Base):
master_lb_enabled = Column(Boolean, default=False)
class ReplicationController(Base):
"""Represents a pod replication controller."""
__tablename__ = 'replicationcontroller'
__table_args__ = (
schema.UniqueConstraint('uuid',
name='uniq_replicationcontroller0uuid'),
table_args()
)
id = Column(Integer, primary_key=True)
uuid = Column(String(36))
name = Column(String(255))
bay_uuid = Column(String(36))
images = Column(JSONEncodedList)
labels = Column(JSONEncodedDict)
replicas = Column(Integer())
project_id = Column(String(255))
user_id = Column(String(255))
class X509KeyPair(Base):
"""X509KeyPair"""
__tablename__ = 'x509keypair'

View File

@ -40,10 +40,6 @@ msgstr "'add' と 'replace' 処理には、値が必要です。"
msgid "'manifest' can't be empty"
msgstr "「マニフェスト」は空にできません"
#, python-format
msgid "A ReplicationController with UUID %(uuid)s already exists."
msgstr "UUID %(uuid)s の複製コントローラーは既に存在します。"
#, python-format
msgid "A baymodel with UUID %(uuid)s already exists."
msgstr "UUID %(uuid)s のベイモデルは既に存在します。"
@ -341,10 +337,6 @@ msgstr ""
"OpenStack サービスとの通信に使用する Identity サービスカタログ内のリージョ"
"ン。"
#, python-format
msgid "ReplicationController %(rc)s could not be found."
msgstr "複製コントローラー %(rc)s が見つかりませんでした。"
msgid "Request not acceptable."
msgstr "要求は受け入れられませんでした。"

View File

@ -16,19 +16,16 @@ from magnum.objects import bay
from magnum.objects import baymodel
from magnum.objects import certificate
from magnum.objects import magnum_service
from magnum.objects import replicationcontroller as rc
from magnum.objects import x509keypair
Bay = bay.Bay
BayModel = baymodel.BayModel
MagnumService = magnum_service.MagnumService
ReplicationController = rc.ReplicationController
X509KeyPair = x509keypair.X509KeyPair
Certificate = certificate.Certificate
__all__ = (Bay,
BayModel,
MagnumService,
ReplicationController,
X509KeyPair,
Certificate)

View File

@ -1,118 +0,0 @@
# Copyright 2015 IBM Corp.
#
# 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
@base.MagnumObjectRegistry.register
class ReplicationController(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),
'images': fields.ListOfStringsField(nullable=True),
'bay_uuid': fields.StringField(nullable=True),
'labels': fields.DictOfStringsField(nullable=True),
'replicas': fields.IntegerField(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):
"""Return a :class:`ReplicationController` object based on uuid.
:param context: Security context
:param uuid: the uuid of a ReplicationController.
:param bay_uuid: the UUID of the Bay.
:returns: a :class:`ReplicationController` object.
"""
try:
resp = 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)
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
def get_by_name(cls, context, name, bay_uuid, k8s_api):
"""Return a :class:`ReplicationController` object based on name.
:param context: Security context
:param name: the name of a ReplicationController.
:param bay_uuid: the UUID of the Bay.
:returns: a :class:`ReplicationController` object.
"""
try:
resp = k8s_api.read_namespaced_replication_controller(
name=name,
namespace='default')
except rest.ApiException as err:
raise exception.KubernetesAPIFailed(err=err)
if resp is None:
raise exception.ReplicationControllerNotFound(rc=name)
rc = {}
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
# Convert string to dictionary
rc['labels'] = ast.literal_eval(resp.metadata.labels)
rc['replicas'] = resp.status.replicas
rc_obj = ReplicationController(context, **rc)
return rc_obj

View File

@ -25,7 +25,6 @@ import magnum.common.service
import magnum.common.x509.config
import magnum.conductor.config
import magnum.conductor.handlers.bay_conductor
import magnum.conductor.handlers.k8s_conductor
import magnum.db
import magnum.drivers.common.template_def

View File

@ -780,12 +780,6 @@ class TestDelete(api_base.FunctionalTest):
self.assertEqual('application/json', response.content_type)
self.assertTrue(response.json['errors'])
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,
expect_errors=True)
self.assertEqual(204, response.status_int)
def test_delete_bay_with_name_not_found(self):
response = self.delete('/bays/not_found', expect_errors=True)
self.assertEqual(404, response.status_int)

View File

@ -1,231 +0,0 @@
# Copyright 2014 NEC Corporation. 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.
from k8sclient.client import rest
import mock
from mock import patch
from magnum.common import exception
from magnum.conductor.handlers import k8s_conductor
from magnum import objects
from magnum.tests import base
class TestK8sConductor(base.TestCase):
def setUp(self):
super(TestK8sConductor, self).setUp()
self.kube_handler = k8s_conductor.Handler()
def mock_rc(self):
return objects.ReplicationController({})
def mock_bay(self):
return objects.Bay({})
def mock_baymodel(self):
return objects.BayModel({})
@patch('magnum.conductor.utils.retrieve_bay')
@patch('ast.literal_eval')
def test_rc_create_with_success(self, mock_ast, mock_retrieve):
expected_rc = mock.MagicMock()
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"}'
mock_ast.return_value = {}
with patch('magnum.conductor.k8s_api.create_k8s_api') as \
mock_kube_api:
self.kube_handler.rc_create({}, expected_rc)
(mock_kube_api.return_value
.create_namespaced_replication_controller
.assert_called_once_with(body=manifest, namespace='default'))
@patch('magnum.conductor.utils.retrieve_bay')
def test_rc_create_with_failure(self, mock_retrieve):
expected_rc = mock.MagicMock()
manifest = {"key": "value"}
expected_rc.manifest = '{"key": "value"}'
with patch('magnum.conductor.k8s_api.create_k8s_api') as \
mock_kube_api:
err = rest.ApiException(status=500)
(mock_kube_api.return_value
.create_namespaced_replication_controller.side_effect) = err
self.assertRaises(exception.KubernetesAPIFailed,
self.kube_handler.rc_create,
self.context, expected_rc)
(mock_kube_api.return_value
.create_namespaced_replication_controller
.assert_called_once_with(body=manifest, namespace='default'))
@patch('magnum.conductor.utils.object_has_stack')
@patch('magnum.objects.ReplicationController.get_by_name')
@patch('magnum.objects.Bay.get_by_name')
def test_rc_delete_with_success(self, mock_bay_get_by_name,
mock_rc_get_by_name,
mock_object_has_stack):
mock_bay = mock.MagicMock()
mock_bay_get_by_name.return_value = mock_bay
mock_rc = mock.MagicMock()
mock_rc.name = 'test-rc'
mock_rc.uuid = 'test-uuid'
mock_rc_get_by_name.return_value = mock_rc
bay_uuid = 'test-bay-uuid'
mock_object_has_stack.return_value = True
with patch('magnum.conductor.k8s_api.create_k8s_api') as \
mock_kube_api:
self.kube_handler.rc_delete(self.context, mock_rc.name, bay_uuid)
(mock_kube_api.return_value
.delete_namespaced_replication_controller
.assert_called_once_with(name=mock_rc.name, body={},
namespace='default'))
@patch('magnum.conductor.utils.object_has_stack')
@patch('magnum.objects.ReplicationController.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_bay = mock.MagicMock()
mock_bay_get_by_name.return_value = mock_bay
mock_rc = mock.MagicMock()
mock_rc.name = 'test-rc'
mock_rc.uuid = 'test-uuid'
mock_rc.bay_uuid = 'test-bay-uuid'
mock_rc_get_by_uuid.return_value = mock_rc
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_replication_controller.side_effect) = err
self.assertRaises(exception.KubernetesAPIFailed,
self.kube_handler.rc_delete,
self.context, mock_rc.name,
mock_rc.bay_uuid)
(mock_kube_api.return_value
.delete_namespaced_replication_controller
.assert_called_once_with(name=mock_rc.name, body={},
namespace='default'))
self.assertFalse(mock_rc.destroy.called)
@patch('magnum.conductor.utils.object_has_stack')
@patch('magnum.objects.ReplicationController.get_by_uuid')
@patch('magnum.objects.Bay.get_by_name')
def test_rc_delete_succeeds_when_not_found(
self, mock_bay_get_by_name,
mock_rc_get_by_uuid,
mock_object_has_stack):
mock_bay = mock.MagicMock()
mock_bay_get_by_name.return_value = mock_bay
mock_rc = mock.MagicMock()
mock_rc.name = 'test-rc'
mock_rc.uuid = 'test-uuid'
mock_rc.bay_uuid = 'test-bay-uuid'
mock_rc_get_by_uuid.return_value = mock_rc
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_replication_controller.side_effect) = err
self.kube_handler.rc_delete(self.context,
mock_rc.name,
mock_rc.bay_uuid)
(mock_kube_api.return_value
.delete_namespaced_replication_controller
.assert_called_once_with(name=mock_rc.name, body={},
namespace='default'))
@patch('magnum.objects.ReplicationController.get_by_name')
@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.name = 'test-name'
expected_rc.bay_uuid = 'test-bay-uuid'
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:
self.kube_handler.rc_update(self.context, expected_rc.name,
expected_rc.bay_uuid,
expected_rc.manifest)
(mock_kube_api.return_value
.replace_namespaced_replication_controller
.assert_called_once_with(body=expected_rc.manifest,
name=name_rc,
namespace='default'))
@patch('magnum.objects.ReplicationController.get_by_name')
@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.name = 'test-name'
expected_rc.bay_uuid = 'test-bay-uuid'
mock_rc_get_by_uuid.return_value = expected_rc
mock_rc_get_by_name.return_value = expected_rc
expected_rc.manifest = '{"key": "value"}'
name_rc = expected_rc.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_replication_controller
.side_effect) = err
self.assertRaises(exception.KubernetesAPIFailed,
self.kube_handler.rc_update,
self.context, expected_rc.name,
expected_rc.bay_uuid,
expected_rc.manifest)
(mock_kube_api.return_value
.replace_namespaced_replication_controller
.assert_called_once_with(body=expected_rc.manifest,
name=name_rc,
namespace='default'))

View File

@ -28,7 +28,6 @@ class RPCAPITestCase(base.DbTestCase):
def setUp(self):
super(RPCAPITestCase, self).setUp()
self.fake_bay = dbutils.get_test_bay(driver='fake-driver')
self.fake_rc = dbutils.get_test_rc(driver='fake-driver')
self.fake_certificate = objects.Certificate.from_db_bay(self.fake_bay)
self.fake_certificate.csr = 'fake-csr'
@ -97,33 +96,6 @@ class RPCAPITestCase(base.DbTestCase):
version='1.1',
bay=self.fake_bay['name'])
def test_rc_create(self):
self._test_rpcapi('rc_create',
'call',
version='1.0',
rc=self.fake_rc)
def test_rc_update(self):
self._test_rpcapi('rc_update',
'call',
version='1.0',
rc_ident=self.fake_rc['uuid'],
bay_ident=self.fake_rc['bay_uuid'],
manifest={})
def test_rc_delete(self):
self._test_rpcapi('rc_delete',
'call',
version='1.0',
rc_ident=self.fake_rc['uuid'],
bay_ident=self.fake_rc['bay_uuid'])
self._test_rpcapi('rc_delete',
'call',
version='1.1',
rc_ident=self.fake_rc['uuid'],
bay_ident=self.fake_rc['bay_uuid'])
def test_ping_conductor(self):
self._test_rpcapi('ping_conductor',
'call',

View File

@ -27,14 +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_rc(self,
mock_bay_get_by_uuid):
rc = objects.ReplicationController({})
rc.bay_uuid = '5d12f6fd-a196-4bf0-ae4c-1f639a523a52'
self._test_retrieve_bay(rc.bay_uuid,
mock_bay_get_by_uuid)
@patch('magnum.objects.BayModel.get_by_uuid')
def test_retrieve_baymodel(self, mock_baymodel_get_by_uuid):
expected_context = 'context'

View File

@ -23,44 +23,47 @@ from magnum.tests.unit.db import base
class SqlAlchemyCustomTypesTestCase(base.DbTestCase):
def test_JSONEncodedDict_default_value(self):
# Create rc w/o labels
rc1_id = uuidutils.generate_uuid()
self.dbapi.create_rc({'uuid': rc1_id})
rc1 = sa_api.model_query(
models.ReplicationController).filter_by(uuid=rc1_id).one()
self.assertEqual({}, rc1.labels)
# Create baymodel w/o labels
baymodel1_id = uuidutils.generate_uuid()
self.dbapi.create_baymodel({'uuid': baymodel1_id})
baymodel1 = sa_api.model_query(
models.BayModel).filter_by(uuid=baymodel1_id).one()
self.assertEqual({}, baymodel1.labels)
# Create rc with labels
rc2_id = uuidutils.generate_uuid()
self.dbapi.create_rc({'uuid': rc2_id, 'labels': {'bar': 'foo'}})
rc2 = sa_api.model_query(
models.ReplicationController).filter_by(uuid=rc2_id).one()
self.assertEqual('foo', rc2.labels['bar'])
# Create baymodel with labels
baymodel2_id = uuidutils.generate_uuid()
self.dbapi.create_baymodel(
{'uuid': baymodel2_id, 'labels': {'bar': 'foo'}})
baymodel2 = sa_api.model_query(
models.BayModel).filter_by(uuid=baymodel2_id).one()
self.assertEqual('foo', baymodel2.labels['bar'])
def test_JSONEncodedDict_type_check(self):
self.assertRaises(db_exc.DBError,
self.dbapi.create_rc,
self.dbapi.create_baymodel,
{'labels':
['this is not a dict']})
def test_JSONEncodedList_default_value(self):
# Create rc w/o images
rc1_id = uuidutils.generate_uuid()
self.dbapi.create_rc({'uuid': rc1_id})
rc1 = sa_api.model_query(
models.ReplicationController).filter_by(uuid=rc1_id).one()
self.assertEqual([], rc1.images)
# Create bay w/o master_addresses
bay1_id = uuidutils.generate_uuid()
self.dbapi.create_bay({'uuid': bay1_id})
bay1 = sa_api.model_query(
models.Bay).filter_by(uuid=bay1_id).one()
self.assertEqual([], bay1.master_addresses)
# Create rc with images
rc2_id = uuidutils.generate_uuid()
self.dbapi.create_rc({'uuid': rc2_id,
'images': ['myimage1', 'myimage2']})
rc2 = sa_api.model_query(
models.ReplicationController).filter_by(uuid=rc2_id).one()
self.assertEqual(['myimage1', 'myimage2'], rc2.images)
# Create bay with master_addresses
bay2_id = uuidutils.generate_uuid()
self.dbapi.create_bay({'uuid': bay2_id,
'master_addresses': ['mymaster_address1',
'mymaster_address2']})
bay2 = sa_api.model_query(
models.Bay).filter_by(uuid=bay2_id).one()
self.assertEqual(['mymaster_address1', 'mymaster_address2'],
bay2.master_addresses)
def test_JSONEncodedList_type_check(self):
self.assertRaises(db_exc.DBError,
self.dbapi.create_rc,
{'images':
self.dbapi.create_bay,
{'master_addresses':
{'this is not a list': 'test'}})

View File

@ -192,24 +192,6 @@ class DbBayTestCase(base.DbTestCase):
self.dbapi.destroy_bay,
'12345678-9999-0000-aaaa-123456789012')
def test_destroy_bay_that_has_rc(self):
bay = utils.create_test_bay()
rc = utils.create_test_rc(bay_uuid=bay.uuid)
self.assertEqual(bay.uuid, rc.bay_uuid)
self.dbapi.destroy_bay(bay.id)
self.assertRaises(exception.ReplicationControllerNotFound,
self.dbapi.get_rc_by_id,
self.context, rc.id)
def test_destroy_bay_that_has_rc_by_uuid(self):
bay = utils.create_test_bay()
rc = utils.create_test_rc(bay_uuid=bay.uuid)
self.assertEqual(bay.uuid, rc.bay_uuid)
self.dbapi.destroy_bay(bay.uuid)
self.assertRaises(exception.ReplicationControllerNotFound,
self.dbapi.get_rc_by_id,
self.context, rc.id)
def test_update_bay(self):
bay = utils.create_test_bay()
old_nc = bay.node_count

View File

@ -1,142 +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 DbRCTestCase(base.DbTestCase):
def setUp(self):
# This method creates a replication controller for every test and
# replaces a test for creating a replication controller.
super(DbRCTestCase, self).setUp()
self.bay = utils.create_test_bay()
self.rc = utils.create_test_rc(bay_uuid=self.bay.uuid)
def test_create_rc_duplicated_uuid(self):
self.assertRaises(exception.ReplicationControllerAlreadyExists,
utils.create_test_rc,
uuid=self.rc.uuid,
bay_uuid=self.bay.uuid)
def test_get_rc_by_id(self):
rc = self.dbapi.get_rc_by_id(self.context, self.rc.id)
self.assertEqual(self.rc.id, rc.id)
self.assertEqual(self.rc.uuid, rc.uuid)
def test_get_rc_by_uuid(self):
rc = self.dbapi.get_rc_by_uuid(self.context, self.rc.uuid)
self.assertEqual(self.rc.id, rc.id)
self.assertEqual(self.rc.uuid, rc.uuid)
def test_get_rc_by_name(self):
res = self.dbapi.get_rc_by_name(self.context, self.rc.name)
self.assertEqual(self.rc.name, res.name)
self.assertEqual(self.rc.uuid, res.uuid)
def test_get_rc_by_name_multiple_rcs(self):
utils.create_test_rc(bay_uuid=self.bay.uuid,
uuid=uuidutils.generate_uuid())
self.assertRaises(exception.Conflict, self.dbapi.get_rc_by_name,
self.context, self.rc.name)
def test_get_rc_by_name_not_found(self):
self.assertRaises(exception.ReplicationControllerNotFound,
self.dbapi.get_rc_by_name, self.context,
'not_found')
def test_get_rc_that_does_not_exist(self):
self.assertRaises(exception.ReplicationControllerNotFound,
self.dbapi.get_rc_by_id, self.context, 999)
self.assertRaises(exception.ReplicationControllerNotFound,
self.dbapi.get_rc_by_uuid,
self.context,
uuidutils.generate_uuid())
def test_get_rc_list(self):
uuids = [self.rc.uuid]
for i in range(1, 6):
rc = utils.create_test_rc(
bay_uuid=self.bay.uuid,
uuid=uuidutils.generate_uuid())
uuids.append(six.text_type(rc.uuid))
rc = self.dbapi.get_rc_list(self.context)
rc_uuids = [r.uuid for r in rc]
self.assertEqual(sorted(uuids), sorted(rc_uuids))
def test_get_rc_list_sorted(self):
uuids = [self.rc.uuid]
for _ in range(5):
rc = utils.create_test_rc(uuid=uuidutils.generate_uuid())
uuids.append(six.text_type(rc.uuid))
res = self.dbapi.get_rc_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_rc_list,
self.context,
sort_key='foo')
def test_get_rc_list_bay_not_exist(self):
rc = self.dbapi.get_rc_list(self.context, filters={
'bay_uuid': self.bay.uuid})
self.assertEqual(1, len(rc))
rc = self.dbapi.get_rc_list(self.context, filters={
'bay_uuid': uuidutils.generate_uuid()})
self.assertEqual(0, len(rc))
def test_destroy_rc(self):
self.dbapi.destroy_rc(self.rc.id)
self.assertRaises(exception.ReplicationControllerNotFound,
self.dbapi.get_rc_by_id, self.context, self.rc.id)
def test_destroy_rc_by_uuid(self):
self.assertIsNotNone(self.dbapi.get_rc_by_uuid(self.context,
self.rc.uuid))
self.dbapi.destroy_rc(self.rc.uuid)
self.assertRaises(exception.ReplicationControllerNotFound,
self.dbapi.get_rc_by_uuid,
self.context, self.rc.uuid)
def test_destroy_rc_that_does_not_exist(self):
self.assertRaises(exception.ReplicationControllerNotFound,
self.dbapi.destroy_rc,
uuidutils.generate_uuid())
def test_update_rc(self):
old_name = self.rc.name
new_name = 'new-rc'
self.assertNotEqual(old_name, new_name)
res = self.dbapi.update_rc(self.rc.id, {'name': new_name})
self.assertEqual(new_name, res.name)
def test_update_rc_not_found(self):
rc_uuid = uuidutils.generate_uuid()
self.assertRaises(exception.ReplicationControllerNotFound,
self.dbapi.update_rc,
rc_uuid, {'replica': 4})
def test_update_rc_uuid(self):
self.assertRaises(exception.InvalidParameterValue,
self.dbapi.update_rc, self.rc.id,
{'uuid': ''})

View File

@ -121,40 +121,6 @@ def create_test_bay(**kw):
return dbapi.create_bay(bay)
def get_test_rc(**kw):
return {
'id': kw.get('id', 42),
'uuid': kw.get('uuid', '10a47dd1-4874-4298-91cf-eff046dbdb8d'),
'name': kw.get('name', 'replication_controller'),
'project_id': kw.get('project_id', 'fake_project'),
'user_id': kw.get('user_id', 'fake_user'),
'images': kw.get('images', ['steak/for-dinner']),
'bay_uuid': kw.get('bay_uuid', '5d12f6fd-a196-4bf0-ae4c-1f639a523a52'),
'labels': kw.get('labels', {'name': 'foo'}),
'replicas': kw.get('replicas', 3),
'manifest_url': kw.get('file:///tmp/rc.yaml'),
'created_at': kw.get('created_at'),
'updated_at': kw.get('updated_at'),
}
def create_test_rc(**kw):
"""Create test rc entry in DB and return ReplicationController DB object.
Function to be used to create test ReplicationController objects in the
database.
:param kw: kwargs with overriding values for
replication controller's attributes.
:returns: Test ReplicationController DB object.
"""
replication_controller = get_test_rc(**kw)
# Let DB generate ID if it isn't specified explicitly
if 'id' not in kw:
del replication_controller['id']
dbapi = db_api.get_instance()
return dbapi.create_rc(replication_controller)
def get_test_x509keypair(**kw):
return {
'id': kw.get('id', 42),

View File

@ -367,7 +367,6 @@ object_data = {
'Certificate': '1.0-2aff667971b85c1edf8d15684fd7d5e2',
'MyObj': '1.0-b43567e512438205e32f4e95ca616697',
'MyObj': '1.0-34c4b1aadefd177b13f9a2f894cc23cd',
'ReplicationController': '1.0-a471c2429c212ed91833cfcf0f934eab',
'X509KeyPair': '1.2-d81950af36c59a71365e33ce539d24f9',
'MagnumService': '1.0-2d397ec59b0046bd5ec35cd3e06efeca',
}

View File

@ -1,95 +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 TestReplicationControllerObject(base.DbTestCase):
def setUp(self):
super(TestReplicationControllerObject, self).setUp()
self.fake_rc = utils.get_test_rc()
@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_rc['uuid']
bay_uuid = self.fake_rc['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': {}
},
'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']
bay_uuid = self.fake_rc['bay_uuid']
mock_ast.return_value = {}
k8s_api_mock = mock.MagicMock()
mock_kube_api.return_value = k8s_api_mock
fake_rc = mock.MagicMock()
fake_rc.metadata.uid = 'fake-uuid'
fake_rc.metadata.name = 'fake-name'
fake_rc.items[0].spec.template.spec.containers.image = ['fake-images']
fake_rc.metadata.labels = mock_ast.return_value
fake_rc.status.replicas = 10
k8s_api_mock.read_namespaced_replication_controller\
.return_value = fake_rc
objects.ReplicationController.get_by_name(self.context,
name,
bay_uuid,
k8s_api_mock)
(k8s_api_mock.read_namespaced_replication_controller
.assert_called_once_with(name=name, namespace='default'))

View File

@ -87,33 +87,6 @@ def create_test_bay(context, **kw):
return bay
def get_test_rc(context, **kw):
"""Return a ReplicationController 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_rc = db_utils.get_test_rc(**kw)
# Let DB generate ID if it isn't specified explicitly
if 'id' not in kw:
del db_rc['id']
rc = objects.ReplicationController(context)
for key in db_rc:
setattr(rc, key, db_rc[key])
return rc
def create_test_rc(context, **kw):
"""Create and return a test ReplicationController object.
Create a replication controller in the DB and return a
ReplicationController object with appropriate attributes.
"""
rc = get_test_rc(context, **kw)
rc.manifest = '{"foo": "bar"}'
return rc
def get_test_x509keypair(context, **kw):
"""Return a X509KeyPair object with appropriate attributes.