mirror of https://github.com/docker/docker-py.git
Add support for publish mode for endpointspec ports
Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
parent
0750337f6a
commit
5347c168d0
|
@ -3,7 +3,7 @@ from .. import auth, errors, utils
|
||||||
from ..types import ServiceMode
|
from ..types import ServiceMode
|
||||||
|
|
||||||
|
|
||||||
def _check_api_features(version, task_template, update_config):
|
def _check_api_features(version, task_template, update_config, endpoint_spec):
|
||||||
|
|
||||||
def raise_version_error(param, min_version):
|
def raise_version_error(param, min_version):
|
||||||
raise errors.InvalidVersion(
|
raise errors.InvalidVersion(
|
||||||
|
@ -23,6 +23,11 @@ def _check_api_features(version, task_template, update_config):
|
||||||
if 'Order' in update_config:
|
if 'Order' in update_config:
|
||||||
raise_version_error('UpdateConfig.order', '1.29')
|
raise_version_error('UpdateConfig.order', '1.29')
|
||||||
|
|
||||||
|
if endpoint_spec is not None:
|
||||||
|
if utils.version_lt(version, '1.32') and 'Ports' in endpoint_spec:
|
||||||
|
if any(p.get('PublishMode') for p in endpoint_spec['Ports']):
|
||||||
|
raise_version_error('EndpointSpec.Ports[].mode', '1.32')
|
||||||
|
|
||||||
if task_template is not None:
|
if task_template is not None:
|
||||||
if 'ForceUpdate' in task_template and utils.version_lt(
|
if 'ForceUpdate' in task_template and utils.version_lt(
|
||||||
version, '1.25'):
|
version, '1.25'):
|
||||||
|
@ -125,7 +130,9 @@ class ServiceApiMixin(object):
|
||||||
)
|
)
|
||||||
endpoint_spec = endpoint_config
|
endpoint_spec = endpoint_config
|
||||||
|
|
||||||
_check_api_features(self._version, task_template, update_config)
|
_check_api_features(
|
||||||
|
self._version, task_template, update_config, endpoint_spec
|
||||||
|
)
|
||||||
|
|
||||||
url = self._url('/services/create')
|
url = self._url('/services/create')
|
||||||
headers = {}
|
headers = {}
|
||||||
|
@ -370,7 +377,9 @@ class ServiceApiMixin(object):
|
||||||
)
|
)
|
||||||
endpoint_spec = endpoint_config
|
endpoint_spec = endpoint_config
|
||||||
|
|
||||||
_check_api_features(self._version, task_template, update_config)
|
_check_api_features(
|
||||||
|
self._version, task_template, update_config, endpoint_spec
|
||||||
|
)
|
||||||
|
|
||||||
if fetch_current_spec:
|
if fetch_current_spec:
|
||||||
inspect_defaults = True
|
inspect_defaults = True
|
||||||
|
|
|
@ -450,8 +450,9 @@ class EndpointSpec(dict):
|
||||||
``'vip'`` if not provided.
|
``'vip'`` if not provided.
|
||||||
ports (dict): Exposed ports that this service is accessible on from the
|
ports (dict): Exposed ports that this service is accessible on from the
|
||||||
outside, in the form of ``{ published_port: target_port }`` or
|
outside, in the form of ``{ published_port: target_port }`` or
|
||||||
``{ published_port: (target_port, protocol) }``. Ports can only be
|
``{ published_port: <port_config_tuple> }``. Port config tuple format
|
||||||
provided if the ``vip`` resolution mode is used.
|
is ``(target_port [, protocol [, publish_mode]])``.
|
||||||
|
Ports can only be provided if the ``vip`` resolution mode is used.
|
||||||
"""
|
"""
|
||||||
def __init__(self, mode=None, ports=None):
|
def __init__(self, mode=None, ports=None):
|
||||||
if ports:
|
if ports:
|
||||||
|
@ -477,8 +478,15 @@ def convert_service_ports(ports):
|
||||||
|
|
||||||
if isinstance(v, tuple):
|
if isinstance(v, tuple):
|
||||||
port_spec['TargetPort'] = v[0]
|
port_spec['TargetPort'] = v[0]
|
||||||
if len(v) == 2:
|
if len(v) >= 2 and v[1] is not None:
|
||||||
port_spec['Protocol'] = v[1]
|
port_spec['Protocol'] = v[1]
|
||||||
|
if len(v) == 3:
|
||||||
|
port_spec['PublishMode'] = v[2]
|
||||||
|
if len(v) > 3:
|
||||||
|
raise ValueError(
|
||||||
|
'Service port configuration can have at most 3 elements: '
|
||||||
|
'(target_port, protocol, mode)'
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
port_spec['TargetPort'] = v
|
port_spec['TargetPort'] = v
|
||||||
|
|
||||||
|
|
|
@ -353,7 +353,6 @@ class ServiceTest(BaseAPIIntegrationTest):
|
||||||
task_tmpl, name=name, endpoint_spec=endpoint_spec
|
task_tmpl, name=name, endpoint_spec=endpoint_spec
|
||||||
)
|
)
|
||||||
svc_info = self.client.inspect_service(svc_id)
|
svc_info = self.client.inspect_service(svc_id)
|
||||||
print(svc_info)
|
|
||||||
ports = svc_info['Spec']['EndpointSpec']['Ports']
|
ports = svc_info['Spec']['EndpointSpec']['Ports']
|
||||||
for port in ports:
|
for port in ports:
|
||||||
if port['PublishedPort'] == 12562:
|
if port['PublishedPort'] == 12562:
|
||||||
|
@ -370,6 +369,26 @@ class ServiceTest(BaseAPIIntegrationTest):
|
||||||
|
|
||||||
assert len(ports) == 3
|
assert len(ports) == 3
|
||||||
|
|
||||||
|
@requires_api_version('1.32')
|
||||||
|
def test_create_service_with_endpoint_spec_host_publish_mode(self):
|
||||||
|
container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])
|
||||||
|
task_tmpl = docker.types.TaskTemplate(container_spec)
|
||||||
|
name = self.get_service_name()
|
||||||
|
endpoint_spec = docker.types.EndpointSpec(ports={
|
||||||
|
12357: (1990, None, 'host'),
|
||||||
|
})
|
||||||
|
svc_id = self.client.create_service(
|
||||||
|
task_tmpl, name=name, endpoint_spec=endpoint_spec
|
||||||
|
)
|
||||||
|
svc_info = self.client.inspect_service(svc_id)
|
||||||
|
ports = svc_info['Spec']['EndpointSpec']['Ports']
|
||||||
|
assert len(ports) == 1
|
||||||
|
port = ports[0]
|
||||||
|
assert port['PublishedPort'] == 12357
|
||||||
|
assert port['TargetPort'] == 1990
|
||||||
|
assert port['Protocol'] == 'tcp'
|
||||||
|
assert port['PublishMode'] == 'host'
|
||||||
|
|
||||||
def test_create_service_with_env(self):
|
def test_create_service_with_env(self):
|
||||||
container_spec = docker.types.ContainerSpec(
|
container_spec = docker.types.ContainerSpec(
|
||||||
BUSYBOX, ['true'], env={'DOCKER_PY_TEST': 1}
|
BUSYBOX, ['true'], env={'DOCKER_PY_TEST': 1}
|
||||||
|
|
|
@ -11,6 +11,7 @@ from docker.types import (
|
||||||
ContainerConfig, ContainerSpec, EndpointConfig, HostConfig, IPAMConfig,
|
ContainerConfig, ContainerSpec, EndpointConfig, HostConfig, IPAMConfig,
|
||||||
IPAMPool, LogConfig, Mount, ServiceMode, Ulimit,
|
IPAMPool, LogConfig, Mount, ServiceMode, Ulimit,
|
||||||
)
|
)
|
||||||
|
from docker.types.services import convert_service_ports
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
@ -423,3 +424,77 @@ class MountTest(unittest.TestCase):
|
||||||
assert mount['Source'] == "C:/foo/bar"
|
assert mount['Source'] == "C:/foo/bar"
|
||||||
assert mount['Target'] == "/baz"
|
assert mount['Target'] == "/baz"
|
||||||
assert mount['Type'] == 'bind'
|
assert mount['Type'] == 'bind'
|
||||||
|
|
||||||
|
|
||||||
|
class ServicePortsTest(unittest.TestCase):
|
||||||
|
def test_convert_service_ports_simple(self):
|
||||||
|
ports = {8080: 80}
|
||||||
|
assert convert_service_ports(ports) == [{
|
||||||
|
'Protocol': 'tcp',
|
||||||
|
'PublishedPort': 8080,
|
||||||
|
'TargetPort': 80,
|
||||||
|
}]
|
||||||
|
|
||||||
|
def test_convert_service_ports_with_protocol(self):
|
||||||
|
ports = {8080: (80, 'udp')}
|
||||||
|
|
||||||
|
assert convert_service_ports(ports) == [{
|
||||||
|
'Protocol': 'udp',
|
||||||
|
'PublishedPort': 8080,
|
||||||
|
'TargetPort': 80,
|
||||||
|
}]
|
||||||
|
|
||||||
|
def test_convert_service_ports_with_protocol_and_mode(self):
|
||||||
|
ports = {8080: (80, 'udp', 'ingress')}
|
||||||
|
|
||||||
|
assert convert_service_ports(ports) == [{
|
||||||
|
'Protocol': 'udp',
|
||||||
|
'PublishedPort': 8080,
|
||||||
|
'TargetPort': 80,
|
||||||
|
'PublishMode': 'ingress',
|
||||||
|
}]
|
||||||
|
|
||||||
|
def test_convert_service_ports_invalid(self):
|
||||||
|
ports = {8080: ('way', 'too', 'many', 'items', 'here')}
|
||||||
|
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
convert_service_ports(ports)
|
||||||
|
|
||||||
|
def test_convert_service_ports_no_protocol_and_mode(self):
|
||||||
|
ports = {8080: (80, None, 'host')}
|
||||||
|
|
||||||
|
assert convert_service_ports(ports) == [{
|
||||||
|
'Protocol': 'tcp',
|
||||||
|
'PublishedPort': 8080,
|
||||||
|
'TargetPort': 80,
|
||||||
|
'PublishMode': 'host',
|
||||||
|
}]
|
||||||
|
|
||||||
|
def test_convert_service_ports_multiple(self):
|
||||||
|
ports = {
|
||||||
|
8080: (80, None, 'host'),
|
||||||
|
9999: 99,
|
||||||
|
2375: (2375,)
|
||||||
|
}
|
||||||
|
|
||||||
|
converted_ports = convert_service_ports(ports)
|
||||||
|
assert {
|
||||||
|
'Protocol': 'tcp',
|
||||||
|
'PublishedPort': 8080,
|
||||||
|
'TargetPort': 80,
|
||||||
|
'PublishMode': 'host',
|
||||||
|
} in converted_ports
|
||||||
|
|
||||||
|
assert {
|
||||||
|
'Protocol': 'tcp',
|
||||||
|
'PublishedPort': 9999,
|
||||||
|
'TargetPort': 99,
|
||||||
|
} in converted_ports
|
||||||
|
|
||||||
|
assert {
|
||||||
|
'Protocol': 'tcp',
|
||||||
|
'PublishedPort': 2375,
|
||||||
|
'TargetPort': 2375,
|
||||||
|
} in converted_ports
|
||||||
|
|
||||||
|
assert len(converted_ports) == 3
|
||||||
|
|
Loading…
Reference in New Issue