|  | @@ -87,7 +87,16 @@ ConvergencePlan = namedtuple('ConvergencePlan', 'action containers')
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class Service(object):
 | 
	
		
			
				|  |  | -    def __init__(self, name, client=None, project='default', links=None, external_links=None, volumes_from=None, net=None, **options):
 | 
	
		
			
				|  |  | +    def __init__(
 | 
	
		
			
				|  |  | +        self,
 | 
	
		
			
				|  |  | +        name,
 | 
	
		
			
				|  |  | +        client=None,
 | 
	
		
			
				|  |  | +        project='default',
 | 
	
		
			
				|  |  | +        links=None,
 | 
	
		
			
				|  |  | +        volumes_from=None,
 | 
	
		
			
				|  |  | +        net=None,
 | 
	
		
			
				|  |  | +        **options
 | 
	
		
			
				|  |  | +    ):
 | 
	
		
			
				|  |  |          if not re.match('^%s+$' % VALID_NAME_CHARS, project):
 | 
	
		
			
				|  |  |              raise ConfigError('Invalid project name "%s" - only %s are allowed' % (project, VALID_NAME_CHARS))
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -95,9 +104,8 @@ class Service(object):
 | 
	
		
			
				|  |  |          self.client = client
 | 
	
		
			
				|  |  |          self.project = project
 | 
	
		
			
				|  |  |          self.links = links or []
 | 
	
		
			
				|  |  | -        self.external_links = external_links or []
 | 
	
		
			
				|  |  |          self.volumes_from = volumes_from or []
 | 
	
		
			
				|  |  | -        self.net = net or None
 | 
	
		
			
				|  |  | +        self.net = net or Net(None)
 | 
	
		
			
				|  |  |          self.options = options
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      def containers(self, stopped=False, one_off=False, filters={}):
 | 
	
	
		
			
				|  | @@ -480,26 +488,26 @@ class Service(object):
 | 
	
		
			
				|  |  |          return {
 | 
	
		
			
				|  |  |              'options': self.options,
 | 
	
		
			
				|  |  |              'image_id': self.image()['Id'],
 | 
	
		
			
				|  |  | +            'links': self.get_link_names(),
 | 
	
		
			
				|  |  | +            'net': self.net.id,
 | 
	
		
			
				|  |  | +            'volumes_from': self.get_volumes_from_names(),
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      def get_dependency_names(self):
 | 
	
		
			
				|  |  | -        net_name = self.get_net_name()
 | 
	
		
			
				|  |  | -        return (self.get_linked_names() +
 | 
	
		
			
				|  |  | +        net_name = self.net.service_name
 | 
	
		
			
				|  |  | +        return (self.get_linked_service_names() +
 | 
	
		
			
				|  |  |                  self.get_volumes_from_names() +
 | 
	
		
			
				|  |  |                  ([net_name] if net_name else []))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    def get_linked_names(self):
 | 
	
		
			
				|  |  | -        return [s.name for (s, _) in self.links]
 | 
	
		
			
				|  |  | +    def get_linked_service_names(self):
 | 
	
		
			
				|  |  | +        return [service.name for (service, _) in self.links]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def get_link_names(self):
 | 
	
		
			
				|  |  | +        return [(service.name, alias) for service, alias in self.links]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      def get_volumes_from_names(self):
 | 
	
		
			
				|  |  |          return [s.name for s in self.volumes_from if isinstance(s, Service)]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    def get_net_name(self):
 | 
	
		
			
				|  |  | -        if isinstance(self.net, Service):
 | 
	
		
			
				|  |  | -            return self.net.name
 | 
	
		
			
				|  |  | -        else:
 | 
	
		
			
				|  |  | -            return
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      def get_container_name(self, number, one_off=False):
 | 
	
		
			
				|  |  |          # TODO: Implement issue #652 here
 | 
	
		
			
				|  |  |          return build_container_name(self.project, self.name, number, one_off)
 | 
	
	
		
			
				|  | @@ -528,7 +536,7 @@ class Service(object):
 | 
	
		
			
				|  |  |                  links.append((container.name, self.name))
 | 
	
		
			
				|  |  |                  links.append((container.name, container.name))
 | 
	
		
			
				|  |  |                  links.append((container.name, container.name_without_project))
 | 
	
		
			
				|  |  | -        for external_link in self.external_links:
 | 
	
		
			
				|  |  | +        for external_link in self.options.get('external_links') or []:
 | 
	
		
			
				|  |  |              if ':' not in external_link:
 | 
	
		
			
				|  |  |                  link_name = external_link
 | 
	
		
			
				|  |  |              else:
 | 
	
	
		
			
				|  | @@ -551,25 +559,6 @@ class Service(object):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          return volumes_from
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    def _get_net(self):
 | 
	
		
			
				|  |  | -        if not self.net:
 | 
	
		
			
				|  |  | -            return None
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if isinstance(self.net, Service):
 | 
	
		
			
				|  |  | -            containers = self.net.containers()
 | 
	
		
			
				|  |  | -            if len(containers) > 0:
 | 
	
		
			
				|  |  | -                net = 'container:' + containers[0].id
 | 
	
		
			
				|  |  | -            else:
 | 
	
		
			
				|  |  | -                log.warning("Warning: Service %s is trying to use reuse the network stack "
 | 
	
		
			
				|  |  | -                            "of another service that is not running." % (self.net.name))
 | 
	
		
			
				|  |  | -                net = None
 | 
	
		
			
				|  |  | -        elif isinstance(self.net, Container):
 | 
	
		
			
				|  |  | -            net = 'container:' + self.net.id
 | 
	
		
			
				|  |  | -        else:
 | 
	
		
			
				|  |  | -            net = self.net
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        return net
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      def _get_container_create_options(
 | 
	
		
			
				|  |  |              self,
 | 
	
		
			
				|  |  |              override_options,
 | 
	
	
		
			
				|  | @@ -683,7 +672,7 @@ class Service(object):
 | 
	
		
			
				|  |  |              binds=options.get('binds'),
 | 
	
		
			
				|  |  |              volumes_from=self._get_volumes_from(),
 | 
	
		
			
				|  |  |              privileged=privileged,
 | 
	
		
			
				|  |  | -            network_mode=self._get_net(),
 | 
	
		
			
				|  |  | +            network_mode=self.net.mode,
 | 
	
		
			
				|  |  |              devices=devices,
 | 
	
		
			
				|  |  |              dns=dns,
 | 
	
		
			
				|  |  |              dns_search=dns_search,
 | 
	
	
		
			
				|  | @@ -782,6 +771,61 @@ class Service(object):
 | 
	
		
			
				|  |  |          stream_output(output, sys.stdout)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +class Net(object):
 | 
	
		
			
				|  |  | +    """A `standard` network mode (ex: host, bridge)"""
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    service_name = None
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __init__(self, net):
 | 
	
		
			
				|  |  | +        self.net = net
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @property
 | 
	
		
			
				|  |  | +    def id(self):
 | 
	
		
			
				|  |  | +        return self.net
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    mode = id
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class ContainerNet(object):
 | 
	
		
			
				|  |  | +    """A network mode that uses a container's network stack."""
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    service_name = None
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __init__(self, container):
 | 
	
		
			
				|  |  | +        self.container = container
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @property
 | 
	
		
			
				|  |  | +    def id(self):
 | 
	
		
			
				|  |  | +        return self.container.id
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @property
 | 
	
		
			
				|  |  | +    def mode(self):
 | 
	
		
			
				|  |  | +        return 'container:' + self.container.id
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class ServiceNet(object):
 | 
	
		
			
				|  |  | +    """A network mode that uses a service's network stack."""
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __init__(self, service):
 | 
	
		
			
				|  |  | +        self.service = service
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @property
 | 
	
		
			
				|  |  | +    def id(self):
 | 
	
		
			
				|  |  | +        return self.service.name
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    service_name = id
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @property
 | 
	
		
			
				|  |  | +    def mode(self):
 | 
	
		
			
				|  |  | +        containers = self.service.containers()
 | 
	
		
			
				|  |  | +        if containers:
 | 
	
		
			
				|  |  | +            return 'container:' + containers[0].id
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        log.warn("Warning: Service %s is trying to use reuse the network stack "
 | 
	
		
			
				|  |  | +                 "of another service that is not running." % (self.id))
 | 
	
		
			
				|  |  | +        return None
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  # Names
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 |