Kaydet (Commit) b2d08e64 authored tarafından Viktor Adam's avatar Viktor Adam

Service model update changes

Signed-off-by: 's avatarViktor Adam <rycus86@gmail.com>
üst 6e5eb2eb
...@@ -363,8 +363,15 @@ class ServiceApiMixin(object): ...@@ -363,8 +363,15 @@ class ServiceApiMixin(object):
data = {} data = {}
headers = {} headers = {}
data['Name'] = name if name is not None else current.get('Name') if name is not None:
data['Labels'] = labels if labels is not None else current.get('Labels') data['Name'] = name
else:
data['Name'] = current.get('Name')
if labels is not None:
data['Labels'] = labels
else:
data['Labels'] = current.get('Labels')
if mode is not None: if mode is not None:
if not isinstance(mode, dict): if not isinstance(mode, dict):
...@@ -373,23 +380,17 @@ class ServiceApiMixin(object): ...@@ -373,23 +380,17 @@ class ServiceApiMixin(object):
else: else:
data['Mode'] = current.get('Mode') data['Mode'] = current.get('Mode')
merged_task_template = current.get('TaskTemplate', {}) data['TaskTemplate'] = self._merge_task_template(
if task_template is not None: current.get('TaskTemplate', {}), task_template
for task_template_key, task_template_value in task_template.items(): )
if task_template_key == 'ContainerSpec':
if 'ContainerSpec' not in merged_task_template: container_spec = data['TaskTemplate'].get('ContainerSpec', {})
merged_task_template['ContainerSpec'] = {} image = container_spec.get('Image', None)
for container_spec_key, container_spec_value in task_template['ContainerSpec'].items(): if image is not None:
merged_task_template['ContainerSpec'][container_spec_key] = container_spec_value registry, repo_name = auth.resolve_repository_name(image)
else: auth_header = auth.get_config_header(self, registry)
merged_task_template[task_template_key] = task_template_value if auth_header:
image = merged_task_template.get('ContainerSpec', {}).get('Image', None) headers['X-Registry-Auth'] = auth_header
if image is not None:
registry, repo_name = auth.resolve_repository_name(image)
auth_header = auth.get_config_header(self, registry)
if auth_header:
headers['X-Registry-Auth'] = auth_header
data['TaskTemplate'] = merged_task_template
if update_config is not None: if update_config is not None:
data['UpdateConfig'] = update_config data['UpdateConfig'] = update_config
...@@ -397,11 +398,15 @@ class ServiceApiMixin(object): ...@@ -397,11 +398,15 @@ class ServiceApiMixin(object):
data['UpdateConfig'] = current.get('UpdateConfig') data['UpdateConfig'] = current.get('UpdateConfig')
if networks is not None: if networks is not None:
data['TaskTemplate']['Networks'] = utils.convert_service_networks(networks) converted_networks = utils.convert_service_networks(networks)
else: data['TaskTemplate']['Networks'] = converted_networks
existing_networks = current.get('TaskTemplate', {}).get('Networks') or current.get('Networks') elif data['TaskTemplate'].get('Networks') is None:
if existing_networks is not None: current_task_template = current.get('TaskTemplate', {})
data['TaskTemplate']['Networks'] = existing_networks current_networks = current_task_template.get('Networks')
if current_networks is None:
current_networks = current.get('Networks')
if current_networks is not None:
data['TaskTemplate']['Networks'] = current_networks
if endpoint_spec is not None: if endpoint_spec is not None:
data['EndpointSpec'] = endpoint_spec data['EndpointSpec'] = endpoint_spec
...@@ -413,3 +418,17 @@ class ServiceApiMixin(object): ...@@ -413,3 +418,17 @@ class ServiceApiMixin(object):
) )
self._raise_for_status(resp) self._raise_for_status(resp)
return True return True
@staticmethod
def _merge_task_template(current, override):
merged = current.copy()
if override is not None:
for ts_key, ts_value in override.items():
if ts_key == 'ContainerSpec':
if 'ContainerSpec' not in merged:
merged['ContainerSpec'] = {}
for cs_key, cs_value in override['ContainerSpec'].items():
merged['ContainerSpec'][cs_key] = cs_value
else:
merged[ts_key] = ts_value
return merged
...@@ -251,6 +251,7 @@ CONTAINER_SPEC_KWARGS = [ ...@@ -251,6 +251,7 @@ CONTAINER_SPEC_KWARGS = [
# kwargs to copy straight over to TaskTemplate # kwargs to copy straight over to TaskTemplate
TASK_TEMPLATE_KWARGS = [ TASK_TEMPLATE_KWARGS = [
'networks',
'resources', 'resources',
'restart_policy', 'restart_policy',
] ]
...@@ -261,7 +262,6 @@ CREATE_SERVICE_KWARGS = [ ...@@ -261,7 +262,6 @@ CREATE_SERVICE_KWARGS = [
'labels', 'labels',
'mode', 'mode',
'update_config', 'update_config',
'networks',
'endpoint_spec', 'endpoint_spec',
] ]
...@@ -295,6 +295,15 @@ def _get_create_service_kwargs(func_name, kwargs): ...@@ -295,6 +295,15 @@ def _get_create_service_kwargs(func_name, kwargs):
'Options': kwargs.pop('log_driver_options', {}) 'Options': kwargs.pop('log_driver_options', {})
} }
if func_name == 'update':
if 'force_update' in kwargs:
task_template_kwargs['force_update'] = kwargs.pop('force_update')
# use the current spec by default if updating the service
# through the model
use_current_spec = kwargs.pop('use_current_spec', True)
create_kwargs['use_current_spec'] = use_current_spec
# All kwargs should have been consumed by this point, so raise # All kwargs should have been consumed by this point, so raise
# error if any are left # error if any are left
if kwargs: if kwargs:
......
...@@ -4,7 +4,7 @@ from .. import errors ...@@ -4,7 +4,7 @@ from .. import errors
from ..constants import IS_WINDOWS_PLATFORM from ..constants import IS_WINDOWS_PLATFORM
from ..utils import ( from ..utils import (
check_resource, format_environment, format_extra_hosts, parse_bytes, check_resource, format_environment, format_extra_hosts, parse_bytes,
split_command, split_command, convert_service_networks,
) )
...@@ -26,11 +26,14 @@ class TaskTemplate(dict): ...@@ -26,11 +26,14 @@ class TaskTemplate(dict):
placement (Placement): Placement instructions for the scheduler. placement (Placement): Placement instructions for the scheduler.
If a list is passed instead, it is assumed to be a list of If a list is passed instead, it is assumed to be a list of
constraints as part of a :py:class:`Placement` object. constraints as part of a :py:class:`Placement` object.
networks (:py:class:`list`): List of network names or IDs to attach
the containers to.
force_update (int): A counter that triggers an update even if no force_update (int): A counter that triggers an update even if no
relevant parameters have been changed. relevant parameters have been changed.
""" """
def __init__(self, container_spec, resources=None, restart_policy=None, def __init__(self, container_spec, resources=None, restart_policy=None,
placement=None, log_driver=None, force_update=None): placement=None, log_driver=None, networks=None,
force_update=None):
self['ContainerSpec'] = container_spec self['ContainerSpec'] = container_spec
if resources: if resources:
self['Resources'] = resources self['Resources'] = resources
...@@ -42,6 +45,8 @@ class TaskTemplate(dict): ...@@ -42,6 +45,8 @@ class TaskTemplate(dict):
self['Placement'] = placement self['Placement'] = placement
if log_driver: if log_driver:
self['LogDriver'] = log_driver self['LogDriver'] = log_driver
if networks:
self['Networks'] = convert_service_networks(networks)
if force_update is not None: if force_update is not None:
if not isinstance(force_update, int): if not isinstance(force_update, int):
......
...@@ -725,7 +725,9 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -725,7 +725,9 @@ class ServiceTest(BaseAPIIntegrationTest):
version_index = svc_info['Version']['Index'] version_index = svc_info['Version']['Index']
task_tmpl = docker.types.TaskTemplate(container_spec, force_update=10) task_tmpl = docker.types.TaskTemplate(container_spec, force_update=10)
self.client.update_service(name, version_index, task_tmpl, use_current_spec=True) self._update_service(
svc_id, name, version_index, task_tmpl, use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index'] new_index = svc_info['Version']['Index']
assert new_index > version_index assert new_index > version_index
...@@ -739,7 +741,9 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -739,7 +741,9 @@ class ServiceTest(BaseAPIIntegrationTest):
) )
task_tmpl = docker.types.TaskTemplate(container_spec) task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name() name = self.get_service_name()
svc_id = self.client.create_service(task_tmpl, name=name, labels={'service.label': 'SampleLabel'}) svc_id = self.client.create_service(
task_tmpl, name=name, labels={'service.label': 'SampleLabel'}
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
assert 'Labels' in svc_info['Spec'] assert 'Labels' in svc_info['Spec']
assert 'service.label' in svc_info['Spec']['Labels'] assert 'service.label' in svc_info['Spec']['Labels']
...@@ -747,7 +751,10 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -747,7 +751,10 @@ class ServiceTest(BaseAPIIntegrationTest):
version_index = svc_info['Version']['Index'] version_index = svc_info['Version']['Index']
task_tmpl = docker.types.TaskTemplate(container_spec, force_update=10) task_tmpl = docker.types.TaskTemplate(container_spec, force_update=10)
self.client.update_service(name, version_index, task_tmpl, name=name, use_current_spec=True) self._update_service(
svc_id, name, version_index, task_tmpl, name=name,
use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index'] new_index = svc_info['Version']['Index']
assert new_index > version_index assert new_index > version_index
...@@ -761,8 +768,10 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -761,8 +768,10 @@ class ServiceTest(BaseAPIIntegrationTest):
) )
task_tmpl = docker.types.TaskTemplate(container_spec) task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name() name = self.get_service_name()
svc_id = self.client.create_service(task_tmpl, name=name, svc_id = self.client.create_service(
mode=docker.types.ServiceMode(mode='replicated', replicas=2)) task_tmpl, name=name,
mode=docker.types.ServiceMode(mode='replicated', replicas=2)
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
assert 'Mode' in svc_info['Spec'] assert 'Mode' in svc_info['Spec']
assert 'Replicated' in svc_info['Spec']['Mode'] assert 'Replicated' in svc_info['Spec']['Mode']
...@@ -770,7 +779,10 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -770,7 +779,10 @@ class ServiceTest(BaseAPIIntegrationTest):
assert svc_info['Spec']['Mode']['Replicated']['Replicas'] == 2 assert svc_info['Spec']['Mode']['Replicated']['Replicas'] == 2
version_index = svc_info['Version']['Index'] version_index = svc_info['Version']['Index']
self.client.update_service(name, version_index, labels={'force': 'update'}, use_current_spec=True) self._update_service(
svc_id, name, version_index, labels={'force': 'update'},
use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index'] new_index = svc_info['Version']['Index']
assert new_index > version_index assert new_index > version_index
...@@ -786,35 +798,45 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -786,35 +798,45 @@ class ServiceTest(BaseAPIIntegrationTest):
) )
task_tmpl = docker.types.TaskTemplate(container_spec) task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name() name = self.get_service_name()
svc_id = self.client.create_service(task_tmpl, name=name, labels={'service.label': 'SampleLabel'}) svc_id = self.client.create_service(
task_tmpl, name=name, labels={'service.label': 'SampleLabel'}
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
assert 'TaskTemplate' in svc_info['Spec'] assert 'TaskTemplate' in svc_info['Spec']
assert 'ContainerSpec' in svc_info['Spec']['TaskTemplate'] assert 'ContainerSpec' in svc_info['Spec']['TaskTemplate']
assert 'Labels' in svc_info['Spec']['TaskTemplate']['ContainerSpec'] assert 'Labels' in svc_info['Spec']['TaskTemplate']['ContainerSpec']
assert svc_info['Spec']['TaskTemplate']['ContainerSpec']['Labels']['container.label'] == 'SampleLabel' labels = svc_info['Spec']['TaskTemplate']['ContainerSpec']['Labels']
assert labels['container.label'] == 'SampleLabel'
version_index = svc_info['Version']['Index'] version_index = svc_info['Version']['Index']
self.client.update_service(name, version_index, labels={'force': 'update'}, use_current_spec=True) self._update_service(
svc_id, name, version_index, labels={'force': 'update'},
use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index'] new_index = svc_info['Version']['Index']
assert new_index > version_index assert new_index > version_index
assert 'TaskTemplate' in svc_info['Spec'] assert 'TaskTemplate' in svc_info['Spec']
assert 'ContainerSpec' in svc_info['Spec']['TaskTemplate'] assert 'ContainerSpec' in svc_info['Spec']['TaskTemplate']
assert 'Labels' in svc_info['Spec']['TaskTemplate']['ContainerSpec'] assert 'Labels' in svc_info['Spec']['TaskTemplate']['ContainerSpec']
assert svc_info['Spec']['TaskTemplate']['ContainerSpec']['Labels']['container.label'] == 'SampleLabel' labels = svc_info['Spec']['TaskTemplate']['ContainerSpec']['Labels']
assert labels['container.label'] == 'SampleLabel'
container_spec = docker.types.ContainerSpec( container_spec = docker.types.ContainerSpec(
'busybox', ['echo', 'hello'] 'busybox', ['echo', 'hello']
) )
task_tmpl = docker.types.TaskTemplate(container_spec) task_tmpl = docker.types.TaskTemplate(container_spec)
self.client.update_service(name, new_index, task_tmpl, use_current_spec=True) self._update_service(
svc_id, name, new_index, task_tmpl, use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
newer_index = svc_info['Version']['Index'] newer_index = svc_info['Version']['Index']
assert newer_index > new_index assert newer_index > new_index
assert 'TaskTemplate' in svc_info['Spec'] assert 'TaskTemplate' in svc_info['Spec']
assert 'ContainerSpec' in svc_info['Spec']['TaskTemplate'] assert 'ContainerSpec' in svc_info['Spec']['TaskTemplate']
assert 'Labels' in svc_info['Spec']['TaskTemplate']['ContainerSpec'] assert 'Labels' in svc_info['Spec']['TaskTemplate']['ContainerSpec']
assert svc_info['Spec']['TaskTemplate']['ContainerSpec']['Labels']['container.label'] == 'SampleLabel' labels = svc_info['Spec']['TaskTemplate']['ContainerSpec']['Labels']
assert labels['container.label'] == 'SampleLabel'
def test_update_service_with_defaults_update_config(self): def test_update_service_with_defaults_update_config(self):
container_spec = docker.types.ContainerSpec(BUSYBOX, ['true']) container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
...@@ -834,7 +856,10 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -834,7 +856,10 @@ class ServiceTest(BaseAPIIntegrationTest):
assert update_config['FailureAction'] == uc['FailureAction'] assert update_config['FailureAction'] == uc['FailureAction']
version_index = svc_info['Version']['Index'] version_index = svc_info['Version']['Index']
self.client.update_service(name, version_index, labels={'force': 'update'}, use_current_spec=True) self._update_service(
svc_id, name, version_index, labels={'force': 'update'},
use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index'] new_index = svc_info['Version']['Index']
assert new_index > version_index assert new_index > version_index
...@@ -869,7 +894,10 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -869,7 +894,10 @@ class ServiceTest(BaseAPIIntegrationTest):
version_index = svc_info['Version']['Index'] version_index = svc_info['Version']['Index']
self.client.update_service(name, version_index, labels={'force': 'update'}, use_current_spec=True) self._update_service(
svc_id, name, version_index, labels={'force': 'update'},
use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index'] new_index = svc_info['Version']['Index']
assert new_index > version_index assert new_index > version_index
...@@ -878,7 +906,10 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -878,7 +906,10 @@ class ServiceTest(BaseAPIIntegrationTest):
{'Target': net1['Id']}, {'Target': net2['Id']} {'Target': net1['Id']}, {'Target': net2['Id']}
] ]
self.client.update_service(name, new_index, networks=[net1['Id']], use_current_spec=True) self._update_service(
svc_id, name, new_index, networks=[net1['Id']],
use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
assert 'Networks' in svc_info['Spec']['TaskTemplate'] assert 'Networks' in svc_info['Spec']['TaskTemplate']
assert svc_info['Spec']['TaskTemplate']['Networks'] == [ assert svc_info['Spec']['TaskTemplate']['Networks'] == [
...@@ -918,7 +949,10 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -918,7 +949,10 @@ class ServiceTest(BaseAPIIntegrationTest):
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
version_index = svc_info['Version']['Index'] version_index = svc_info['Version']['Index']
self.client.update_service(name, version_index, labels={'force': 'update'}, use_current_spec=True) self._update_service(
svc_id, name, version_index, labels={'force': 'update'},
use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index'] new_index = svc_info['Version']['Index']
assert new_index > version_index assert new_index > version_index
...@@ -968,13 +1002,16 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -968,13 +1002,16 @@ class ServiceTest(BaseAPIIntegrationTest):
version_index = svc_info['Version']['Index'] version_index = svc_info['Version']['Index']
self.client.update_service(name, version_index, task_tmpl, use_current_spec=True) self._update_service(
svc_id, name, version_index, task_tmpl, use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index'] new_index = svc_info['Version']['Index']
assert new_index > version_index assert new_index > version_index
container_spec = svc_info['Spec']['TaskTemplate']['ContainerSpec']
assert ( assert (
'Healthcheck' not in svc_info['Spec']['TaskTemplate']['ContainerSpec'] or 'Healthcheck' not in container_spec or
not svc_info['Spec']['TaskTemplate']['ContainerSpec']['Healthcheck'] not container_spec['Healthcheck']
) )
def test_update_service_remove_labels(self): def test_update_service_remove_labels(self):
...@@ -983,14 +1020,18 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -983,14 +1020,18 @@ class ServiceTest(BaseAPIIntegrationTest):
) )
task_tmpl = docker.types.TaskTemplate(container_spec) task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name() name = self.get_service_name()
svc_id = self.client.create_service(task_tmpl, name=name, labels={'service.label': 'SampleLabel'}) svc_id = self.client.create_service(
task_tmpl, name=name, labels={'service.label': 'SampleLabel'}
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
assert 'Labels' in svc_info['Spec'] assert 'Labels' in svc_info['Spec']
assert 'service.label' in svc_info['Spec']['Labels'] assert 'service.label' in svc_info['Spec']['Labels']
assert svc_info['Spec']['Labels']['service.label'] == 'SampleLabel' assert svc_info['Spec']['Labels']['service.label'] == 'SampleLabel'
version_index = svc_info['Version']['Index'] version_index = svc_info['Version']['Index']
self.client.update_service(name, version_index, labels={}, use_current_spec=True) self._update_service(
svc_id, name, version_index, labels={}, use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index'] new_index = svc_info['Version']['Index']
assert new_index > version_index assert new_index > version_index
...@@ -1003,12 +1044,15 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -1003,12 +1044,15 @@ class ServiceTest(BaseAPIIntegrationTest):
) )
task_tmpl = docker.types.TaskTemplate(container_spec) task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name() name = self.get_service_name()
svc_id = self.client.create_service(task_tmpl, name=name, labels={'service.label': 'SampleLabel'}) svc_id = self.client.create_service(
task_tmpl, name=name, labels={'service.label': 'SampleLabel'}
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
assert 'TaskTemplate' in svc_info['Spec'] assert 'TaskTemplate' in svc_info['Spec']
assert 'ContainerSpec' in svc_info['Spec']['TaskTemplate'] assert 'ContainerSpec' in svc_info['Spec']['TaskTemplate']
assert 'Labels' in svc_info['Spec']['TaskTemplate']['ContainerSpec'] assert 'Labels' in svc_info['Spec']['TaskTemplate']['ContainerSpec']
assert svc_info['Spec']['TaskTemplate']['ContainerSpec']['Labels']['container.label'] == 'SampleLabel' labels = svc_info['Spec']['TaskTemplate']['ContainerSpec']['Labels']
assert labels['container.label'] == 'SampleLabel'
version_index = svc_info['Version']['Index'] version_index = svc_info['Version']['Index']
container_spec = docker.types.ContainerSpec( container_spec = docker.types.ContainerSpec(
...@@ -1016,10 +1060,103 @@ class ServiceTest(BaseAPIIntegrationTest): ...@@ -1016,10 +1060,103 @@ class ServiceTest(BaseAPIIntegrationTest):
labels={} labels={}
) )
task_tmpl = docker.types.TaskTemplate(container_spec) task_tmpl = docker.types.TaskTemplate(container_spec)
self.client.update_service(name, version_index, task_tmpl, use_current_spec=True) self._update_service(
svc_id, name, version_index, task_tmpl, use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id) svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index'] new_index = svc_info['Version']['Index']
assert new_index > version_index assert new_index > version_index
assert 'TaskTemplate' in svc_info['Spec'] assert 'TaskTemplate' in svc_info['Spec']
assert 'ContainerSpec' in svc_info['Spec']['TaskTemplate'] assert 'ContainerSpec' in svc_info['Spec']['TaskTemplate']
assert not svc_info['Spec']['TaskTemplate']['ContainerSpec'].get('Labels') container_spec = svc_info['Spec']['TaskTemplate']['ContainerSpec']
assert not container_spec.get('Labels')
@requires_api_version('1.29')
def test_update_service_with_network_change(self):
container_spec = docker.types.ContainerSpec(
'busybox', ['echo', 'hello']
)
task_tmpl = docker.types.TaskTemplate(container_spec)
net1 = self.client.create_network(
'dockerpytest_1', driver='overlay', ipam={'Driver': 'default'}
)
self.tmp_networks.append(net1['Id'])
net2 = self.client.create_network(
'dockerpytest_2', driver='overlay', ipam={'Driver': 'default'}
)
self.tmp_networks.append(net2['Id'])
name = self.get_service_name()
svc_id = self.client.create_service(
task_tmpl, name=name, networks=[net1['Id']]
)
svc_info = self.client.inspect_service(svc_id)
assert 'Networks' in svc_info['Spec']
assert len(svc_info['Spec']['Networks']) > 0
assert svc_info['Spec']['Networks'][0]['Target'] == net1['Id']
svc_info = self.client.inspect_service(svc_id)
version_index = svc_info['Version']['Index']
task_tmpl = docker.types.TaskTemplate(container_spec)
self._update_service(
svc_id, name, version_index, task_tmpl, name=name,
networks=[net2['Id']], use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id)
task_template = svc_info['Spec']['TaskTemplate']
assert 'Networks' in task_template
assert len(task_template['Networks']) > 0
assert task_template['Networks'][0]['Target'] == net2['Id']
svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index']
assert new_index > version_index
self._update_service(
svc_id, name, new_index, name=name, networks=[net1['Id']],
use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id)
task_template = svc_info['Spec']['TaskTemplate']
assert 'ContainerSpec' in task_template
new_spec = task_template['ContainerSpec']
assert 'Image' in new_spec
assert new_spec['Image'].split(':')[0] == 'busybox'
assert 'Command' in new_spec
assert new_spec['Command'] == ['echo', 'hello']
assert 'Networks' in task_template
assert len(task_template['Networks']) > 0
assert task_template['Networks'][0]['Target'] == net1['Id']
svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index']
task_tmpl = docker.types.TaskTemplate(
container_spec, networks=[net2['Id']]
)
self._update_service(
svc_id, name, new_index, task_tmpl, name=name,
use_current_spec=True
)
svc_info = self.client.inspect_service(svc_id)
task_template = svc_info['Spec']['TaskTemplate']
assert 'Networks' in task_template
assert len(task_template['Networks']) > 0
assert task_template['Networks'][0]['Target'] == net2['Id']
def _update_service(self, svc_id, *args, **kwargs):
# service update tests seem to be a bit flaky
# give them a chance to retry the update with a new version index
try:
self.client.update_service(*args, **kwargs)
except docker.errors.APIError as e:
if e.explanation == "update out of sequence":
svc_info = self.client.inspect_service(svc_id)
version_index = svc_info['Version']['Index']
if len(args) > 1:
args = (args[0], version_index) + args[2:]
else:
kwargs['version'] = version_index
self.client.update_service(*args, **kwargs)
import unittest import unittest
import docker import docker
import pytest
from .. import helpers from .. import helpers
from .base import TEST_API_VERSION from .base import TEST_API_VERSION
...@@ -36,6 +35,25 @@ class ServiceTest(unittest.TestCase): ...@@ -36,6 +35,25 @@ class ServiceTest(unittest.TestCase):
assert "alpine" in container_spec['Image'] assert "alpine" in container_spec['Image']
assert container_spec['Labels'] == {'container': 'label'} assert container_spec['Labels'] == {'container': 'label'}
def test_create_with_network(self):
client = docker.from_env(version=TEST_API_VERSION)
name = helpers.random_name()
network = client.networks.create(
helpers.random_name(), driver='overlay'
)
service = client.services.create(
# create arguments
name=name,
# ContainerSpec arguments
image="alpine",
command="sleep 300",
networks=[network.id]
)
assert 'Networks' in service.attrs['Spec']['TaskTemplate']
networks = service.attrs['Spec']['TaskTemplate']['Networks']
assert len(networks) == 1
assert networks[0]['Target'] == network.id
def test_get(self): def test_get(self):
client = docker.from_env(version=TEST_API_VERSION) client = docker.from_env(version=TEST_API_VERSION)
name = helpers.random_name() name = helpers.random_name()
...@@ -82,7 +100,6 @@ class ServiceTest(unittest.TestCase): ...@@ -82,7 +100,6 @@ class ServiceTest(unittest.TestCase):
assert len(tasks) == 1 assert len(tasks) == 1
assert tasks[0]['ServiceID'] == service2.id assert tasks[0]['ServiceID'] == service2.id
@pytest.mark.skip(reason="Makes Swarm unstable?")
def test_update(self): def test_update(self):
client = docker.from_env(version=TEST_API_VERSION) client = docker.from_env(version=TEST_API_VERSION)
service = client.services.create( service = client.services.create(
...@@ -101,3 +118,105 @@ class ServiceTest(unittest.TestCase): ...@@ -101,3 +118,105 @@ class ServiceTest(unittest.TestCase):
service.reload() service.reload()
container_spec = service.attrs['Spec']['TaskTemplate']['ContainerSpec'] container_spec = service.attrs['Spec']['TaskTemplate']['ContainerSpec']
assert container_spec['Command'] == ["sleep", "600"] assert container_spec['Command'] == ["sleep", "600"]
def test_update_retains_service_labels(self):
client = docker.from_env(version=TEST_API_VERSION)
service = client.services.create(
# create arguments
name=helpers.random_name(),
labels={'service.label': 'SampleLabel'},
# ContainerSpec arguments
image="alpine",
command="sleep 300"
)
service.update(
# create argument
name=service.name,
# ContainerSpec argument
command="sleep 600"
)
service.reload()
labels = service.attrs['Spec']['Labels']
assert labels == {'service.label': 'SampleLabel'}
def test_update_retains_container_labels(self):
client = docker.from_env(version=TEST_API_VERSION)
service = client.services.create(
# create arguments
name=helpers.random_name(),
# ContainerSpec arguments
image="alpine",
command="sleep 300",
container_labels={'container.label': 'SampleLabel'}
)
service.update(
# create argument
name=service.name,
# ContainerSpec argument
command="sleep 600"
)
service.reload()
container_spec = service.attrs['Spec']['TaskTemplate']['ContainerSpec']
assert container_spec['Labels'] == {'container.label': 'SampleLabel'}
def test_update_remove_service_labels(self):
client = docker.from_env(version=TEST_API_VERSION)
service = client.services.create(
# create arguments
name=helpers.random_name(),
labels={'service.label': 'SampleLabel'},
# ContainerSpec arguments
image="alpine",
command="sleep 300"
)
service.update(
# create argument
name=service.name,
labels={},
# ContainerSpec argument
command="sleep 600"
)
service.reload()
assert not service.attrs['Spec'].get('Labels')
def test_scale_service(self):
client = docker.from_env(version=TEST_API_VERSION)
service = client.services.create(
# create arguments
name=helpers.random_name(),
# ContainerSpec arguments
image="alpine",
command="sleep 300"
)
assert len(service.tasks()) == 1
service.update(
# create argument
name=service.name,
mode=docker.types.ServiceMode('replicated', replicas=2),
# ContainerSpec argument
command="sleep 600"
)
service.reload()
assert len(service.tasks()) >= 2
@helpers.requires_api_version('1.25')
def test_restart_service(self):
client = docker.from_env(version=TEST_API_VERSION)
service = client.services.create(
# create arguments
name=helpers.random_name(),
# ContainerSpec arguments
image="alpine",
command="sleep 300"
)
initial_version = service.version
service.update(
# create argument
name=service.name,
# task template argument
force_update=10,
# ContainerSpec argument
command="sleep 600"
)
service.reload()
assert service.version > initial_version
...@@ -35,18 +35,18 @@ class CreateServiceKwargsTest(unittest.TestCase): ...@@ -35,18 +35,18 @@ class CreateServiceKwargsTest(unittest.TestCase):
'labels': {'key': 'value'}, 'labels': {'key': 'value'},
'mode': 'global', 'mode': 'global',
'update_config': {'update': 'config'}, 'update_config': {'update': 'config'},
'networks': ['somenet'],
'endpoint_spec': {'blah': 'blah'}, 'endpoint_spec': {'blah': 'blah'},
} }
assert set(task_template.keys()) == set([ assert set(task_template.keys()) == set([
'ContainerSpec', 'Resources', 'RestartPolicy', 'Placement', 'ContainerSpec', 'Resources', 'RestartPolicy', 'Placement',
'LogDriver' 'LogDriver', 'Networks'
]) ])
assert task_template['Placement'] == {'Constraints': ['foo=bar']} assert task_template['Placement'] == {'Constraints': ['foo=bar']}
assert task_template['LogDriver'] == { assert task_template['LogDriver'] == {
'Name': 'logdriver', 'Name': 'logdriver',
'Options': {'foo': 'bar'} 'Options': {'foo': 'bar'}
} }
assert task_template['Networks'] == [{'Target': 'somenet'}]
assert set(task_template['ContainerSpec'].keys()) == set([ assert set(task_template['ContainerSpec'].keys()) == set([
'Image', 'Command', 'Args', 'Hostname', 'Env', 'Dir', 'User', 'Image', 'Command', 'Args', 'Hostname', 'Env', 'Dir', 'User',
'Labels', 'Mounts', 'StopGracePeriod' 'Labels', 'Mounts', 'StopGracePeriod'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment