Add field for container status

This adds an enum for the different statuses and changes over to use
those constants in docker conducter.

An UNKNOWN value was also added because the API tests expected 'Unknown'
so this value needed to be added to the field in order to be valid.

Change-Id: Ic79317f0fbdaf99c1979d3023f04c4eba44b412a
Closes-Bug: #1489136
This commit is contained in:
Ryan Rossiter 2015-08-26 21:44:39 +00:00
parent cac328d1c4
commit 5ac2dce563
7 changed files with 76 additions and 39 deletions

View File

@ -32,6 +32,7 @@ from magnum.common import exception
from magnum.common import policy from magnum.common import policy
from magnum.i18n import _LE from magnum.i18n import _LE
from magnum import objects from magnum import objects
from magnum.objects import fields
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -291,7 +292,7 @@ class ContainersController(rest.RestController):
LOG.exception(_LE("Error while list container %(uuid)s: " LOG.exception(_LE("Error while list container %(uuid)s: "
"%(e)s."), "%(e)s."),
{'uuid': c.uuid, 'e': e}) {'uuid': c.uuid, 'e': e})
containers[i].status = objects.container.UNKNOWN containers[i].status = fields.ContainerStatus.UNKNOWN
return ContainerCollection.convert_with_links(containers, limit, return ContainerCollection.convert_with_links(containers, limit,
url=resource_url, url=resource_url,

View File

@ -25,7 +25,7 @@ from magnum.conductor.handlers.common import docker_client
from magnum.conductor import utils as conductor_utils from magnum.conductor import utils as conductor_utils
from magnum.i18n import _LE from magnum.i18n import _LE
from magnum import objects from magnum import objects
from magnum.objects import container as obj_container from magnum.objects import fields
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
CONF = cfg.CONF CONF = cfg.CONF
@ -130,10 +130,10 @@ class Handler(object):
docker.create_container(image, name=name, docker.create_container(image, name=name,
hostname=container_uuid, hostname=container_uuid,
command=container.command) command=container.command)
container.status = obj_container.STOPPED container.status = fields.ContainerStatus.STOPPED
return container return container
except errors.APIError as api_error: except errors.APIError as api_error:
container.status = obj_container.ERROR container.status = fields.ContainerStatus.ERROR
raise exception.ContainerException( raise exception.ContainerException(
"Docker API Error : %s" % str(api_error)) "Docker API Error : %s" % str(api_error))
finally: finally:
@ -162,26 +162,26 @@ class Handler(object):
if not docker_id: if not docker_id:
LOG.exception(_LE("Can not find docker instance with %s," LOG.exception(_LE("Can not find docker instance with %s,"
"set it to Error status"), container_uuid) "set it to Error status"), container_uuid)
container.status = obj_container.ERROR container.status = fields.ContainerStatus.ERROR
container.save() container.save()
return container return container
result = docker.inspect_container(docker_id) result = docker.inspect_container(docker_id)
status = result.get('State') status = result.get('State')
if status: if status:
if status.get('Error') is True: if status.get('Error') is True:
container.status = obj_container.ERROR container.status = fields.ContainerStatus.ERROR
elif status.get('Running'): elif status.get('Running'):
container.status = obj_container.RUNNING container.status = fields.ContainerStatus.RUNNING
elif status.get('Paused'): elif status.get('Paused'):
container.status = obj_container.PAUSED container.status = fields.ContainerStatus.PAUSED
else: else:
container.status = obj_container.STOPPED container.status = fields.ContainerStatus.STOPPED
container.save() container.save()
return container return container
except errors.APIError as api_error: except errors.APIError as api_error:
error_message = str(api_error) error_message = str(api_error)
if '404' in error_message: if '404' in error_message:
container.status = obj_container.ERROR container.status = fields.ContainerStatus.ERROR
container.save() container.save()
return container return container
raise exception.ContainerException( raise exception.ContainerException(
@ -204,23 +204,25 @@ class Handler(object):
def container_reboot(self, context, container_uuid): def container_reboot(self, context, container_uuid):
return self._container_action(context, container_uuid, return self._container_action(context, container_uuid,
obj_container.RUNNING, 'restart') fields.ContainerStatus.RUNNING,
'restart')
def container_stop(self, context, container_uuid): def container_stop(self, context, container_uuid):
return self._container_action(context, container_uuid, return self._container_action(context, container_uuid,
obj_container.STOPPED, 'stop') fields.ContainerStatus.STOPPED, 'stop')
def container_start(self, context, container_uuid): def container_start(self, context, container_uuid):
return self._container_action(context, container_uuid, return self._container_action(context, container_uuid,
obj_container.RUNNING, 'start') fields.ContainerStatus.RUNNING, 'start')
def container_pause(self, context, container_uuid): def container_pause(self, context, container_uuid):
return self._container_action(context, container_uuid, return self._container_action(context, container_uuid,
obj_container.PAUSED, 'pause') fields.ContainerStatus.PAUSED, 'pause')
def container_unpause(self, context, container_uuid): def container_unpause(self, context, container_uuid):
return self._container_action(context, container_uuid, return self._container_action(context, container_uuid,
obj_container.RUNNING, 'unpause') fields.ContainerStatus.RUNNING,
'unpause')
@wrap_container_exception @wrap_container_exception
def container_logs(self, context, container_uuid): def container_logs(self, context, container_uuid):

View File

@ -18,13 +18,7 @@ from oslo_versionedobjects import fields
from magnum.db import api as dbapi from magnum.db import api as dbapi
from magnum.objects import base from magnum.objects import base
from magnum.objects import fields as m_fields
# possible status
ERROR = 'Error'
RUNNING = 'Running'
STOPPED = 'Stopped'
PAUSED = 'Paused'
UNKNOWN = 'Unknown'
@base.MagnumObjectRegistry.register @base.MagnumObjectRegistry.register
@ -44,7 +38,7 @@ class Container(base.MagnumPersistentObject, base.MagnumObject,
'image': fields.StringField(nullable=True), 'image': fields.StringField(nullable=True),
'command': fields.StringField(nullable=True), 'command': fields.StringField(nullable=True),
'bay_uuid': fields.StringField(nullable=True), 'bay_uuid': fields.StringField(nullable=True),
'status': fields.StringField(nullable=True), 'status': m_fields.ContainerStatusField(nullable=True),
} }
@staticmethod @staticmethod

View File

@ -34,9 +34,25 @@ class BayStatus(fields.Enum):
super(BayStatus, self).__init__(valid_values=BayStatus.ALL) super(BayStatus, self).__init__(valid_values=BayStatus.ALL)
class ContainerStatus(fields.Enum):
ALL = (
ERROR, RUNNING, STOPPED, PAUSED, UNKNOWN,
) = (
'Error', 'Running', 'Stopped', 'Paused', 'Unknown',
)
def __init__(self):
super(ContainerStatus, self).__init__(
valid_values=ContainerStatus.ALL)
class ListOfDictsField(fields.AutoTypedField): class ListOfDictsField(fields.AutoTypedField):
AUTO_TYPE = fields.List(fields.Dict(fields.FieldType())) AUTO_TYPE = fields.List(fields.Dict(fields.FieldType()))
class BayStatusField(fields.BaseEnumField): class BayStatusField(fields.BaseEnumField):
AUTO_TYPE = BayStatus() AUTO_TYPE = BayStatus()
class ContainerStatusField(fields.BaseEnumField):
AUTO_TYPE = ContainerStatus()

View File

@ -12,6 +12,7 @@
from magnum.common import utils as comm_utils from magnum.common import utils as comm_utils
from magnum import objects from magnum import objects
from magnum.objects import fields
from magnum.tests.unit.api import base as api_base from magnum.tests.unit.api import base as api_base
from magnum.tests.unit.db import utils from magnum.tests.unit.db import utils
@ -253,7 +254,7 @@ class TestContainerController(api_base.FunctionalTest):
test_container['uuid']) test_container['uuid'])
self.assertEqual(actual_containers[0].get('status'), self.assertEqual(actual_containers[0].get('status'),
objects.container.UNKNOWN) fields.ContainerStatus.UNKNOWN)
@patch('magnum.conductor.api.API.container_show') @patch('magnum.conductor.api.API.container_show')
@patch('magnum.objects.Container.get_by_uuid') @patch('magnum.objects.Container.get_by_uuid')

View File

@ -20,7 +20,7 @@ import six
from magnum.common import exception from magnum.common import exception
from magnum.conductor.handlers import docker_conductor from magnum.conductor.handlers import docker_conductor
from magnum import objects from magnum import objects
from magnum.objects import container as obj_container from magnum.objects import fields
from magnum.tests import base from magnum.tests import base
from mock import patch from mock import patch
@ -129,7 +129,7 @@ class TestDockerConductor(base.BaseTestCase):
name='some-name', name='some-name',
hostname='some-uuid', hostname='some-uuid',
command=None) command=None)
self.assertEqual(obj_container.STOPPED, container.status) self.assertEqual(fields.ContainerStatus.STOPPED, container.status)
@mock.patch.object(docker_conductor.Handler, 'get_docker_client') @mock.patch.object(docker_conductor.Handler, 'get_docker_client')
def test_container_create_with_command(self, mock_get_docker_client): def test_container_create_with_command(self, mock_get_docker_client):
@ -154,7 +154,7 @@ class TestDockerConductor(base.BaseTestCase):
name='some-name', name='some-name',
hostname='some-uuid', hostname='some-uuid',
command='env') command='env')
self.assertEqual(obj_container.STOPPED, container.status) self.assertEqual(fields.ContainerStatus.STOPPED, container.status)
def test_encode_utf8_unicode(self): def test_encode_utf8_unicode(self):
image = 'some_image:some_tag' image = 'some_image:some_tag'
@ -181,7 +181,8 @@ class TestDockerConductor(base.BaseTestCase):
tag='some_tag') tag='some_tag')
self.assertFalse(mock_docker.create_container.called) self.assertFalse(mock_docker.create_container.called)
mock_init.assert_called_once_with() mock_init.assert_called_once_with()
self.assertEqual(obj_container.ERROR, mock_container.status) self.assertEqual(fields.ContainerStatus.ERROR,
mock_container.status)
def test_find_container_by_name_not_found(self): def test_find_container_by_name_not_found(self):
mock_docker = mock.MagicMock() mock_docker = mock.MagicMock()
@ -282,7 +283,7 @@ class TestDockerConductor(base.BaseTestCase):
mock_docker.restart.assert_called_once_with(mock_docker_id) mock_docker.restart.assert_called_once_with(mock_docker_id)
mock_find_container.assert_called_once_with(mock_docker, mock_find_container.assert_called_once_with(mock_docker,
mock_container_uuid) mock_container_uuid)
self.assertEqual(obj_container.RUNNING, mock_container.status) self.assertEqual(fields.ContainerStatus.RUNNING, mock_container.status)
@patch.object(docker_conductor.Handler, '_find_container_by_name') @patch.object(docker_conductor.Handler, '_find_container_by_name')
@mock.patch.object(docker_conductor.Handler, 'get_docker_client') @mock.patch.object(docker_conductor.Handler, 'get_docker_client')
@ -323,7 +324,7 @@ class TestDockerConductor(base.BaseTestCase):
mock_docker.start.assert_called_once_with(mock_docker_id) mock_docker.start.assert_called_once_with(mock_docker_id)
mock_find_container.assert_called_once_with(mock_docker, mock_find_container.assert_called_once_with(mock_docker,
mock_container_uuid) mock_container_uuid)
self.assertEqual(obj_container.RUNNING, mock_container.status) self.assertEqual(fields.ContainerStatus.RUNNING, mock_container.status)
@patch.object(docker_conductor.Handler, '_find_container_by_name') @patch.object(docker_conductor.Handler, '_find_container_by_name')
@mock.patch.object(docker_conductor.Handler, 'get_docker_client') @mock.patch.object(docker_conductor.Handler, 'get_docker_client')
@ -364,7 +365,7 @@ class TestDockerConductor(base.BaseTestCase):
mock_docker.stop.assert_called_once_with(mock_docker_id) mock_docker.stop.assert_called_once_with(mock_docker_id)
mock_find_container.assert_called_once_with(mock_docker, mock_find_container.assert_called_once_with(mock_docker,
mock_container_uuid) mock_container_uuid)
self.assertEqual(obj_container.STOPPED, mock_container.status) self.assertEqual(fields.ContainerStatus.STOPPED, mock_container.status)
@patch.object(docker_conductor.Handler, '_find_container_by_name') @patch.object(docker_conductor.Handler, '_find_container_by_name')
@mock.patch.object(docker_conductor.Handler, 'get_docker_client') @mock.patch.object(docker_conductor.Handler, 'get_docker_client')
@ -404,7 +405,7 @@ class TestDockerConductor(base.BaseTestCase):
mock_docker.pause.assert_called_once_with(mock_docker_id) mock_docker.pause.assert_called_once_with(mock_docker_id)
mock_find_container.assert_called_once_with(mock_docker, mock_find_container.assert_called_once_with(mock_docker,
mock_container_uuid) mock_container_uuid)
self.assertEqual(obj_container.PAUSED, mock_container.status) self.assertEqual(fields.ContainerStatus.PAUSED, mock_container.status)
@patch.object(docker_conductor.Handler, '_find_container_by_name') @patch.object(docker_conductor.Handler, '_find_container_by_name')
@mock.patch.object(docker_conductor.Handler, 'get_docker_client') @mock.patch.object(docker_conductor.Handler, 'get_docker_client')
@ -444,7 +445,7 @@ class TestDockerConductor(base.BaseTestCase):
mock_docker.unpause.assert_called_once_with(mock_docker_id) mock_docker.unpause.assert_called_once_with(mock_docker_id)
mock_find_container.assert_called_once_with(mock_docker, mock_find_container.assert_called_once_with(mock_docker,
mock_container_uuid) mock_container_uuid)
self.assertEqual(obj_container.RUNNING, mock_container.status) self.assertEqual(fields.ContainerStatus.RUNNING, mock_container.status)
@patch.object(docker_conductor.Handler, '_find_container_by_name') @patch.object(docker_conductor.Handler, '_find_container_by_name')
@mock.patch.object(docker_conductor.Handler, 'get_docker_client') @mock.patch.object(docker_conductor.Handler, 'get_docker_client')
@ -505,7 +506,7 @@ class TestDockerConductor(base.BaseTestCase):
'Paused': False}} 'Paused': False}}
mock_docker.inspect_container.return_value = mock_container_detail mock_docker.inspect_container.return_value = mock_container_detail
self.conductor.container_show(None, mock_container_uuid) self.conductor.container_show(None, mock_container_uuid)
self.assertEqual(obj_container.RUNNING, mock_container.status) self.assertEqual(fields.ContainerStatus.RUNNING, mock_container.status)
@mock.patch.object(objects.Container, 'get_by_uuid') @mock.patch.object(objects.Container, 'get_by_uuid')
@mock.patch.object(docker_conductor.Handler, '_find_container_by_name') @mock.patch.object(docker_conductor.Handler, '_find_container_by_name')
@ -525,7 +526,7 @@ class TestDockerConductor(base.BaseTestCase):
'Paused': False}} 'Paused': False}}
mock_docker.inspect_container.return_value = mock_container_detail mock_docker.inspect_container.return_value = mock_container_detail
self.conductor.container_show(None, mock_container_uuid) self.conductor.container_show(None, mock_container_uuid)
self.assertEqual(obj_container.STOPPED, mock_container.status) self.assertEqual(fields.ContainerStatus.STOPPED, mock_container.status)
@mock.patch.object(objects.Container, 'get_by_uuid') @mock.patch.object(objects.Container, 'get_by_uuid')
@mock.patch.object(docker_conductor.Handler, '_find_container_by_name') @mock.patch.object(docker_conductor.Handler, '_find_container_by_name')
@ -545,7 +546,7 @@ class TestDockerConductor(base.BaseTestCase):
'Paused': True}} 'Paused': True}}
mock_docker.inspect_container.return_value = mock_container_detail mock_docker.inspect_container.return_value = mock_container_detail
self.conductor.container_show(None, mock_container_uuid) self.conductor.container_show(None, mock_container_uuid)
self.assertEqual(obj_container.PAUSED, mock_container.status) self.assertEqual(fields.ContainerStatus.PAUSED, mock_container.status)
@mock.patch.object(objects.Container, 'get_by_uuid') @mock.patch.object(objects.Container, 'get_by_uuid')
@mock.patch.object(docker_conductor.Handler, '_find_container_by_name') @mock.patch.object(docker_conductor.Handler, '_find_container_by_name')
@ -565,7 +566,7 @@ class TestDockerConductor(base.BaseTestCase):
'Paused': False}} 'Paused': False}}
mock_docker.inspect_container.return_value = mock_container_detail mock_docker.inspect_container.return_value = mock_container_detail
self.conductor.container_show(None, mock_container_uuid) self.conductor.container_show(None, mock_container_uuid)
self.assertEqual(obj_container.ERROR, mock_container.status) self.assertEqual(fields.ContainerStatus.ERROR, mock_container.status)
@mock.patch.object(objects.Container, 'get_by_uuid') @mock.patch.object(objects.Container, 'get_by_uuid')
@patch.object(docker_conductor.Handler, '_find_container_by_name') @patch.object(docker_conductor.Handler, '_find_container_by_name')
@ -615,7 +616,8 @@ class TestDockerConductor(base.BaseTestCase):
mock_find_container.assert_called_once_with(mock_docker, mock_find_container.assert_called_once_with(mock_docker,
mock_container_uuid) mock_container_uuid)
mock_init.assert_called_once_with() mock_init.assert_called_once_with()
self.assertEqual(obj_container.ERROR, mock_container.status) self.assertEqual(fields.ContainerStatus.ERROR,
mock_container.status)
@mock.patch.object(objects.Container, 'get_by_uuid') @mock.patch.object(objects.Container, 'get_by_uuid')
@patch.object(docker_conductor.Handler, '_find_container_by_name') @patch.object(docker_conductor.Handler, '_find_container_by_name')
@ -634,7 +636,7 @@ class TestDockerConductor(base.BaseTestCase):
self.conductor.container_show(None, mock_container_uuid) self.conductor.container_show(None, mock_container_uuid)
mock_find_container.assert_called_once_with(mock_docker, mock_find_container.assert_called_once_with(mock_docker,
mock_container_uuid) mock_container_uuid)
self.assertEqual(obj_container.ERROR, mock_container.status) self.assertEqual(fields.ContainerStatus.ERROR, mock_container.status)
@patch.object(docker_conductor.Handler, '_find_container_by_name') @patch.object(docker_conductor.Handler, '_find_container_by_name')
@mock.patch.object(docker_conductor.Handler, 'get_docker_client') @mock.patch.object(docker_conductor.Handler, 'get_docker_client')

View File

@ -43,3 +43,24 @@ class TestBayStatus(test_fields.TestField):
def test_stringify_invalid(self): def test_stringify_invalid(self):
self.assertRaises(ValueError, self.field.stringify, 'DELETE_STOPPED') self.assertRaises(ValueError, self.field.stringify, 'DELETE_STOPPED')
class TestContainerStatus(test_fields.TestField):
def setUp(self):
super(TestContainerStatus, self).setUp()
self.field = fields.ContainerStatusField()
self.coerce_good_values = [('Error', 'Error'), ('Running', 'Running'),
('Stopped', 'Stopped'),
('Paused', 'Paused'),
('Unknown', 'Unknown'), ]
self.coerce_bad_values = ['DELETED']
self.to_primitive_values = self.coerce_good_values[0:1]
self.from_primitive_values = self.coerce_good_values[0:1]
def test_stringify(self):
self.assertEqual("'Stopped'",
self.field.stringify('Stopped'))
def test_stringify_invalid(self):
self.assertRaises(ValueError, self.field.stringify, 'DELETED')