summaryrefslogtreecommitdiff
path: root/lorrycontroller
diff options
context:
space:
mode:
authorBen Hutchings <ben.hutchings@codethink.co.uk>2020-05-14 00:21:01 +0100
committerBen Hutchings <ben.hutchings@codethink.co.uk>2020-06-01 17:03:37 +0100
commit38697c01cc12c4e8cc57b3bb372c5cf5f34ce167 (patch)
treef7a3d3a0348f43630320785be9d3c1bbe0cdbaa5 /lorrycontroller
parent75c990bc607b1059a4ea89b323a7b2658b9c313a (diff)
downloadlorry-controller-38697c01cc12c4e8cc57b3bb372c5cf5f34ce167.tar.gz
Introduce and use SshCommand class for running commands via ssh
Most of the ssh parameters are given by a URL, which should be configurable. Additional options can be set by keyword arguments. runcmd already has a function like this, but it doesn't take a URL and runcmd.shell_quote doesn't handle empty strings correctly. Use this in the Gerrit host connector. It could be used in the Gitano host connector as well, but I want to avoid making further changes there that I can't test.
Diffstat (limited to 'lorrycontroller')
-rw-r--r--lorrycontroller/gerrit.py30
-rw-r--r--lorrycontroller/hosts.py38
2 files changed, 47 insertions, 21 deletions
diff --git a/lorrycontroller/gerrit.py b/lorrycontroller/gerrit.py
index c18f2ed..dad964f 100644
--- a/lorrycontroller/gerrit.py
+++ b/lorrycontroller/gerrit.py
@@ -32,27 +32,15 @@ class GerritDownstream(hosts.DownstreamHost):
'''
def __init__(self, app_settings):
- # XXX These need to be configurable
- host = 'localhost'
- port = 29418
- user = 'lorry'
-
- self._ssh_command_args = [
- 'ssh', '-oStrictHostKeyChecking=no', '-oBatchMode=yes', '-p%i' % port,
- '%s@%s' % (user, host)]
-
- def _ssh_command(self, command):
- quoted_args = [cliapp.shell_quote(x) for x in command]
- out = cliapp.runcmd(self._ssh_command_args + quoted_args)
- if isinstance(out, bytes):
- out = out.decode('utf-8', errors='replace')
- return out
+ # XXX This needs to be configurable
+ url = 'ssh://lorry@localhost:29418'
+ self._ssh_command = hosts.SshCommand(url, StrictHostKeyChecking='no')
def _has_project(self, name):
# There's no 'does this project exist' command in Gerrit 2.9.4; 'list
# all projects with this prefix' is as close we can get.
- output = self._ssh_command([
+ output = self._ssh_command.run([
'gerrit', 'ls-projects', '--type=ALL', '--prefix=%s' % name])
projects = output.strip().split('\n')
@@ -72,17 +60,17 @@ class GerritDownstream(hosts.DownstreamHost):
logging.info('Project %s exists in local Gerrit already.',
name)
else:
- self._ssh_command(['gerrit', 'create-project', name])
+ self._ssh_command.run(['gerrit', 'create-project', name])
logging.info('Created %s project in local Gerrit.', name)
# We can only set this metadata if we're the owner of the
# repository. For now, ignore failures.
try:
if 'head' in metadata:
- self._ssh_command(['gerrit', 'set-head', name,
- '--new-head', metadata['head']])
+ self._ssh_command.run(['gerrit', 'set-head', name,
+ '--new-head', metadata['head']])
if 'description' in metadata:
- self._ssh_command(['gerrit', 'set-project', name,
- '-d', metadata['description']])
+ self._ssh_command.run(['gerrit', 'set-project', name,
+ '-d', metadata['description']])
except cliapp.AppException:
pass
diff --git a/lorrycontroller/hosts.py b/lorrycontroller/hosts.py
index 39cae57..fb892dc 100644
--- a/lorrycontroller/hosts.py
+++ b/lorrycontroller/hosts.py
@@ -14,6 +14,10 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import abc
+import shlex
+import urllib.parse
+
+import cliapp
class DownstreamHost(abc.ABC):
@@ -119,3 +123,37 @@ class UpstreamHost(abc.ABC):
DownstreamHost.prepare_repo.
'''
pass
+
+
+class SshCommand:
+ def __init__(self, urlstring, **options):
+ try:
+ url = urllib.parse.urlsplit(urlstring, allow_fragments=False)
+ url.port
+ except ValueError:
+ raise cliapp.AppException('Invalid URL: %s' % urlstring)
+
+ if url.scheme != 'ssh':
+ raise cliapp.AppException('Not an SSH URL: %s' % urlstring)
+ if url.path not in ['', '/']:
+ raise cliapp.AppException('Unexpected path part in SSH URL')
+ if url.query != '':
+ raise cliapp.AppException('Unexpected query part in SSH URL')
+ if url.password is not None:
+ raise cliapp.AppException('Unexpected password in SSH URL')
+
+ self._ssh_args = ['ssh', '-oBatchMode=yes']
+ for key, value in options.items():
+ self._ssh_args.append('-o%s=%s' % (key, value))
+ if url.username is not None:
+ self._ssh_args.append('-oUser=%s' % url.username)
+ if url.port is not None:
+ self._ssh_args.append('-p%i' % url.port)
+ self._ssh_args.append(url.hostname)
+
+ def run(self, args):
+ quoted_args = [shlex.quote(arg) for arg in args]
+ stdout = cliapp.runcmd(self._ssh_args + quoted_args)
+ if isinstance(stdout, bytes):
+ stdout = stdout.decode('utf-8', errors='replace')
+ return stdout