Repository: docker/docker-py

Issue:
Update config does not support order property
Update config for docker services does not support the "update-order" property, which is documented here: https://docs.docker.com/engine/reference/commandline/service_update/ .



Discussion:

Resolving patch:
diff --git a/docker/api/service.py b/docker/api/service.py
--- a/docker/api/service.py
+++ b/docker/api/service.py
@@ -19,6 +19,10 @@ def raise_version_error(param, min_version):
             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'):
diff --git a/docker/types/services.py b/docker/types/services.py
--- a/docker/types/services.py
+++ b/docker/types/services.py
@@ -334,9 +334,11 @@ class UpdateConfig(dict):
         max_failure_ratio (float): The fraction of tasks that may fail during
           an update before the failure action is invoked, specified as a
           floating point number between 0 and 1. Default: 0
+        order (string): Specifies the order of operations when rolling out an
+          updated task. Either ``start_first`` or ``stop_first`` are accepted.
     """
     def __init__(self, parallelism=0, delay=None, failure_action='continue',
-                 monitor=None, max_failure_ratio=None):
+                 monitor=None, max_failure_ratio=None, order=None):
         self['Parallelism'] = parallelism
         if delay is not None:
             self['Delay'] = delay
@@ -360,6 +362,13 @@ def __init__(self, parallelism=0, delay=None, failure_action='continue',
                 )
             self['MaxFailureRatio'] = max_failure_ratio
 
+        if order is not None:
+            if order not in ('start-first', 'stop-first'):
+                raise errors.InvalidArgument(
+                    'order must be either `start-first` or `stop-first`'
+                )
+            self['Order'] = order
+
 
 class RestartConditionTypesEnum(object):
     _values = (


Test patch:
diff --git a/tests/integration/api_service_test.py b/tests/integration/api_service_test.py
--- a/tests/integration/api_service_test.py
+++ b/tests/integration/api_service_test.py
@@ -386,6 +386,24 @@ def test_create_service_with_env(self):
         assert 'Env' in con_spec
         assert con_spec['Env'] == ['DOCKER_PY_TEST=1']
 
+    @requires_api_version('1.29')
+    def test_create_service_with_update_order(self):
+        container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
+        task_tmpl = docker.types.TaskTemplate(container_spec)
+        update_config = docker.types.UpdateConfig(
+            parallelism=10, delay=5, order='start-first'
+        )
+        name = self.get_service_name()
+        svc_id = self.client.create_service(
+            task_tmpl, update_config=update_config, name=name
+        )
+        svc_info = self.client.inspect_service(svc_id)
+        assert 'UpdateConfig' in svc_info['Spec']
+        uc = svc_info['Spec']['UpdateConfig']
+        assert update_config['Parallelism'] == uc['Parallelism']
+        assert update_config['Delay'] == uc['Delay']
+        assert update_config['Order'] == uc['Order']
+
     @requires_api_version('1.25')
     def test_create_service_with_tty(self):
         container_spec = docker.types.ContainerSpec(