diff options
author | Helmut Grohne <helmut@subdivi.de> | 2023-04-08 21:37:55 +0200 |
---|---|---|
committer | Helmut Grohne <helmut@subdivi.de> | 2023-04-08 21:37:55 +0200 |
commit | 02ddcaa3e330e638326a8694e753da5fa048d2b5 (patch) | |
tree | 394365d8e00b1e96eba2b7b533d1c3840f9c34c5 | |
parent | 1f2f09a3c0927665ce455043475132c10966fc74 (diff) | |
download | mdbp-02ddcaa3e330e638326a8694e753da5fa048d2b5.tar.gz |
mdbp-ssh: add option --proxyrepos to forward repositories
Given this option, http repositories will be forwarded using a ssh port
forward and rewritten such they work on the remote side forwarding their
traffic through ssh.
-rw-r--r-- | mdbp/ssh.py | 66 |
1 files changed, 64 insertions, 2 deletions
diff --git a/mdbp/ssh.py b/mdbp/ssh.py index 8445dc7..c0a295c 100644 --- a/mdbp/ssh.py +++ b/mdbp/ssh.py @@ -7,13 +7,63 @@ import contextlib import io import json import pathlib +import random +import re import subprocess import sys import tarfile import typing +import urllib.parse from .common import JsonObject, buildjson, get_dsc_files, tar_add + +class RepoForward: + def __init__(self): + self.forwards = {} + + + def get_forward(self, destination: str) -> str: + try: + return self.forwards[destination] + except KeyError: + forward = "localhost:%d" % random.randrange(1024, 65536) + self.forwards[destination] = forward + return forward + + + def proxy(self, repoline: str) -> str: + """Transform an extra repository line and to pass it through a ssh + forward.""" + match = re.match( + r"^(deb(?:-src)?(?:\s+\[[^]]*\])?)\s+(\S+)\s+(.*)$", repoline + ) + if not match: + raise ValueError( + "failed to understand repository specification %r" % repoline + ) + head, url, tail = match.groups() + spliturl = urllib.parse.urlsplit(url) + if spliturl.scheme != "http": + raise ValueError("cannot proxy url of scheme %r" % spliturl.scheme) + netloc = self.get_forward( + "%s:%d" % (spliturl.hostname, spliturl.port or 80) + ) + if spliturl.username: + netloc = "@" + netloc + if spliturl.password: + netloc = ":" + spliturl.password + netloc + netloc = spliturl.username + netloc + url = urllib.parse.urlunsplit((spliturl.scheme, netloc) + spliturl[2:]) + return " ".join((head, url, tail)) + + + def ssh_options(self) -> typing.Iterable[str]: + for dest, proxy in self.forwards.items(): + yield "-R" + yield "%s:%s" % (proxy, dest) + + def produce_request_tar(buildjsonobj: JsonObject, fileobj: typing.IO[bytes]) -> None: """Write a tar file suitable for mdbp-streamapi into the given `fileobj` @@ -47,14 +97,26 @@ def produce_request_tar(buildjsonobj: JsonObject, def main() -> None: """Entry point for mdbp-ssh backend""" parser = argparse.ArgumentParser() + parser.add_argument( + "--proxyrepos", + default=False, + action="store_true", + help="proxy http repositories over the ssh connection", + ) parser.add_argument("host", type=str) parser.add_argument("command", nargs=argparse.REMAINDER) args = parser.parse_args() if len(args.command) < 2: parser.error("missing command or json file") build = buildjson(args.command.pop()) - - cmd = ["ssh", args.host, "mdbp-streamapi", *args.command] + cmd = ["ssh"] + if args.proxyrepos and "extrarepositories" in build: + repoforward = RepoForward() + build["extrarepositories"] = list( + map(repoforward.proxy, build["extrarepositories"]) + ) + cmd.extend(repoforward.ssh_options()) + cmd.extend([args.host, "mdbp-streamapi", *args.command]) with contextlib.ExitStack() as stack: proc = stack.enter_context( subprocess.Popen( |