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:
parent
8b6893e7fb
commit
769c3a423c
|
@ -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()
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue