mirror of https://github.com/docker/compose.git
Merge pull request #2743 from aanand/network-mode
Implement network_mode option
This commit is contained in:
commit
4b84d088e0
|
@ -19,7 +19,8 @@ from .errors import CircularReference
|
||||||
from .errors import ComposeFileNotFound
|
from .errors import ComposeFileNotFound
|
||||||
from .errors import ConfigurationError
|
from .errors import ConfigurationError
|
||||||
from .interpolation import interpolate_environment_variables
|
from .interpolation import interpolate_environment_variables
|
||||||
from .sort_services import get_service_name_from_net
|
from .sort_services import get_container_name_from_network_mode
|
||||||
|
from .sort_services import get_service_name_from_network_mode
|
||||||
from .sort_services import sort_service_dicts
|
from .sort_services import sort_service_dicts
|
||||||
from .types import parse_extra_hosts
|
from .types import parse_extra_hosts
|
||||||
from .types import parse_restart_spec
|
from .types import parse_restart_spec
|
||||||
|
@ -30,6 +31,7 @@ from .validation import validate_against_fields_schema
|
||||||
from .validation import validate_against_service_schema
|
from .validation import validate_against_service_schema
|
||||||
from .validation import validate_depends_on
|
from .validation import validate_depends_on
|
||||||
from .validation import validate_extends_file_path
|
from .validation import validate_extends_file_path
|
||||||
|
from .validation import validate_network_mode
|
||||||
from .validation import validate_top_level_object
|
from .validation import validate_top_level_object
|
||||||
from .validation import validate_top_level_service_objects
|
from .validation import validate_top_level_service_objects
|
||||||
from .validation import validate_ulimits
|
from .validation import validate_ulimits
|
||||||
|
@ -490,10 +492,15 @@ def validate_extended_service_dict(service_dict, filename, service):
|
||||||
"%s services with 'volumes_from' cannot be extended" % error_prefix)
|
"%s services with 'volumes_from' cannot be extended" % error_prefix)
|
||||||
|
|
||||||
if 'net' in service_dict:
|
if 'net' in service_dict:
|
||||||
if get_service_name_from_net(service_dict['net']) is not None:
|
if get_container_name_from_network_mode(service_dict['net']):
|
||||||
raise ConfigurationError(
|
raise ConfigurationError(
|
||||||
"%s services with 'net: container' cannot be extended" % error_prefix)
|
"%s services with 'net: container' cannot be extended" % error_prefix)
|
||||||
|
|
||||||
|
if 'network_mode' in service_dict:
|
||||||
|
if get_service_name_from_network_mode(service_dict['network_mode']):
|
||||||
|
raise ConfigurationError(
|
||||||
|
"%s services with 'network_mode: service' cannot be extended" % error_prefix)
|
||||||
|
|
||||||
if 'depends_on' in service_dict:
|
if 'depends_on' in service_dict:
|
||||||
raise ConfigurationError(
|
raise ConfigurationError(
|
||||||
"%s services with 'depends_on' cannot be extended" % error_prefix)
|
"%s services with 'depends_on' cannot be extended" % error_prefix)
|
||||||
|
@ -505,6 +512,7 @@ def validate_service(service_config, service_names, version):
|
||||||
validate_paths(service_dict)
|
validate_paths(service_dict)
|
||||||
|
|
||||||
validate_ulimits(service_config)
|
validate_ulimits(service_config)
|
||||||
|
validate_network_mode(service_config, service_names)
|
||||||
validate_depends_on(service_config, service_names)
|
validate_depends_on(service_config, service_names)
|
||||||
|
|
||||||
if not service_dict.get('image') and has_uppercase(service_name):
|
if not service_dict.get('image') and has_uppercase(service_name):
|
||||||
|
@ -565,6 +573,14 @@ def finalize_service(service_config, service_names, version):
|
||||||
service_dict['volumes'] = [
|
service_dict['volumes'] = [
|
||||||
VolumeSpec.parse(v) for v in service_dict['volumes']]
|
VolumeSpec.parse(v) for v in service_dict['volumes']]
|
||||||
|
|
||||||
|
if 'net' in service_dict:
|
||||||
|
network_mode = service_dict.pop('net')
|
||||||
|
container_name = get_container_name_from_network_mode(network_mode)
|
||||||
|
if container_name and container_name in service_names:
|
||||||
|
service_dict['network_mode'] = 'service:{}'.format(container_name)
|
||||||
|
else:
|
||||||
|
service_dict['network_mode'] = network_mode
|
||||||
|
|
||||||
if 'restart' in service_dict:
|
if 'restart' in service_dict:
|
||||||
service_dict['restart'] = parse_restart_spec(service_dict['restart'])
|
service_dict['restart'] = parse_restart_spec(service_dict['restart'])
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,7 @@
|
||||||
"mac_address": {"type": "string"},
|
"mac_address": {"type": "string"},
|
||||||
"mem_limit": {"type": ["number", "string"]},
|
"mem_limit": {"type": ["number", "string"]},
|
||||||
"memswap_limit": {"type": ["number", "string"]},
|
"memswap_limit": {"type": ["number", "string"]},
|
||||||
|
"network_mode": {"type": "string"},
|
||||||
|
|
||||||
"networks": {
|
"networks": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
|
|
@ -4,14 +4,22 @@ from __future__ import unicode_literals
|
||||||
from compose.config.errors import DependencyError
|
from compose.config.errors import DependencyError
|
||||||
|
|
||||||
|
|
||||||
def get_service_name_from_net(net_config):
|
def get_service_name_from_network_mode(network_mode):
|
||||||
if not net_config:
|
return get_source_name_from_network_mode(network_mode, 'service')
|
||||||
|
|
||||||
|
|
||||||
|
def get_container_name_from_network_mode(network_mode):
|
||||||
|
return get_source_name_from_network_mode(network_mode, 'container')
|
||||||
|
|
||||||
|
|
||||||
|
def get_source_name_from_network_mode(network_mode, source_type):
|
||||||
|
if not network_mode:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not net_config.startswith('container:'):
|
if not network_mode.startswith(source_type+':'):
|
||||||
return
|
return
|
||||||
|
|
||||||
_, net_name = net_config.split(':', 1)
|
_, net_name = network_mode.split(':', 1)
|
||||||
return net_name
|
return net_name
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,7 +41,7 @@ def sort_service_dicts(services):
|
||||||
service for service in services
|
service for service in services
|
||||||
if (name in get_service_names(service.get('links', [])) or
|
if (name in get_service_names(service.get('links', [])) or
|
||||||
name in get_service_names_from_volumes_from(service.get('volumes_from', [])) or
|
name in get_service_names_from_volumes_from(service.get('volumes_from', [])) or
|
||||||
name == get_service_name_from_net(service.get('net')) or
|
name == get_service_name_from_network_mode(service.get('network_mode')) or
|
||||||
name in service.get('depends_on', []))
|
name in service.get('depends_on', []))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ from jsonschema import RefResolver
|
||||||
from jsonschema import ValidationError
|
from jsonschema import ValidationError
|
||||||
|
|
||||||
from .errors import ConfigurationError
|
from .errors import ConfigurationError
|
||||||
|
from .sort_services import get_service_name_from_network_mode
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
@ -147,6 +148,24 @@ def validate_extends_file_path(service_name, extends_options, filename):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_network_mode(service_config, service_names):
|
||||||
|
network_mode = service_config.config.get('network_mode')
|
||||||
|
if not network_mode:
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'networks' in service_config.config:
|
||||||
|
raise ConfigurationError("'network_mode' and 'networks' cannot be combined")
|
||||||
|
|
||||||
|
dependency = get_service_name_from_network_mode(network_mode)
|
||||||
|
if not dependency:
|
||||||
|
return
|
||||||
|
|
||||||
|
if dependency not in service_names:
|
||||||
|
raise ConfigurationError(
|
||||||
|
"Service '{s.name}' uses the network stack of service '{dep}' which "
|
||||||
|
"is undefined.".format(s=service_config, dep=dependency))
|
||||||
|
|
||||||
|
|
||||||
def validate_depends_on(service_config, service_names):
|
def validate_depends_on(service_config, service_names):
|
||||||
for dependency in service_config.config.get('depends_on', []):
|
for dependency in service_config.config.get('depends_on', []):
|
||||||
if dependency not in service_names:
|
if dependency not in service_names:
|
||||||
|
|
|
@ -10,7 +10,8 @@ from docker.errors import NotFound
|
||||||
|
|
||||||
from . import parallel
|
from . import parallel
|
||||||
from .config import ConfigurationError
|
from .config import ConfigurationError
|
||||||
from .config.sort_services import get_service_name_from_net
|
from .config.sort_services import get_container_name_from_network_mode
|
||||||
|
from .config.sort_services import get_service_name_from_network_mode
|
||||||
from .const import DEFAULT_TIMEOUT
|
from .const import DEFAULT_TIMEOUT
|
||||||
from .const import IMAGE_EVENTS
|
from .const import IMAGE_EVENTS
|
||||||
from .const import LABEL_ONE_OFF
|
from .const import LABEL_ONE_OFF
|
||||||
|
@ -18,11 +19,11 @@ from .const import LABEL_PROJECT
|
||||||
from .const import LABEL_SERVICE
|
from .const import LABEL_SERVICE
|
||||||
from .container import Container
|
from .container import Container
|
||||||
from .network import Network
|
from .network import Network
|
||||||
from .service import ContainerNet
|
from .service import ContainerNetworkMode
|
||||||
from .service import ConvergenceStrategy
|
from .service import ConvergenceStrategy
|
||||||
from .service import Net
|
from .service import NetworkMode
|
||||||
from .service import Service
|
from .service import Service
|
||||||
from .service import ServiceNet
|
from .service import ServiceNetworkMode
|
||||||
from .utils import microseconds_from_time_nano
|
from .utils import microseconds_from_time_nano
|
||||||
from .volume import Volume
|
from .volume import Volume
|
||||||
|
|
||||||
|
@ -86,12 +87,11 @@ class Project(object):
|
||||||
for service_dict in config_data.services:
|
for service_dict in config_data.services:
|
||||||
if use_networking:
|
if use_networking:
|
||||||
networks = get_networks(service_dict, all_networks)
|
networks = get_networks(service_dict, all_networks)
|
||||||
net = Net(networks[0]) if networks else Net("none")
|
|
||||||
else:
|
else:
|
||||||
networks = []
|
networks = []
|
||||||
net = project.get_net(service_dict)
|
|
||||||
|
|
||||||
links = project.get_links(service_dict)
|
links = project.get_links(service_dict)
|
||||||
|
network_mode = project.get_network_mode(service_dict, networks)
|
||||||
volumes_from = get_volumes_from(project, service_dict)
|
volumes_from = get_volumes_from(project, service_dict)
|
||||||
|
|
||||||
if config_data.version == 2:
|
if config_data.version == 2:
|
||||||
|
@ -110,7 +110,7 @@ class Project(object):
|
||||||
use_networking=use_networking,
|
use_networking=use_networking,
|
||||||
networks=networks,
|
networks=networks,
|
||||||
links=links,
|
links=links,
|
||||||
net=net,
|
network_mode=network_mode,
|
||||||
volumes_from=volumes_from,
|
volumes_from=volumes_from,
|
||||||
**service_dict)
|
**service_dict)
|
||||||
)
|
)
|
||||||
|
@ -197,27 +197,27 @@ class Project(object):
|
||||||
del service_dict['links']
|
del service_dict['links']
|
||||||
return links
|
return links
|
||||||
|
|
||||||
def get_net(self, service_dict):
|
def get_network_mode(self, service_dict, networks):
|
||||||
net = service_dict.pop('net', None)
|
network_mode = service_dict.pop('network_mode', None)
|
||||||
if not net:
|
if not network_mode:
|
||||||
return Net(None)
|
if self.use_networking:
|
||||||
|
return NetworkMode(networks[0]) if networks else NetworkMode('none')
|
||||||
|
return NetworkMode(None)
|
||||||
|
|
||||||
net_name = get_service_name_from_net(net)
|
service_name = get_service_name_from_network_mode(network_mode)
|
||||||
if not net_name:
|
if service_name:
|
||||||
return Net(net)
|
return ServiceNetworkMode(self.get_service(service_name))
|
||||||
|
|
||||||
|
container_name = get_container_name_from_network_mode(network_mode)
|
||||||
|
if container_name:
|
||||||
try:
|
try:
|
||||||
return ServiceNet(self.get_service(net_name))
|
return ContainerNetworkMode(Container.from_id(self.client, container_name))
|
||||||
except NoSuchService:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
return ContainerNet(Container.from_id(self.client, net_name))
|
|
||||||
except APIError:
|
except APIError:
|
||||||
raise ConfigurationError(
|
raise ConfigurationError(
|
||||||
'Service "%s" is trying to use the network of "%s", '
|
"Service '{name}' uses the network stack of container '{dep}' which "
|
||||||
'which is not the name of a service or container.' % (
|
"does not exist.".format(name=service_dict['name'], dep=container_name))
|
||||||
service_dict['name'],
|
|
||||||
net_name))
|
return NetworkMode(network_mode)
|
||||||
|
|
||||||
def start(self, service_names=None, **options):
|
def start(self, service_names=None, **options):
|
||||||
containers = []
|
containers = []
|
||||||
|
@ -465,9 +465,12 @@ class Project(object):
|
||||||
|
|
||||||
|
|
||||||
def get_networks(service_dict, network_definitions):
|
def get_networks(service_dict, network_definitions):
|
||||||
|
if 'network_mode' in service_dict:
|
||||||
|
return []
|
||||||
|
|
||||||
networks = []
|
networks = []
|
||||||
for name in service_dict.pop('networks', ['default']):
|
for name in service_dict.pop('networks', ['default']):
|
||||||
if name in ['bridge', 'host']:
|
if name in ['bridge']:
|
||||||
networks.append(name)
|
networks.append(name)
|
||||||
else:
|
else:
|
||||||
matches = [n for n in network_definitions if n.name == name]
|
matches = [n for n in network_definitions if n.name == name]
|
||||||
|
|
|
@ -47,7 +47,6 @@ DOCKER_START_KEYS = [
|
||||||
'extra_hosts',
|
'extra_hosts',
|
||||||
'ipc',
|
'ipc',
|
||||||
'read_only',
|
'read_only',
|
||||||
'net',
|
|
||||||
'log_driver',
|
'log_driver',
|
||||||
'log_opt',
|
'log_opt',
|
||||||
'mem_limit',
|
'mem_limit',
|
||||||
|
@ -113,7 +112,7 @@ class Service(object):
|
||||||
use_networking=False,
|
use_networking=False,
|
||||||
links=None,
|
links=None,
|
||||||
volumes_from=None,
|
volumes_from=None,
|
||||||
net=None,
|
network_mode=None,
|
||||||
networks=None,
|
networks=None,
|
||||||
**options
|
**options
|
||||||
):
|
):
|
||||||
|
@ -123,7 +122,7 @@ class Service(object):
|
||||||
self.use_networking = use_networking
|
self.use_networking = use_networking
|
||||||
self.links = links or []
|
self.links = links or []
|
||||||
self.volumes_from = volumes_from or []
|
self.volumes_from = volumes_from or []
|
||||||
self.net = net or Net(None)
|
self.network_mode = network_mode or NetworkMode(None)
|
||||||
self.networks = networks or []
|
self.networks = networks or []
|
||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
|
@ -472,7 +471,7 @@ class Service(object):
|
||||||
'options': self.options,
|
'options': self.options,
|
||||||
'image_id': self.image()['Id'],
|
'image_id': self.image()['Id'],
|
||||||
'links': self.get_link_names(),
|
'links': self.get_link_names(),
|
||||||
'net': self.net.id,
|
'net': self.network_mode.id,
|
||||||
'volumes_from': [
|
'volumes_from': [
|
||||||
(v.source.name, v.mode)
|
(v.source.name, v.mode)
|
||||||
for v in self.volumes_from if isinstance(v.source, Service)
|
for v in self.volumes_from if isinstance(v.source, Service)
|
||||||
|
@ -480,7 +479,7 @@ class Service(object):
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_dependency_names(self):
|
def get_dependency_names(self):
|
||||||
net_name = self.net.service_name
|
net_name = self.network_mode.service_name
|
||||||
return (self.get_linked_service_names() +
|
return (self.get_linked_service_names() +
|
||||||
self.get_volumes_from_names() +
|
self.get_volumes_from_names() +
|
||||||
([net_name] if net_name else []) +
|
([net_name] if net_name else []) +
|
||||||
|
@ -636,7 +635,7 @@ class Service(object):
|
||||||
binds=options.get('binds'),
|
binds=options.get('binds'),
|
||||||
volumes_from=self._get_volumes_from(),
|
volumes_from=self._get_volumes_from(),
|
||||||
privileged=options.get('privileged', False),
|
privileged=options.get('privileged', False),
|
||||||
network_mode=self.net.mode,
|
network_mode=self.network_mode.mode,
|
||||||
devices=options.get('devices'),
|
devices=options.get('devices'),
|
||||||
dns=options.get('dns'),
|
dns=options.get('dns'),
|
||||||
dns_search=options.get('dns_search'),
|
dns_search=options.get('dns_search'),
|
||||||
|
@ -774,22 +773,22 @@ class Service(object):
|
||||||
log.error(six.text_type(e))
|
log.error(six.text_type(e))
|
||||||
|
|
||||||
|
|
||||||
class Net(object):
|
class NetworkMode(object):
|
||||||
"""A `standard` network mode (ex: host, bridge)"""
|
"""A `standard` network mode (ex: host, bridge)"""
|
||||||
|
|
||||||
service_name = None
|
service_name = None
|
||||||
|
|
||||||
def __init__(self, net):
|
def __init__(self, network_mode):
|
||||||
self.net = net
|
self.network_mode = network_mode
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
return self.net
|
return self.network_mode
|
||||||
|
|
||||||
mode = id
|
mode = id
|
||||||
|
|
||||||
|
|
||||||
class ContainerNet(object):
|
class ContainerNetworkMode(object):
|
||||||
"""A network mode that uses a container's network stack."""
|
"""A network mode that uses a container's network stack."""
|
||||||
|
|
||||||
service_name = None
|
service_name = None
|
||||||
|
@ -806,7 +805,7 @@ class ContainerNet(object):
|
||||||
return 'container:' + self.container.id
|
return 'container:' + self.container.id
|
||||||
|
|
||||||
|
|
||||||
class ServiceNet(object):
|
class ServiceNetworkMode(object):
|
||||||
"""A network mode that uses a service's network stack."""
|
"""A network mode that uses a service's network stack."""
|
||||||
|
|
||||||
def __init__(self, service):
|
def __init__(self, service):
|
||||||
|
|
|
@ -437,14 +437,29 @@ Specify logging options as key-value pairs. An example of `syslog` options:
|
||||||
### net
|
### net
|
||||||
|
|
||||||
> [Version 1 file format](#version-1) only. In version 2, use
|
> [Version 1 file format](#version-1) only. In version 2, use
|
||||||
> [networks](#networks).
|
> [network_mode](#network_mode).
|
||||||
|
|
||||||
Networking mode. Use the same values as the docker client `--net` parameter.
|
Network mode. Use the same values as the docker client `--net` parameter.
|
||||||
|
The `container:...` form can take a service name instead of a container name or
|
||||||
|
id.
|
||||||
|
|
||||||
net: "bridge"
|
net: "bridge"
|
||||||
net: "none"
|
|
||||||
net: "container:[name or id]"
|
|
||||||
net: "host"
|
net: "host"
|
||||||
|
net: "none"
|
||||||
|
net: "container:[service name or container name/id]"
|
||||||
|
|
||||||
|
### network_mode
|
||||||
|
|
||||||
|
> [Version 2 file format](#version-1) only. In version 1, use [net](#net).
|
||||||
|
|
||||||
|
Network mode. Use the same values as the docker client `--net` parameter, plus
|
||||||
|
the special form `service:[service name]`.
|
||||||
|
|
||||||
|
network_mode: "bridge"
|
||||||
|
network_mode: "host"
|
||||||
|
network_mode: "none"
|
||||||
|
network_mode: "service:[service name]"
|
||||||
|
network_mode: "container:[container name/id]"
|
||||||
|
|
||||||
### networks
|
### networks
|
||||||
|
|
||||||
|
@ -457,8 +472,8 @@ Networks to join, referencing entries under the
|
||||||
- some-network
|
- some-network
|
||||||
- other-network
|
- other-network
|
||||||
|
|
||||||
The values `bridge`, `host` and `none` can also be used, and are equivalent to
|
The value `bridge` can also be used to make containers join the pre-defined
|
||||||
`net: "bridge"`, `net: "host"` or `net: "none"` in version 1.
|
`bridge` network.
|
||||||
|
|
||||||
There is no equivalent to `net: "container:[name or id]"`.
|
There is no equivalent to `net: "container:[name or id]"`.
|
||||||
|
|
||||||
|
@ -918,16 +933,22 @@ It's more complicated if you're using particular configuration features:
|
||||||
your service's containers to an
|
your service's containers to an
|
||||||
[external network](networking.md#using-a-pre-existing-network).
|
[external network](networking.md#using-a-pre-existing-network).
|
||||||
|
|
||||||
- `net`: If you're using `host`, `bridge` or `none`, this is now replaced by
|
- `net`: This is now replaced by [network_mode](#network_mode):
|
||||||
`networks`:
|
|
||||||
|
|
||||||
net: host -> networks: ["host"]
|
net: host -> network_mode: host
|
||||||
net: bridge -> networks: ["bridge"]
|
net: bridge -> network_mode: bridge
|
||||||
net: none -> networks: ["none"]
|
net: none -> network_mode: none
|
||||||
|
|
||||||
If you're using `net: "container:<name>"`, there is no equivalent to this in
|
If you're using `net: "container:[service name]"`, you must now use
|
||||||
version 2 - you should use [Docker networks](networking.md) for
|
`network_mode: "service:[service name]"` instead.
|
||||||
communication instead.
|
|
||||||
|
net: "container:web" -> network_mode: "service:web"
|
||||||
|
|
||||||
|
If you're using `net: "container:[container name/id]"`, the value does not
|
||||||
|
need to change.
|
||||||
|
|
||||||
|
net: "container:cont-name" -> network_mode: "container:cont-name"
|
||||||
|
net: "container:abc12345" -> network_mode: "container:abc12345"
|
||||||
|
|
||||||
|
|
||||||
## Variable substitution
|
## Variable substitution
|
||||||
|
|
|
@ -144,15 +144,3 @@ If you want your containers to join a pre-existing network, use the [`external`
|
||||||
name: my-pre-existing-network
|
name: my-pre-existing-network
|
||||||
|
|
||||||
Instead of attemping to create a network called `[projectname]_default`, Compose will look for a network called `my-pre-existing-network` and connect your app's containers to it.
|
Instead of attemping to create a network called `[projectname]_default`, Compose will look for a network called `my-pre-existing-network` and connect your app's containers to it.
|
||||||
|
|
||||||
## Custom container network modes
|
|
||||||
|
|
||||||
The `docker` CLI command allows you to specify a custom network mode for a container with the `--net` option - for example, `--net=host` specifies that the container should use the same network namespace as the Docker host, and `--net=none` specifies that it should have no networking capabilities.
|
|
||||||
|
|
||||||
To make use of this in Compose, specify a `networks` list with a single item `host`, `bridge` or `none`:
|
|
||||||
|
|
||||||
app:
|
|
||||||
build: ./app
|
|
||||||
networks: ["host"]
|
|
||||||
|
|
||||||
There is no equivalent to `--net=container:CONTAINER_NAME` in the v2 Compose file format. You should instead use networks to enable communication.
|
|
||||||
|
|
|
@ -496,8 +496,29 @@ class CLITestCase(DockerClientTestCase):
|
||||||
assert 'Service "web" uses an undefined network "foo"' in result.stderr
|
assert 'Service "web" uses an undefined network "foo"' in result.stderr
|
||||||
|
|
||||||
@v2_only()
|
@v2_only()
|
||||||
def test_up_predefined_networks(self):
|
def test_up_with_bridge_network_plus_default(self):
|
||||||
filename = 'predefined-networks.yml'
|
filename = 'bridge.yml'
|
||||||
|
|
||||||
|
self.base_dir = 'tests/fixtures/networks'
|
||||||
|
self._project = get_project(self.base_dir, [filename])
|
||||||
|
|
||||||
|
self.dispatch(['-f', filename, 'up', '-d'], None)
|
||||||
|
|
||||||
|
container = self.project.containers()[0]
|
||||||
|
|
||||||
|
assert sorted(list(container.get('NetworkSettings.Networks'))) == sorted([
|
||||||
|
'bridge',
|
||||||
|
self.project.default_network.full_name,
|
||||||
|
])
|
||||||
|
|
||||||
|
@v2_only()
|
||||||
|
def test_up_with_network_mode(self):
|
||||||
|
c = self.client.create_container('busybox', 'top', name='composetest_network_mode_container')
|
||||||
|
self.addCleanup(self.client.remove_container, c, force=True)
|
||||||
|
self.client.start(c)
|
||||||
|
container_mode_source = 'container:{}'.format(c['Id'])
|
||||||
|
|
||||||
|
filename = 'network-mode.yml'
|
||||||
|
|
||||||
self.base_dir = 'tests/fixtures/networks'
|
self.base_dir = 'tests/fixtures/networks'
|
||||||
self._project = get_project(self.base_dir, [filename])
|
self._project = get_project(self.base_dir, [filename])
|
||||||
|
@ -515,6 +536,16 @@ class CLITestCase(DockerClientTestCase):
|
||||||
assert list(container.get('NetworkSettings.Networks')) == [name]
|
assert list(container.get('NetworkSettings.Networks')) == [name]
|
||||||
assert container.get('HostConfig.NetworkMode') == name
|
assert container.get('HostConfig.NetworkMode') == name
|
||||||
|
|
||||||
|
service_mode_source = 'container:{}'.format(
|
||||||
|
self.project.get_service('bridge').containers()[0].id)
|
||||||
|
service_mode_container = self.project.get_service('service').containers()[0]
|
||||||
|
assert not service_mode_container.get('NetworkSettings.Networks')
|
||||||
|
assert service_mode_container.get('HostConfig.NetworkMode') == service_mode_source
|
||||||
|
|
||||||
|
container_mode_container = self.project.get_service('container').containers()[0]
|
||||||
|
assert not container_mode_container.get('NetworkSettings.Networks')
|
||||||
|
assert container_mode_container.get('HostConfig.NetworkMode') == container_mode_source
|
||||||
|
|
||||||
@v2_only()
|
@v2_only()
|
||||||
def test_up_external_networks(self):
|
def test_up_external_networks(self):
|
||||||
filename = 'external-networks.yml'
|
filename = 'external-networks.yml'
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
web:
|
web:
|
||||||
image: busybox
|
image: busybox
|
||||||
command: /bin/true
|
command: /bin/true
|
||||||
|
net: host
|
||||||
environment:
|
environment:
|
||||||
- FOO=1
|
- FOO=1
|
||||||
- BAR=1
|
- BAR=1
|
||||||
|
|
|
@ -11,6 +11,7 @@ myweb:
|
||||||
BAR: "2"
|
BAR: "2"
|
||||||
# add BAZ
|
# add BAZ
|
||||||
BAZ: "2"
|
BAZ: "2"
|
||||||
|
net: bridge
|
||||||
mydb:
|
mydb:
|
||||||
image: busybox
|
image: busybox
|
||||||
command: top
|
command: top
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
version: 2
|
||||||
|
services:
|
||||||
|
myweb:
|
||||||
|
build: '.'
|
||||||
|
extends:
|
||||||
|
service: web
|
||||||
|
command: top
|
||||||
|
web:
|
||||||
|
build: '.'
|
||||||
|
network_mode: "service:net"
|
||||||
|
net:
|
||||||
|
build: '.'
|
|
@ -0,0 +1,9 @@
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: busybox
|
||||||
|
command: top
|
||||||
|
networks:
|
||||||
|
- bridge
|
||||||
|
- default
|
|
@ -0,0 +1,27 @@
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
services:
|
||||||
|
bridge:
|
||||||
|
image: busybox
|
||||||
|
command: top
|
||||||
|
network_mode: bridge
|
||||||
|
|
||||||
|
service:
|
||||||
|
image: busybox
|
||||||
|
command: top
|
||||||
|
network_mode: "service:bridge"
|
||||||
|
|
||||||
|
container:
|
||||||
|
image: busybox
|
||||||
|
command: top
|
||||||
|
network_mode: "container:composetest_network_mode_container"
|
||||||
|
|
||||||
|
host:
|
||||||
|
image: busybox
|
||||||
|
command: top
|
||||||
|
network_mode: host
|
||||||
|
|
||||||
|
none:
|
||||||
|
image: busybox
|
||||||
|
command: top
|
||||||
|
network_mode: none
|
|
@ -1,17 +0,0 @@
|
||||||
version: 2
|
|
||||||
|
|
||||||
services:
|
|
||||||
bridge:
|
|
||||||
image: busybox
|
|
||||||
command: top
|
|
||||||
networks: ["bridge"]
|
|
||||||
|
|
||||||
host:
|
|
||||||
image: busybox
|
|
||||||
command: top
|
|
||||||
networks: ["host"]
|
|
||||||
|
|
||||||
none:
|
|
||||||
image: busybox
|
|
||||||
command: top
|
|
||||||
networks: []
|
|
|
@ -4,10 +4,12 @@ from __future__ import unicode_literals
|
||||||
import random
|
import random
|
||||||
|
|
||||||
import py
|
import py
|
||||||
|
import pytest
|
||||||
from docker.errors import NotFound
|
from docker.errors import NotFound
|
||||||
|
|
||||||
from .testcases import DockerClientTestCase
|
from .testcases import DockerClientTestCase
|
||||||
from compose.config import config
|
from compose.config import config
|
||||||
|
from compose.config import ConfigurationError
|
||||||
from compose.config.types import VolumeFromSpec
|
from compose.config.types import VolumeFromSpec
|
||||||
from compose.config.types import VolumeSpec
|
from compose.config.types import VolumeSpec
|
||||||
from compose.const import LABEL_PROJECT
|
from compose.const import LABEL_PROJECT
|
||||||
|
@ -104,7 +106,71 @@ class ProjectTest(DockerClientTestCase):
|
||||||
db = project.get_service('db')
|
db = project.get_service('db')
|
||||||
self.assertEqual(db._get_volumes_from(), [data_container.id + ':rw'])
|
self.assertEqual(db._get_volumes_from(), [data_container.id + ':rw'])
|
||||||
|
|
||||||
def test_net_from_service(self):
|
@v2_only()
|
||||||
|
def test_network_mode_from_service(self):
|
||||||
|
project = Project.from_config(
|
||||||
|
name='composetest',
|
||||||
|
client=self.client,
|
||||||
|
config_data=build_service_dicts({
|
||||||
|
'version': 2,
|
||||||
|
'services': {
|
||||||
|
'net': {
|
||||||
|
'image': 'busybox:latest',
|
||||||
|
'command': ["top"]
|
||||||
|
},
|
||||||
|
'web': {
|
||||||
|
'image': 'busybox:latest',
|
||||||
|
'network_mode': 'service:net',
|
||||||
|
'command': ["top"]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
project.up()
|
||||||
|
|
||||||
|
web = project.get_service('web')
|
||||||
|
net = project.get_service('net')
|
||||||
|
self.assertEqual(web.network_mode.mode, 'container:' + net.containers()[0].id)
|
||||||
|
|
||||||
|
@v2_only()
|
||||||
|
def test_network_mode_from_container(self):
|
||||||
|
def get_project():
|
||||||
|
return Project.from_config(
|
||||||
|
name='composetest',
|
||||||
|
config_data=build_service_dicts({
|
||||||
|
'version': 2,
|
||||||
|
'services': {
|
||||||
|
'web': {
|
||||||
|
'image': 'busybox:latest',
|
||||||
|
'network_mode': 'container:composetest_net_container'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
client=self.client,
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(ConfigurationError) as excinfo:
|
||||||
|
get_project()
|
||||||
|
|
||||||
|
assert "container 'composetest_net_container' which does not exist" in excinfo.exconly()
|
||||||
|
|
||||||
|
net_container = Container.create(
|
||||||
|
self.client,
|
||||||
|
image='busybox:latest',
|
||||||
|
name='composetest_net_container',
|
||||||
|
command='top',
|
||||||
|
labels={LABEL_PROJECT: 'composetest'},
|
||||||
|
)
|
||||||
|
net_container.start()
|
||||||
|
|
||||||
|
project = get_project()
|
||||||
|
project.up()
|
||||||
|
|
||||||
|
web = project.get_service('web')
|
||||||
|
self.assertEqual(web.network_mode.mode, 'container:' + net_container.id)
|
||||||
|
|
||||||
|
def test_net_from_service_v1(self):
|
||||||
project = Project.from_config(
|
project = Project.from_config(
|
||||||
name='composetest',
|
name='composetest',
|
||||||
config_data=build_service_dicts({
|
config_data=build_service_dicts({
|
||||||
|
@ -125,19 +191,11 @@ class ProjectTest(DockerClientTestCase):
|
||||||
|
|
||||||
web = project.get_service('web')
|
web = project.get_service('web')
|
||||||
net = project.get_service('net')
|
net = project.get_service('net')
|
||||||
self.assertEqual(web.net.mode, 'container:' + net.containers()[0].id)
|
self.assertEqual(web.network_mode.mode, 'container:' + net.containers()[0].id)
|
||||||
|
|
||||||
def test_net_from_container(self):
|
def test_net_from_container_v1(self):
|
||||||
net_container = Container.create(
|
def get_project():
|
||||||
self.client,
|
return Project.from_config(
|
||||||
image='busybox:latest',
|
|
||||||
name='composetest_net_container',
|
|
||||||
command='top',
|
|
||||||
labels={LABEL_PROJECT: 'composetest'},
|
|
||||||
)
|
|
||||||
net_container.start()
|
|
||||||
|
|
||||||
project = Project.from_config(
|
|
||||||
name='composetest',
|
name='composetest',
|
||||||
config_data=build_service_dicts({
|
config_data=build_service_dicts({
|
||||||
'web': {
|
'web': {
|
||||||
|
@ -148,10 +206,25 @@ class ProjectTest(DockerClientTestCase):
|
||||||
client=self.client,
|
client=self.client,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
with pytest.raises(ConfigurationError) as excinfo:
|
||||||
|
get_project()
|
||||||
|
|
||||||
|
assert "container 'composetest_net_container' which does not exist" in excinfo.exconly()
|
||||||
|
|
||||||
|
net_container = Container.create(
|
||||||
|
self.client,
|
||||||
|
image='busybox:latest',
|
||||||
|
name='composetest_net_container',
|
||||||
|
command='top',
|
||||||
|
labels={LABEL_PROJECT: 'composetest'},
|
||||||
|
)
|
||||||
|
net_container.start()
|
||||||
|
|
||||||
|
project = get_project()
|
||||||
project.up()
|
project.up()
|
||||||
|
|
||||||
web = project.get_service('web')
|
web = project.get_service('web')
|
||||||
self.assertEqual(web.net.mode, 'container:' + net_container.id)
|
self.assertEqual(web.network_mode.mode, 'container:' + net_container.id)
|
||||||
|
|
||||||
def test_start_pause_unpause_stop_kill_remove(self):
|
def test_start_pause_unpause_stop_kill_remove(self):
|
||||||
web = self.create_service('web')
|
web = self.create_service('web')
|
||||||
|
|
|
@ -26,7 +26,7 @@ from compose.const import LABEL_VERSION
|
||||||
from compose.container import Container
|
from compose.container import Container
|
||||||
from compose.service import ConvergencePlan
|
from compose.service import ConvergencePlan
|
||||||
from compose.service import ConvergenceStrategy
|
from compose.service import ConvergenceStrategy
|
||||||
from compose.service import Net
|
from compose.service import NetworkMode
|
||||||
from compose.service import Service
|
from compose.service import Service
|
||||||
|
|
||||||
|
|
||||||
|
@ -752,17 +752,17 @@ class ServiceTest(DockerClientTestCase):
|
||||||
assert len(service.containers(stopped=True)) == 2
|
assert len(service.containers(stopped=True)) == 2
|
||||||
|
|
||||||
def test_network_mode_none(self):
|
def test_network_mode_none(self):
|
||||||
service = self.create_service('web', net=Net('none'))
|
service = self.create_service('web', network_mode=NetworkMode('none'))
|
||||||
container = create_and_start_container(service)
|
container = create_and_start_container(service)
|
||||||
self.assertEqual(container.get('HostConfig.NetworkMode'), 'none')
|
self.assertEqual(container.get('HostConfig.NetworkMode'), 'none')
|
||||||
|
|
||||||
def test_network_mode_bridged(self):
|
def test_network_mode_bridged(self):
|
||||||
service = self.create_service('web', net=Net('bridge'))
|
service = self.create_service('web', network_mode=NetworkMode('bridge'))
|
||||||
container = create_and_start_container(service)
|
container = create_and_start_container(service)
|
||||||
self.assertEqual(container.get('HostConfig.NetworkMode'), 'bridge')
|
self.assertEqual(container.get('HostConfig.NetworkMode'), 'bridge')
|
||||||
|
|
||||||
def test_network_mode_host(self):
|
def test_network_mode_host(self):
|
||||||
service = self.create_service('web', net=Net('host'))
|
service = self.create_service('web', network_mode=NetworkMode('host'))
|
||||||
container = create_and_start_container(service)
|
container = create_and_start_container(service)
|
||||||
self.assertEqual(container.get('HostConfig.NetworkMode'), 'host')
|
self.assertEqual(container.get('HostConfig.NetworkMode'), 'host')
|
||||||
|
|
||||||
|
|
|
@ -1015,6 +1015,126 @@ class ConfigTest(unittest.TestCase):
|
||||||
assert "Service 'one' depends on service 'three'" in exc.exconly()
|
assert "Service 'one' depends on service 'three'" in exc.exconly()
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkModeTest(unittest.TestCase):
|
||||||
|
def test_network_mode_standard(self):
|
||||||
|
config_data = config.load(build_config_details({
|
||||||
|
'version': 2,
|
||||||
|
'services': {
|
||||||
|
'web': {
|
||||||
|
'image': 'busybox',
|
||||||
|
'command': "top",
|
||||||
|
'network_mode': 'bridge',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
assert config_data.services[0]['network_mode'] == 'bridge'
|
||||||
|
|
||||||
|
def test_network_mode_standard_v1(self):
|
||||||
|
config_data = config.load(build_config_details({
|
||||||
|
'web': {
|
||||||
|
'image': 'busybox',
|
||||||
|
'command': "top",
|
||||||
|
'net': 'bridge',
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
assert config_data.services[0]['network_mode'] == 'bridge'
|
||||||
|
assert 'net' not in config_data.services[0]
|
||||||
|
|
||||||
|
def test_network_mode_container(self):
|
||||||
|
config_data = config.load(build_config_details({
|
||||||
|
'version': 2,
|
||||||
|
'services': {
|
||||||
|
'web': {
|
||||||
|
'image': 'busybox',
|
||||||
|
'command': "top",
|
||||||
|
'network_mode': 'container:foo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
assert config_data.services[0]['network_mode'] == 'container:foo'
|
||||||
|
|
||||||
|
def test_network_mode_container_v1(self):
|
||||||
|
config_data = config.load(build_config_details({
|
||||||
|
'web': {
|
||||||
|
'image': 'busybox',
|
||||||
|
'command': "top",
|
||||||
|
'net': 'container:foo',
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
assert config_data.services[0]['network_mode'] == 'container:foo'
|
||||||
|
|
||||||
|
def test_network_mode_service(self):
|
||||||
|
config_data = config.load(build_config_details({
|
||||||
|
'version': 2,
|
||||||
|
'services': {
|
||||||
|
'web': {
|
||||||
|
'image': 'busybox',
|
||||||
|
'command': "top",
|
||||||
|
'network_mode': 'service:foo',
|
||||||
|
},
|
||||||
|
'foo': {
|
||||||
|
'image': 'busybox',
|
||||||
|
'command': "top",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
assert config_data.services[1]['network_mode'] == 'service:foo'
|
||||||
|
|
||||||
|
def test_network_mode_service_v1(self):
|
||||||
|
config_data = config.load(build_config_details({
|
||||||
|
'web': {
|
||||||
|
'image': 'busybox',
|
||||||
|
'command': "top",
|
||||||
|
'net': 'container:foo',
|
||||||
|
},
|
||||||
|
'foo': {
|
||||||
|
'image': 'busybox',
|
||||||
|
'command': "top",
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
assert config_data.services[1]['network_mode'] == 'service:foo'
|
||||||
|
|
||||||
|
def test_network_mode_service_nonexistent(self):
|
||||||
|
with pytest.raises(ConfigurationError) as excinfo:
|
||||||
|
config.load(build_config_details({
|
||||||
|
'version': 2,
|
||||||
|
'services': {
|
||||||
|
'web': {
|
||||||
|
'image': 'busybox',
|
||||||
|
'command': "top",
|
||||||
|
'network_mode': 'service:foo',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
assert "service 'foo' which is undefined" in excinfo.exconly()
|
||||||
|
|
||||||
|
def test_network_mode_plus_networks_is_invalid(self):
|
||||||
|
with pytest.raises(ConfigurationError) as excinfo:
|
||||||
|
config.load(build_config_details({
|
||||||
|
'version': 2,
|
||||||
|
'services': {
|
||||||
|
'web': {
|
||||||
|
'image': 'busybox',
|
||||||
|
'command': "top",
|
||||||
|
'network_mode': 'bridge',
|
||||||
|
'networks': ['front'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'networks': {
|
||||||
|
'front': None,
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
assert "'network_mode' and 'networks' cannot be combined" in excinfo.exconly()
|
||||||
|
|
||||||
|
|
||||||
class PortsTest(unittest.TestCase):
|
class PortsTest(unittest.TestCase):
|
||||||
INVALID_PORTS_TYPES = [
|
INVALID_PORTS_TYPES = [
|
||||||
{"1": "8000"},
|
{"1": "8000"},
|
||||||
|
@ -1642,6 +1762,7 @@ class ExtendsTest(unittest.TestCase):
|
||||||
'name': 'myweb',
|
'name': 'myweb',
|
||||||
'image': 'busybox',
|
'image': 'busybox',
|
||||||
'command': 'top',
|
'command': 'top',
|
||||||
|
'network_mode': 'bridge',
|
||||||
'links': ['mydb:db'],
|
'links': ['mydb:db'],
|
||||||
'environment': {
|
'environment': {
|
||||||
"FOO": "1",
|
"FOO": "1",
|
||||||
|
@ -1659,6 +1780,7 @@ class ExtendsTest(unittest.TestCase):
|
||||||
'name': 'web',
|
'name': 'web',
|
||||||
'image': 'busybox',
|
'image': 'busybox',
|
||||||
'command': '/bin/true',
|
'command': '/bin/true',
|
||||||
|
'network_mode': 'host',
|
||||||
'environment': {
|
'environment': {
|
||||||
"FOO": "2",
|
"FOO": "2",
|
||||||
"BAR": "1",
|
"BAR": "1",
|
||||||
|
@ -1677,6 +1799,7 @@ class ExtendsTest(unittest.TestCase):
|
||||||
'name': 'myweb',
|
'name': 'myweb',
|
||||||
'image': 'busybox',
|
'image': 'busybox',
|
||||||
'command': '/bin/true',
|
'command': '/bin/true',
|
||||||
|
'network_mode': 'host',
|
||||||
'environment': {
|
'environment': {
|
||||||
"FOO": "2",
|
"FOO": "2",
|
||||||
"BAR": "2",
|
"BAR": "2",
|
||||||
|
@ -1867,11 +1990,18 @@ class ExtendsTest(unittest.TestCase):
|
||||||
load_from_filename('tests/fixtures/extends/invalid-volumes.yml')
|
load_from_filename('tests/fixtures/extends/invalid-volumes.yml')
|
||||||
|
|
||||||
def test_invalid_net_in_extended_service(self):
|
def test_invalid_net_in_extended_service(self):
|
||||||
expected_error_msg = "services with 'net: container' cannot be extended"
|
with pytest.raises(ConfigurationError) as excinfo:
|
||||||
|
load_from_filename('tests/fixtures/extends/invalid-net-v2.yml')
|
||||||
|
|
||||||
with self.assertRaisesRegexp(ConfigurationError, expected_error_msg):
|
assert 'network_mode: service' in excinfo.exconly()
|
||||||
|
assert 'cannot be extended' in excinfo.exconly()
|
||||||
|
|
||||||
|
with pytest.raises(ConfigurationError) as excinfo:
|
||||||
load_from_filename('tests/fixtures/extends/invalid-net.yml')
|
load_from_filename('tests/fixtures/extends/invalid-net.yml')
|
||||||
|
|
||||||
|
assert 'net: container' in excinfo.exconly()
|
||||||
|
assert 'cannot be extended' in excinfo.exconly()
|
||||||
|
|
||||||
@mock.patch.dict(os.environ)
|
@mock.patch.dict(os.environ)
|
||||||
def test_load_config_runs_interpolation_in_extended_service(self):
|
def test_load_config_runs_interpolation_in_extended_service(self):
|
||||||
os.environ.update(HOSTNAME_VALUE="penguin")
|
os.environ.update(HOSTNAME_VALUE="penguin")
|
||||||
|
|
|
@ -100,7 +100,7 @@ class TestSortService(object):
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'parent',
|
'name': 'parent',
|
||||||
'net': 'container:child'
|
'network_mode': 'service:child'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'child'
|
'name': 'child'
|
||||||
|
@ -137,7 +137,7 @@ class TestSortService(object):
|
||||||
def test_sort_service_dicts_7(self):
|
def test_sort_service_dicts_7(self):
|
||||||
services = [
|
services = [
|
||||||
{
|
{
|
||||||
'net': 'container:three',
|
'network_mode': 'service:three',
|
||||||
'name': 'four'
|
'name': 'four'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -349,7 +349,7 @@ class ProjectTest(unittest.TestCase):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
service = project.get_service('test')
|
service = project.get_service('test')
|
||||||
self.assertEqual(service.net.id, None)
|
self.assertEqual(service.network_mode.id, None)
|
||||||
self.assertNotIn('NetworkMode', service._get_container_host_config({}))
|
self.assertNotIn('NetworkMode', service._get_container_host_config({}))
|
||||||
|
|
||||||
def test_use_net_from_container(self):
|
def test_use_net_from_container(self):
|
||||||
|
@ -365,7 +365,7 @@ class ProjectTest(unittest.TestCase):
|
||||||
{
|
{
|
||||||
'name': 'test',
|
'name': 'test',
|
||||||
'image': 'busybox:latest',
|
'image': 'busybox:latest',
|
||||||
'net': 'container:aaa'
|
'network_mode': 'container:aaa'
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
networks=None,
|
networks=None,
|
||||||
|
@ -373,7 +373,7 @@ class ProjectTest(unittest.TestCase):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
service = project.get_service('test')
|
service = project.get_service('test')
|
||||||
self.assertEqual(service.net.mode, 'container:' + container_id)
|
self.assertEqual(service.network_mode.mode, 'container:' + container_id)
|
||||||
|
|
||||||
def test_use_net_from_service(self):
|
def test_use_net_from_service(self):
|
||||||
container_name = 'test_aaa_1'
|
container_name = 'test_aaa_1'
|
||||||
|
@ -398,7 +398,7 @@ class ProjectTest(unittest.TestCase):
|
||||||
{
|
{
|
||||||
'name': 'test',
|
'name': 'test',
|
||||||
'image': 'busybox:latest',
|
'image': 'busybox:latest',
|
||||||
'net': 'container:aaa'
|
'network_mode': 'service:aaa'
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
networks=None,
|
networks=None,
|
||||||
|
@ -407,7 +407,7 @@ class ProjectTest(unittest.TestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
service = project.get_service('test')
|
service = project.get_service('test')
|
||||||
self.assertEqual(service.net.mode, 'container:' + container_name)
|
self.assertEqual(service.network_mode.mode, 'container:' + container_name)
|
||||||
|
|
||||||
def test_uses_default_network_true(self):
|
def test_uses_default_network_true(self):
|
||||||
project = Project.from_config(
|
project = Project.from_config(
|
||||||
|
|
|
@ -15,16 +15,16 @@ from compose.const import LABEL_SERVICE
|
||||||
from compose.container import Container
|
from compose.container import Container
|
||||||
from compose.service import build_ulimits
|
from compose.service import build_ulimits
|
||||||
from compose.service import build_volume_binding
|
from compose.service import build_volume_binding
|
||||||
from compose.service import ContainerNet
|
from compose.service import ContainerNetworkMode
|
||||||
from compose.service import get_container_data_volumes
|
from compose.service import get_container_data_volumes
|
||||||
from compose.service import ImageType
|
from compose.service import ImageType
|
||||||
from compose.service import merge_volume_bindings
|
from compose.service import merge_volume_bindings
|
||||||
from compose.service import NeedsBuildError
|
from compose.service import NeedsBuildError
|
||||||
from compose.service import Net
|
from compose.service import NetworkMode
|
||||||
from compose.service import NoSuchImageError
|
from compose.service import NoSuchImageError
|
||||||
from compose.service import parse_repository_tag
|
from compose.service import parse_repository_tag
|
||||||
from compose.service import Service
|
from compose.service import Service
|
||||||
from compose.service import ServiceNet
|
from compose.service import ServiceNetworkMode
|
||||||
from compose.service import warn_on_masked_volume
|
from compose.service import warn_on_masked_volume
|
||||||
|
|
||||||
|
|
||||||
|
@ -407,7 +407,7 @@ class ServiceTest(unittest.TestCase):
|
||||||
'foo',
|
'foo',
|
||||||
image='example.com/foo',
|
image='example.com/foo',
|
||||||
client=self.mock_client,
|
client=self.mock_client,
|
||||||
net=ServiceNet(Service('other')),
|
network_mode=ServiceNetworkMode(Service('other')),
|
||||||
links=[(Service('one'), 'one')],
|
links=[(Service('one'), 'one')],
|
||||||
volumes_from=[VolumeFromSpec(Service('two'), 'rw', 'service')])
|
volumes_from=[VolumeFromSpec(Service('two'), 'rw', 'service')])
|
||||||
|
|
||||||
|
@ -421,7 +421,7 @@ class ServiceTest(unittest.TestCase):
|
||||||
}
|
}
|
||||||
self.assertEqual(config_dict, expected)
|
self.assertEqual(config_dict, expected)
|
||||||
|
|
||||||
def test_config_dict_with_net_from_container(self):
|
def test_config_dict_with_network_mode_from_container(self):
|
||||||
self.mock_client.inspect_image.return_value = {'Id': 'abcd'}
|
self.mock_client.inspect_image.return_value = {'Id': 'abcd'}
|
||||||
container = Container(
|
container = Container(
|
||||||
self.mock_client,
|
self.mock_client,
|
||||||
|
@ -430,7 +430,7 @@ class ServiceTest(unittest.TestCase):
|
||||||
'foo',
|
'foo',
|
||||||
image='example.com/foo',
|
image='example.com/foo',
|
||||||
client=self.mock_client,
|
client=self.mock_client,
|
||||||
net=container)
|
network_mode=ContainerNetworkMode(container))
|
||||||
|
|
||||||
config_dict = service.config_dict()
|
config_dict = service.config_dict()
|
||||||
expected = {
|
expected = {
|
||||||
|
@ -589,20 +589,20 @@ class BuildUlimitsTestCase(unittest.TestCase):
|
||||||
|
|
||||||
class NetTestCase(unittest.TestCase):
|
class NetTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def test_net(self):
|
def test_network_mode(self):
|
||||||
net = Net('host')
|
network_mode = NetworkMode('host')
|
||||||
self.assertEqual(net.id, 'host')
|
self.assertEqual(network_mode.id, 'host')
|
||||||
self.assertEqual(net.mode, 'host')
|
self.assertEqual(network_mode.mode, 'host')
|
||||||
self.assertEqual(net.service_name, None)
|
self.assertEqual(network_mode.service_name, None)
|
||||||
|
|
||||||
def test_net_container(self):
|
def test_network_mode_container(self):
|
||||||
container_id = 'abcd'
|
container_id = 'abcd'
|
||||||
net = ContainerNet(Container(None, {'Id': container_id}))
|
network_mode = ContainerNetworkMode(Container(None, {'Id': container_id}))
|
||||||
self.assertEqual(net.id, container_id)
|
self.assertEqual(network_mode.id, container_id)
|
||||||
self.assertEqual(net.mode, 'container:' + container_id)
|
self.assertEqual(network_mode.mode, 'container:' + container_id)
|
||||||
self.assertEqual(net.service_name, None)
|
self.assertEqual(network_mode.service_name, None)
|
||||||
|
|
||||||
def test_net_service(self):
|
def test_network_mode_service(self):
|
||||||
container_id = 'bbbb'
|
container_id = 'bbbb'
|
||||||
service_name = 'web'
|
service_name = 'web'
|
||||||
mock_client = mock.create_autospec(docker.Client)
|
mock_client = mock.create_autospec(docker.Client)
|
||||||
|
@ -611,23 +611,23 @@ class NetTestCase(unittest.TestCase):
|
||||||
]
|
]
|
||||||
|
|
||||||
service = Service(name=service_name, client=mock_client)
|
service = Service(name=service_name, client=mock_client)
|
||||||
net = ServiceNet(service)
|
network_mode = ServiceNetworkMode(service)
|
||||||
|
|
||||||
self.assertEqual(net.id, service_name)
|
self.assertEqual(network_mode.id, service_name)
|
||||||
self.assertEqual(net.mode, 'container:' + container_id)
|
self.assertEqual(network_mode.mode, 'container:' + container_id)
|
||||||
self.assertEqual(net.service_name, service_name)
|
self.assertEqual(network_mode.service_name, service_name)
|
||||||
|
|
||||||
def test_net_service_no_containers(self):
|
def test_network_mode_service_no_containers(self):
|
||||||
service_name = 'web'
|
service_name = 'web'
|
||||||
mock_client = mock.create_autospec(docker.Client)
|
mock_client = mock.create_autospec(docker.Client)
|
||||||
mock_client.containers.return_value = []
|
mock_client.containers.return_value = []
|
||||||
|
|
||||||
service = Service(name=service_name, client=mock_client)
|
service = Service(name=service_name, client=mock_client)
|
||||||
net = ServiceNet(service)
|
network_mode = ServiceNetworkMode(service)
|
||||||
|
|
||||||
self.assertEqual(net.id, service_name)
|
self.assertEqual(network_mode.id, service_name)
|
||||||
self.assertEqual(net.mode, None)
|
self.assertEqual(network_mode.mode, None)
|
||||||
self.assertEqual(net.service_name, service_name)
|
self.assertEqual(network_mode.service_name, service_name)
|
||||||
|
|
||||||
|
|
||||||
def build_mount(destination, source, mode='rw'):
|
def build_mount(destination, source, mode='rw'):
|
||||||
|
|
Loading…
Reference in New Issue