|
2 | 2 | coordinator, acquire a place and interact with the connected resources""" |
3 | 3 | import argparse |
4 | 4 | import asyncio |
| 5 | +import atexit |
5 | 6 | import contextlib |
| 7 | +import enum |
6 | 8 | import os |
7 | 9 | import subprocess |
8 | 10 | import traceback |
9 | 11 | import logging |
10 | 12 | import signal |
11 | 13 | import sys |
| 14 | +import shlex |
| 15 | +import json |
12 | 16 | from textwrap import indent |
13 | 17 | from socket import gethostname |
14 | 18 | from getpass import getuser |
|
27 | 31 | from .. import Target, target_factory |
28 | 32 | from ..util.proxy import proxymanager |
29 | 33 | from ..util.helper import processwrapper |
| 34 | +from ..util import atomic_replace |
30 | 35 | from ..driver import Mode |
31 | 36 |
|
32 | 37 | txaio.use_asyncio() |
@@ -1327,6 +1332,34 @@ async def print_reservations(self): |
1327 | 1332 | print(f"Reservation '{res.token}':") |
1328 | 1333 | res.show(level=1) |
1329 | 1334 |
|
| 1335 | + async def export(self, place, target): |
| 1336 | + exported = target.export() |
| 1337 | + exported["LG__CLIENT_PID"] = str(os.getpid()) |
| 1338 | + if self.args.format is ExportFormat.SHELL: |
| 1339 | + lines = [] |
| 1340 | + for k, v in sorted(exported.items()): |
| 1341 | + lines.append(f"{k}={shlex.quote(v)}") |
| 1342 | + data = "\n".join(lines) |
| 1343 | + elif self.args.format is ExportFormat.SHELL_EXPORT: |
| 1344 | + lines = [] |
| 1345 | + for k, v in sorted(exported.items()): |
| 1346 | + lines.append(f"export {k}={shlex.quote(v)}") |
| 1347 | + data = "\n".join(lines)+"\n" |
| 1348 | + elif self.args.format is ExportFormat.JSON: |
| 1349 | + data = json.dumps(exported) |
| 1350 | + if self.args.filename == "-": |
| 1351 | + sys.stdout.write(data) |
| 1352 | + else: |
| 1353 | + atomic_replace(self.args.filename, data.encode()) |
| 1354 | + print(f"Exported to {self.args.filename}", file=sys.stderr) |
| 1355 | + try: |
| 1356 | + print("Waiting for CTRL+C or SIGTERM...", file=sys.stderr) |
| 1357 | + while True: |
| 1358 | + await asyncio.sleep(1.0) |
| 1359 | + except GeneratorExit: |
| 1360 | + print("Exiting...\n", file=sys.stderr) |
| 1361 | + export.needs_target = True |
| 1362 | + |
1330 | 1363 |
|
1331 | 1364 | def start_session(url, realm, extra): |
1332 | 1365 | from autobahn.asyncio.wamp import ApplicationRunner |
@@ -1421,6 +1454,16 @@ def __call__(self, parser, namespace, value, option_string): |
1421 | 1454 | v.append((local, remote)) |
1422 | 1455 | setattr(namespace, self.dest, v) |
1423 | 1456 |
|
| 1457 | + |
| 1458 | +class ExportFormat(enum.Enum): |
| 1459 | + SHELL = "shell" |
| 1460 | + SHELL_EXPORT = "shell-export" |
| 1461 | + JSON = "json" |
| 1462 | + |
| 1463 | + def __str__(self): |
| 1464 | + return self.value |
| 1465 | + |
| 1466 | + |
1424 | 1467 | def main(): |
1425 | 1468 | processwrapper.enable_logging() |
1426 | 1469 | logging.basicConfig( |
@@ -1756,6 +1799,13 @@ def main(): |
1756 | 1799 | subparser = subparsers.add_parser('reservations', help="list current reservations") |
1757 | 1800 | subparser.set_defaults(func=ClientSession.print_reservations) |
1758 | 1801 |
|
| 1802 | + subparser = subparsers.add_parser('export', help="export driver information to a file (needs environment with drivers)") |
| 1803 | + subparser.add_argument('--format', dest='format', |
| 1804 | + type=ExportFormat, choices=ExportFormat, default=ExportFormat.SHELL_EXPORT, |
| 1805 | + help="output format (default: %(default)s)") |
| 1806 | + subparser.add_argument('filename', help='output filename') |
| 1807 | + subparser.set_defaults(func=ClientSession.export) |
| 1808 | + |
1759 | 1809 | # make any leftover arguments available for some commands |
1760 | 1810 | args, leftover = parser.parse_known_args() |
1761 | 1811 | if args.command not in ['ssh', 'rsync', 'forward']: |
@@ -1806,6 +1856,8 @@ def main(): |
1806 | 1856 | if args.command and args.command != 'help': |
1807 | 1857 | exitcode = 0 |
1808 | 1858 | try: |
| 1859 | + signal.signal(signal.SIGTERM, lambda *_: sys.exit(0)) |
| 1860 | + |
1809 | 1861 | session = start_session(args.crossbar, os.environ.get("LG_CROSSBAR_REALM", "realm1"), |
1810 | 1862 | extra) |
1811 | 1863 | try: |
|
0 commit comments