Merge pull request #2743 from aanand/network-mode

Implement network_mode option
This commit is contained in:
Joffrey F 2016-01-25 18:26:35 -08:00
commit 4b84d088e0
21 changed files with 467 additions and 145 deletions

View File

@ -19,7 +19,8 @@ from .errors import CircularReference
from .errors import ComposeFileNotFound
from .errors import ConfigurationError
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 .types import parse_extra_hosts
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_depends_on
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_service_objects
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)
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(
"%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:
raise ConfigurationError(
"%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_ulimits(service_config)
validate_network_mode(service_config, service_names)
validate_depends_on(service_config, service_names)
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'] = [
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:
service_dict['restart'] = parse_restart_spec(service_dict['restart'])

View File

@ -103,6 +103,7 @@
"mac_address": {"type": "string"},
"mem_limit": {"type": ["number", "string"]},
"memswap_limit": {"type": ["number", "string"]},
"network_mode": {"type": "string"},
"networks": {
"type": "array",

View File

@ -4,14 +4,22 @@ from __future__ import unicode_literals
from compose.config.errors import DependencyError
def get_service_name_from_net(net_config):
if not net_config:
def get_service_name_from_network_mode(network_mode):
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
if not net_config.startswith('container:'):
if not network_mode.startswith(source_type+':'):
return
_, net_name = net_config.split(':', 1)
_, net_name = network_mode.split(':', 1)
return net_name
@ -33,7 +41,7 @@ def sort_service_dicts(services):
service for service in services
if (name in get_service_names(service.get('links', [])) 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', []))
]

View File

@ -15,6 +15,7 @@ from jsonschema import RefResolver
from jsonschema import ValidationError
from .errors import ConfigurationError
from .sort_services import get_service_name_from_network_mode
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):
for dependency in service_config.config.get('depends_on', []):
if dependency not in service_names:

View File

@ -10,7 +10,8 @@ from docker.errors import NotFound
from . import parallel
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 IMAGE_EVENTS
from .const import LABEL_ONE_OFF
@ -18,11 +19,11 @@ from .const import LABEL_PROJECT
from .const import LABEL_SERVICE
from .container import Container
from .network import Network
from .service import ContainerNet
from .service import ContainerNetworkMode
from .service import ConvergenceStrategy
from .service import Net
from .service import NetworkMode
from .service import Service
from .service import ServiceNet
from .service import ServiceNetworkMode
from .utils import microseconds_from_time_nano
from .volume import Volume
@ -86,12 +87,11 @@ class Project(object):
for service_dict in config_data.services:
if use_networking:
networks = get_networks(service_dict, all_networks)
net = Net(networks[0]) if networks else Net("none")
else:
networks = []
net = project.get_net(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)
if config_data.version == 2:
@ -110,7 +110,7 @@ class Project(object):
use_networking=use_networking,
networks=networks,
links=links,
net=net,
network_mode=network_mode,
volumes_from=volumes_from,
**service_dict)
)
@ -197,27 +197,27 @@ class Project(object):
del service_dict['links']
return links
def get_net(self, service_dict):
net = service_dict.pop('net', None)
if not net:
return Net(None)
def get_network_mode(self, service_dict, networks):
network_mode = service_dict.pop('network_mode', None)
if not network_mode:
if self.use_networking:
return NetworkMode(networks[0]) if networks else NetworkMode('none')
return NetworkMode(None)
net_name = get_service_name_from_net(net)
if not net_name:
return Net(net)
service_name = get_service_name_from_network_mode(network_mode)
if service_name:
return ServiceNetworkMode(self.get_service(service_name))
container_name = get_container_name_from_network_mode(network_mode)
if container_name:
try:
return ServiceNet(self.get_service(net_name))
except NoSuchService:
pass
try:
return ContainerNet(Container.from_id(self.client, net_name))
return ContainerNetworkMode(Container.from_id(self.client, container_name))
except APIError:
raise ConfigurationError(
'Service "%s" is trying to use the network of "%s", '
'which is not the name of a service or container.' % (
service_dict['name'],
net_name))
"Service '{name}' uses the network stack of container '{dep}' which "
"does not exist.".format(name=service_dict['name'], dep=container_name))
return NetworkMode(network_mode)
def start(self, service_names=None, **options):
containers = []
@ -465,9 +465,12 @@ class Project(object):
def get_networks(service_dict, network_definitions):
if 'network_mode' in service_dict:
return []
networks = []
for name in service_dict.pop('networks', ['default']):
if name in ['bridge', 'host']:
if name in ['bridge']:
networks.append(name)
else:
matches = [n for n in network_definitions if n.name == name]

