From 53919e8d9db09b7d6817dca73ca731bd6fa21ad8 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Fri, 27 Sep 2024 12:45:17 +0200 Subject: [PATCH] Flock: CLI first try (starts and stops the hypervisor) --- flock/flock-cli | 133 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100755 flock/flock-cli diff --git a/flock/flock-cli b/flock/flock-cli new file mode 100755 index 00000000..4318a328 --- /dev/null +++ b/flock/flock-cli @@ -0,0 +1,133 @@ +#!/usr/bin/python3 + +import cbor2 +import os +import pathlib +import socket +import subprocess +import sys + +DEFAULT_RUN_PATH = pathlib.Path(f"/run/user/{os.getuid()}/flock") +handlers = {} + +class HandlerError(Exception): + pass + +def handler(fun): + items = fun.__name__.split("_") + + hx = handlers + while len(items) > 1: + if (s := items.pop(0)) not in hx: + hx[s] = dict() + hx = hx[s] + + if items[0] in hx: + raise Exception(f"Duplicate handler {fun.__name__}") + + hx[items[0]] = fun + +class HypervisorNonexistentError(HandlerError): + def __init__(self, *args, **kwargs): + return super().__init__("Hypervisor not found", *args, **kwargs) + +class HypervisorStaleError(HandlerError): + def __init__(self, *args, **kwargs): + return super().__init__("Hypervisor stale", *args, **kwargs) + +def connect(where: pathlib.Path): + if not where.exists(): + raise HypervisorNonexistentError() + + client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + client.connect(bytes(where)) + except ConnectionRefusedError: + raise HypervisorStaleError() + return client + +def ctl_path(name: str): + return DEFAULT_RUN_PATH / f"{name}.ctl" + +def msg(name: str, data: dict): + try: + ctl = connect(ctl_path(name)) + except HypervisorNonexistentError as e: + e.add_note(f"Failed to send message {data} to {name}") + raise e + + ctl.sendall(cbor2.dumps(data)) + return cbor2.loads(ctl.recv(1024)) + +@handler +def start(name: str): + DEFAULT_RUN_PATH.mkdir(parents=True, exist_ok=True) + try: + connect(ctl := ctl_path(name)) + raise HandlerError("Hypervisor already exists") + except HypervisorNonexistentError: + pass + + subprocess.run(["./flock-sim", "-s", ctl, name]) + +@handler +def stop(name: str): + for k,v in msg(name, { 0: None }).items(): + assert(k == -1) + assert(v == "OK") + +@handler +def cleanup(name: str): + try: + connect(ctl := ctl_path(name)) + raise HandlerError("Hypervisor is not stale") + except HypervisorStaleError: + ctl.unlink() + +@handler +def container_start(hypervisor: str, name: str): + print(f"start a machine {name} in {hypervisor}") + +try: + binname = sys.argv.pop(0) +except Exception as e: + raise RuntimeError from e + +def usage(name: str): + print( + f"Usage: {name} ", + f"", + f"Available commands:", + f"\tstart start Flock hypervisor", + f"\t creates .ctl in {DEFAULT_RUN_PATH}", + f"\tstop stop Flock hypervisor", + f"\tcleanup cleanup the control socket left behind a stale hypervisor", + f"\tcontainer start start virtual machine", + f"\tcontainer stop stop virtual machine", + f"\ttelnet run telnet to this machine", + sep="\n") + +cmd = [] +hx = handlers +while type(hx) is dict: + try: + hx = hx[cx := sys.argv.pop(0)] + except (IndexError, KeyError): + usage(binname) + exit(2) + + cmd.append(cx) + +try: + hx(*sys.argv) +except HandlerError as e: + print(f"Error: {e}") +# raise e + exit(1) +except TypeError as e: + usage(binname) + print() + print(f"Error in command {' '.join(cmd)}.") + raise RuntimeError from e + exit(2) +