Add bay_uuid attribute to Container model

partially implements blueprint docker-conductor-connect-to-docker-bay

Change-Id: Ied85b4e2a69369ed39be3549e743fd0ea30f13a5
This commit is contained in:
digambar 2015-04-22 17:13:05 +05:30
parent 552879b6a9
commit 14ff11c017
6 changed files with 124 additions and 7 deletions

View File

@ -36,7 +36,10 @@ LOG = logging.getLogger(__name__)
class ContainerPatchType(types.JsonPatchType):
pass
@staticmethod
def mandatory_attrs():
return ['/bay_uuid']
class Container(base.APIBase):
@ -47,6 +50,24 @@ class Container(base.APIBase):
container.
"""
_bay_uuid = None
def _get_bay_uuid(self):
return self._bay_uuid
def _set_bay_uuid(self, value):
if value and self._bay_uuid != value:
try:
bay = objects.Bay.get_by_uuid(pecan.request.context, value)
self._bay_uuid = bay['uuid']
except exception.BayNotFound as e:
# Change error code because 404 (NotFound) is inappropriate
# response for a POST request to create a Service
e.code = 400 # BadRequest
raise e
elif value == wtypes.Unset:
self._bay_uuid = wtypes.Unset
uuid = types.uuid
"""Unique UUID for this container"""
@ -56,6 +77,10 @@ class Container(base.APIBase):
image_id = wtypes.text
"""The image name or UUID to use as a base image for this baymodel"""
bay_uuid = wsme.wsproperty(types.uuid, _get_bay_uuid, _set_bay_uuid,
mandatory=True)
"""Unique UUID of the bay this runs on"""
links = wsme.wsattr([link.Link], readonly=True)
"""A list containing a self link and associated container links"""
@ -74,7 +99,7 @@ class Container(base.APIBase):
@staticmethod
def _convert_with_links(container, url, expand=True):
if not expand:
container.unset_fields_except(['uuid', 'name',
container.unset_fields_except(['uuid', 'name', 'bay_uuid',
'image_id', 'command'])
container.links = [link.Link.make_link('self', url,
@ -97,6 +122,7 @@ class Container(base.APIBase):
name='example',
image_id='ubuntu',
command='env',
bay_uuid="fff114da-3bfa-4a0f-a123-c0dffad9718e",
created_at=datetime.datetime.utcnow(),
updated_at=datetime.datetime.utcnow())
return cls._convert_with_links(sample, 'http://localhost:9511', expand)

View File

@ -0,0 +1,31 @@
# 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.
"""add bay uuid
Revision ID: 2d8657c0cdc
Revises: e772b2598d9
Create Date: 2015-04-22 16:59:06.799384
"""
# revision identifiers, used by Alembic.
revision = '2d8657c0cdc'
down_revision = 'e772b2598d9'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('container', sa.Column('bay_uuid',
sa.String(length=255), nullable=True))

View File

@ -185,6 +185,7 @@ class Container(Base):
name = Column(String(255))
image_id = Column(String(255))
command = Column(String(255))
bay_uuid = Column(String(36))
class Node(Base):

View File

@ -32,6 +32,7 @@ class Container(base.MagnumObject):
'user_id': obj_utils.str_or_none,
'image_id': obj_utils.str_or_none,
'command': obj_utils.str_or_none,
'bay_uuid': obj_utils.str_or_none,
}
@staticmethod

View File

@ -9,13 +9,17 @@
# 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 magnum import objects
from magnum.tests.unit.db import base as db_base
from magnum.tests.unit.db import utils
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')
@ -34,7 +38,8 @@ class TestContainerController(db_base.DbTestCase):
mock_container_stop,
mock_container_start,
mock_container_delete,
mock_container_create):
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
@ -45,7 +50,14 @@ class TestContainerController(db_base.DbTestCase):
mock_container_execute.return_value = None
# Create a container
params = '{"name": "My Docker", "image_id": "ubuntu"}'
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')
@ -106,20 +118,65 @@ class TestContainerController(db_base.DbTestCase):
c = response.json['containers']
self.assertEqual(0, len(c))
@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_container_create,
mock_get_by_uuid):
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"}')
'"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'))
self.assertEqual('env', c.get('command'))
# 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))
@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.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')
self.assertEqual(response.status_int, 201)
# get all containers
response = self.app.get('/v1/containers')
self.assertEqual(response.status_int, 200)

View File

@ -183,6 +183,7 @@ def get_test_container(**kw):
'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'),
}