Allow container name as identifier in API calls

This change adds support for using a Container's name instead of
it's UUID in Container API calls. If there is more than one
Container with the same name, an exception will be raised and the
user will need to provide a UUID instead.

Closes-Bug: #1452650

Change-Id: I058bde5f41016c91cf68a5b5c574d181a58e4836
This commit is contained in:
Andrew Melton 2015-05-08 10:54:53 -07:00
parent 8b6893e7fb
commit 769c3a423c
7 changed files with 384 additions and 143 deletions

View File

@ -152,77 +152,92 @@ class ContainerCollection(collection.Collection):
class StartController(object):
@wsme_pecan.wsexpose(wtypes.text, wtypes.text)
def _default(self, container_uuid):
@wsme_pecan.wsexpose(types.uuid_or_name, wtypes.text)
def _default(self, container_ident):
if pecan.request.method != 'PUT':
pecan.abort(405, ('HTTP method %s is not allowed'
% pecan.request.method))
container_uuid = api_utils.get_rpc_resource('Container',
container_ident).uuid
LOG.debug('Calling conductor.container_start with %s' %
container_uuid)
return pecan.request.rpcapi.container_start(container_uuid)
class StopController(object):
@wsme_pecan.wsexpose(wtypes.text, wtypes.text)
def _default(self, container_uuid, *remainder):
@wsme_pecan.wsexpose(types.uuid_or_name, wtypes.text)
def _default(self, container_ident, *remainder):
if pecan.request.method != 'PUT':
pecan.abort(405, ('HTTP method %s is not allowed'
% pecan.request.method))
container_uuid = api_utils.get_rpc_resource('Container',
container_ident).uuid
LOG.debug('Calling conductor.container_stop with %s' %
container_uuid)
return pecan.request.rpcapi.container_stop(container_uuid)
class RebootController(object):
@wsme_pecan.wsexpose(wtypes.text, wtypes.text)
def _default(self, container_uuid, *remainder):
@wsme_pecan.wsexpose(types.uuid_or_name, wtypes.text)
def _default(self, container_ident, *remainder):
if pecan.request.method != 'PUT':
pecan.abort(405, ('HTTP method %s is not allowed'
% pecan.request.method))
container_uuid = api_utils.get_rpc_resource('Container',
container_ident).uuid
LOG.debug('Calling conductor.container_reboot with %s' %
container_uuid)
return pecan.request.rpcapi.container_reboot(container_uuid)
class PauseController(object):
@wsme_pecan.wsexpose(wtypes.text, wtypes.text)
def _default(self, container_uuid, *remainder):
@wsme_pecan.wsexpose(types.uuid_or_name, wtypes.text)
def _default(self, container_ident, *remainder):
if pecan.request.method != 'PUT':
pecan.abort(405, ('HTTP method %s is not allowed'
% pecan.request.method))
container_uuid = api_utils.get_rpc_resource('Container',
container_ident).uuid
LOG.debug('Calling conductor.container_pause with %s' %
container_uuid)
return pecan.request.rpcapi.container_pause(container_uuid)
class UnpauseController(object):
@wsme_pecan.wsexpose(wtypes.text, wtypes.text)
def _default(self, container_uuid, *remainder):
@wsme_pecan.wsexpose(types.uuid_or_name, wtypes.text)
def _default(self, container_ident, *remainder):
if pecan.request.method != 'PUT':
pecan.abort(405, ('HTTP method %s is not allowed'
% pecan.request.method))
container_uuid = api_utils.get_rpc_resource('Container',
container_ident).uuid
LOG.debug('Calling conductor.container_unpause with %s' %
container_uuid)
return pecan.request.rpcapi.container_unpause(container_uuid)
class LogsController(object):
@wsme_pecan.wsexpose(wtypes.text, wtypes.text)
def _default(self, container_uuid, *remainder):
@wsme_pecan.wsexpose(types.uuid_or_name, wtypes.text)
def _default(self, container_ident, *remainder):
if pecan.request.method != 'GET':
pecan.abort(405, ('HTTP method %s is not allowed'
% pecan.request.method))
container_uuid = api_utils.get_rpc_resource('Container',
container_ident).uuid
LOG.debug('Calling conductor.container_logs with %s' %
container_uuid)
return pecan.request.rpcapi.container_logs(container_uuid)
class ExecuteController(object):
@wsme_pecan.wsexpose(wtypes.text, wtypes.text, wtypes.text)
def _default(self, container_uuid, command, *remainder):
@wsme_pecan.wsexpose(types.uuid_or_name, wtypes.text, wtypes.text)
def _default(self, container_ident, command, *remainder):
if pecan.request.method != 'PUT':
pecan.abort(405, ('HTTP method %s is not allowed'
% pecan.request.method))
container_uuid = api_utils.get_rpc_resource('Container',
container_ident).uuid
LOG.debug('Calling conductor.container_execute with %s command %s'
% (container_uuid, command))
return pecan.request.rpcapi.container_execute(container_uuid, command)
@ -309,17 +324,17 @@ class ContainersController(rest.RestController):
sort_key, sort_dir, expand,
resource_url)
@wsme_pecan.wsexpose(Container, types.uuid)
def get_one(self, container_uuid):
@wsme_pecan.wsexpose(Container, types.uuid_or_name)
def get_one(self, container_ident):
"""Retrieve information about the given container.
:param container_uuid: UUID of a container.
:param container_ident: UUID or name of a container.
"""
if self.from_containers:
raise exception.OperationNotPermitted
rpc_container = objects.Container.get_by_uuid(pecan.request.context,
container_uuid)
rpc_container = api_utils.get_rpc_resource('Container',
container_ident)
return Container.convert_with_links(rpc_container)
@wsme_pecan.wsexpose(Container, body=Container, status_code=201)
@ -348,18 +363,19 @@ class ContainersController(rest.RestController):
return Container.convert_with_links(res_container)
@wsme.validate(types.uuid, [ContainerPatchType])
@wsme_pecan.wsexpose(Container, types.uuid, body=[ContainerPatchType])
def patch(self, container_uuid, patch):
@wsme_pecan.wsexpose(Container, types.uuid_or_name,
body=[ContainerPatchType])
def patch(self, container_ident, patch):
"""Update an existing container.
:param container_uuid: UUID of a container.
:param container_ident: UUID or name of a container.
:param patch: a json PATCH document to apply to this container.
"""
if self.from_containers:
raise exception.OperationNotPermitted
rpc_container = objects.Container.get_by_uuid(pecan.request.context,
container_uuid)
rpc_container = api_utils.get_rpc_resource('Container',
container_ident)
try:
container_dict = rpc_container.as_dict()
container = Container(**api_utils.apply_jsonpatch(
@ -382,8 +398,8 @@ class ContainersController(rest.RestController):
rpc_container.save()
return Container.convert_with_links(rpc_container)
@wsme_pecan.wsexpose(None, types.uuid, status_code=204)
def delete(self, container_uuid):
@wsme_pecan.wsexpose(None, types.uuid_or_name, status_code=204)
def delete(self, container_ident):
"""Delete a container.
:param container_uuid: UUID of a container.
@ -391,7 +407,7 @@ class ContainersController(rest.RestController):
if self.from_containers:
raise exception.OperationNotPermitted
rpc_container = objects.Container.get_by_uuid(pecan.request.context,
container_uuid)
pecan.request.rpcapi.container_delete(container_uuid)
rpc_container = api_utils.get_rpc_resource('Container',
container_ident)
pecan.request.rpcapi.container_delete(rpc_container.uuid)
rpc_container.destroy()

View File

@ -304,6 +304,15 @@ class Connection(object):
: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.

View File

@ -456,6 +456,19 @@ class Connection(api.Connection):
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():

View File

@ -73,6 +73,18 @@ class Container(base.MagnumObject):
container = Container._from_db_object(cls(context), db_container)
return container
@base.remotable_classmethod
def get_by_name(cls, context, name):
"""Find a bay based on name and return a Bay object.
:param name: the logical name of a bay.
:param context: Security context
:returns: a :class:`Bay` 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):

View File

@ -14,136 +14,47 @@ from magnum import objects
from magnum.tests.unit.db import base as db_base
from magnum.tests.unit.db import utils
import mock
from mock import patch
from webtest.app import AppError
class TestContainerController(db_base.DbTestCase):
@patch('magnum.objects.bay.Bay.get_by_uuid')
@patch('magnum.conductor.api.API.container_create')
@patch('magnum.conductor.api.API.container_delete')
@patch('magnum.conductor.api.API.container_start')
@patch('magnum.conductor.api.API.container_stop')
@patch('magnum.conductor.api.API.container_pause')
@patch('magnum.conductor.api.API.container_unpause')
@patch('magnum.conductor.api.API.container_reboot')
@patch('magnum.conductor.api.API.container_logs')
@patch('magnum.conductor.api.API.container_execute')
def test_containers_api(self,
mock_container_execute,
mock_container_logs,
mock_container_reboot,
mock_container_unpause,
mock_container_pause,
mock_container_stop,
mock_container_start,
mock_container_delete,
mock_container_create,
mock_get_by_uuid):
mock_container_create.side_effect = lambda x, y, z: z
mock_container_start.return_value = None
mock_container_stop.return_value = None
mock_container_pause.return_value = None
mock_container_unpause.return_value = None
mock_container_reboot.return_value = None
mock_container_logs.return_value = None
mock_container_execute.return_value = None
def setUp(self):
super(TestContainerController, self).setUp()
self.bay_get_by_uuid_patch = patch('magnum.objects.Bay.get_by_uuid')
self.mock_bay_get_by_uuid = self.bay_get_by_uuid_patch.start()
self.addCleanup(self.bay_get_by_uuid_patch.stop)
def fake_get_by_uuid(context, uuid):
return objects.Bay(self.context, **utils.get_test_bay(uuid=uuid))
self.mock_bay_get_by_uuid.side_effect = fake_get_by_uuid
@patch('magnum.conductor.api.API.container_create')
def test_create_container(self, mock_container_create,):
mock_container_create.side_effect = lambda x, y, z: z
# Create a container
params = ('{"name": "My Docker", "image_id": "ubuntu",'
'"command": "env",'
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e"}')
self.fake_bay = utils.get_test_bay()
value = self.fake_bay['uuid']
mock_get_by_uuid.return_value = self.fake_bay
bay = objects.Bay.get_by_uuid(self.context, value)
self.assertEqual(value, bay['uuid'])
response = self.app.post('/v1/containers',
params=params,
content_type='application/json')
self.assertEqual(response.status_int, 201)
# Get all containers
response = self.app.get('/v1/containers')
self.assertEqual(response.status_int, 200)
self.assertEqual(1, len(response.json))
c = response.json['containers'][0]
self.assertIsNotNone(c.get('uuid'))
self.assertEqual('My Docker', c.get('name'))
# Get just the one we created
response = self.app.get('/v1/containers/%s' % c.get('uuid'))
self.assertEqual(response.status_int, 200)
# Update the description
params = [{'path': '/name',
'value': 'container_example_B',
'op': 'replace'}]
response = self.app.patch_json('/v1/containers/%s' % c.get('uuid'),
params=params)
self.assertEqual(response.status_int, 200)
# Execute some actions
actions = ['start', 'stop', 'pause', 'unpause',
'reboot']
for action in actions:
response = self.app.put('/v1/containers/%s/%s' % (c.get('uuid'),
action))
self.assertEqual(response.status_int, 200)
# Only PUT should work, others like GET should fail
self.assertRaises(AppError, self.app.get,
('/v1/containers/%s/%s' %
(c.get('uuid'), action)))
# Fetch the logs
response = self.app.get('/v1/containers/%s/logs' % c.get('uuid'))
self.assertEqual(response.status_int, 200)
# Fetch the logs should fail with put
self.assertRaises(AppError, self.app.put,
('/v1/containers/%s/logs' % c.get('uuid')))
# Execute command in docker container
response = self.app.put('/v1/containers/%s/%s' % (c.get('uuid'),
'execute'), {'command': 'ls'})
self.assertEqual(response.status_int, 200)
# Delete the container we created
response = self.app.delete('/v1/containers/%s' % c.get('uuid'))
self.assertEqual(response.status_int, 204)
response = self.app.get('/v1/containers')
self.assertEqual(response.status_int, 200)
c = response.json['containers']
self.assertEqual(0, len(c))
self.assertTrue(mock_container_create.called)
self.assertTrue(mock_container_start.called)
self.assertTrue(mock_container_stop.called)
self.assertTrue(mock_container_pause.called)
self.assertTrue(mock_container_unpause.called)
self.assertTrue(mock_container_reboot.called)
self.assertTrue(mock_container_logs.called)
self.assertTrue(mock_container_execute.called)
@patch('magnum.objects.bay.Bay.get_by_uuid')
@patch('magnum.conductor.api.API.container_create')
@patch('magnum.conductor.api.API.container_delete')
def test_create_container_with_command(self,
mock_container_delete,
mock_container_create,
mock_get_by_uuid):
mock_container_create):
mock_container_create.side_effect = lambda x, y, z: z
# Create a container with a command
params = ('{"name": "My Docker", "image_id": "ubuntu",'
'"command": "env",'
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e"}')
self.fake_bay = utils.get_test_bay()
value = self.fake_bay['uuid']
mock_get_by_uuid.return_value = self.fake_bay
bay = objects.Bay.get_by_uuid(self.context, value)
self.assertEqual(value, bay['uuid'])
response = self.app.post('/v1/containers',
params=params,
content_type='application/json')
@ -166,23 +77,16 @@ class TestContainerController(db_base.DbTestCase):
self.assertEqual(0, len(c))
self.assertTrue(mock_container_create.called)
@patch('magnum.objects.bay.Bay.get_by_uuid')
@patch('magnum.conductor.api.API.container_create')
@patch('magnum.conductor.api.API.container_delete')
def test_create_container_with_bay_uuid(self,
mock_container_delete,
mock_container_create,
mock_get_by_uuid):
mock_container_create):
mock_container_create.side_effect = lambda x, y, z: z
# Create a container with a command
params = ('{"name": "My Docker", "image_id": "ubuntu",'
'"command": "env",'
'"bay_uuid": "fff114da-3bfa-4a0f-a123-c0dffad9718e"}')
self.fake_bay = utils.get_test_bay()
value = self.fake_bay['uuid']
mock_get_by_uuid.return_value = self.fake_bay
bay = objects.Bay.get_by_uuid(self.context, value)
self.assertEqual(value, bay['uuid'])
response = self.app.post('/v1/containers',
params=params,
content_type='application/json')
@ -223,3 +127,274 @@ class TestContainerController(db_base.DbTestCase):
self.assertRaises(AppError, self.app.post, '/v1/containers',
params=params, content_type='application/json')
self.assertTrue(mock_container_create.not_called)
@patch('magnum.objects.Container.list')
def test_get_all_containers(self, mock_container_list):
test_container = utils.get_test_container()
containers = [objects.Container(self.context, **test_container)]
mock_container_list.return_value = containers
response = self.app.get('/v1/containers')
mock_container_list.assert_called_once_with(mock.ANY,
1000, None, sort_dir='asc',
sort_key='id')
self.assertEqual(response.status_int, 200)
actual_containers = response.json['containers']
self.assertEqual(len(actual_containers), 1)
self.assertEqual(actual_containers[0].get('uuid'),
test_container['uuid'])
@patch('magnum.objects.Container.get_by_uuid')
def test_get_one_by_uuid(self, mock_container_get_by_uuid):
test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container)
mock_container_get_by_uuid.return_value = test_container_obj
response = self.app.get('/v1/containers/%s' % test_container['uuid'])
mock_container_get_by_uuid.assert_called_once_with(mock.ANY,
test_container['uuid'])
self.assertEqual(response.status_int, 200)
self.assertEqual(response.json['uuid'],
test_container['uuid'])
@patch('magnum.objects.Container.get_by_name')
def test_get_one_by_name(self, mock_container_get_by_name):
test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container)
mock_container_get_by_name.return_value = test_container_obj
response = self.app.get('/v1/containers/%s' % test_container['name'])
mock_container_get_by_name.assert_called_once_with(mock.ANY,
test_container['name'])
self.assertEqual(response.status_int, 200)
self.assertEqual(response.json['uuid'],
test_container['uuid'])
@patch('magnum.objects.Container.get_by_uuid')
def test_patch_by_uuid(self, mock_container_get_by_uuid):
test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container)
mock_container_get_by_uuid.return_value = test_container_obj
with patch.object(test_container_obj, 'save') as mock_save:
params = [{'path': '/name',
'value': 'new_name',
'op': 'replace'}]
container_uuid = test_container.get('uuid')
response = self.app.patch_json(
'/v1/containers/%s' % container_uuid,
params=params)
mock_save.assert_called_once_with()
self.assertEqual(response.status_int, 200)
self.assertEqual(test_container_obj.name, 'new_name')
@patch('magnum.objects.Container.get_by_name')
def test_patch_by_name(self, mock_container_get_by_name):
test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container)
mock_container_get_by_name.return_value = test_container_obj
with patch.object(test_container_obj, 'save') as mock_save:
params = [{'path': '/name',
'value': 'new_name',
'op': 'replace'}]
container_name = test_container.get('name')
response = self.app.patch_json(
'/v1/containers/%s' % container_name,
params=params)
mock_save.assert_called_once_with()
self.assertEqual(response.status_int, 200)
self.assertEqual(test_container_obj.name, 'new_name')
def _action_test(self, container, action, ident_field):
test_container_obj = objects.Container(self.context, **container)
ident = container.get(ident_field)
get_by_ident_loc = 'magnum.objects.Container.get_by_%s' % ident_field
with patch(get_by_ident_loc) as mock_get_by_indent:
mock_get_by_indent.return_value = test_container_obj
response = self.app.put('/v1/containers/%s/%s' % (ident,
action))
self.assertEqual(response.status_int, 200)
# Only PUT should work, others like GET should fail
self.assertRaises(AppError, self.app.get,
('/v1/containers/%s/%s' %
(ident, action)))
@patch('magnum.conductor.api.API.container_start')
def test_start_by_uuid(self, mock_container_start):
test_container = utils.get_test_container()
self._action_test(test_container, 'start', 'uuid')
mock_container_start.assert_called_once_with(
test_container.get('uuid'))
@patch('magnum.conductor.api.API.container_start')
def test_start_by_name(self, mock_container_start):
test_container = utils.get_test_container()
self._action_test(test_container, 'start', 'name')
mock_container_start.assert_called_once_with(
test_container.get('uuid'))
@patch('magnum.conductor.api.API.container_stop')
def test_stop_by_uuid(self, mock_container_stop):
test_container = utils.get_test_container()
self._action_test(test_container, 'stop', 'uuid')
mock_container_stop.assert_called_once_with(
test_container.get('uuid'))
@patch('magnum.conductor.api.API.container_stop')
def test_stop_by_name(self, mock_container_stop):
test_container = utils.get_test_container()
self._action_test(test_container, 'stop', 'name')
mock_container_stop.assert_called_once_with(
test_container.get('uuid'))
@patch('magnum.conductor.api.API.container_pause')
def test_pause_by_uuid(self, mock_container_pause):
test_container = utils.get_test_container()
self._action_test(test_container, 'pause', 'uuid')
mock_container_pause.assert_called_once_with(
test_container.get('uuid'))
@patch('magnum.conductor.api.API.container_pause')
def test_pause_by_name(self, mock_container_pause):
test_container = utils.get_test_container()
self._action_test(test_container, 'pause', 'name')
mock_container_pause.assert_called_once_with(
test_container.get('uuid'))
@patch('magnum.conductor.api.API.container_unpause')
def test_unpause_by_uuid(self, mock_container_unpause):
test_container = utils.get_test_container()
self._action_test(test_container, 'unpause', 'uuid')
mock_container_unpause.assert_called_once_with(
test_container.get('uuid'))
@patch('magnum.conductor.api.API.container_unpause')
def test_unpause_by_name(self, mock_container_unpause):
test_container = utils.get_test_container()
self._action_test(test_container, 'unpause', 'name')
mock_container_unpause.assert_called_once_with(
test_container.get('uuid'))
@patch('magnum.conductor.api.API.container_reboot')
def test_reboot_by_uuid(self, mock_container_reboot):
test_container = utils.get_test_container()
self._action_test(test_container, 'reboot', 'uuid')
mock_container_reboot.assert_called_once_with(
test_container.get('uuid'))
@patch('magnum.conductor.api.API.container_reboot')
def test_reboot_by_name(self, mock_container_reboot):
test_container = utils.get_test_container()
self._action_test(test_container, 'reboot', 'name')
mock_container_reboot.assert_called_once_with(
test_container.get('uuid'))
@patch('magnum.conductor.api.API.container_logs')
@patch('magnum.objects.Container.get_by_uuid')
def test_get_logs_by_uuid(self, mock_get_by_uuid, mock_container_logs):
test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container)
mock_get_by_uuid.return_value = test_container_obj
container_uuid = test_container.get('uuid')
response = self.app.get('/v1/containers/%s/logs' % container_uuid)
self.assertEqual(response.status_int, 200)
mock_container_logs.assert_called_once_with(container_uuid)
@patch('magnum.conductor.api.API.container_logs')
@patch('magnum.objects.Container.get_by_name')
def test_get_logs_by_name(self, mock_get_by_name, mock_container_logs):
test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container)
mock_get_by_name.return_value = test_container_obj
container_name = test_container.get('name')
container_uuid = test_container.get('uuid')
response = self.app.get('/v1/containers/%s/logs' % container_name)
self.assertEqual(response.status_int, 200)
mock_container_logs.assert_called_once_with(container_uuid)
@patch('magnum.conductor.api.API.container_logs')
@patch('magnum.objects.Container.get_by_uuid')
def test_get_logs_put_fails(self, mock_get_by_uuid, mock_container_logs):
test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container)
mock_get_by_uuid.return_value = test_container_obj
container_uuid = test_container.get('uuid')
self.assertRaises(AppError, self.app.put,
'/v1/containers/%s/logs' % container_uuid)
self.assertFalse(mock_container_logs.called)
@patch('magnum.conductor.api.API.container_execute')
@patch('magnum.objects.Container.get_by_uuid')
def test_execute_command_by_uuid(self, mock_get_by_uuid,
mock_container_execute):
test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container)
mock_get_by_uuid.return_value = test_container_obj
container_uuid = test_container.get('uuid')
url = '/v1/containers/%s/%s' % (container_uuid, 'execute')
cmd = {'command': 'ls'}
response = self.app.put(url, cmd)
self.assertEqual(response.status_int, 200)
mock_container_execute.assert_called_one_with(container_uuid, cmd)
@patch('magnum.conductor.api.API.container_execute')
@patch('magnum.objects.Container.get_by_name')
def test_execute_command_by_name(self, mock_get_by_name,
mock_container_execute):
test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container)
mock_get_by_name.return_value = test_container_obj
container_name = test_container.get('name')
container_uuid = test_container.get('uuid')
url = '/v1/containers/%s/%s' % (container_name, 'execute')
cmd = {'command': 'ls'}
response = self.app.put(url, cmd)
self.assertEqual(response.status_int, 200)
mock_container_execute.assert_called_one_with(container_uuid, cmd)
@patch('magnum.conductor.api.API.container_delete')
@patch('magnum.objects.Container.get_by_uuid')
def test_delete_container_by_uuid(self, mock_get_by_uuid,
mock_container_delete):
test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container)
mock_get_by_uuid.return_value = test_container_obj
with patch.object(test_container_obj, 'destroy') as mock_destroy:
container_uuid = test_container.get('uuid')
response = self.app.delete('/v1/containers/%s' % container_uuid)
self.assertEqual(response.status_int, 204)
mock_container_delete.assert_called_once_with(container_uuid)
mock_destroy.assert_called_once_with()
@patch('magnum.conductor.api.API.container_delete')
@patch('magnum.objects.Container.get_by_name')
def test_delete_container_by_name(self, mock_get_by_name,
mock_container_delete):
test_container = utils.get_test_container()
test_container_obj = objects.Container(self.context, **test_container)
mock_get_by_name.return_value = test_container_obj
with patch.object(test_container_obj, 'destroy') as mock_destroy:
container_name = test_container.get('name')
container_uuid = test_container.get('uuid')
response = self.app.delete('/v1/containers/%s' % container_name)
self.assertEqual(response.status_int, 204)
mock_container_delete.assert_called_once_with(container_uuid)
mock_destroy.assert_called_once_with()

View File

@ -46,6 +46,13 @@ class DbContainerTestCase(base.DbTestCase):
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)

View File

@ -48,6 +48,15 @@ class TestContainerObject(base.DbTestCase):
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: