diff --git a/docker/api/service.py b/docker/api/service.py index 372dd10b5..e9027bfa2 100644 --- a/docker/api/service.py +++ b/docker/api/service.py @@ -135,8 +135,9 @@ def create_service( of the service. Default: ``None`` rollback_config (RollbackConfig): Specification for the rollback strategy of the service. Default: ``None`` - networks (:py:class:`list`): List of network names or IDs to attach - the service to. Default: ``None``. + networks (:py:class:`list`): List of network names or IDs or + :py:class:`~docker.types.NetworkAttachmentConfig` to attach the + service to. Default: ``None``. endpoint_spec (EndpointSpec): Properties that can be configured to access and load balance a service. Default: ``None``. @@ -383,8 +384,9 @@ def update_service(self, service, version, task_template=None, name=None, of the service. Default: ``None``. rollback_config (RollbackConfig): Specification for the rollback strategy of the service. Default: ``None`` - networks (:py:class:`list`): List of network names or IDs to attach - the service to. Default: ``None``. + networks (:py:class:`list`): List of network names or IDs or + :py:class:`~docker.types.NetworkAttachmentConfig` to attach 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 diff --git a/docker/models/services.py b/docker/models/services.py index 2b6479f2a..5eff8c88b 100644 --- a/docker/models/services.py +++ b/docker/models/services.py @@ -178,8 +178,9 @@ def create(self, image, command=None, **kwargs): ``source:target:options``, where options is either ``ro`` or ``rw``. name (str): Name to give to the service. - networks (list of str): List of network names or IDs to attach - the service to. Default: ``None``. + networks (:py:class:`list`): List of network names or IDs or + :py:class:`~docker.types.NetworkAttachmentConfig` to attach the + service to. Default: ``None``. resources (Resources): Resource limits and reservations. restart_policy (RestartPolicy): Restart policy for containers. secrets (list of :py:class:`docker.types.SecretReference`): List diff --git a/docker/types/__init__.py b/docker/types/__init__.py index f3cac1bc1..5db330e28 100644 --- a/docker/types/__init__.py +++ b/docker/types/__init__.py @@ -7,6 +7,6 @@ ConfigReference, ContainerSpec, DNSConfig, DriverConfig, EndpointSpec, Mount, Placement, PlacementPreference, Privileges, Resources, RestartPolicy, RollbackConfig, SecretReference, ServiceMode, TaskTemplate, - UpdateConfig + UpdateConfig, NetworkAttachmentConfig ) from .swarm import SwarmSpec, SwarmExternalCA diff --git a/docker/types/services.py b/docker/types/services.py index 5722b0e33..05dda15d7 100644 --- a/docker/types/services.py +++ b/docker/types/services.py @@ -26,8 +26,8 @@ class TaskTemplate(dict): placement (Placement): Placement instructions for the scheduler. If a list is passed instead, it is assumed to be a list of constraints as part of a :py:class:`Placement` object. - networks (:py:class:`list`): List of network names or IDs to attach - the containers to. + networks (:py:class:`list`): List of network names or IDs or + :py:class:`NetworkAttachmentConfig` to attach the service to. force_update (int): A counter that triggers an update even if no relevant parameters have been changed. """ @@ -770,3 +770,21 @@ def __init__(self, credentialspec_file=None, credentialspec_registry=None, if len(selinux_context) > 0: self['SELinuxContext'] = selinux_context + + +class NetworkAttachmentConfig(dict): + """ + Network attachment options for a service. + + Args: + target (str): The target network for attachment. + Can be a network name or ID. + aliases (:py:class:`list`): A list of discoverable alternate names + for the service. + options (:py:class:`dict`): Driver attachment options for the + network target. + """ + def __init__(self, target, aliases=None, options=None): + self['Target'] = target + self['Aliases'] = aliases + self['DriverOpts'] = options diff --git a/docs/api.rst b/docs/api.rst index edb8fffad..bd0466143 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -142,6 +142,7 @@ Configuration types .. autoclass:: IPAMPool .. autoclass:: LogConfig .. autoclass:: Mount +.. autoclass:: NetworkAttachmentConfig .. autoclass:: Placement .. autoclass:: PlacementPreference .. autoclass:: Privileges diff --git a/tests/integration/api_service_test.py b/tests/integration/api_service_test.py index 71e0869e9..520c0d682 100644 --- a/tests/integration/api_service_test.py +++ b/tests/integration/api_service_test.py @@ -371,6 +371,35 @@ def test_create_service_with_custom_networks(self): {'Target': net1['Id']}, {'Target': net2['Id']} ] + def test_create_service_with_network_attachment_config(self): + network = self.client.create_network( + 'dockerpytest_1', driver='overlay', ipam={'Driver': 'default'} + ) + self.tmp_networks.append(network['Id']) + container_spec = docker.types.ContainerSpec(BUSYBOX, ['true']) + network_config = docker.types.NetworkAttachmentConfig( + target='dockerpytest_1', + aliases=['dockerpytest_1_alias'], + options={ + 'foo': 'bar' + } + ) + task_tmpl = docker.types.TaskTemplate( + container_spec, + networks=[network_config] + ) + name = self.get_service_name() + svc_id = self.client.create_service( + task_tmpl, name=name + ) + svc_info = self.client.inspect_service(svc_id) + assert 'Networks' in svc_info['Spec']['TaskTemplate'] + service_networks_info = svc_info['Spec']['TaskTemplate']['Networks'] + assert len(service_networks_info) == 1 + assert service_networks_info[0]['Target'] == network['Id'] + assert service_networks_info[0]['Aliases'] == ['dockerpytest_1_alias'] + assert service_networks_info[0]['DriverOpts'] == {'foo': 'bar'} + def test_create_service_with_placement(self): node_id = self.client.nodes()[0]['ID'] container_spec = docker.types.ContainerSpec(BUSYBOX, ['true'])