@@ -19,6 +19,10 @@ def raise_version_error(param, min_version):
19
19
if 'Monitor' in update_config :
20
20
raise_version_error ('UpdateConfig.monitor' , '1.25' )
21
21
22
+ if utils .version_lt (version , '1.29' ):
23
+ if 'Order' in update_config :
24
+ raise_version_error ('UpdateConfig.order' , '1.29' )
25
+
22
26
if task_template is not None :
23
27
if 'ForceUpdate' in task_template and utils .version_lt (
24
28
version , '1.25' ):
@@ -62,6 +66,21 @@ def raise_version_error(param, min_version):
62
66
raise_version_error ('ContainerSpec.privileges' , '1.30' )
63
67
64
68
69
+ def _merge_task_template (current , override ):
70
+ merged = current .copy ()
71
+ if override is not None :
72
+ for ts_key , ts_value in override .items ():
73
+ if ts_key == 'ContainerSpec' :
74
+ if 'ContainerSpec' not in merged :
75
+ merged ['ContainerSpec' ] = {}
76
+ for cs_key , cs_value in override ['ContainerSpec' ].items ():
77
+ if cs_value is not None :
78
+ merged ['ContainerSpec' ][cs_key ] = cs_value
79
+ elif ts_value is not None :
80
+ merged [ts_key ] = ts_value
81
+ return merged
82
+
83
+
65
84
class ServiceApiMixin (object ):
66
85
@utils .minimum_version ('1.24' )
67
86
def create_service (
@@ -306,7 +325,7 @@ def tasks(self, filters=None):
306
325
def update_service (self , service , version , task_template = None , name = None ,
307
326
labels = None , mode = None , update_config = None ,
308
327
networks = None , endpoint_config = None ,
309
- endpoint_spec = None ):
328
+ endpoint_spec = None , fetch_current_spec = False ):
310
329
"""
311
330
Update a service.
312
331
@@ -328,6 +347,8 @@ def update_service(self, service, version, task_template=None, name=None,
328
347
the service to. Default: ``None``.
329
348
endpoint_spec (EndpointSpec): Properties that can be configured to
330
349
access and load balance a service. Default: ``None``.
350
+ fetch_current_spec (boolean): Use the undefined settings from the
351
+ current specification of the service. Default: ``False``
331
352
332
353
Returns:
333
354
``True`` if successful.
@@ -345,32 +366,64 @@ def update_service(self, service, version, task_template=None, name=None,
345
366
346
367
_check_api_features (self ._version , task_template , update_config )
347
368
369
+ if fetch_current_spec :
370
+ inspect_defaults = True
371
+ if utils .version_lt (self ._version , '1.29' ):
372
+ inspect_defaults = None
373
+ current = self .inspect_service (
374
+ service , insert_defaults = inspect_defaults
375
+ )['Spec' ]
376
+
377
+ else :
378
+ current = {}
379
+
348
380
url = self ._url ('/services/{0}/update' , service )
349
381
data = {}
350
382
headers = {}
351
- if name is not None :
352
- data ['Name' ] = name
353
- if labels is not None :
354
- data ['Labels' ] = labels
383
+
384
+ data ['Name' ] = current .get ('Name' ) if name is None else name
385
+
386
+ data ['Labels' ] = current .get ('Labels' ) if labels is None else labels
387
+
355
388
if mode is not None :
356
389
if not isinstance (mode , dict ):
357
390
mode = ServiceMode (mode )
358
391
data ['Mode' ] = mode
359
- if task_template is not None :
360
- image = task_template .get ('ContainerSpec' , {}).get ('Image' , None )
361
- if image is not None :
362
- registry , repo_name = auth .resolve_repository_name (image )
363
- auth_header = auth .get_config_header (self , registry )
364
- if auth_header :
365
- headers ['X-Registry-Auth' ] = auth_header
366
- data ['TaskTemplate' ] = task_template
392
+ else :
393
+ data ['Mode' ] = current .get ('Mode' )
394
+
395
+ data ['TaskTemplate' ] = _merge_task_template (
396
+ current .get ('TaskTemplate' , {}), task_template
397
+ )
398
+
399
+ container_spec = data ['TaskTemplate' ].get ('ContainerSpec' , {})
400
+ image = container_spec .get ('Image' , None )
401
+ if image is not None :
402
+ registry , repo_name = auth .resolve_repository_name (image )
403
+ auth_header = auth .get_config_header (self , registry )
404
+ if auth_header :
405
+ headers ['X-Registry-Auth' ] = auth_header
406
+
367
407
if update_config is not None :
368
408
data ['UpdateConfig' ] = update_config
409
+ else :
410
+ data ['UpdateConfig' ] = current .get ('UpdateConfig' )
369
411
370
412
if networks is not None :
371
- data ['Networks' ] = utils .convert_service_networks (networks )
413
+ converted_networks = utils .convert_service_networks (networks )
414
+ data ['TaskTemplate' ]['Networks' ] = converted_networks
415
+ elif data ['TaskTemplate' ].get ('Networks' ) is None :
416
+ current_task_template = current .get ('TaskTemplate' , {})
417
+ current_networks = current_task_template .get ('Networks' )
418
+ if current_networks is None :
419
+ current_networks = current .get ('Networks' )
420
+ if current_networks is not None :
421
+ data ['TaskTemplate' ]['Networks' ] = current_networks
422
+
372
423
if endpoint_spec is not None :
373
424
data ['EndpointSpec' ] = endpoint_spec
425
+ else :
426
+ data ['EndpointSpec' ] = current .get ('EndpointSpec' )
374
427
375
428
resp = self ._post_json (
376
429
url , data = data , params = {'version' : version }, headers = headers
0 commit comments