Add canonical hostname to source object

This is the start of the implementation of:
http://lists.openstack.org/pipermail/openstack-infra/2017-March/005208.html

It lets us associate a canonical hostname with every connection
that we will later use to uniquely identify source code repos.

Story: 2000953
Change-Id: I7f2e64944d46f304e63a54078e682fd5e1682f27
diff --git a/doc/source/connections.rst b/doc/source/connections.rst
index 298100a..614b44a 100644
--- a/doc/source/connections.rst
+++ b/doc/source/connections.rst
@@ -22,6 +22,13 @@
   FQDN of Gerrit server.
   ``server=review.example.com``
 
+**canonical_hostname**
+  The canonical hostname associated with the git repos on the Gerrit
+  server.  Defaults to the value of **server**.  This is used to
+  identify repos from this connection by name and in preparing repos
+  on the filesystem for use by jobs.
+  ``canonical_hostname=git.example.com``
+
 **port**
   Optional: Gerrit server port.
   ``port=29418``
diff --git a/zuul/driver/gerrit/gerritconnection.py b/zuul/driver/gerrit/gerritconnection.py
index e3c726f..e18daa9 100644
--- a/zuul/driver/gerrit/gerritconnection.py
+++ b/zuul/driver/gerrit/gerritconnection.py
@@ -253,6 +253,8 @@
 
         self.user = self.connection_config.get('user')
         self.server = self.connection_config.get('server')
+        self.canonical_hostname = self.connection_config.get(
+            'canonical_hostname', self.server)
         self.port = int(self.connection_config.get('port', 29418))
         self.keyfile = self.connection_config.get('sshkey', None)
         self.keepalive = int(self.connection_config.get('keepalive', 60))
diff --git a/zuul/driver/gerrit/gerritsource.py b/zuul/driver/gerrit/gerritsource.py
index c5e46b1..2271cde 100644
--- a/zuul/driver/gerrit/gerritsource.py
+++ b/zuul/driver/gerrit/gerritsource.py
@@ -20,6 +20,11 @@
     name = 'gerrit'
     log = logging.getLogger("zuul.source.Gerrit")
 
+    def __init__(self, driver, connection, config=None):
+        hostname = connection.canonical_hostname
+        super(GerritSource, self).__init__(driver, connection,
+                                           hostname, config)
+
     def getRefSha(self, project, ref):
         return self.connection.getRefSha(project, ref)
 
diff --git a/zuul/driver/git/gitconnection.py b/zuul/driver/git/gitconnection.py
index e72cc77..9c8d658 100644
--- a/zuul/driver/git/gitconnection.py
+++ b/zuul/driver/git/gitconnection.py
@@ -14,6 +14,8 @@
 # under the License.
 
 import logging
+from six.moves import urllib
+
 import voluptuous as v
 
 from zuul.connection import BaseConnection
@@ -30,8 +32,15 @@
         if 'baseurl' not in self.connection_config:
             raise Exception('baseurl is required for git connections in '
                             '%s' % self.connection_name)
-
         self.baseurl = self.connection_config.get('baseurl')
+        self.canonical_hostname = self.connection_config.get(
+            'canonical_hostname')
+        if not self.canonical_hostname:
+            r = urllib.parse.urlparse(self.baseurl)
+            if r.hostname:
+                self.canonical_hostname = r.hostname
+            else:
+                self.canonical_hostname = 'localhost'
         self.projects = {}
 
     def getProject(self, name):
diff --git a/zuul/driver/git/gitsource.py b/zuul/driver/git/gitsource.py
index bbe799a..076e8b7 100644
--- a/zuul/driver/git/gitsource.py
+++ b/zuul/driver/git/gitsource.py
@@ -20,6 +20,11 @@
     name = 'git'
     log = logging.getLogger("zuul.source.Git")
 
+    def __init__(self, driver, connection, config=None):
+        hostname = connection.canonical_hostname
+        super(GitSource, self).__init__(driver, connection,
+                                        hostname, config)
+
     def getRefSha(self, project, ref):
         raise NotImplemented()
 
diff --git a/zuul/source/__init__.py b/zuul/source/__init__.py
index 0fc9dd3..f0eeba6 100644
--- a/zuul/source/__init__.py
+++ b/zuul/source/__init__.py
@@ -27,9 +27,10 @@
 
     Defines the exact public methods that must be supplied."""
 
-    def __init__(self, driver, connection, config=None):
+    def __init__(self, driver, connection, canonical_hostname, config=None):
         self.driver = driver
         self.connection = connection
+        self.canonical_hostname = canonical_hostname
         self.config = config or {}
 
     @abc.abstractmethod