Fix setting of GIT_SSH for timer merge jobs

Problem is that merge jobs triggered by timer don't supply
"refspec" event attribute, and, naturally, nothing is merged
but the repo is updated.
But, in such case, no connection info is passed to merger,
and GIT_SSH is not set.
So, the merge job will fail (perhaps, until some
other change events with "refspec" defined will
make this merger to set GIT_SSH properly)

Change-Id: I6dd96ae0bdcdf4c3db4c931a8c6ef7d5edfc1257
diff --git a/tests/fixtures/zuul-connections-same-gerrit.conf b/tests/fixtures/zuul-connections-same-gerrit.conf
index af31c8a..b3b0e3f 100644
--- a/tests/fixtures/zuul-connections-same-gerrit.conf
+++ b/tests/fixtures/zuul-connections-same-gerrit.conf
@@ -26,13 +26,13 @@
 driver=gerrit
 server=review.example.com
 user=jenkins
-sshkey=none
+sshkey=fake_id_rsa1
 
 [connection alt_voting_gerrit]
 driver=gerrit
 server=review.example.com
 user=civoter
-sshkey=none
+sshkey=fake_id_rsa2
 
 [connection outgoing_smtp]
 driver=smtp
diff --git a/tests/fixtures/zuul.conf b/tests/fixtures/zuul.conf
index b250c6d..0956cc4 100644
--- a/tests/fixtures/zuul.conf
+++ b/tests/fixtures/zuul.conf
@@ -26,7 +26,7 @@
 driver=gerrit
 server=review.example.com
 user=jenkins
-sshkey=none
+sshkey=fake_id_rsa_path
 
 [connection smtp]
 driver=smtp
diff --git a/tests/test_scheduler.py b/tests/test_scheduler.py
index b6fa4a3..80097b8 100755
--- a/tests/test_scheduler.py
+++ b/tests/test_scheduler.py
@@ -3020,6 +3020,49 @@
         self.worker.release('.*')
         self.waitUntilSettled()
 
+    def test_timer_sshkey(self):
+        "Test that a periodic job can setup SSH key authentication"
+        self.worker.hold_jobs_in_build = True
+        self.config.set('zuul', 'layout_config',
+                        'tests/fixtures/layout-timer.yaml')
+        self.sched.reconfigure(self.config)
+        self.registerJobs()
+
+        # The pipeline triggers every second, so we should have seen
+        # several by now.
+        time.sleep(5)
+        self.waitUntilSettled()
+
+        self.assertEqual(len(self.builds), 2)
+
+        ssh_wrapper = os.path.join(self.git_root, ".ssh_wrapper_gerrit")
+        self.assertTrue(os.path.isfile(ssh_wrapper))
+        with open(ssh_wrapper) as f:
+            ssh_wrapper_content = f.read()
+        self.assertIn("fake_id_rsa", ssh_wrapper_content)
+        # In the unit tests Merger runs in the same process,
+        # so we see its' environment variables
+        self.assertEqual(os.environ['GIT_SSH'], ssh_wrapper)
+
+        self.worker.release('.*')
+        self.waitUntilSettled()
+        self.assertEqual(len(self.history), 2)
+
+        self.assertEqual(self.getJobFromHistory(
+            'project-bitrot-stable-old').result, 'SUCCESS')
+        self.assertEqual(self.getJobFromHistory(
+            'project-bitrot-stable-older').result, 'SUCCESS')
+
+        # Stop queuing timer triggered jobs and let any that may have
+        # queued through so that end of test assertions pass.
+        self.config.set('zuul', 'layout_config',
+                        'tests/fixtures/layout-no-timer.yaml')
+        self.sched.reconfigure(self.config)
+        self.registerJobs()
+        self.waitUntilSettled()
+        self.worker.release('.*')
+        self.waitUntilSettled()
+
     def test_client_enqueue_change(self):
         "Test that the RPC client can enqueue a change"
         A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
diff --git a/zuul/merger/client.py b/zuul/merger/client.py
index 950c385..9e8c243 100644
--- a/zuul/merger/client.py
+++ b/zuul/merger/client.py
@@ -97,9 +97,10 @@
         data = dict(items=items)
         self.submitJob('merger:merge', data, build_set, precedence)
 
-    def updateRepo(self, project, url, build_set,
+    def updateRepo(self, project, connection_name, url, build_set,
                    precedence=zuul.model.PRECEDENCE_NORMAL):
         data = dict(project=project,
+                    connection_name=connection_name,
                     url=url)
         self.submitJob('merger:update', data, build_set, precedence)
 
diff --git a/zuul/merger/merger.py b/zuul/merger/merger.py
index b82a7de..a974e9c 100644
--- a/zuul/merger/merger.py
+++ b/zuul/merger/merger.py
@@ -223,6 +223,14 @@
         fd.close()
         os.chmod(name, 0o755)
 
+    def _setGitSsh(self, connection_name):
+        wrapper_name = '.ssh_wrapper_%s' % connection_name
+        name = os.path.join(self.working_root, wrapper_name)
+        if os.path.isfile(name):
+            os.environ['GIT_SSH'] = name
+        elif 'GIT_SSH' in os.environ:
+            del os.environ['GIT_SSH']
+
     def addProject(self, project, url):
         repo = None
         try:
@@ -242,7 +250,8 @@
                             " without a url" % (project,))
         return self.addProject(project, url)
 
-    def updateRepo(self, project, url):
+    def updateRepo(self, project, connection_name, url):
+        self._setGitSsh(connection_name)
         repo = self.getRepo(project, url)
         try:
             self.log.info("Updating local repository %s", project)
@@ -279,14 +288,6 @@
 
         return commit
 
-    def _setGitSsh(self, connection_name):
-        wrapper_name = '.ssh_wrapper_%s' % connection_name
-        name = os.path.join(self.working_root, wrapper_name)
-        if os.path.isfile(name):
-            os.environ['GIT_SSH'] = name
-        elif 'GIT_SSH' in os.environ:
-            del os.environ['GIT_SSH']
-
     def _mergeItem(self, item, recent):
         self.log.debug("Processing refspec %s for project %s / %s ref %s" %
                        (item['refspec'], item['project'], item['branch'],
diff --git a/zuul/merger/server.py b/zuul/merger/server.py
index d56993c..b1921d9 100644
--- a/zuul/merger/server.py
+++ b/zuul/merger/server.py
@@ -109,7 +109,9 @@
 
     def update(self, job):
         args = json.loads(job.arguments)
-        self.merger.updateRepo(args['project'], args['url'])
+        self.merger.updateRepo(args['project'],
+                               args['connection_name'],
+                               args['url'])
         result = dict(updated=True,
                       zuul_url=self.zuul_url)
         job.sendWorkComplete(json.dumps(result))
diff --git a/zuul/scheduler.py b/zuul/scheduler.py
index 8c26541..161bfc3 100644
--- a/zuul/scheduler.py
+++ b/zuul/scheduler.py
@@ -1501,8 +1501,9 @@
         else:
             self.log.debug("Preparing update repo for: %s" % item.change)
             url = self.pipeline.source.getGitUrl(item.change.project)
+            connection_name = self.pipeline.source.connection.connection_name
             self.sched.merger.updateRepo(item.change.project.name,
-                                         url, build_set,
+                                         connection_name, url, build_set,
                                          self.pipeline.precedence)
         # merge:merge has been emitted properly:
         build_set.merge_state = build_set.PENDING