Kaydet (Commit) d22e2fec authored tarafından Joffrey F's avatar Joffrey F

Add support for force_update in TaskTemplate

Add min version checks in create_service and update_service
Signed-off-by: 's avatarJoffrey F <joffrey@docker.com>
üst fc5cd1a9
......@@ -62,10 +62,24 @@ class ServiceApiMixin(object):
'Labels': labels,
'TaskTemplate': task_template,
'Mode': mode,
'UpdateConfig': update_config,
'Networks': utils.convert_service_networks(networks),
'EndpointSpec': endpoint_spec
}
if update_config is not None:
if utils.version_lt(self._version, '1.25'):
if 'MaxFailureRatio' in update_config:
raise errors.InvalidVersion(
'UpdateConfig.max_failure_ratio is not supported in'
' API version < 1.25'
)
if 'Monitor' in update_config:
raise errors.InvalidVersion(
'UpdateConfig.monitor is not supported in'
' API version < 1.25'
)
data['UpdateConfig'] = update_config
return self._result(
self._post_json(url, data=data, headers=headers), True
)
......@@ -230,6 +244,12 @@ class ServiceApiMixin(object):
mode = ServiceMode(mode)
data['Mode'] = mode
if task_template is not None:
if 'ForceUpdate' in task_template and utils.version_lt(
self._version, '1.25'):
raise errors.InvalidVersion(
'force_update is not supported in API version < 1.25'
)
image = task_template.get('ContainerSpec', {}).get('Image', None)
if image is not None:
registry, repo_name = auth.resolve_repository_name(image)
......@@ -238,7 +258,19 @@ class ServiceApiMixin(object):
headers['X-Registry-Auth'] = auth_header
data['TaskTemplate'] = task_template
if update_config is not None:
if utils.version_lt(self._version, '1.25'):
if 'MaxFailureRatio' in update_config:
raise errors.InvalidVersion(
'UpdateConfig.max_failure_ratio is not supported in'
' API version < 1.25'
)
if 'Monitor' in update_config:
raise errors.InvalidVersion(
'UpdateConfig.monitor is not supported in'
' API version < 1.25'
)
data['UpdateConfig'] = update_config
if networks is not None:
data['Networks'] = utils.convert_service_networks(networks)
if endpoint_spec is not None:
......
......@@ -21,9 +21,11 @@ class TaskTemplate(dict):
restart_policy (RestartPolicy): Specification for the restart policy
which applies to containers created as part of this service.
placement (:py:class:`list`): A list of constraints.
force_update (int): A counter that triggers an update even if no
relevant parameters have been changed.
"""
def __init__(self, container_spec, resources=None, restart_policy=None,
placement=None, log_driver=None):
placement=None, log_driver=None, force_update=None):
self['ContainerSpec'] = container_spec
if resources:
self['Resources'] = resources
......@@ -36,6 +38,11 @@ class TaskTemplate(dict):
if log_driver:
self['LogDriver'] = log_driver
if force_update is not None:
if not isinstance(force_update, int):
raise TypeError('force_update must be an integer')
self['ForceUpdate'] = force_update
@property
def container_spec(self):
return self.get('ContainerSpec')
......
......@@ -70,7 +70,9 @@ def force_leave_swarm(client):
occasionally throws "context deadline exceeded" errors when leaving."""
while True:
try:
return client.swarm.leave(force=True)
if isinstance(client, docker.DockerClient):
return client.swarm.leave(force=True)
return client.leave_swarm(force=True) # elif APIClient
except docker.errors.APIError as e:
if e.explanation == "context deadline exceeded":
continue
......
......@@ -2,14 +2,14 @@ import random
import docker
from ..helpers import requires_api_version
from ..helpers import force_leave_swarm, requires_api_version
from .base import BaseAPIIntegrationTest
class ServiceTest(BaseAPIIntegrationTest):
def setUp(self):
super(ServiceTest, self).setUp()
self.client.leave_swarm(force=True)
force_leave_swarm(self.client)
self.init_swarm()
def tearDown(self):
......@@ -19,7 +19,7 @@ class ServiceTest(BaseAPIIntegrationTest):
self.client.remove_service(service['ID'])
except docker.errors.APIError:
pass
self.client.leave_swarm(force=True)
force_leave_swarm(self.client)
def get_service_name(self):
return 'dockerpytest_{0:x}'.format(random.getrandbits(64))
......@@ -296,3 +296,24 @@ class ServiceTest(BaseAPIIntegrationTest):
assert 'Mode' in svc_info['Spec']
assert 'Replicated' in svc_info['Spec']['Mode']
assert svc_info['Spec']['Mode']['Replicated'] == {'Replicas': 5}
@requires_api_version('1.25')
def test_update_service_force_update(self):
container_spec = docker.types.ContainerSpec(
'busybox', ['echo', 'hello']
)
task_tmpl = docker.types.TaskTemplate(container_spec)
name = self.get_service_name()
svc_id = self.client.create_service(task_tmpl, name=name)
svc_info = self.client.inspect_service(svc_id)
assert 'TaskTemplate' in svc_info['Spec']
assert 'ForceUpdate' in svc_info['Spec']['TaskTemplate']
assert svc_info['Spec']['TaskTemplate']['ForceUpdate'] == 0
version_index = svc_info['Version']['Index']
task_tmpl = docker.types.TaskTemplate(container_spec, force_update=10)
self.client.update_service(name, version_index, task_tmpl, name=name)
svc_info = self.client.inspect_service(svc_id)
new_index = svc_info['Version']['Index']
assert new_index > version_index
assert svc_info['Spec']['TaskTemplate']['ForceUpdate'] == 10
......@@ -2,18 +2,18 @@ import copy
import docker
import pytest
from ..helpers import requires_api_version
from ..helpers import force_leave_swarm, requires_api_version
from .base import BaseAPIIntegrationTest
class SwarmTest(BaseAPIIntegrationTest):
def setUp(self):
super(SwarmTest, self).setUp()
self.client.leave_swarm(force=True)
force_leave_swarm(self.client)
def tearDown(self):
super(SwarmTest, self).tearDown()
self.client.leave_swarm(force=True)
force_leave_swarm(self.client)
@requires_api_version('1.24')
def test_init_swarm_simple(self):
......
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