summaryrefslogtreecommitdiff
path: root/docker/api/service.py
diff options
context:
space:
mode:
Diffstat (limited to 'docker/api/service.py')
-rw-r--r--docker/api/service.py81
1 files changed, 67 insertions, 14 deletions
diff --git a/docker/api/service.py b/docker/api/service.py
index 4c10ef8..86f4b07 100644
--- a/docker/api/service.py
+++ b/docker/api/service.py
@@ -19,6 +19,10 @@ def _check_api_features(version, task_template, update_config):
if 'Monitor' in update_config:
raise_version_error('UpdateConfig.monitor', '1.25')
+ if utils.version_lt(version, '1.29'):
+ if 'Order' in update_config:
+ raise_version_error('UpdateConfig.order', '1.29')
+
if task_template is not None:
if 'ForceUpdate' in task_template and utils.version_lt(
version, '1.25'):
@@ -62,6 +66,21 @@ def _check_api_features(version, task_template, update_config):
raise_version_error('ContainerSpec.privileges', '1.30')
+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():
+ if cs_value is not None:
+ merged['ContainerSpec'][cs_key] = cs_value
+ elif ts_value is not None:
+ merged[ts_key] = ts_value
+ return merged
+
+
class ServiceApiMixin(object):
@utils.minimum_version('1.24')
def create_service(
@@ -306,7 +325,7 @@ class ServiceApiMixin(object):
def update_service(self, service, version, task_template=None, name=None,
labels=None, mode=None, update_config=None,
networks=None, endpoint_config=None,
- endpoint_spec=None):
+ endpoint_spec=None, fetch_current_spec=False):
"""
Update a service.
@@ -328,6 +347,8 @@ class ServiceApiMixin(object):
the service to. Default: ``None``.
endpoint_spec (EndpointSpec): Properties that can be configured to
access and load balance a service. Default: ``None``.
+ fetch_current_spec (boolean): Use the undefined settings from the
+ current specification of the service. Default: ``False``
Returns:
``True`` if successful.
@@ -345,32 +366,64 @@ class ServiceApiMixin(object):
_check_api_features(self._version, task_template, update_config)
+ if fetch_current_spec:
+ inspect_defaults = True
+ if utils.version_lt(self._version, '1.29'):
+ inspect_defaults = None
+ current = self.inspect_service(
+ service, insert_defaults=inspect_defaults
+ )['Spec']
+
+ else:
+ current = {}
+
url = self._url('/services/{0}/update', service)
data = {}
headers = {}
- if name is not None:
- data['Name'] = name
- if labels is not None:
- data['Labels'] = labels
+
+ data['Name'] = current.get('Name') if name is None else name
+
+ data['Labels'] = current.get('Labels') if labels is None else labels
+
if mode is not None:
if not isinstance(mode, dict):
mode = ServiceMode(mode)
data['Mode'] = mode
- if task_template is not None:
- image = task_template.get('ContainerSpec', {}).get('Image', None)
- 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'] = task_template
+ else:
+ data['Mode'] = current.get('Mode')
+
+ data['TaskTemplate'] = _merge_task_template(
+ current.get('TaskTemplate', {}), task_template
+ )
+
+ container_spec = data['TaskTemplate'].get('ContainerSpec', {})
+ image = container_spec.get('Image', None)
+ 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
+
if update_config is not None:
data['UpdateConfig'] = update_config
+ else:
+ data['UpdateConfig'] = current.get('UpdateConfig')
if networks is not None:
- data['Networks'] = utils.convert_service_networks(networks)
+ converted_networks = utils.convert_service_networks(networks)
+ data['TaskTemplate']['Networks'] = converted_networks
+ elif data['TaskTemplate'].get('Networks') is None:
+ current_task_template = current.get('TaskTemplate', {})
+ 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:
data['EndpointSpec'] = endpoint_spec
+ else:
+ data['EndpointSpec'] = current.get('EndpointSpec')
resp = self._post_json(
url, data=data, params={'version': version}, headers=headers