From 42577072443384d2dc35cc4f827bc57239a42757 Mon Sep 17 00:00:00 2001
From: Jason Bernardino Alonso <jalonso@lumino.so>
Date: Wed, 8 Oct 2014 22:31:04 -0400
Subject: [PATCH] Accept an external_links list in the service configuration
 dictionary to create links to containers outside of the project

Signed-off-by: Jason Bernardino Alonso <jalonso@luminoso.com>
Signed-off-by: Mauricio de Abreu Antunes <mauricio.abreua@gmail.com>
---
 docs/yml.md                       | 12 ++++++++++++
 fig/service.py                    | 12 ++++++++++--
 tests/integration/service_test.py | 20 ++++++++++++++++++++
 3 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/docs/yml.md b/docs/yml.md
index a911e450b..71d2cb7a2 100644
--- a/docs/yml.md
+++ b/docs/yml.md
@@ -58,6 +58,18 @@ An entry with the alias' name will be created in `/etc/hosts` inside containers
 
 Environment variables will also be created - see the [environment variable reference](env.html) for details.
 
+### external_links
+
+Link to containers started outside this `fig.yml` or even outside of fig, especially for containers that provide shared or common services.
+`external_links` follow semantics similar to `links` when specifying both the container name and the link alias (`CONTAINER:ALIAS`).
+
+```
+external_links:
+ - redis_1
+ - project_db_1:mysql
+ - project_db_1:postgresql
+```
+
 ### ports
 
 Expose ports. Either specify both ports (`HOST:CONTAINER`), or just the container port (a random host port will be chosen).
diff --git a/fig/service.py b/fig/service.py
index bd3000c62..f88b466d5 100644
--- a/fig/service.py
+++ b/fig/service.py
@@ -74,7 +74,7 @@ ServiceName = namedtuple('ServiceName', 'project service number')
 
 
 class Service(object):
-    def __init__(self, name, client=None, project='default', links=None, volumes_from=None, **options):
+    def __init__(self, name, client=None, project='default', links=None, external_links=None, volumes_from=None, **options):
         if not re.match('^%s+$' % VALID_NAME_CHARS, name):
             raise ConfigError('Invalid service name "%s" - only %s are allowed' % (name, VALID_NAME_CHARS))
         if not re.match('^%s+$' % VALID_NAME_CHARS, project):
@@ -82,7 +82,8 @@ class Service(object):
         if 'image' in options and 'build' in options:
             raise ConfigError('Service %s has both an image and build path specified. A service can either be built to image or use an existing image, not both.' % name)
 
-        supported_options = DOCKER_CONFIG_KEYS + ['build', 'expose']
+        supported_options = DOCKER_CONFIG_KEYS + ['build', 'expose',
+                                                  'external_links']
 
         for k in options:
             if k not in supported_options:
@@ -95,6 +96,7 @@ 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.options = options
 
@@ -345,6 +347,12 @@ 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:
+            if ':' not in external_link:
+                link_name = external_link
+            else:
+                external_link, link_name = external_link.split(':')
+            links.append((external_link, link_name))
         return links
 
     def _get_volumes_from(self, intermediate_container=None):
diff --git a/tests/integration/service_test.py b/tests/integration/service_test.py
index a1740272b..bbe348eed 100644
--- a/tests/integration/service_test.py
+++ b/tests/integration/service_test.py
@@ -219,6 +219,26 @@ class ServiceTest(DockerClientTestCase):
             ]),
         )
 
+    def test_start_container_with_external_links(self):
+        db = self.create_service('db')
+        web = self.create_service('web', external_links=['figtest_db_1',
+                                                         'figtest_db_2',
+                                                         'figtest_db_3:db_3'])
+
+        db.start_container()
+        db.start_container()
+        db.start_container()
+        web.start_container()
+
+        self.assertEqual(
+            set(web.containers()[0].links()),
+            set([
+                'figtest_db_1',
+                'figtest_db_2',
+                'db_3',
+                ]),
+        )
+
     def test_start_normal_container_does_not_create_links_to_its_own_service(self):
         db = self.create_service('db')