Allow user to specify custom network aliases

Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
Joffrey F 2016-02-12 16:10:36 -08:00 committed by Daniel Nephin
parent d78ea85301
commit 2f7a77e954
6 changed files with 42 additions and 14 deletions

View File

@ -30,6 +30,7 @@ from .types import ServiceLink
from .types import VolumeFromSpec from .types import VolumeFromSpec
from .types import VolumeSpec from .types import VolumeSpec
from .validation import match_named_volumes from .validation import match_named_volumes
from .validation import match_network_aliases
from .validation import validate_against_fields_schema 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
@ -535,6 +536,8 @@ def validate_service(service_config, service_names, version):
validate_network_mode(service_config, service_names) validate_network_mode(service_config, service_names)
validate_depends_on(service_config, service_names) validate_depends_on(service_config, service_names)
match_network_aliases(service_config.config)
if not service_dict.get('image') and has_uppercase(service_name): if not service_dict.get('image') and has_uppercase(service_name):
raise ConfigurationError( raise ConfigurationError(
"Service '{name}' contains uppercase characters which are not valid " "Service '{name}' contains uppercase characters which are not valid "

View File

@ -107,9 +107,16 @@
"network_mode": {"type": "string"}, "network_mode": {"type": "string"},
"networks": { "networks": {
"type": "array", "$ref": "#/definitions/list_of_strings"
"items": {"type": "string"}, },
"uniqueItems": true "network_aliases": {
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9._-]+$": {
"$ref": "#/definitions/list_of_strings"
}
},
"additionalProperties": false
}, },
"pid": {"type": ["string", "null"]}, "pid": {"type": ["string", "null"]},

View File

@ -91,6 +91,19 @@ def match_named_volumes(service_dict, project_volumes):
) )
def match_network_aliases(service_dict):
networks = service_dict.get('networks', [])
aliased_networks = service_dict.get('network_aliases', {}).keys()
for n in aliased_networks:
if n not in networks:
raise ConfigurationError(
'Network "{0}" is referenced in network_aliases, but is not'
'declared in the networks list for service "{1}"'.format(
n, service_dict.get('name')
)
)
def validate_top_level_service_objects(filename, service_dicts): def validate_top_level_service_objects(filename, service_dicts):
"""Perform some high level validation of the service name and value. """Perform some high level validation of the service name and value.

View File

@ -15,7 +15,7 @@ log = logging.getLogger(__name__)
class Network(object): class Network(object):
def __init__(self, client, project, name, driver=None, driver_opts=None, def __init__(self, client, project, name, driver=None, driver_opts=None,
ipam=None, external_name=None): ipam=None, external_name=None, aliases=None):
self.client = client self.client = client
self.project = project self.project = project
self.name = name self.name = name
@ -23,6 +23,7 @@ class Network(object):
self.driver_opts = driver_opts self.driver_opts = driver_opts
self.ipam = create_ipam_config_from_dict(ipam) self.ipam = create_ipam_config_from_dict(ipam)
self.external_name = external_name self.external_name = external_name
self.aliases = aliases or []
def ensure(self): def ensure(self):
if self.external_name: if self.external_name:
@ -166,14 +167,18 @@ def get_network_names_for_service(service_dict):
def get_networks(service_dict, network_definitions): def get_networks(service_dict, network_definitions):
networks = [] networks = {}
aliases = service_dict.get('network_aliases', {})
for name in get_network_names_for_service(service_dict): for name in get_network_names_for_service(service_dict):
log.debug(name)
network = network_definitions.get(name) network = network_definitions.get(name)
if network: if network:
networks.append(network.full_name) log.debug(aliases)
networks[network.full_name] = aliases.get(name, [])
else: else:
raise ConfigurationError( raise ConfigurationError(
'Service "{}" uses an undefined network "{}"' 'Service "{}" uses an undefined network "{}"'
.format(service_dict['name'], name)) .format(service_dict['name'], name))
log.debug(networks)
return networks return networks

View File

@ -69,11 +69,11 @@ class Project(object):
if use_networking: if use_networking:
service_networks = get_networks(service_dict, networks) service_networks = get_networks(service_dict, networks)
else: else:
service_networks = [] service_networks = {}
service_dict.pop('networks', None) service_dict.pop('networks', None)
links = project.get_links(service_dict) links = project.get_links(service_dict)
network_mode = project.get_network_mode(service_dict, service_networks) network_mode = project.get_network_mode(service_dict, service_networks.keys())
volumes_from = get_volumes_from(project, service_dict) volumes_from = get_volumes_from(project, service_dict)
if config_data.version != V1: if config_data.version != V1:

View File

@ -123,7 +123,7 @@ class Service(object):
self.links = links or [] self.links = links or []
self.volumes_from = volumes_from or [] self.volumes_from = volumes_from or []
self.network_mode = network_mode or NetworkMode(None) self.network_mode = network_mode or NetworkMode(None)
self.networks = networks or [] self.networks = networks or {}
self.options = options self.options = options
def containers(self, stopped=False, one_off=False, filters={}): def containers(self, stopped=False, one_off=False, filters={}):
@ -431,14 +431,14 @@ class Service(object):
def connect_container_to_networks(self, container): def connect_container_to_networks(self, container):
connected_networks = container.get('NetworkSettings.Networks') connected_networks = container.get('NetworkSettings.Networks')
for network in self.networks: for network, aliases in self.networks.items():
if network in connected_networks: if network in connected_networks:
self.client.disconnect_container_from_network( self.client.disconnect_container_from_network(
container.id, network) container.id, network)
self.client.connect_container_to_network( self.client.connect_container_to_network(
container.id, network, container.id, network,
aliases=self._get_aliases(container), aliases=list(self._get_aliases(container).union(aliases)),
links=self._get_links(False), links=self._get_links(False),
) )
@ -472,7 +472,7 @@ class Service(object):
'image_id': self.image()['Id'], 'image_id': self.image()['Id'],
'links': self.get_link_names(), 'links': self.get_link_names(),
'net': self.network_mode.id, 'net': self.network_mode.id,
'networks': self.networks, 'networks': self.networks.keys(),
'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)
@ -513,9 +513,9 @@ class Service(object):
def _get_aliases(self, container): def _get_aliases(self, container):
if container.labels.get(LABEL_ONE_OFF) == "True": if container.labels.get(LABEL_ONE_OFF) == "True":
return [] return set()
return [self.name, container.short_id] return set([self.name, container.short_id])
def _get_links(self, link_to_self): def _get_links(self, link_to_self):
links = {} links = {}