From 4f1bba5c626960c2d6359ee632332d605b613510 Mon Sep 17 00:00:00 2001 From: Charles Short Date: Tue, 24 Oct 2023 12:28:42 -0400 Subject: [PATCH] Add support for "compose exec" Add support to run shell commands inside a checked out ostree branch. The way that this works is the following: 1. Determine the branch to checkout. 2. Checkout the branch in the workspace. 3. Use systemd-nspawn to create a shell inside the branch. Test Plan PASSED Installed apt-ostree from git repo. PASSED Run sudo apt-ostree compose create \ --base config/debian/bookworm \ --repo /repo debian/bookworm \ bookworm-test PASSED Run sudo apt-ostree compose exec --repo /repo --branch bookwork-test "cat /etc/debian_version" Story: 2010867 Task: 48556 Change-Id: I6ff9658fc04ec83d50d2cb5f3b8dbb70e3065688 Signed-off-by: Charles Short --- apt_ostree/cmd/compose/__init__.py | 2 ++ apt_ostree/cmd/compose/run.py | 54 ++++++++++++++++++++++++++++++ apt_ostree/run.py | 53 +++++++++++++++++++++++++++++ etc/mounts.yaml | 3 ++ 4 files changed, 112 insertions(+) create mode 100644 apt_ostree/cmd/compose/run.py create mode 100644 apt_ostree/run.py create mode 100644 etc/mounts.yaml diff --git a/apt_ostree/cmd/compose/__init__.py b/apt_ostree/cmd/compose/__init__.py index 70aaca0..45fe649 100644 --- a/apt_ostree/cmd/compose/__init__.py +++ b/apt_ostree/cmd/compose/__init__.py @@ -15,6 +15,7 @@ from apt_ostree.cmd.compose.init import init from apt_ostree.cmd.compose.install import install from apt_ostree.cmd.compose.repo import repo from apt_ostree.cmd.compose.restore import restore +from apt_ostree.cmd.compose.run import run from apt_ostree.cmd.compose.uninstall import uninstall from apt_ostree.cmd.compose.upgrade import upgrade @@ -34,4 +35,5 @@ compose.add_command(install) compose.add_command(upgrade) compose.add_command(repo) compose.add_command(restore) +compose.add_command(run) compose.add_command(uninstall) diff --git a/apt_ostree/cmd/compose/run.py b/apt_ostree/cmd/compose/run.py new file mode 100644 index 0000000..8b5f698 --- /dev/null +++ b/apt_ostree/cmd/compose/run.py @@ -0,0 +1,54 @@ +""" +Copyright (c) 2023 Wind River Systems, Inc. + +SPDX-License-Identifier: Apache-2.0 + +""" + +import errno +import sys + +import click + +from apt_ostree.cmd import pass_state_context +from apt_ostree.run import RunCommand + + +@click.command( + name="exec", + help="Run a command or shell from an Ostree branch.") +@pass_state_context +@click.option( + "--mounts", + help="Path to yaml configuration for mount points.", + type=click.Path(exists=True) +) +@click.option( + "--root", + help="Path to operate on", +) +@click.option( + "--pre-exec", + 'pre_exec', + help="Run the command before executing the container", +) +@click.argument( + "cmd", + # If command not specified then execute a shell. + default="" +) +def run(state, + mounts, + root, + pre_exec, + cmd): + try: + RunCommand(state).run_command(cmd, mounts, pre_exec, root) + except KeyboardInterrupt: + click.secho("\n" + ("Exiting at your request.")) + sys.exit(130) + except BrokenPipeError: + sys.exit() + except OSError as error: + if error.errno == errno.ENOSPC: + sys.exit("error - No space left on device.") diff --git a/apt_ostree/run.py b/apt_ostree/run.py new file mode 100644 index 0000000..d426fd5 --- /dev/null +++ b/apt_ostree/run.py @@ -0,0 +1,53 @@ +""" +Copyright (c) 2023 Wind River Systems, Inc. + +SPDX-License-Identifier: Apache-2.0 + +""" + +import os +import sys + +import click +from rich.console import Console +import yaml + +from apt_ostree import utils + + +class RunCommand: + def __init__(self, state): + self.state = state + self.console = Console() + + def run_command(self, command, mount_points, pre_exec, rootfs): + """Run a command in an ostree branch.""" + if not os.path.exists(rootfs): + click.secho(f"Directory not found: {rootfs}", fg="red") + sys.exit(1) + + mounts = None + if mount_points: + self.console.print("Loading configuration.") + with open(mount_points, "r") as f: + mounts = yaml.safe_load(f) + + if pre_exec: + self.console.print(f"Executing pre-command: {pre_exec}", + highlight=False) + cmd = ["systemd-nspawn", "-q", "-D", rootfs] + cmd += pre_exec.split() + r = utils.run_command(cmd) + if r.returncode != 0: + self.console.print("Sucessfully executed pre-command") + + # Run the systemd-nspawn command. + cmd = ["systemd-nspawn", "-q"] + if mounts: + for m in mounts: + cmd += (["--bind", f"{m}"]) + cmd += ["-D", rootfs] + if len(command) != 0: + cmd += command.split() + + utils.run_command(cmd, check=False) diff --git a/etc/mounts.yaml b/etc/mounts.yaml new file mode 100644 index 0000000..1757a7c --- /dev/null +++ b/etc/mounts.yaml @@ -0,0 +1,3 @@ +# example configuration for apt-ostree compose exec +--- +- /var/www/html/repo:/ostree