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:
parent
87db93f02c
commit
decf54d3c0
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue