summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2023-04-08 21:37:55 +0200
committerHelmut Grohne <helmut@subdivi.de>2023-04-08 21:37:55 +0200
commit02ddcaa3e330e638326a8694e753da5fa048d2b5 (patch)
tree394365d8e00b1e96eba2b7b533d1c3840f9c34c5
parent1f2f09a3c0927665ce455043475132c10966fc74 (diff)
downloadmdbp-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.py66
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(