68 lines
2.5 KiB
Python
Executable File
68 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Push a local script into the running maintenance guest and run it.
|
|
|
|
sudo owuivm-guest-run vm/images/ubuntu/by-hand.sh
|
|
|
|
WHY THIS EXISTS
|
|
|
|
Preparing a base image by hand means typing into a VNC console, and the
|
|
list of things to do to it is a hundred lines long. Everything on that
|
|
list is ordinary shell, so the only real problem is getting the text in
|
|
there - and the machine already has a channel for exactly that, the same
|
|
one every session uses.
|
|
|
|
It needs qemu-guest-agent inside the guest, which is also the one thing
|
|
on that list that genuinely has to be typed by hand: it is what this
|
|
speaks to. So the sequence is always "install the guest agent by hand,
|
|
then push the rest".
|
|
|
|
Deliberately the maintenance socket only. A session's guest belongs to
|
|
the agent, and a way to inject a script into it from the host is not
|
|
something this host should own.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
|
|
sys.path.insert(0, "/usr/local/lib/owuivm")
|
|
|
|
from guest import Guest, GuestError # noqa: E402
|
|
|
|
SOCKET = "/run/owuivm/00000000000000000000000000000000/ga.sock"
|
|
|
|
|
|
def main(argv: list[str]) -> int:
|
|
if len(argv) != 2:
|
|
print(f"usage: {argv[0]} <script>", file=sys.stderr)
|
|
return 64
|
|
with open(argv[1], "rb") as handle:
|
|
body = handle.read()
|
|
remote = "/root/" + argv[1].rsplit("/", 1)[-1]
|
|
|
|
try:
|
|
with Guest(SOCKET, timeout=30.0) as agent:
|
|
if not agent.ping(timeout=10.0):
|
|
raise GuestError("the guest agent did not answer")
|
|
agent.write_file(remote, body)
|
|
print(f"pushed {len(body)} bytes to {remote}; running it\n", flush=True)
|
|
# No timeout worth arguing about: this installs packages over
|
|
# a link that is as fast as the host's, and a run that is
|
|
# still going is not a run that has failed.
|
|
result = agent.shell(f"bash {remote}", timeout_s=1800.0)
|
|
except (GuestError, OSError) as exc:
|
|
print(f"could not reach the machine: {exc}", file=sys.stderr)
|
|
print("\nIs it running, and is qemu-guest-agent installed inside it?"
|
|
"\n sudo apt install -y qemu-guest-agent"
|
|
"\n sudo systemctl enable --now qemu-guest-agent", file=sys.stderr)
|
|
return 69
|
|
|
|
sys.stdout.write(result["stdout"])
|
|
if result["stderr"].strip():
|
|
sys.stderr.write("\n-- stderr --\n" + result["stderr"])
|
|
print(f"\nexit code: {result['exit_code']} ({result['seconds']}s)")
|
|
return 0 if result["exit_code"] == 0 else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main(sys.argv))
|