Add docker profile support update operation

- Add docker profile support update name

Change-Id: Ide88ee6a55a4d7d1882eb40aade8d70e528cc7cd
Signed-off-by: Yuanbin.Chen <cybing4@gmail.com>
This commit is contained in:
Yuanbin.Chen 2018-05-30 11:20:15 +08:00
parent 87db93f02c
commit decf54d3c0
4 changed files with 173 additions and 1 deletions

View File

@ -52,3 +52,7 @@ class DockerClient(object):
def stop(self, container, timeout=None):
params = {'timeout': timeout}
self._dockerclient.stop(container, **params)
@sdk.translate_exception
def rename(self, container, name):
self._dockerclient.rename(container, name)

View File

@ -58,7 +58,8 @@ class DockerProfile(base.Profile):
required=True,
),
NAME: schema.String(
_('The name of the container.')
_('The name of the container.'),
updatable=True,
),
COMMAND: schema.String(
_('The command to run when container is started.')
@ -330,6 +331,53 @@ class DockerProfile(base.Profile):
db_api.node_remove_dependents(ctx, self.host.id, obj.id)
return
def do_update(self, obj, new_profile=None, **params):
"""Perform update on the container.
:param obj: the container to operate on
:param new_profile: the new profile for the container.
:param params: a dictionary of optional parameters.
:returns: True if update was successful or False otherwise.
:raises: `EResourceUpdate` if operation fails.
"""
self.server_id = obj.physical_id
if not self.server_id:
return False
if not new_profile:
return False
if not self.validate_for_update(new_profile):
return False
name_changed, new_name = self._check_container_name(obj, new_profile)
if name_changed:
self._update_name(obj, new_name)
return True
def _check_container_name(self, obj, profile):
"""Check if there is a new name to be assigned to the container.
:param obj: The node object to operate on.
:param new_profile: The new profile which may contain a name for
the container.
:return: A tuple consisting a boolean indicating whether the name
needs change and the container name determined.
"""
old_name = self.properties[self.NAME] or obj.name
new_name = profile.properties[self.NAME] or obj.name
if old_name == new_name:
return False, new_name
return True, new_name
def _update_name(self, obj, new_name):
try:
self.docker(obj).rename(obj.physical_id, new_name)
except exc.InternalError as ex:
raise exc.EResourceUpdate(type='container', id=obj.physical_id,
message=six.text_type(ex))
def handle_reboot(self, obj, **options):
"""Handler for a reboot operation.

View File

@ -106,3 +106,10 @@ class TestDocker(base.SenlinTestCase):
self.assertIsNone(res)
self.x_docker.stop.assert_called_once_with(container, **params)
def test_rename(self):
container = mock.Mock()
res = self.sot.rename(container, 'new_name')
self.assertIsNone(res)
self.x_docker.rename.assert_called_once_with(container, 'new_name')

View File

@ -476,6 +476,119 @@ class TestContainerDockerProfile(base.SenlinTestCase):
self.assertRaises(exc.EResourceDeletion,
profile.do_delete, obj)
@mock.patch.object(dp.DockerProfile, 'docker')
def test_update_name(self, mock_docker):
x_docker = mock.Mock()
x_docker = mock_docker.return_value
obj = mock.Mock(physical_id='FAKE_ID')
docker = dp.DockerProfile('container', self.spec)
res = docker._update_name(obj, 'NEW_NAME')
self.assertIsNone(res)
x_docker.rename.assert_called_once_with('FAKE_ID', 'NEW_NAME')
@mock.patch.object(dp.DockerProfile, 'docker')
def test_update_name_docker_failure(self, mock_docker):
x_docker = mock.Mock()
x_docker = mock_docker.return_value
x_docker.rename.side_effect = exc.InternalError(message='BOOM')
obj = mock.Mock(physical_id='FAKE_ID')
docker = dp.DockerProfile('container', self.spec)
ex = self.assertRaises(exc.EResourceUpdate,
docker._update_name,
obj, 'NEW_NAME')
self.assertEqual("Failed in updating container 'FAKE_ID': BOOM.",
six.text_type(ex))
x_docker.rename.assert_called_once_with('FAKE_ID', 'NEW_NAME')
@mock.patch.object(dp.DockerProfile, 'docker')
def test_do_update(self, mock_docker):
obj = mock.Mock(physical_id='FAKE_ID')
docker = dp.DockerProfile('container', self.spec)
new_spec = {
'type': 'container.dockerinc.docker',
'version': '1.0',
'properties': {
'context': {
'region_name': 'RegionOne'
},
'name': 'new_name',
'image': 'hello-world',
'command': '/bin/sleep 30',
'port': 2375,
'host_node': 'fake_node',
}
}
new_profile = dp.DockerProfile('u', new_spec)
res = docker.do_update(obj, new_profile)
self.assertTrue(res)
@mock.patch.object(dp.DockerProfile, 'docker')
def test_do_update_no_new_profile(self, mock_docker):
obj = mock.Mock(physical_id='FAKE_ID')
docker = dp.DockerProfile('container', self.spec)
params = {}
res = docker.do_update(obj, params)
self.assertFalse(res)
def test_do_update_no_physical_id(self):
obj = mock.Mock(physical_id=None)
profile = dp.DockerProfile('container', self.spec)
self.assertFalse(profile.do_update(obj))
def test_check_container_name(self):
obj = mock.Mock(physical_id='FAKE_ID')
docker = dp.DockerProfile('container', self.spec)
new_spec = {
'type': 'container.dockerinc.docker',
'version': '1.0',
'properties': {
'context': {
'region_name': 'RegionOne'
},
'name': 'new_name',
'image': 'hello-world',
'command': '/bin/sleep 30',
'port': 2375,
'host_node': 'fake_node',
}
}
new_profile = dp.DockerProfile('u', new_spec)
res, new_name = docker._check_container_name(obj, new_profile)
self.assertTrue(res)
def test_check_container_same_name(self):
obj = mock.Mock(physical_id='FAKE_ID')
docker = dp.DockerProfile('container', self.spec)
new_spec = {
'type': 'container.dockerinc.docker',
'version': '1.0',
'properties': {
'context': {
'region_name': 'RegionOne'
},
'name': 'docker_container',
'image': 'hello-world',
'command': '/bin/sleep 30',
'port': 2375,
'host_node': 'fake_node',
}
}
new_profile = dp.DockerProfile('u', new_spec)
res, new_name = docker._check_container_name(obj, new_profile)
self.assertFalse(res)
@mock.patch.object(dp.DockerProfile, 'docker')
def test_handle_reboot(self, mock_docker):
x_docker = mock.Mock()