diff --git a/etc/magnum/policy.json b/etc/magnum/policy.json index 74b3f84b4e..7e49e1d1f0 100644 --- a/etc/magnum/policy.json +++ b/etc/magnum/policy.json @@ -27,13 +27,6 @@ "rc:get_all": "rule:default", "rc:update": "rule:default", - "container:create": "rule:admin_or_user", - "container:delete": "rule:admin_or_user", - "container:detail": "rule:default", - "container:get": "rule:default", - "container:get_all": "rule:default", - "container:update": "rule:admin_or_user", - "certificate:create": "rule:admin_or_user", "certificate:get": "rule:admin_or_user", diff --git a/magnum/cmd/conductor.py b/magnum/cmd/conductor.py index 9617f3a44e..c9dd3bdc6a 100644 --- a/magnum/cmd/conductor.py +++ b/magnum/cmd/conductor.py @@ -28,7 +28,6 @@ from magnum.common import short_id 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 docker_conductor from magnum.conductor.handlers import indirection_api from magnum.conductor.handlers import k8s_conductor from magnum.i18n import _LI @@ -51,7 +50,6 @@ def main(): conductor_id = short_id.generate_id() endpoints = [ indirection_api.Handler(), - docker_conductor.Handler(), k8s_conductor.Handler(), bay_conductor.Handler(), conductor_listener.Handler(), diff --git a/magnum/common/docker_utils.py b/magnum/common/docker_utils.py index 325b87b055..703dcc5ed1 100644 --- a/magnum/common/docker_utils.py +++ b/magnum/common/docker_utils.py @@ -18,11 +18,9 @@ from docker import client from docker import tls from docker.utils import utils from oslo_config import cfg -from oslo_utils import uuidutils from magnum.conductor.handlers.common import cert_manager from magnum.conductor import utils as conductor_utils -from magnum import objects docker_opts = [ @@ -76,15 +74,6 @@ def is_docker_api_version_atleast(docker, version): return False -@contextlib.contextmanager -def docker_for_container(context, container): - if uuidutils.is_uuid_like(container): - container = objects.Container.get_by_uuid(context, container) - bay = conductor_utils.retrieve_bay(context, container.bay_uuid) - with docker_for_bay(context, bay) as docker: - yield docker - - @contextlib.contextmanager def docker_for_bay(context, bay): baymodel = conductor_utils.retrieve_baymodel(context, bay) diff --git a/magnum/conductor/api.py b/magnum/conductor/api.py index 4402b2f488..6461250035 100644 --- a/magnum/conductor/api.py +++ b/magnum/conductor/api.py @@ -59,39 +59,6 @@ class API(rpc_service.API): return self._call('rc_show', rc_ident=rc_ident, bay_ident=bay_ident) - # Container operations - - def container_create(self, container): - return self._call('container_create', container=container) - - def container_delete(self, container_uuid): - return self._call('container_delete', container_uuid=container_uuid) - - def container_show(self, container_uuid): - return self._call('container_show', container_uuid=container_uuid) - - def container_reboot(self, container_uuid): - return self._call('container_reboot', container_uuid=container_uuid) - - def container_stop(self, container_uuid): - return self._call('container_stop', container_uuid=container_uuid) - - def container_start(self, container_uuid): - return self._call('container_start', container_uuid=container_uuid) - - def container_pause(self, container_uuid): - return self._call('container_pause', container_uuid=container_uuid) - - def container_unpause(self, container_uuid): - return self._call('container_unpause', container_uuid=container_uuid) - - def container_logs(self, container_uuid): - return self._call('container_logs', container_uuid=container_uuid) - - def container_exec(self, container_uuid, command): - return self._call('container_exec', container_uuid=container_uuid, - command=command) - # CA operations def sign_certificate(self, bay, certificate): diff --git a/magnum/conductor/handlers/docker_conductor.py b/magnum/conductor/handlers/docker_conductor.py deleted file mode 100644 index d909fc2a4f..0000000000 --- a/magnum/conductor/handlers/docker_conductor.py +++ /dev/null @@ -1,212 +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. - -"""Magnum Docker RPC handler.""" - -import functools - -from docker import errors -from oslo_log import log as logging -import six - -from magnum.common import docker_utils -from magnum.common import exception -from magnum.common import utils as magnum_utils -from magnum.i18n import _LE -from magnum import objects -from magnum.objects import fields - -LOG = logging.getLogger(__name__) - - -def wrap_container_exception(f): - def wrapped(self, context, *args, **kwargs): - try: - return f(self, context, *args, **kwargs) - except Exception as e: - container_uuid = None - if 'container_uuid' in kwargs: - container_uuid = kwargs.get('container_uuid') - elif 'container' in kwargs: - container_uuid = kwargs.get('container').uuid - - LOG.exception(_LE("Error while connect to docker " - "container %s"), container_uuid) - raise exception.ContainerException( - "Docker internal Error: %s" % str(e)) - return functools.wraps(f)(wrapped) - - -class Handler(object): - - def __init__(self): - super(Handler, self).__init__() - - @staticmethod - def _find_container_by_name(docker, name): - try: - for info in docker.list_instances(inspect=True): - if info['Config'].get('Hostname') == name: - return info - except errors.APIError as e: - if e.response.status_code != 404: - raise - return {} - - def _encode_utf8(self, value): - if six.PY2 and not isinstance(value, unicode): - value = unicode(value) - return value.encode('utf-8') - - # Container operations - - @wrap_container_exception - def container_create(self, context, container): - with docker_utils.docker_for_container(context, container) as docker: - name = container.name - container_uuid = container.uuid - image = container.image - LOG.debug('Creating container with image %s name %s', image, name) - try: - image_repo, image_tag = docker_utils.parse_docker_image(image) - docker.pull(image_repo, tag=image_tag) - docker.inspect_image(self._encode_utf8(container.image)) - kwargs = {'name': name, - 'hostname': container_uuid, - 'command': container.command, - 'environment': container.environment} - if docker_utils.is_docker_api_version_atleast(docker, '1.19'): - if container.memory is not None: - kwargs['host_config'] = { - 'Memory': - magnum_utils.get_docker_quantity(container.memory)} - else: - kwargs['mem_limit'] = container.memory - - docker.create_container(image, **kwargs) - container.status = fields.ContainerStatus.STOPPED - return container - except errors.APIError: - container.status = fields.ContainerStatus.ERROR - raise - finally: - container.save() - - @wrap_container_exception - def container_delete(self, context, container_uuid): - LOG.debug("container_delete %s", container_uuid) - with docker_utils.docker_for_container(context, - container_uuid) as docker: - docker_id = self._find_container_by_name(docker, - container_uuid) - if not docker_id: - return None - return docker.remove_container(docker_id) - - @wrap_container_exception - def container_show(self, context, container_uuid): - LOG.debug("container_show %s", container_uuid) - with docker_utils.docker_for_container(context, - container_uuid) as docker: - container = objects.Container.get_by_uuid(context, container_uuid) - try: - docker_id = self._find_container_by_name(docker, - container_uuid) - if not docker_id: - LOG.exception(_LE("Can not find docker instance with %s," - "set it to Error status"), - container_uuid) - container.status = fields.ContainerStatus.ERROR - container.save() - return container - result = docker.inspect_container(docker_id) - status = result.get('State') - if status: - if status.get('Error') is True: - container.status = fields.ContainerStatus.ERROR - elif status.get('Paused'): - container.status = fields.ContainerStatus.PAUSED - elif status.get('Running'): - container.status = fields.ContainerStatus.RUNNING - else: - container.status = fields.ContainerStatus.STOPPED - container.save() - return container - except errors.APIError as api_error: - error_message = str(api_error) - if '404' in error_message: - container.status = fields.ContainerStatus.ERROR - container.save() - return container - raise - - @wrap_container_exception - def _container_action(self, context, container_uuid, status, docker_func): - LOG.debug("%s container %s ...", docker_func, container_uuid) - with docker_utils.docker_for_container(context, - container_uuid) as docker: - docker_id = self._find_container_by_name(docker, - container_uuid) - result = getattr(docker, docker_func)(docker_id) - container = objects.Container.get_by_uuid(context, - container_uuid) - container.status = status - container.save() - return result - - def container_reboot(self, context, container_uuid): - return self._container_action(context, container_uuid, - fields.ContainerStatus.RUNNING, - 'restart') - - def container_stop(self, context, container_uuid): - return self._container_action(context, container_uuid, - fields.ContainerStatus.STOPPED, 'stop') - - def container_start(self, context, container_uuid): - return self._container_action(context, container_uuid, - fields.ContainerStatus.RUNNING, 'start') - - def container_pause(self, context, container_uuid): - return self._container_action(context, container_uuid, - fields.ContainerStatus.PAUSED, 'pause') - - def container_unpause(self, context, container_uuid): - return self._container_action(context, container_uuid, - fields.ContainerStatus.RUNNING, - 'unpause') - - @wrap_container_exception - def container_logs(self, context, container_uuid): - LOG.debug("container_logs %s", container_uuid) - with docker_utils.docker_for_container(context, - container_uuid) as docker: - docker_id = self._find_container_by_name(docker, - container_uuid) - return {'output': docker.logs(docker_id)} - - @wrap_container_exception - def container_exec(self, context, container_uuid, command): - LOG.debug("container_exec %s command %s", - container_uuid, command) - with docker_utils.docker_for_container(context, - container_uuid) as docker: - docker_id = self._find_container_by_name(docker, - container_uuid) - if docker_utils.is_docker_library_version_atleast('1.2.0'): - create_res = docker.exec_create(docker_id, command, True, - True, False) - exec_output = docker.exec_start(create_res, False, False, - False) - else: - exec_output = docker.execute(docker_id, command) - return {'output': exec_output} diff --git a/magnum/conductor/monitors.py b/magnum/conductor/monitors.py index 2d3cd00a00..096330f722 100644 --- a/magnum/conductor/monitors.py +++ b/magnum/conductor/monitors.py @@ -27,10 +27,10 @@ LOG = log.getLogger(__name__) CONF = cfg.CONF CONF.import_opt('docker_remote_api_version', - 'magnum.conductor.handlers.docker_conductor', + 'magnum.common.docker_utils', group='docker') CONF.import_opt('default_timeout', - 'magnum.conductor.handlers.docker_conductor', + 'magnum.common.docker_utils', group='docker') COE_CLASS_PATH = { diff --git a/magnum/db/api.py b/magnum/db/api.py index 023a18d166..7c633bbe0d 100644 --- a/magnum/db/api.py +++ b/magnum/db/api.py @@ -204,90 +204,6 @@ class Connection(object): :raises: BayModelNotFound """ - @abc.abstractmethod - def get_container_list(self, context, filters=None, - limit=None, marker=None, sort_key=None, - sort_dir=None): - """Get matching containers. - - Return a list of the specified columns for all containers that match - the specified filters. - - :param context: The security context - :param filters: Filters to apply. Defaults to None. - - :param limit: Maximum number of containers 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_container(self, values): - """Create a new container. - - :param values: A dict containing several items used to identify - and track the container, and several dicts which are - passed - into the Drivers when managing this container. For - example: - - :: - - { - 'uuid': uuidutils.generate_uuid(), - 'name': 'example', - 'type': 'virt' - } - :returns: A container. - """ - - @abc.abstractmethod - def get_container_by_id(self, context, container_id): - """Return a container. - - :param context: The security context - :param container_id: The id of a container. - :returns: A container. - """ - - @abc.abstractmethod - def get_container_by_uuid(self, context, container_uuid): - """Return a container. - - :param context: The security context - :param container_uuid: The uuid of a container. - :returns: A container. - """ - - @abc.abstractmethod - def get_container_by_name(self, context, container_name): - """Return a container. - - :param context: The security context - :param container_name: The name of a container. - :returns: A container. - """ - - @abc.abstractmethod - def destroy_container(self, container_id): - """Destroy a container and all associated interfaces. - - :param container_id: The id or uuid of a container. - """ - - @abc.abstractmethod - def update_container(self, container_id, values): - """Update properties of a container. - - :param container_id: The id or uuid of a container. - :returns: A container. - :raises: ContainerNotFound - """ - @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/1f196a3dabae_remove_container.py b/magnum/db/sqlalchemy/alembic/versions/1f196a3dabae_remove_container.py new file mode 100644 index 0000000000..15413814dd --- /dev/null +++ b/magnum/db/sqlalchemy/alembic/versions/1f196a3dabae_remove_container.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 container object + +Revision ID: 1f196a3dabae +Revises: e0653b2d5271 +Create Date: 2016-06-02 11:42:42.200992 + +""" + +# revision identifiers, used by Alembic. +revision = '1f196a3dabae' +down_revision = 'e0653b2d5271' + +from alembic import op + + +def upgrade(): + op.drop_table('container') diff --git a/magnum/db/sqlalchemy/api.py b/magnum/db/sqlalchemy/api.py index b64e286e5c..599ee1c470 100644 --- a/magnum/db/sqlalchemy/api.py +++ b/magnum/db/sqlalchemy/api.py @@ -198,11 +198,6 @@ class Connection(api.Connection): if query.count() != 0: query.delete() - query = model_query(models.Container, session=session) - query = self._add_containers_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) @@ -370,103 +365,6 @@ class Connection(api.Connection): ref.update(values) return ref - def _add_containers_filters(self, query, filters): - if filters is None: - filters = {} - - filter_names = ['name', 'image', 'project_id', 'user_id', - 'memory', 'bay_uuid'] - for name in filter_names: - if name in filters: - query = query.filter_by(**{name: filters[name]}) - - return query - - def get_container_list(self, context, filters=None, limit=None, - marker=None, sort_key=None, sort_dir=None): - query = model_query(models.Container) - query = self._add_tenant_filters(context, query) - query = self._add_containers_filters(query, filters) - return _paginate_query(models.Container, limit, marker, - sort_key, sort_dir, query) - - def create_container(self, values): - # ensure defaults are present for new containers - if not values.get('uuid'): - values['uuid'] = uuidutils.generate_uuid() - - container = models.Container() - container.update(values) - try: - container.save() - except db_exc.DBDuplicateEntry: - raise exception.ContainerAlreadyExists(uuid=values['uuid']) - return container - - def get_container_by_id(self, context, container_id): - query = model_query(models.Container) - query = self._add_tenant_filters(context, query) - query = query.filter_by(id=container_id) - try: - return query.one() - except NoResultFound: - raise exception.ContainerNotFound(container=container_id) - - def get_container_by_uuid(self, context, container_uuid): - query = model_query(models.Container) - query = self._add_tenant_filters(context, query) - query = query.filter_by(uuid=container_uuid) - try: - return query.one() - except NoResultFound: - raise exception.ContainerNotFound(container=container_uuid) - - def get_container_by_name(self, context, container_name): - query = model_query(models.Container) - query = self._add_tenant_filters(context, query) - query = query.filter_by(name=container_name) - try: - return query.one() - except NoResultFound: - raise exception.ContainerNotFound(container=container_name) - except MultipleResultsFound: - raise exception.Conflict('Multiple containers exist with same ' - 'name. Please use the container uuid ' - 'instead.') - - def destroy_container(self, container_id): - session = get_session() - with session.begin(): - query = model_query(models.Container, session=session) - query = add_identity_filter(query, container_id) - count = query.delete() - if count != 1: - raise exception.ContainerNotFound(container_id) - - def update_container(self, container_id, values): - # NOTE(dtantsur): this can lead to very strange errors - if 'uuid' in values: - msg = _("Cannot overwrite UUID for an existing Container.") - raise exception.InvalidParameterValue(err=msg) - - return self._do_update_container(container_id, values) - - def _do_update_container(self, container_id, values): - session = get_session() - with session.begin(): - query = model_query(models.Container, session=session) - query = add_identity_filter(query, container_id) - try: - ref = query.with_lockmode('update').one() - except NoResultFound: - raise exception.ContainerNotFound(container=container_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 7e8b53461e..acdc92adbb 100644 --- a/magnum/db/sqlalchemy/models.py +++ b/magnum/db/sqlalchemy/models.py @@ -179,27 +179,6 @@ class BayModel(Base): master_lb_enabled = Column(Boolean, default=False) -class Container(Base): - """Represents a container.""" - - __tablename__ = 'container' - __table_args__ = ( - schema.UniqueConstraint('uuid', name='uniq_container0uuid'), - table_args() - ) - id = Column(Integer, primary_key=True) - project_id = Column(String(255)) - user_id = Column(String(255)) - uuid = Column(String(36)) - name = Column(String(255)) - image = Column(String(255)) - command = Column(String(255)) - bay_uuid = Column(String(36)) - status = Column(String(20)) - memory = Column(String(255)) - environment = Column(JSONEncodedDict) - - class ReplicationController(Base): """Represents a pod replication controller.""" diff --git a/magnum/objects/__init__.py b/magnum/objects/__init__.py index 621e3b42ab..dadbd79a98 100644 --- a/magnum/objects/__init__.py +++ b/magnum/objects/__init__.py @@ -15,13 +15,11 @@ from magnum.objects import bay from magnum.objects import baymodel 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 x509keypair -Container = container.Container Bay = bay.Bay BayModel = baymodel.BayModel MagnumService = magnum_service.MagnumService @@ -30,7 +28,6 @@ X509KeyPair = x509keypair.X509KeyPair Certificate = certificate.Certificate __all__ = (Bay, BayModel, - Container, MagnumService, ReplicationController, X509KeyPair, diff --git a/magnum/objects/container.py b/magnum/objects/container.py deleted file mode 100644 index dce5187cda..0000000000 --- a/magnum/objects/container.py +++ /dev/null @@ -1,186 +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 oslo_versionedobjects import fields - -from magnum.db import api as dbapi -from magnum.objects import base -from magnum.objects import fields as m_fields - - -@base.MagnumObjectRegistry.register -class Container(base.MagnumPersistentObject, base.MagnumObject, - base.MagnumObjectDictCompat): - # Version 1.0: Initial version - # Version 1.1: Add memory field - # Version 1.2: Add environment field - # Version 1.3: Add filters to list() - VERSION = '1.3' - - 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), - 'image': fields.StringField(nullable=True), - 'command': fields.StringField(nullable=True), - 'bay_uuid': fields.StringField(nullable=True), - 'status': m_fields.ContainerStatusField(nullable=True), - 'memory': fields.StringField(nullable=True), - 'environment': fields.DictOfStringsField(nullable=True), - } - - @staticmethod - def _from_db_object(container, db_container): - """Converts a database entity to a formal object.""" - for field in container.fields: - container[field] = db_container[field] - - container.obj_reset_changes() - return container - - @staticmethod - def _from_db_object_list(db_objects, cls, context): - """Converts a list of database entities to a list of formal objects.""" - return [Container._from_db_object(cls(context), obj) - for obj in db_objects] - - @base.remotable_classmethod - def get_by_id(cls, context, container_id): - """Find a container based on its integer id and return a Container object. - - :param container_id: the id of a container. - :param context: Security context - :returns: a :class:`Container` object. - """ - db_container = cls.dbapi.get_container_by_id(context, container_id) - container = Container._from_db_object(cls(context), db_container) - return container - - @base.remotable_classmethod - def get_by_uuid(cls, context, uuid): - """Find a container based on uuid and return a :class:`Container` object. - - :param uuid: the uuid of a container. - :param context: Security context - :returns: a :class:`Container` object. - """ - db_container = cls.dbapi.get_container_by_uuid(context, uuid) - container = Container._from_db_object(cls(context), db_container) - return container - - @base.remotable_classmethod - def get_by_name(cls, context, name): - """Find a container based on name and return a Container object. - - :param name: the logical name of a container. - :param context: Security context - :returns: a :class:`Container` object. - """ - db_bay = cls.dbapi.get_container_by_name(context, name) - bay = Container._from_db_object(cls(context), db_bay) - return bay - - @base.remotable_classmethod - def list(cls, context, limit=None, marker=None, - sort_key=None, sort_dir=None, filters=None): - """Return a list of Container objects. - - :param context: Security context. - :param limit: maximum number of resources to return in a single result. - :param marker: pagination marker for large data sets. - :param sort_key: column to sort results by. - :param sort_dir: direction to sort. "asc" or "desc". - :param filters: filters when list containers, the filter name could be - 'name', 'image', 'project_id', 'user_id', 'memory', - 'bay_uuid'. For example, filters={'bay_uuid': '1'} - :returns: a list of :class:`Container` object. - - """ - db_containers = cls.dbapi.get_container_list(context, limit=limit, - marker=marker, - sort_key=sort_key, - sort_dir=sort_dir, - filters=filters) - return Container._from_db_object_list(db_containers, cls, context) - - @base.remotable - def create(self, context=None): - """Create a Container 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.: Container(context) - - """ - values = self.obj_get_changes() - db_container = self.dbapi.create_container(values) - self._from_db_object(self, db_container) - - @base.remotable - def destroy(self, context=None): - """Delete the Container 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.: Container(context) - """ - self.dbapi.destroy_container(self.uuid) - self.obj_reset_changes() - - @base.remotable - def save(self, context=None): - """Save updates to this Container. - - 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.: Container(context) - """ - updates = self.obj_get_changes() - self.dbapi.update_container(self.uuid, updates) - - self.obj_reset_changes() - - @base.remotable - def refresh(self, context=None): - """Loads updates for this Container. - - Loads a container with the same uuid from the database and - checks for updated attributes. Updates are applied from - the loaded container 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.: Container(context) - """ - current = self.__class__.get_by_uuid(self._context, uuid=self.uuid) - for field in self.fields: - if self.obj_attr_is_set(field) and self[field] != current[field]: - self[field] = current[field] diff --git a/magnum/opts.py b/magnum/opts.py index 6c51db53ea..be6f2b953d 100644 --- a/magnum/opts.py +++ b/magnum/opts.py @@ -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.docker_conductor import magnum.conductor.handlers.k8s_conductor import magnum.db import magnum.drivers.common.template_def diff --git a/magnum/tests/fake_policy.py b/magnum/tests/fake_policy.py index 87d18f0d37..29acd18ad5 100644 --- a/magnum/tests/fake_policy.py +++ b/magnum/tests/fake_policy.py @@ -39,13 +39,6 @@ policy_data = """ "rc:detail": "", "rc:get": "", "rc:get_all": "", - "rc:update": "", - - "container:create": "", - "container:delete": "", - "container:detail": "", - "container:get": "", - "container:get_all": "", - "container:update": "" + "rc:update": "" } """ diff --git a/magnum/tests/unit/common/test_docker_utils.py b/magnum/tests/unit/common/test_docker_utils.py index ef30f8e474..81228ae019 100644 --- a/magnum/tests/unit/common/test_docker_utils.py +++ b/magnum/tests/unit/common/test_docker_utils.py @@ -29,123 +29,6 @@ CONF.import_opt('default_timeout', 'magnum.common.docker_utils', class TestDockerUtils(base.BaseTestCase): - @mock.patch('magnum.common.docker_utils.DockerHTTPClient') - @mock.patch.object(docker_utils, 'cert_manager') - @mock.patch.object(docker_utils.objects.BayModel, 'get_by_uuid') - @mock.patch.object(docker_utils.objects.Bay, 'get_by_name') - def test_docker_for_container(self, mock_get_bay_by_name, - mock_get_baymodel_by_uuid, - mock_cert_manager, - mock_docker_client): - mock_container = mock.MagicMock() - mock_bay = mock.MagicMock() - mock_bay.api_address = 'https://1.2.3.4:2376' - mock_get_bay_by_name.return_value = mock_bay - mock_baymodel = mock.MagicMock() - mock_baymodel.tls_disabled = False - mock_get_baymodel_by_uuid.return_value = mock_baymodel - mock_ca_cert = mock.MagicMock() - mock_magnum_key = mock.MagicMock() - mock_magnum_cert = mock.MagicMock() - mock_cert_manager.create_client_files.return_value = ( - mock_ca_cert, mock_magnum_key, mock_magnum_cert - ) - - mock_docker = mock.MagicMock() - mock_docker_client.return_value = mock_docker - - with docker_utils.docker_for_container(mock.sentinel.context, - mock_container) as docker: - self.assertEqual(mock_docker, docker) - - mock_get_bay_by_name.assert_called_once_with(mock.sentinel.context, - mock_container.bay_uuid) - mock_get_baymodel_by_uuid.assert_called_once_with( - mock.sentinel.context, mock_bay.baymodel_id) - mock_docker_client.assert_called_once_with( - 'https://1.2.3.4:2376', - CONF.docker.docker_remote_api_version, - CONF.docker.default_timeout, - ca_cert=mock_ca_cert.name, - client_key=mock_magnum_key.name, - client_cert=mock_magnum_cert.name) - - @mock.patch('magnum.common.docker_utils.DockerHTTPClient') - @mock.patch.object(docker_utils, 'cert_manager') - @mock.patch.object(docker_utils.objects.BayModel, 'get_by_uuid') - @mock.patch.object(docker_utils.objects.Bay, 'get_by_name') - @mock.patch.object(docker_utils.objects.Container, 'get_by_uuid') - def test_docker_for_container_uuid(self, mock_get_container_by_uuid, - mock_get_bay_by_name, - mock_get_baymodel_by_uuid, - mock_cert_manager, - mock_docker_client): - mock_container = mock.MagicMock() - mock_container.uuid = '8e48ffb1-754d-4f21-bdd0-1a39bf796389' - mock_get_container_by_uuid.return_value = mock_container - mock_bay = mock.MagicMock() - mock_bay.api_address = 'https://1.2.3.4:2376' - mock_get_bay_by_name.return_value = mock_bay - mock_baymodel = mock.MagicMock() - mock_baymodel.tls_disabled = False - mock_get_baymodel_by_uuid.return_value = mock_baymodel - mock_ca_cert = mock.MagicMock() - mock_magnum_key = mock.MagicMock() - mock_magnum_cert = mock.MagicMock() - mock_cert_manager.create_client_files.return_value = ( - mock_ca_cert, mock_magnum_key, mock_magnum_cert - ) - - mock_docker = mock.MagicMock() - mock_docker_client.return_value = mock_docker - - with docker_utils.docker_for_container( - mock.sentinel.context, mock_container.uuid) as docker: - self.assertEqual(mock_docker, docker) - - mock_get_container_by_uuid.assert_called_once_with( - mock.sentinel.context, mock_container.uuid - ) - mock_get_bay_by_name.assert_called_once_with(mock.sentinel.context, - mock_container.bay_uuid) - mock_get_baymodel_by_uuid.assert_called_once_with( - mock.sentinel.context, mock_bay.baymodel_id) - mock_docker_client.assert_called_once_with( - 'https://1.2.3.4:2376', - CONF.docker.docker_remote_api_version, - CONF.docker.default_timeout, - ca_cert=mock_ca_cert.name, - client_key=mock_magnum_key.name, - client_cert=mock_magnum_cert.name) - - @mock.patch('magnum.common.docker_utils.DockerHTTPClient') - @mock.patch.object(docker_utils.objects.BayModel, 'get_by_uuid') - @mock.patch.object(docker_utils.objects.Bay, 'get_by_name') - def test_docker_for_container_tls_disabled(self, mock_get_bay_by_name, - mock_get_baymodel_by_uuid, - mock_docker_client): - mock_container = mock.MagicMock() - mock_bay = mock.MagicMock() - mock_bay.api_address = 'tcp://1.2.3.4:2376' - mock_get_bay_by_name.return_value = mock_bay - mock_baymodel = mock.MagicMock() - mock_baymodel.tls_disabled = True - mock_get_baymodel_by_uuid.return_value = mock_baymodel - mock_docker = mock.MagicMock() - mock_docker_client.return_value = mock_docker - - with docker_utils.docker_for_container(mock.sentinel.context, - mock_container) as docker: - self.assertEqual(mock_docker, docker) - - mock_get_bay_by_name.assert_called_once_with(mock.sentinel.context, - mock_container.bay_uuid) - mock_get_baymodel_by_uuid.assert_called_once_with( - mock.sentinel.context, mock_bay.baymodel_id) - mock_docker_client.assert_called_once_with( - 'tcp://1.2.3.4:2376', - CONF.docker.docker_remote_api_version, - CONF.docker.default_timeout) def test_is_docker_api_version_atleast(self): diff --git a/magnum/tests/unit/conductor/handlers/test_docker_conductor.py b/magnum/tests/unit/conductor/handlers/test_docker_conductor.py deleted file mode 100644 index 1d4e40dbd3..0000000000 --- a/magnum/tests/unit/conductor/handlers/test_docker_conductor.py +++ /dev/null @@ -1,558 +0,0 @@ -# Copyright 2015 Rackspace 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 docker -from docker import errors -import mock -import six - -from magnum.common import docker_utils -from magnum.common import exception -from magnum.conductor.handlers import docker_conductor -from magnum import objects -from magnum.objects import fields -from magnum.tests import base - - -class TestDockerHandler(base.BaseTestCase): - def setUp(self): - super(TestDockerHandler, self).setUp() - self.conductor = docker_conductor.Handler() - dfc_patcher = mock.patch.object(docker_utils, - 'docker_for_container') - docker_for_container = dfc_patcher.start() - self.dfc_context_manager = docker_for_container.return_value - self.mock_docker = mock.MagicMock() - self.dfc_context_manager.__enter__.return_value = self.mock_docker - self.addCleanup(dfc_patcher.stop) - - @mock.patch.object(docker_utils, 'is_docker_api_version_atleast') - def _test_container_create(self, container_dict, expected_kwargs, - mock_version, expected_image='test_image', - expected_tag='some_tag', - api_version='1.18'): - - mock_version.return_value = (float(api_version) > 1.18) - - name = container_dict.pop('name') - mock_container = mock.MagicMock(**container_dict) - type(mock_container).name = mock.PropertyMock(return_value=name) - - container = self.conductor.container_create( - None, mock_container) - - utf8_image = self.conductor._encode_utf8(mock_container.image) - self.mock_docker.inspect_image.assert_called_once_with(utf8_image) - self.mock_docker.pull.assert_called_once_with(expected_image, - tag=expected_tag) - self.mock_docker.create_container.assert_called_once_with( - mock_container.image, **expected_kwargs) - self.assertEqual(fields.ContainerStatus.STOPPED, container.status) - - def test_container_create(self): - container_dict = { - 'name': 'some-name', - 'uuid': 'some-uuid', - 'image': 'test_image:some_tag', - 'command': None, - 'memory': None, - 'environment': None, - } - expected_kwargs = { - 'name': 'some-name', - 'hostname': 'some-uuid', - 'command': None, - 'mem_limit': None, - 'environment': None, - } - self._test_container_create(container_dict, expected_kwargs) - - def test_container_create_api_1_19(self): - container_dict = { - 'name': 'some-name', - 'uuid': 'some-uuid', - 'image': 'test_image:some_tag', - 'command': None, - 'memory': '100m', - 'environment': None, - } - expected_kwargs = { - 'name': 'some-name', - 'hostname': 'some-uuid', - 'command': None, - 'host_config': {'Memory': 100 * 1024 * 1024}, - 'environment': None, - } - self._test_container_create(container_dict, expected_kwargs, - api_version='1.19') - - def test_container_create_with_command(self): - container_dict = { - 'name': 'some-name', - 'uuid': 'some-uuid', - 'image': 'test_image:some_tag', - 'command': 'env', - 'memory': None, - 'environment': None, - } - expected_kwargs = { - 'name': 'some-name', - 'hostname': 'some-uuid', - 'command': 'env', - 'mem_limit': None, - 'environment': None, - } - self._test_container_create(container_dict, expected_kwargs) - - def test_container_create_with_memory(self): - container_dict = { - 'name': 'some-name', - 'uuid': 'some-uuid', - 'image': 'test_image:some_tag', - 'command': None, - 'memory': '512m', - 'environment': None, - } - expected_kwargs = { - 'name': 'some-name', - 'hostname': 'some-uuid', - 'command': None, - 'mem_limit': '512m', - 'environment': None, - } - self._test_container_create(container_dict, expected_kwargs) - - def test_container_create_with_environment(self): - container_dict = { - 'name': 'some-name', - 'uuid': 'some-uuid', - 'image': 'test_image:some_tag', - 'command': None, - 'memory': '512m', - 'environment': {'key1': 'val1', 'key2': 'val2'}, - } - expected_kwargs = { - 'name': 'some-name', - 'hostname': 'some-uuid', - 'command': None, - 'mem_limit': '512m', - 'environment': {'key1': 'val1', 'key2': 'val2'}, - } - self._test_container_create(container_dict, expected_kwargs) - - def test_encode_utf8_unicode(self): - image = 'some_image:some_tag' - unicode_image = six.u(image) - utf8_image = self.conductor._encode_utf8(unicode_image) - self.assertEqual(unicode_image.encode('utf-8'), utf8_image) - - @mock.patch.object(errors.APIError, '__str__') - def test_container_create_with_failure(self, mock_init): - mock_container = mock.MagicMock() - mock_container.image = 'test_image:some_tag' - mock_init.return_value = 'hit error' - self.mock_docker.pull = mock.Mock( - side_effect=errors.APIError('Error', '', '')) - - self.assertRaises(exception.ContainerException, - self.conductor.container_create, - None, mock_container) - self.mock_docker.pull.assert_called_once_with( - 'test_image', - tag='some_tag') - self.assertFalse(self.mock_docker.create_container.called) - mock_init.assert_called_with() - self.assertEqual(fields.ContainerStatus.ERROR, - mock_container.status) - - def test_find_container_by_name_not_found(self): - mock_docker = mock.MagicMock() - fake_response = mock.MagicMock() - fake_response.content = 'not_found' - fake_response.status_code = 404 - mock_docker.list_instances.side_effect = errors.APIError( - 'not_found', fake_response) - ret = self.conductor._find_container_by_name(mock_docker, '1') - self.assertEqual({}, ret) - - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_delete(self, mock_find_container): - mock_container_uuid = 'd545a92d-609a-428f-8edb-16b02ad20ca1' - mock_docker_id = '2703ef2b705d' - mock_find_container.return_value = mock_docker_id - self.conductor.container_delete(None, mock_container_uuid) - self.mock_docker.remove_container.assert_called_once_with( - mock_docker_id) - mock_find_container.assert_called_once_with(self.mock_docker, - mock_container_uuid) - - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_delete_with_container_not_exist(self, - mock_find_container): - mock_container_uuid = 'd545a92d-609a-428f-8edb-16b02ad20ca1' - mock_docker_id = {} - mock_find_container.return_value = mock_docker_id - res = self.conductor.container_delete(None, mock_container_uuid) - self.assertIsNone(res) - self.assertFalse(self.mock_docker.remove_container.called) - mock_find_container.assert_called_once_with(self.mock_docker, - mock_container_uuid) - - @mock.patch.object(errors.APIError, '__str__') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_delete_with_failure(self, mock_find_container, - mock_init): - mock_container_uuid = 'd545a92d-609a-428f-8edb-16b02ad20ca1' - mock_docker_id = '2703ef2b705d' - mock_find_container.return_value = mock_docker_id - mock_init.return_value = 'hit error' - self.mock_docker.remove_container = mock.Mock( - side_effect=errors.APIError('Error', '', '')) - self.assertRaises(exception.ContainerException, - self.conductor.container_delete, - None, mock_container_uuid) - self.mock_docker.remove_container.assert_called_once_with( - mock_docker_id) - mock_find_container.assert_called_once_with(self.mock_docker, - mock_container_uuid) - mock_init.assert_called_with() - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_action(self, mock_find_container, mock_get_by_uuid): - mock_container = mock.MagicMock() - mock_get_by_uuid.return_value = mock_container - mock_container_uuid = 'd545a92d-609a-428f-8edb-16b02ad20ca1' - mock_docker_id = '2703ef2b705d' - mock_find_container.return_value = mock_docker_id - self.conductor._container_action(None, mock_container_uuid, - 'fake-status', 'fake-func') - self.assertEqual('fake-status', mock_container.status) - - def _test_container(self, action, docker_func_name, expected_status, - mock_find_container, mock_get_by_uuid): - mock_container = mock.MagicMock() - mock_get_by_uuid.return_value = mock_container - mock_container_uuid = 'd545a92d-609a-428f-8edb-16b02ad20ca1' - mock_docker_id = '2703ef2b705d' - mock_find_container.return_value = mock_docker_id - action_func = getattr(self.conductor, action) - action_func(None, mock_container_uuid) - docker_func = getattr(self.mock_docker, docker_func_name) - docker_func.assert_called_once_with(mock_docker_id) - mock_find_container.assert_called_once_with(self.mock_docker, - mock_container_uuid) - self.assertEqual(expected_status, mock_container.status) - - @mock.patch.object(errors.APIError, '__str__') - def _test_container_with_failure( - self, action, docker_func_name, mock_find_container, mock_init): - mock_container_uuid = 'd545a92d-609a-428f-8edb-16b02ad20ca1' - mock_docker_id = '2703ef2b705d' - mock_find_container.return_value = mock_docker_id - mock_init.return_value = 'hit error' - setattr(self.mock_docker, docker_func_name, mock.Mock( - side_effect=errors.APIError('Error', '', ''))) - self.assertRaises(exception.ContainerException, - getattr(self.conductor, action), - None, mock_container_uuid) - docker_func = getattr(self.mock_docker, docker_func_name) - docker_func.assert_called_once_with(mock_docker_id) - mock_find_container.assert_called_once_with(self.mock_docker, - mock_container_uuid) - mock_init.assert_called_with() - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_reboot(self, mock_find_container, mock_get_by_uuid): - self._test_container( - 'container_reboot', 'restart', fields.ContainerStatus.RUNNING, - mock_find_container, mock_get_by_uuid) - - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_reboot_with_failure(self, mock_find_container): - self._test_container_with_failure( - 'container_reboot', 'restart', mock_find_container) - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_start(self, mock_find_container, mock_get_by_uuid): - self._test_container( - 'container_start', 'start', fields.ContainerStatus.RUNNING, - mock_find_container, mock_get_by_uuid) - - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_start_with_failure(self, mock_find_container): - self._test_container_with_failure( - 'container_start', 'start', mock_find_container) - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_stop(self, mock_find_container, mock_get_by_uuid): - self._test_container( - 'container_stop', 'stop', fields.ContainerStatus.STOPPED, - mock_find_container, mock_get_by_uuid) - - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_stop_with_failure(self, mock_find_container): - self._test_container_with_failure( - 'container_stop', 'stop', mock_find_container) - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_pause(self, mock_find_container, mock_get_by_uuid): - self._test_container( - 'container_pause', 'pause', fields.ContainerStatus.PAUSED, - mock_find_container, mock_get_by_uuid) - - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_pause_with_failure(self, mock_find_container): - self._test_container_with_failure( - 'container_pause', 'pause', mock_find_container) - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_unpause(self, mock_find_container, mock_get_by_uuid): - self._test_container( - 'container_unpause', 'unpause', fields.ContainerStatus.RUNNING, - mock_find_container, mock_get_by_uuid) - - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_unpause_with_failure(self, mock_find_container): - self._test_container_with_failure( - 'container_unpause', 'unpause', mock_find_container) - - def _test_container_show( - self, mock_find_container, mock_get_by_uuid, container_detail=None, - expected_status=None, mock_docker_id='2703ef2b705d'): - mock_container = mock.MagicMock() - mock_get_by_uuid.return_value = mock_container - mock_container_uuid = 'd545a92d-609a-428f-8edb-16b02ad20ca1' - mock_find_container.return_value = mock_docker_id - if container_detail is not None: - self.mock_docker.inspect_container.return_value = container_detail - - self.conductor.container_show(None, mock_container_uuid) - - if mock_docker_id: - self.mock_docker.inspect_container.assert_called_once_with( - mock_docker_id) - mock_find_container.assert_called_once_with(self.mock_docker, - mock_container_uuid) - if expected_status is not None: - self.assertEqual(expected_status, mock_container.status) - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_show(self, mock_find_container, mock_get_by_uuid): - self._test_container_show(mock_find_container, mock_get_by_uuid) - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_show_with_running_state(self, mock_find_container, - mock_get_by_uuid): - mock_container_detail = {'State': {'Error': '', - 'Running': True, - 'Paused': False}} - self._test_container_show( - mock_find_container, mock_get_by_uuid, mock_container_detail, - fields.ContainerStatus.RUNNING) - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_show_with_stop_state(self, mock_find_container, - mock_get_by_uuid): - mock_container_detail = {'State': {'Error': '', - 'Running': False, - 'Paused': False}} - self._test_container_show( - mock_find_container, mock_get_by_uuid, mock_container_detail, - fields.ContainerStatus.STOPPED) - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_show_with_pause_state(self, mock_find_container, - mock_get_by_uuid): - mock_container_detail = {'State': {'Error': '', - 'Running': True, - 'Paused': True}} - self._test_container_show( - mock_find_container, mock_get_by_uuid, mock_container_detail, - fields.ContainerStatus.PAUSED) - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_show_with_error_status(self, mock_find_container, - mock_get_by_uuid): - mock_container_detail = {'State': {'Error': True, - 'Running': False, - 'Paused': False}} - self._test_container_show( - mock_find_container, mock_get_by_uuid, mock_container_detail, - fields.ContainerStatus.ERROR) - - def _test_container_show_with_failure( - self, mock_find_container, mock_get_by_uuid, error, - assert_raise=True, expected_status=None): - mock_container = mock.MagicMock() - mock_get_by_uuid.return_value = mock_container - mock_container_uuid = 'd545a92d-609a-428f-8edb-1d6b02ad20ca1' - mock_docker_id = '2703ef2b705d' - mock_find_container.return_value = mock_docker_id - with mock.patch.object(errors.APIError, '__str__', - return_value=error) as mock_init: - self.mock_docker.inspect_container = mock.Mock( - side_effect=errors.APIError('Error', '', '')) - - if assert_raise: - self.assertRaises(exception.ContainerException, - self.conductor.container_show, - None, mock_container_uuid) - else: - self.conductor.container_show(None, mock_container_uuid) - - self.mock_docker.inspect_container.assert_called_once_with( - mock_docker_id) - mock_find_container.assert_called_once_with(self.mock_docker, - mock_container_uuid) - mock_init.assert_called_with() - if expected_status is not None: - self.assertEqual(expected_status, mock_container.status) - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_show_with_failure(self, mock_find_container, - mock_get_by_uuid): - self._test_container_show_with_failure( - mock_find_container, mock_get_by_uuid, error='hit error') - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_show_with_not_found(self, mock_find_container, - mock_get_by_uuid): - self._test_container_show_with_failure( - mock_find_container, mock_get_by_uuid, error='404 error', - assert_raise=False, expected_status=fields.ContainerStatus.ERROR) - - @mock.patch.object(objects.Container, 'get_by_uuid') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_show_with_not_found_from_docker(self, - mock_find_container, - mock_get_by_uuid): - self._test_container_show( - mock_find_container, mock_get_by_uuid, mock_docker_id={}, - expected_status=fields.ContainerStatus.ERROR) - - def _test_container_exec(self, mock_find_container, docker_version='1.2.2', - deprecated=False): - mock_container_uuid = 'd545a92d-609a-428f-8edb-16b02ad20ca1' - mock_docker_id = '2703ef2b705d' - docker.version = docker_version - mock_find_container.return_value = mock_docker_id - mock_create_res = mock.MagicMock() - self.mock_docker.exec_create.return_value = mock_create_res - self.conductor.container_exec(None, mock_container_uuid, 'ls') - if deprecated: - self.mock_docker.execute.assert_called_once_with( - mock_docker_id, 'ls') - else: - self.mock_docker.exec_create.assert_called_once_with( - mock_docker_id, 'ls', True, True, False) - self. mock_docker.exec_start.assert_called_once_with( - mock_create_res, False, False, False) - mock_find_container.assert_called_once_with(self.mock_docker, - mock_container_uuid) - - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_exec(self, mock_find_container): - self._test_container_exec(mock_find_container) - - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_exec_deprecated(self, mock_find_container): - self._test_container_exec( - mock_find_container, docker_version='0.7.0', deprecated=True) - - def _test_container_exec_with_failure( - self, mock_find_container, docker_version='1.2.2', - deprecated=False): - mock_container_uuid = 'd545a92d-609a-428f-8edb-16b02ad20ca1' - mock_docker_id = '2703ef2b705d' - docker.version = docker_version - mock_find_container.return_value = mock_docker_id - with mock.patch.object(errors.APIError, '__str__', - return_value='hit error') as mock_init: - if deprecated: - self.mock_docker.execute = mock.Mock( - side_effect=errors.APIError('Error', '', '')) - else: - self.mock_docker.exec_create = mock.Mock( - side_effect=errors.APIError('Error', '', '')) - self.assertRaises(exception.ContainerException, - self.conductor.container_exec, - None, mock_container_uuid, 'ls') - if deprecated: - self.mock_docker.execute.assert_called_once_with( - mock_docker_id, 'ls') - else: - self.mock_docker.exec_create.assert_called_once_with( - mock_docker_id, 'ls', True, True, False) - mock_find_container.assert_called_once_with(self.mock_docker, - mock_container_uuid) - mock_init.assert_called_with() - - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_exec_with_failure(self, mock_find_container): - self._test_container_exec_with_failure(mock_find_container) - - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_exec_deprecated_with_failure(self, mock_find_container): - self._test_container_exec_with_failure( - mock_find_container, docker_version='0.7.0', deprecated=True) - - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_logs(self, mock_find_container): - mock_container_uuid = 'd545a92d-609a-428f-8edb-16b02ad20ca1' - mock_docker_id = '2703ef2b705d' - mock_find_container.return_value = mock_docker_id - self.conductor.container_logs(None, mock_container_uuid) - self.mock_docker.logs.assert_called_once_with( - mock_docker_id) - mock_find_container.assert_called_once_with(self.mock_docker, - mock_container_uuid) - - @mock.patch.object(errors.APIError, '__str__') - @mock.patch.object(docker_conductor.Handler, '_find_container_by_name') - def test_container_logs_with_failure(self, mock_find_container, mock_init): - mock_container_uuid = 'd545a92d-609a-428f-8edb-16b02ad20ca1' - mock_docker_id = '2703ef2b705d' - mock_find_container.return_value = mock_docker_id - mock_init.return_value = 'hit error' - self.mock_docker.logs = mock.Mock( - side_effect=errors.APIError('Error', '', '')) - self.assertRaises(exception.ContainerException, - self.conductor.container_logs, - None, mock_container_uuid) - self.mock_docker.logs.assert_called_once_with( - mock_docker_id) - mock_find_container.assert_called_once_with(self.mock_docker, - mock_container_uuid) - mock_init.assert_called_with() - - def test_container_common_exception(self): - self.dfc_context_manager.__enter__.side_effect = Exception("So bad") - for action in ('container_exec', 'container_logs', 'container_show', - 'container_delete', 'container_create', - '_container_action'): - func = getattr(self.conductor, action) - self.assertRaises(exception.ContainerException, - func, None, None) diff --git a/magnum/tests/unit/conductor/test_rpcapi.py b/magnum/tests/unit/conductor/test_rpcapi.py index 2f25b3b9df..2bf4469dfb 100644 --- a/magnum/tests/unit/conductor/test_rpcapi.py +++ b/magnum/tests/unit/conductor/test_rpcapi.py @@ -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_container = dbutils.get_test_container(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' @@ -125,67 +124,6 @@ class RPCAPITestCase(base.DbTestCase): rc_ident=self.fake_rc['uuid'], bay_ident=self.fake_rc['bay_uuid']) - def test_container_create(self): - self._test_rpcapi('container_create', - 'call', - version='1.0', - container=self.fake_container) - - def test_container_delete(self): - self._test_rpcapi('container_delete', - 'call', - version='1.0', - container_uuid=self.fake_container['uuid']) - - def test_container_show(self): - self._test_rpcapi('container_show', - 'call', - version='1.0', - container_uuid=self.fake_container['uuid']) - - def test_container_reboot(self): - self._test_rpcapi('container_reboot', - 'call', - version='1.0', - container_uuid=self.fake_container['uuid']) - - def test_container_stop(self): - self._test_rpcapi('container_stop', - 'call', - version='1.0', - container_uuid=self.fake_container['uuid']) - - def test_container_start(self): - self._test_rpcapi('container_start', - 'call', - version='1.0', - container_uuid=self.fake_container['uuid']) - - def test_container_pause(self): - self._test_rpcapi('container_pause', - 'call', - version='1.0', - container_uuid=self.fake_container['uuid']) - - def test_container_unpause(self): - self._test_rpcapi('container_unpause', - 'call', - version='1.0', - container_uuid=self.fake_container['uuid']) - - def test_container_logs(self): - self._test_rpcapi('container_logs', - 'call', - version='1.0', - container_uuid=self.fake_container['uuid']) - - def test_container_exec(self): - self._test_rpcapi('container_exec', - 'call', - version='1.0', - container_uuid=self.fake_container['uuid'], - command=self.fake_container['command']) - def test_ping_conductor(self): self._test_rpcapi('ping_conductor', 'call', diff --git a/magnum/tests/unit/conductor/test_utils.py b/magnum/tests/unit/conductor/test_utils.py index 969ab45b02..48c837ec9c 100644 --- a/magnum/tests/unit/conductor/test_utils.py +++ b/magnum/tests/unit/conductor/test_utils.py @@ -35,13 +35,6 @@ class TestConductorUtils(base.TestCase): self._test_retrieve_bay(rc.bay_uuid, mock_bay_get_by_uuid) - @patch('magnum.objects.Bay.get_by_uuid') - def test_retrieve_bay_from_container(self, - 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') def test_retrieve_baymodel(self, mock_baymodel_get_by_uuid): expected_context = 'context' diff --git a/magnum/tests/unit/db/test_bay.py b/magnum/tests/unit/db/test_bay.py index 5f8644c3ad..ecf49a2a01 100644 --- a/magnum/tests/unit/db/test_bay.py +++ b/magnum/tests/unit/db/test_bay.py @@ -210,24 +210,6 @@ class DbBayTestCase(base.DbTestCase): self.dbapi.get_rc_by_id, self.context, rc.id) - def test_destroy_bay_that_has_containers(self): - bay = utils.create_test_bay() - container = utils.create_test_container(bay_uuid=bay.uuid) - self.assertEqual(bay.uuid, container.bay_uuid) - self.dbapi.destroy_bay(bay.id) - self.assertRaises(exception.ContainerNotFound, - self.dbapi.get_container_by_id, - self.context, container.id) - - def test_destroy_bay_that_has_containers_by_uuid(self): - bay = utils.create_test_bay() - container = utils.create_test_container(bay_uuid=bay.uuid) - self.assertEqual(bay.uuid, container.bay_uuid) - self.dbapi.destroy_bay(bay.uuid) - self.assertRaises(exception.ContainerNotFound, - self.dbapi.get_container_by_id, - self.context, container.id) - def test_update_bay(self): bay = utils.create_test_bay() old_nc = bay.node_count diff --git a/magnum/tests/unit/db/test_container.py b/magnum/tests/unit/db/test_container.py deleted file mode 100644 index d9c9fdf7ea..0000000000 --- a/magnum/tests/unit/db/test_container.py +++ /dev/null @@ -1,155 +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 Containers 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 - - -class DbContainerTestCase(base.DbTestCase): - - def test_create_container(self): - utils.create_test_container() - - def test_create_container_already_exists(self): - utils.create_test_container() - self.assertRaises(exception.ContainerAlreadyExists, - utils.create_test_container) - - def test_get_container_by_id(self): - container = utils.create_test_container() - res = self.dbapi.get_container_by_id(self.context, container.id) - self.assertEqual(container.id, res.id) - self.assertEqual(container.uuid, res.uuid) - - def test_get_container_by_uuid(self): - container = utils.create_test_container() - res = self.dbapi.get_container_by_uuid(self.context, - container.uuid) - self.assertEqual(container.id, res.id) - self.assertEqual(container.uuid, res.uuid) - - def test_get_container_by_name(self): - container = utils.create_test_container() - res = self.dbapi.get_container_by_name(self.context, - container.name) - self.assertEqual(container.id, res.id) - self.assertEqual(container.uuid, res.uuid) - - def test_get_container_that_does_not_exist(self): - self.assertRaises(exception.ContainerNotFound, - self.dbapi.get_container_by_id, self.context, 99) - self.assertRaises(exception.ContainerNotFound, - self.dbapi.get_container_by_uuid, - self.context, - uuidutils.generate_uuid()) - - def test_get_container_list(self): - uuids = [] - for i in range(1, 6): - container = utils.create_test_container( - uuid=uuidutils.generate_uuid()) - uuids.append(six.text_type(container['uuid'])) - res = self.dbapi.get_container_list(self.context) - res_uuids = [r.uuid for r in res] - self.assertEqual(sorted(uuids), sorted(res_uuids)) - - def test_get_container_list_sorted(self): - uuids = [] - for _ in range(5): - container = utils.create_test_container( - uuid=uuidutils.generate_uuid()) - uuids.append(six.text_type(container.uuid)) - res = self.dbapi.get_container_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_container_list, - self.context, - sort_key='foo') - - def test_get_container_list_with_filters(self): - container1 = utils.create_test_container( - name='container-one', - uuid=uuidutils.generate_uuid(), - bay_uuid=uuidutils.generate_uuid()) - container2 = utils.create_test_container( - name='container-two', - uuid=uuidutils.generate_uuid(), - bay_uuid=uuidutils.generate_uuid()) - - res = self.dbapi.get_container_list(self.context, - filters={'name': 'container-one'}) - self.assertEqual([container1.id], [r.id for r in res]) - - res = self.dbapi.get_container_list(self.context, - filters={'name': 'container-two'}) - self.assertEqual([container2.id], [r.id for r in res]) - - res = self.dbapi.get_container_list(self.context, - filters={'name': 'bad-container'}) - self.assertEqual([], [r.id for r in res]) - - res = self.dbapi.get_container_list( - self.context, - filters={'bay_uuid': container1.bay_uuid}) - self.assertEqual([container1.id], [r.id for r in res]) - - def test_destroy_container(self): - container = utils.create_test_container() - self.dbapi.destroy_container(container.id) - self.assertRaises(exception.ContainerNotFound, - self.dbapi.get_container_by_id, - self.context, container.id) - - def test_destroy_container_by_uuid(self): - container = utils.create_test_container() - self.dbapi.destroy_container(container.uuid) - self.assertRaises(exception.ContainerNotFound, - self.dbapi.get_container_by_uuid, - self.context, container.uuid) - - def test_destroy_container_that_does_not_exist(self): - self.assertRaises(exception.ContainerNotFound, - self.dbapi.destroy_container, - uuidutils.generate_uuid()) - - def test_update_container(self): - container = utils.create_test_container() - old_image = container.image - new_image = 'new-image' - self.assertNotEqual(old_image, new_image) - - res = self.dbapi.update_container(container.id, - {'image': new_image}) - self.assertEqual(new_image, res.image) - - def test_update_container_not_found(self): - container_uuid = uuidutils.generate_uuid() - new_image = 'new-image' - self.assertRaises(exception.ContainerNotFound, - self.dbapi.update_container, - container_uuid, {'image': new_image}) - - def test_update_container_uuid(self): - container = utils.create_test_container() - self.assertRaises(exception.InvalidParameterValue, - self.dbapi.update_container, container.id, - {'uuid': ''}) diff --git a/magnum/tests/unit/db/utils.py b/magnum/tests/unit/db/utils.py index 9817ed4fc1..b8cbe23c27 100644 --- a/magnum/tests/unit/db/utils.py +++ b/magnum/tests/unit/db/utils.py @@ -121,39 +121,6 @@ def create_test_bay(**kw): return dbapi.create_bay(bay) -def get_test_container(**kw): - return { - 'id': kw.get('id', 42), - 'uuid': kw.get('uuid', 'ea8e2a25-2901-438d-8157-de7ffd68d051'), - 'name': kw.get('name', 'container1'), - 'project_id': kw.get('project_id', 'fake_project'), - 'user_id': kw.get('user_id', 'fake_user'), - 'image': kw.get('image', 'ubuntu'), - 'created_at': kw.get('created_at'), - 'updated_at': kw.get('updated_at'), - 'command': kw.get('command', 'fake_command'), - 'bay_uuid': kw.get('bay_uuid', 'fff114da-3bfa-4a0f-a123-c0dffad9718e'), - 'status': kw.get('state', 'Running'), - 'memory': kw.get('memory', '512m'), - 'environment': kw.get('environment', {'key1': 'val1', 'key2': 'val2'}), - } - - -def create_test_container(**kw): - """Create test container entry in DB and return Container DB object. - - Function to be used to create test Container objects in the database. - :param kw: kwargs with overriding values for container's attributes. - :returns: Test Container DB object. - """ - container = get_test_container(**kw) - # Let DB generate ID if it isn't specified explicitly - if 'id' not in kw: - del container['id'] - dbapi = db_api.get_instance() - return dbapi.create_container(container) - - def get_test_rc(**kw): return { 'id': kw.get('id', 42), diff --git a/magnum/tests/unit/objects/test_container.py b/magnum/tests/unit/objects/test_container.py deleted file mode 100644 index 65e8edd1db..0000000000 --- a/magnum/tests/unit/objects/test_container.py +++ /dev/null @@ -1,141 +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 oslo_utils import uuidutils -from testtools.matchers import HasLength - -from magnum import objects -from magnum.tests.unit.db import base -from magnum.tests.unit.db import utils - - -class TestContainerObject(base.DbTestCase): - - def setUp(self): - super(TestContainerObject, self).setUp() - self.fake_container = utils.get_test_container() - - def test_get_by_id(self): - container_id = self.fake_container['id'] - with mock.patch.object(self.dbapi, 'get_container_by_id', - autospec=True) as mock_get_container: - mock_get_container.return_value = self.fake_container - container = objects.Container.get_by_id(self.context, - container_id) - mock_get_container.assert_called_once_with(self.context, - container_id) - self.assertEqual(self.context, container._context) - - def test_get_by_uuid(self): - uuid = self.fake_container['uuid'] - with mock.patch.object(self.dbapi, 'get_container_by_uuid', - autospec=True) as mock_get_container: - mock_get_container.return_value = self.fake_container - container = objects.Container.get_by_uuid(self.context, uuid) - mock_get_container.assert_called_once_with(self.context, uuid) - self.assertEqual(self.context, container._context) - - def test_get_by_name(self): - name = self.fake_container['name'] - with mock.patch.object(self.dbapi, 'get_container_by_name', - autospec=True) as mock_get_container: - mock_get_container.return_value = self.fake_container - container = objects.Container.get_by_name(self.context, name) - mock_get_container.assert_called_once_with(self.context, name) - self.assertEqual(self.context, container._context) - - def test_list(self): - with mock.patch.object(self.dbapi, 'get_container_list', - autospec=True) as mock_get_list: - mock_get_list.return_value = [self.fake_container] - containers = objects.Container.list(self.context) - self.assertEqual(1, mock_get_list.call_count) - self.assertThat(containers, HasLength(1)) - self.assertIsInstance(containers[0], objects.Container) - self.assertEqual(self.context, containers[0]._context) - - def test_list_with_filters(self): - with mock.patch.object(self.dbapi, 'get_container_list', - autospec=True) as mock_get_list: - mock_get_list.return_value = [self.fake_container] - containers = objects.Container.list(self.context, - filters={'bay_uuid': 'uuid'}) - self.assertEqual(1, mock_get_list.call_count) - self.assertThat(containers, HasLength(1)) - self.assertIsInstance(containers[0], objects.Container) - self.assertEqual(self.context, containers[0]._context) - mock_get_list.assert_called_once_with(self.context, - filters={'bay_uuid': 'uuid'}, - limit=None, marker=None, - sort_key=None, sort_dir=None) - - def test_create(self): - with mock.patch.object(self.dbapi, 'create_container', - autospec=True) as mock_create_container: - mock_create_container.return_value = self.fake_container - container = objects.Container(self.context, **self.fake_container) - container.create() - mock_create_container.assert_called_once_with(self.fake_container) - self.assertEqual(self.context, container._context) - - def test_destroy(self): - uuid = self.fake_container['uuid'] - with mock.patch.object(self.dbapi, 'get_container_by_uuid', - autospec=True) as mock_get_container: - mock_get_container.return_value = self.fake_container - with mock.patch.object(self.dbapi, 'destroy_container', - autospec=True) as mock_destroy_container: - container = objects.Container.get_by_uuid(self.context, uuid) - container.destroy() - mock_get_container.assert_called_once_with(self.context, uuid) - mock_destroy_container.assert_called_once_with(uuid) - self.assertEqual(self.context, container._context) - - def test_save(self): - uuid = self.fake_container['uuid'] - with mock.patch.object(self.dbapi, 'get_container_by_uuid', - autospec=True) as mock_get_container: - mock_get_container.return_value = self.fake_container - with mock.patch.object(self.dbapi, 'update_container', - autospec=True) as mock_update_container: - container = objects.Container.get_by_uuid(self.context, uuid) - container.image = 'container.img' - container.memory = '512m' - container.environment = {"key1": "val", "key2": "val2"} - container.save() - - mock_get_container.assert_called_once_with(self.context, uuid) - mock_update_container.assert_called_once_with( - uuid, {'image': 'container.img', 'memory': '512m', - 'environment': {"key1": "val", "key2": "val2"}}) - self.assertEqual(self.context, container._context) - - def test_refresh(self): - uuid = self.fake_container['uuid'] - new_uuid = uuidutils.generate_uuid() - returns = [dict(self.fake_container, uuid=uuid), - dict(self.fake_container, uuid=new_uuid)] - expected = [mock.call(self.context, uuid), - mock.call(self.context, uuid)] - with mock.patch.object(self.dbapi, 'get_container_by_uuid', - side_effect=returns, - autospec=True) as mock_get_container: - container = objects.Container.get_by_uuid(self.context, uuid) - self.assertEqual(uuid, container.uuid) - container.refresh() - self.assertEqual(new_uuid, container.uuid) - self.assertEqual(expected, mock_get_container.call_args_list) - self.assertEqual(self.context, container._context) diff --git a/magnum/tests/unit/objects/test_objects.py b/magnum/tests/unit/objects/test_objects.py index 361e113d67..ccbfc1cd4b 100644 --- a/magnum/tests/unit/objects/test_objects.py +++ b/magnum/tests/unit/objects/test_objects.py @@ -365,7 +365,6 @@ object_data = { 'Bay': '1.5-a3b9292ef5d35175b93ca46ba3baec2d', 'BayModel': '1.14-ae175b4aaba2c60df37cac63ef734853', 'Certificate': '1.0-2aff667971b85c1edf8d15684fd7d5e2', - 'Container': '1.3-e2d9d2e8a8844d421148cd9fde6c6bd6', 'MyObj': '1.0-b43567e512438205e32f4e95ca616697', 'MyObj': '1.0-34c4b1aadefd177b13f9a2f894cc23cd', 'ReplicationController': '1.0-a471c2429c212ed91833cfcf0f934eab', diff --git a/magnum/tests/unit/objects/utils.py b/magnum/tests/unit/objects/utils.py index c428eaaa9f..2ff6fb55cd 100644 --- a/magnum/tests/unit/objects/utils.py +++ b/magnum/tests/unit/objects/utils.py @@ -154,30 +154,6 @@ def get_test_magnum_service_object(context, **kw): return magnum_service -def create_test_container(context, **kw): - """Create and return a test container object. - - Create a container in the DB and return a container object with - appropriate attributes. - """ - container = get_test_container(context, **kw) - container.create() - return container - - -def get_test_container(context, **kw): - """Return a test container 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_container = db_utils.get_test_container(**kw) - container = objects.Container(context) - for key in db_container: - setattr(container, key, db_container[key]) - return container - - def datetime_or_none(dt): """Validate a datetime or None value.""" if dt is None: