Merge "Merge branch 'master' into feature/zuulv3" into feature/zuulv3
diff --git a/zuul/driver/gerrit/gerritconnection.py b/zuul/driver/gerrit/gerritconnection.py
index daec0f5..460eabb 100644
--- a/zuul/driver/gerrit/gerritconnection.py
+++ b/zuul/driver/gerrit/gerritconnection.py
@@ -230,13 +230,16 @@
                     stdout.channel.close()
             ret = stdout.channel.recv_exit_status()
             self.log.debug("SSH exit status: %s" % ret)
-            client.close()
 
             if ret and ret not in [-1, 130]:
                 raise Exception("Gerrit error executing stream-events")
         except:
             self.log.exception("Exception on ssh event stream:")
             time.sleep(5)
+        finally:
+            # If we don't close on exceptions to connect we can leak the
+            # connection and DoS Gerrit.
+            client.close()
 
     def run(self):
         while not self._stopped:
@@ -731,16 +734,25 @@
         return out
 
     def _open(self):
-        client = paramiko.SSHClient()
-        client.load_system_host_keys()
-        client.set_missing_host_key_policy(paramiko.WarningPolicy())
-        client.connect(self.server,
-                       username=self.user,
-                       port=self.port,
-                       key_filename=self.keyfile)
-        transport = client.get_transport()
-        transport.set_keepalive(self.keepalive)
-        self.client = client
+        if self.client:
+            # Paramiko needs explicit closes, its possible we will open even
+            # with an unclosed client so explicitly close here.
+            self.client.close()
+        try:
+            client = paramiko.SSHClient()
+            client.load_system_host_keys()
+            client.set_missing_host_key_policy(paramiko.WarningPolicy())
+            client.connect(self.server,
+                           username=self.user,
+                           port=self.port,
+                           key_filename=self.keyfile)
+            transport = client.get_transport()
+            transport.set_keepalive(self.keepalive)
+            self.client = client
+        except Exception:
+            client.close()
+            self.client = None
+            raise
 
     def _ssh(self, command, stdin_data=None):
         if not self.client:
diff --git a/zuul/driver/github/githubconnection.py b/zuul/driver/github/githubconnection.py
index 2d9dd94..f31df6a 100644
--- a/zuul/driver/github/githubconnection.py
+++ b/zuul/driver/github/githubconnection.py
@@ -990,5 +990,5 @@
 
 
 def getSchema():
-    github_connection = v.Any(str, v.Schema({}, extra=True))
+    github_connection = v.Any(str, v.Schema(dict))
     return github_connection
diff --git a/zuul/executor/ansiblelaunchserver.py b/zuul/executor/ansiblelaunchserver.py
index 18762b2..753c8c7 100644
--- a/zuul/executor/ansiblelaunchserver.py
+++ b/zuul/executor/ansiblelaunchserver.py
@@ -138,6 +138,11 @@
 
     def __exit__(self, etype, value, tb):
         if not self.keep:
+            # Ensure directories are writeable so that files can be removed
+            # from them.
+            for root, dirs, files in os.walk(self.root):
+                for d in dirs:
+                    os.chmod(os.path.join(root, d), 0o755)
             shutil.rmtree(self.root)