View File

@ -47,7 +47,6 @@ DOCKER_START_KEYS = [
'extra_hosts',
'ipc',
'read_only',
'net',
'log_driver',
'log_opt',
'mem_limit',
@ -113,7 +112,7 @@ class Service(object):
use_networking=False,
links=None,
volumes_from=None,
net=None,
network_mode=None,
networks=None,
**options
):
@ -123,7 +122,7 @@ class Service(object):
self.use_networking = use_networking
self.links = links 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.options = options
@ -472,7 +471,7 @@ class Service(object):
'options': self.options,
'image_id': self.image()['Id'],
'links': self.get_link_names(),
'net': self.net.id,
'net': self.network_mode.id,
'volumes_from': [
(v.source.name, v.mode)
for v in self.volumes_from if isinstance(v.source, Service)
@ -480,7 +479,7 @@ class Service(object):
}
def get_dependency_names(self):
net_name = self.net.service_name
net_name = self.network_mode.service_name
return (self.get_linked_service_names() +
self.get_volumes_from_names() +
([net_name] if net_name else []) +
@ -636,7 +635,7 @@ class Service(object):
binds=options.get('binds'),
volumes_from=self._get_volumes_from(),
privileged=options.get('privileged', False),
network_mode=self.net.mode,
network_mode=self.network_mode.mode,
devices=options.get('devices'),
dns=options.get('dns'),
dns_search=options.get('dns_search'),
@ -774,22 +773,22 @@ class Service(object):
log.error(six.text_type(e))
class Net(object):
class NetworkMode(object):
"""A `standard` network mode (ex: host, bridge)"""
service_name = None
def __init__(self, net):
self.net = net
def __init__(self, network_mode):
self.network_mode = network_mode
@property
def id(self):
return self.net
return self.network_mode
mode = id
class ContainerNet(object):
class ContainerNetworkMode(object):
"""A network mode that uses a container's network stack."""
service_name = None
@ -806,7 +805,7 @@ class ContainerNet(object):
return 'container:' + self.container.id
class ServiceNet(object):
class ServiceNetworkMode(object):
"""A network mode that uses a service's network stack."""
def __init__(self, service):

View File

@ -437,14 +437,29 @@ Specify logging options as key-value pairs. An example of `syslog` options:
### net
> [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: "none"
net: "container:[name or id]"
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
@ -457,8 +472,8 @@ Networks to join, referencing entries under the
- some-network
- other-network
The values `bridge`, `host` and `none` can also be used, and are equivalent to
`net: "bridge"`, `net: "host"` or `net: "none"` in version 1.
The value `bridge` can also be used to make containers join the pre-defined
`bridge` network.
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
[external network](networking.md#using-a-pre-existing-network).
- `net`: If you're using `host`, `bridge` or `none`, this is now replaced by
`networks`:
- `net`: This is now replaced by [network_mode](#network_mode):
net: host -> networks: ["host"]
net: bridge -> networks: ["bridge"]
net: none -> networks: ["none"]
net: host -> network_mode: host
net: bridge -> network_mode: bridge
net: none -> network_mode: none
If you're using `net: "container:<name>"`, there is no equivalent to this in
version 2 - you should use [Docker networks](networking.md) for
communication instead.
If you're using `net: "container:[service name]"`, you must now use
`network_mode: "service:[service name]"` 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

View File

@ -144,15 +144,3 @@ If you want your containers to join a pre-existing network, use the [`external`
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.
## 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.

View File

@ -496,8 +496,29 @@ class CLITestCase(DockerClientTestCase):
assert 'Service "web" uses an undefined network "foo"' in result.stderr
@v2_only()
def test_up_predefined_networks(self):
filename = 'predefined-networks.yml'
def test_up_with_bridge_network_plus_default(self):
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._project = get_project(self.base_dir, [filename])
@ -515,6 +536,16 @@ class CLITestCase(DockerClientTestCase):
assert list(container.get('NetworkSettings.Networks')) == [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()
def test_up_external_networks(self):
filename = 'external-networks.yml'

View File

@ -1,6 +1,7 @@
web:
image: busybox
command: /bin/true
net: host
environment:
- FOO=1
- BAR=1

View File

@ -11,6 +11,7 @@ myweb:
BAR: "2"
# add BAZ
BAZ: "2"
net: bridge
mydb:
image: busybox
command: top

View File

@ -0,0 +1,12 @@
version: 2
services:
myweb:
build: '.'
extends:
service: web
command: top
web:
build: '.'
network_mode: "service:net"
net:
build: '.'

9
tests/fixtures/networks/bridge.yml vendored Normal file
View File

@ -0,0 +1,9 @@
version: 2
services:
web:
image: busybox
command: top
networks:
- bridge
- default

View File

@ -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

View File

@ -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: []

View File

@ -4,10 +4,12 @@ from __future__ import unicode_literals
import random
import py
import pytest
from docker.errors import NotFound
from .testcases import DockerClientTestCase
from compose.config import config
from compose.config import ConfigurationError
from compose.config.types import VolumeFromSpec
from compose.config.types import VolumeSpec
from compose.const import LABEL_PROJECT
@ -104,7 +106,71 @@ class ProjectTest(DockerClientTestCase):
db = project.get_service('db')
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(
name='composetest',
config_data=build_service_dicts({
@ -125,19 +191,11 @@ class ProjectTest(DockerClientTestCase):
web = project.get_service('web')
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):
net_container = Container.create(
self.client,
image='busybox:latest',
name='composetest_net_container',
command='top',
labels={LABEL_PROJECT: 'composetest'},
)
net_container.start()
project = Project.from_config(
def test_net_from_container_v1(self):
def get_project():
return Project.from_config(
name='composetest',
config_data=build_service_dicts({
'web': {
@ -148,10 +206,25 @@ class ProjectTest(DockerClientTestCase):
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.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):
web = self.create_service('web')

View File

@ -26,7 +26,7 @@ from compose.const import LABEL_VERSION
from compose.container import Container
from compose.service import ConvergencePlan
from compose.service import ConvergenceStrategy
from compose.service import Net
from compose.service import NetworkMode
from compose.service import Service
@ -752,17 +752,17 @@ class ServiceTest(DockerClientTestCase):
assert len(service.containers(stopped=True)) == 2
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)
self.assertEqual(container.get('HostConfig.NetworkMode'), 'none')
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)
self.assertEqual(container.get('HostConfig.NetworkMode'), 'bridge')
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)
self.assertEqual(container.get('HostConfig.NetworkMode'), 'host')

View File

@ -1015,6 +1015,126 @@ class ConfigTest(unittest.TestCase):
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):
INVALID_PORTS_TYPES = [
{"1": "8000"},
@ -1642,6 +1762,7 @@ class ExtendsTest(unittest.TestCase):
'name': 'myweb',
'image': 'busybox',
'command': 'top',
'network_mode': 'bridge',
'links': ['mydb:db'],
'environment': {
"FOO": "1",
@ -1659,6 +1780,7 @@ class ExtendsTest(unittest.TestCase):
'name': 'web',
'image': 'busybox',
'command': '/bin/true',
'network_mode': 'host',
'environment': {
"FOO": "2",
"BAR": "1",
@ -1677,6 +1799,7 @@ class ExtendsTest(unittest.TestCase):
'name': 'myweb',
'image': 'busybox',
'command': '/bin/true',
'network_mode': 'host',
'environment': {
"FOO": "2",
"BAR": "2",
@ -1867,11 +1990,18 @@ class ExtendsTest(unittest.TestCase):
load_from_filename('tests/fixtures/extends/invalid-volumes.yml')
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')
assert 'net: container' in excinfo.exconly()
assert 'cannot be extended' in excinfo.exconly()
@mock.patch.dict(os.environ)
def test_load_config_runs_interpolation_in_extended_service(self):
os.environ.update(HOSTNAME_VALUE="penguin")

View File

@ -100,7 +100,7 @@ class TestSortService(object):
},
{
'name': 'parent',
'net': 'container:child'
'network_mode': 'service:child'
},
{
'name': 'child'
@ -137,7 +137,7 @@ class TestSortService(object):
def test_sort_service_dicts_7(self):
services = [
{
'net': 'container:three',
'network_mode': 'service:three',
'name': 'four'
},
{

View File

@ -349,7 +349,7 @@ class ProjectTest(unittest.TestCase):
),
)
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({}))
def test_use_net_from_container(self):
@ -365,7 +365,7 @@ class ProjectTest(unittest.TestCase):
{
'name': 'test',
'image': 'busybox:latest',
'net': 'container:aaa'
'network_mode': 'container:aaa'
},
],
networks=None,
@ -373,7 +373,7 @@ class ProjectTest(unittest.TestCase):
),
)
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):
container_name = 'test_aaa_1'
@ -398,7 +398,7 @@ class ProjectTest(unittest.TestCase):
{
'name': 'test',
'image': 'busybox:latest',
'net': 'container:aaa'
'network_mode': 'service:aaa'
},
],
networks=None,
@ -407,7 +407,7 @@ class ProjectTest(unittest.TestCase):
)
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):
project = Project.from_config(

View File

@ -15,16 +15,16 @@ from compose.const import LABEL_SERVICE
from compose.container import Container
from compose.service import build_ulimits
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 ImageType
from compose.service import merge_volume_bindings
from compose.service import NeedsBuildError
from compose.service import Net
from compose.service import NetworkMode
from compose.service import NoSuchImageError
from compose.service import parse_repository_tag
from compose.service import Service
from compose.service import ServiceNet
from compose.service import ServiceNetworkMode
from compose.service import warn_on_masked_volume
@ -407,7 +407,7 @@ class ServiceTest(unittest.TestCase):
'foo',
image='example.com/foo',
client=self.mock_client,
net=ServiceNet(Service('other')),
network_mode=ServiceNetworkMode(Service('other')),
links=[(Service('one'), 'one')],
volumes_from=[VolumeFromSpec(Service('two'), 'rw', 'service')])
@ -421,7 +421,7 @@ class ServiceTest(unittest.TestCase):
}
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'}
container = Container(
self.mock_client,
@ -430,7 +430,7 @@ class ServiceTest(unittest.TestCase):
'foo',
image='example.com/foo',
client=self.mock_client,
net=container)
network_mode=ContainerNetworkMode(container))
config_dict = service.config_dict()
expected = {
@ -589,20 +589,20 @@ class BuildUlimitsTestCase(unittest.TestCase):
class NetTestCase(unittest.TestCase):
def test_net(self):
net = Net('host')
self.assertEqual(net.id, 'host')
self.assertEqual(net.mode, 'host')
self.assertEqual(net.service_name, None)
def test_network_mode(self):
network_mode = NetworkMode('host')
self.assertEqual(network_mode.id, 'host')
self.assertEqual(network_mode.mode, 'host')
self.assertEqual(network_mode.service_name, None)
def test_net_container(self):
def test_network_mode_container(self):
container_id = 'abcd'
net = ContainerNet(Container(None, {'Id': container_id}))
self.assertEqual(net.id, container_id)
self.assertEqual(net.mode, 'container:' + container_id)
self.assertEqual(net.service_name, None)
network_mode = ContainerNetworkMode(Container(None, {'Id': container_id}))
self.assertEqual(network_mode.id, container_id)
self.assertEqual(network_mode.mode, 'container:' + container_id)
self.assertEqual(network_mode.service_name, None)
def test_net_service(self):
def test_network_mode_service(self):
container_id = 'bbbb'
service_name = 'web'
mock_client = mock.create_autospec(docker.Client)
@ -611,23 +611,23 @@ class NetTestCase(unittest.TestCase):
]
service = Service(name=service_name, client=mock_client)
net = ServiceNet(service)
network_mode = ServiceNetworkMode(service)
self.assertEqual(net.id, service_name)
self.assertEqual(net.mode, 'container:' + container_id)
self.assertEqual(net.service_name, service_name)
self.assertEqual(network_mode.id, service_name)
self.assertEqual(network_mode.mode, 'container:' + container_id)
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'
mock_client = mock.create_autospec(docker.Client)
mock_client.containers.return_value = []
service = Service(name=service_name, client=mock_client)
net = ServiceNet(service)
network_mode = ServiceNetworkMode(service)
self.assertEqual(net.id, service_name)
self.assertEqual(net.mode, None)
self.assertEqual(net.service_name, service_name)
self.assertEqual(network_mode.id, service_name)
self.assertEqual(network_mode.mode, None)
self.assertEqual(network_mode.service_name, service_name)
def build_mount(destination, source, mode='rw'):