From c301b6699a57456712dfece775c21e6e7578d516 Mon Sep 17 00:00:00 2001 From: Alex Tercete Date: Thu, 10 Oct 2024 09:37:59 +0100 Subject: [PATCH 1/8] feat(qemu-system): use consistent "Make" variable name This will allow us to use `$(QEMU_SYSTEM)` in env var substitutions when passing `//labgrid/toolchain/qemu-system:resolved` to `toolchains`. --- labgrid/toolchain/qemu-system/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/labgrid/toolchain/qemu-system/BUILD.bazel b/labgrid/toolchain/qemu-system/BUILD.bazel index 354522b9..d1e160d4 100644 --- a/labgrid/toolchain/qemu-system/BUILD.bazel +++ b/labgrid/toolchain/qemu-system/BUILD.bazel @@ -11,6 +11,7 @@ toolchain_type( toolchain_info( name = "{}-{}-qemu-system-{}".format(cpu, os, bin), target = "//debian/{}/qemu-system-{}:qemu-system-{}".format(cpu, pkg, bin), + variable = "QEMU_SYSTEM", ), toolchain( name = "{}-{}-qemu-system-{}-toolchain".format(cpu, os, bin), -- GitLab From 122923baeb356a70140642b129a4ec1a87ece8f6 Mon Sep 17 00:00:00 2001 From: Alex Tercete Date: Fri, 11 Oct 2024 09:27:15 +0100 Subject: [PATCH 2/8] fix(config): forward data runfiles --- labgrid/config/data.bzl | 2 +- labgrid/config/rule.bzl | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/labgrid/config/data.bzl b/labgrid/config/data.bzl index b51aaf69..553918b8 100644 --- a/labgrid/config/data.bzl +++ b/labgrid/config/data.bzl @@ -8,7 +8,7 @@ ATTRS = {} def implementation(ctx): toolchain = ctx.toolchains["//labgrid/toolchain/config:type"] - return DefaultInfo(files = toolchain.data) + return toolchain.data data = rule( doc = DOC, diff --git a/labgrid/config/rule.bzl b/labgrid/config/rule.bzl index 35d8aea9..df3464ee 100644 --- a/labgrid/config/rule.bzl +++ b/labgrid/config/rule.bzl @@ -113,6 +113,12 @@ def _merge_default_info(ctx, targets): runfiles = runfiles, ) +def _forward_runfiles(ctx, targets): + files = depset(transitive = [d.files for d in targets]) + runfiles = ctx.runfiles() + runfiles = runfiles.merge_all([d.default_runfiles for d in targets]) + return DefaultInfo(files = files, runfiles = runfiles) + def implementation(ctx): data = ctx.attr.data + [ctx.attr.src] + ctx.attr.toolchains env = {k: _expand(ctx, data, v) for k, v in ctx.attr.env.items()} @@ -121,7 +127,7 @@ def implementation(ctx): src = ctx.file.src, deps = [_merge_default_info(ctx, ctx.attr.deps), _merge_py_info(ctx.attr.deps)], env = env, - data = depset(transitive = [d.files for d in data]), + data = _forward_runfiles(ctx, data), managers = [_merge_default_info(ctx, ctx.attr.managers), _merge_py_info(ctx.attr.managers)], ) -- GitLab From eab3953fb102a2043234d08701b1ab3956b0660f Mon Sep 17 00:00:00 2001 From: Alex Tercete Date: Thu, 17 Oct 2024 15:55:40 +0100 Subject: [PATCH 3/8] fix(config): split tools from data We need `data` for the target and `tools` for the exec. --- labgrid/config/BUILD.bazel | 6 ++++++ labgrid/config/rule.bzl | 10 +++++++++- labgrid/config/toolchain/macro.bzl | 3 ++- labgrid/config/tools.bzl | 20 ++++++++++++++++++++ labgrid/executor/BUILD.bazel | 5 ++++- 5 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 labgrid/config/tools.bzl diff --git a/labgrid/config/BUILD.bazel b/labgrid/config/BUILD.bazel index 36c525c3..3d90adba 100644 --- a/labgrid/config/BUILD.bazel +++ b/labgrid/config/BUILD.bazel @@ -2,6 +2,7 @@ load(":data.bzl", "data") load(":deps.bzl", "deps") load(":env.bzl", "env") load(":managers.bzl", "managers") +load(":tools.bzl", "tools") env( name = "env", @@ -13,6 +14,11 @@ data( visibility = ["//:__subpackages__"], ) +tools( + name = "tools", + visibility = ["//:__subpackages__"], +) + managers( name = "managers", visibility = ["//:__subpackages__"], diff --git a/labgrid/config/rule.bzl b/labgrid/config/rule.bzl index df3464ee..d02e5bfc 100644 --- a/labgrid/config/rule.bzl +++ b/labgrid/config/rule.bzl @@ -67,6 +67,12 @@ ATTRS = { allow_files = True, doc = "The data files to use.", providers = [DefaultInfo], + cfg = "target", + ), + "tools": attr.label_list( + allow_files = True, + doc = "The tools to use.", + providers = [DefaultInfo], cfg = "exec", ), "managers": attr.label_list( @@ -120,7 +126,8 @@ def _forward_runfiles(ctx, targets): return DefaultInfo(files = files, runfiles = runfiles) def implementation(ctx): - data = ctx.attr.data + [ctx.attr.src] + ctx.attr.toolchains + data = ctx.attr.data + [ctx.attr.src] + tools = ctx.attr.tools + ctx.attr.toolchains env = {k: _expand(ctx, data, v) for k, v in ctx.attr.env.items()} default = DefaultInfo(files = depset([ctx.file.src])) toolchain = platform_common.ToolchainInfo( @@ -128,6 +135,7 @@ def implementation(ctx): deps = [_merge_default_info(ctx, ctx.attr.deps), _merge_py_info(ctx.attr.deps)], env = env, data = _forward_runfiles(ctx, data), + tools = _forward_runfiles(ctx, tools), managers = [_merge_default_info(ctx, ctx.attr.managers), _merge_py_info(ctx.attr.managers)], ) diff --git a/labgrid/config/toolchain/macro.bzl b/labgrid/config/toolchain/macro.bzl index 13c015d8..b5f8202c 100644 --- a/labgrid/config/toolchain/macro.bzl +++ b/labgrid/config/toolchain/macro.bzl @@ -2,7 +2,7 @@ load("@rules_labgrid//labgrid/config:defs.bzl", "labgrid_config") visibility("//...") -def labgrid_config_toolchain(*, name, src, state, target_compatible_with, managers = [], deps = [], env = {}, data = [], toolchains = []): +def labgrid_config_toolchain(*, name, src, state, target_compatible_with, managers = [], deps = [], env = {}, data = [], tools = [], toolchains = []): src = native.package_relative_label(src) labgrid_config( name = "{}-config".format(name), @@ -13,6 +13,7 @@ def labgrid_config_toolchain(*, name, src, state, target_compatible_with, manage "LG_STATE": state, }, data = data, + tools = tools, toolchains = toolchains, managers = [native.package_relative_label(m) for m in managers], ) diff --git a/labgrid/config/tools.bzl b/labgrid/config/tools.bzl new file mode 100644 index 00000000..009f2c7c --- /dev/null +++ b/labgrid/config/tools.bzl @@ -0,0 +1,20 @@ +load("//labgrid/cfg:unstore.bzl", _cfg = "unstore") + +visibility("//labgrid/config/...") + +DOC = "Unpacks the `tools` from the `//labgrid/toolchain/config:type` toolchain" + +ATTRS = {} + +def implementation(ctx): + toolchain = ctx.toolchains["//labgrid/toolchain/config:type"] + return toolchain.tools + +tools = rule( + doc = DOC, + attrs = ATTRS, + implementation = implementation, + provides = [DefaultInfo], + toolchains = ["//labgrid/toolchain/config:type"], + cfg = _cfg, +) diff --git a/labgrid/executor/BUILD.bazel b/labgrid/executor/BUILD.bazel index db6fcbec..6ead04d6 100644 --- a/labgrid/executor/BUILD.bazel +++ b/labgrid/executor/BUILD.bazel @@ -9,7 +9,10 @@ args( py_binary( name = "executor", srcs = ["executor.py"], - data = ["//labgrid/config:data"], + data = [ + "//labgrid/config:data", + "//labgrid/config:tools", + ], tags = ["manual"], visibility = ["//:__subpackages__"], deps = [ -- GitLab From b25375784077bbe291b43e195c93a621f775f4c8 Mon Sep 17 00:00:00 2001 From: Alex Tercete Date: Fri, 11 Oct 2024 20:46:42 +0100 Subject: [PATCH 4/8] fix(run): allow subprocesses to have their own runfiles Without this, QEMU won't work, as the `debian_launcher` will look for runfiles under `run`. --- labgrid/run/run.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/labgrid/run/run.py b/labgrid/run/run.py index 44e157bb..996557e6 100644 --- a/labgrid/run/run.py +++ b/labgrid/run/run.py @@ -38,6 +38,9 @@ def arguments(prsr: ArgumentParser) -> None: def main(exe: Path, *args: str) -> int: + # Allow subprocesses to have their own runfiles + del environ["RUNFILES_DIR"] + prsr = ArgumentParser( prog=str(exe), description="Runs a command over SSH to a LabGrid Docker device." ) -- GitLab From f05c0f8e8648808c472ab808d05bd86fd77d8a66 Mon Sep 17 00:00:00 2001 From: Alex Tercete Date: Tue, 15 Oct 2024 17:17:31 +0100 Subject: [PATCH 5/8] feat(run): do strategy clean-up at the end We now accept `final_state` in `labgrid_config_toolchain` as the state to transition to after command execution. The defaults of `shell` (for `state`) and `off` serve most built-in Labgrid strategies. --- e2e/docker/BUILD.bazel | 1 + labgrid/config/toolchain/macro.bzl | 3 +- labgrid/run/run.py | 58 +++++++++++++++++------------- 3 files changed, 37 insertions(+), 25 deletions(-) diff --git a/e2e/docker/BUILD.bazel b/e2e/docker/BUILD.bazel index 802fd8e7..60476d55 100644 --- a/e2e/docker/BUILD.bazel +++ b/e2e/docker/BUILD.bazel @@ -25,6 +25,7 @@ platform( labgrid_config_toolchain( name = "config", src = "local-ubuntu.16.04-gnu.yaml", + final_state = "gone", state = "accessible", target_compatible_with = [ ":constraint", diff --git a/labgrid/config/toolchain/macro.bzl b/labgrid/config/toolchain/macro.bzl index b5f8202c..82b5d0d3 100644 --- a/labgrid/config/toolchain/macro.bzl +++ b/labgrid/config/toolchain/macro.bzl @@ -2,7 +2,7 @@ load("@rules_labgrid//labgrid/config:defs.bzl", "labgrid_config") visibility("//...") -def labgrid_config_toolchain(*, name, src, state, target_compatible_with, managers = [], deps = [], env = {}, data = [], tools = [], toolchains = []): +def labgrid_config_toolchain(*, name, src, target_compatible_with, state = "shell", final_state = "off", managers = [], deps = [], env = {}, data = [], tools = [], toolchains = []): src = native.package_relative_label(src) labgrid_config( name = "{}-config".format(name), @@ -11,6 +11,7 @@ def labgrid_config_toolchain(*, name, src, state, target_compatible_with, manage env = env | { "LG_ENV": "$(location {})".format(src), "LG_STATE": state, + "BZL_LG_FINAL_STATE": final_state, }, data = data, tools = tools, diff --git a/labgrid/run/run.py b/labgrid/run/run.py index 996557e6..5d0a236b 100644 --- a/labgrid/run/run.py +++ b/labgrid/run/run.py @@ -35,6 +35,11 @@ def arguments(prsr: ArgumentParser) -> None: help="The state to transition the LabGrid strategy to", default=environ["LG_STATE"], ) + prsr.add_argument( + "--final-state", + help="The state to transition the LabGrid strategy to at the end", + default=environ["BZL_LG_FINAL_STATE"], + ) def main(exe: Path, *args: str) -> int: @@ -53,30 +58,35 @@ def main(exe: Path, *args: str) -> int: env = Environment(str(parsed.config)) target = env.get_target() strategy = target.get_driver("Strategy") - strategy.transition(parsed.state) - - # Retrieve the communication protocols - shell = target.get_driver("CommandProtocol") - transfer = target.get_driver("FileTransferProtocol") - - # Transfer the provided program over to the Docker image - # TODO: this should be a context manager that removes it later - # TODO: this should use a unique remote name/directory - program = "/tmp/{}".format(parsed.program.name) - transfer.put(parsed.program, program) - - # Transfer runfiles - src_runfiles = parsed.program.with_suffix(".runfiles") - dest_runfiles = Path(program).with_suffix(".runfiles") - if src_runfiles.exists(): - transfer.put(src_runfiles, dest_runfiles) - - # Run the transferred program - out, err, code = shell.run(join((program, *parsed.arguments))) - for line in out: - stdout.write(f"{line}{linesep}") - for line in err: - stderr.write(f"{line}{linesep}") + try: + strategy.transition(parsed.state) + + # Retrieve the communication protocols + shell = target.get_driver("CommandProtocol") + transfer = target.get_driver("FileTransferProtocol") + + # Transfer the provided program over to the Docker image + # TODO: this should be a context manager that removes it later + # TODO: this should use a unique remote name/directory + program = "/tmp/{}".format(parsed.program.name) + transfer.put(parsed.program, program) + + # Transfer runfiles + src_runfiles = parsed.program.with_suffix(".runfiles") + dest_runfiles = Path(program).with_suffix(".runfiles") + if src_runfiles.exists(): + transfer.put(src_runfiles, dest_runfiles) + + # Run the transferred program + out, err, code = shell.run(join((program, *parsed.arguments))) + for line in out: + stdout.write(f"{line}{linesep}") + for line in err: + stderr.write(f"{line}{linesep}") + + finally: + strategy.transition(parsed.final_state) + return code -- GitLab From 8d892075491132a4fd27a5c850c59cfc56337aa6 Mon Sep 17 00:00:00 2001 From: Alex Tercete Date: Tue, 15 Oct 2024 17:21:16 +0100 Subject: [PATCH 6/8] feat(QEMUStrategy): replace `accessible` with `shell` By adopting the "default", we can omit `states` when using `labgrid_config_toolchain`. Also, semantically it probably makes sense to call it `shell`, as we wait for the shell to be activated. --- bazel/labgrid/strategy/qemu/strategy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bazel/labgrid/strategy/qemu/strategy.py b/bazel/labgrid/strategy/qemu/strategy.py index 28b071fa..b9296e2c 100644 --- a/bazel/labgrid/strategy/qemu/strategy.py +++ b/bazel/labgrid/strategy/qemu/strategy.py @@ -12,7 +12,7 @@ from labgrid.strategy import Strategy, StrategyError class Status(enum.Enum): unknown = 0 off = 1 - accessible = 2 + shell = 2 @target_factory.reg_driver @@ -37,7 +37,7 @@ class QEMUStrategy(Strategy): self.target.activate(self.qemu) # Stop the QEMU instance self.qemu.off() - elif status == Status.accessible: + elif status == Status.shell: # Resets shell drivers status self.target.deactivate(self.shell) self.target.activate(self.qemu) -- GitLab From ab662b284eb83b3e8c418e415e68078b82422d2c Mon Sep 17 00:00:00 2001 From: Alex Tercete Date: Wed, 16 Oct 2024 09:00:25 +0100 Subject: [PATCH 7/8] style: move debian image to match seed image --- qemu/debian/{ => image}/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) rename qemu/debian/{ => image}/BUILD.bazel (91%) diff --git a/qemu/debian/BUILD.bazel b/qemu/debian/image/BUILD.bazel similarity index 91% rename from qemu/debian/BUILD.bazel rename to qemu/debian/image/BUILD.bazel index 589a0dbe..81e0b2c3 100644 --- a/qemu/debian/BUILD.bazel +++ b/qemu/debian/image/BUILD.bazel @@ -9,6 +9,7 @@ alias( }, no_match_error = "No QEMU Debian image for platform.", ), + visibility = ["//:__subpackages__"], ) build_test( -- GitLab From 0fee819b13aa003df1db998406d1fbebd15d1b9e Mon Sep 17 00:00:00 2001 From: Alex Tercete Date: Wed, 16 Oct 2024 09:05:07 +0100 Subject: [PATCH 8/8] feat(e2e): add QEMU test --- e2e/qemu/BUILD.bazel | 25 +++++++++++++++++ e2e/qemu/stdout.log.expected | 9 +++++++ .../toolchain/config/qemu/amd64/BUILD.bazel | 21 +++++++++++++++ .../toolchain/config/qemu/amd64/config.yaml | 27 +++++++++++++++++++ 4 files changed, 82 insertions(+) create mode 100644 e2e/qemu/BUILD.bazel create mode 100644 e2e/qemu/stdout.log.expected create mode 100644 labgrid/toolchain/config/qemu/amd64/BUILD.bazel create mode 100644 labgrid/toolchain/config/qemu/amd64/config.yaml diff --git a/e2e/qemu/BUILD.bazel b/e2e/qemu/BUILD.bazel new file mode 100644 index 00000000..69a6e7a2 --- /dev/null +++ b/e2e/qemu/BUILD.bazel @@ -0,0 +1,25 @@ +load("@rules_diff//diff/file/test:defs.bzl", "diff_file_test") +load("@rules_labgrid//labgrid/run:defs.bzl", "labgrid_run") + +platform( + name = "platform", + constraint_values = [ + "@toolchain_utils//toolchain/constraint/os:linux", + "@toolchain_utils//toolchain/constraint/cpu:amd64", + ], +) + +labgrid_run( + name = "cat", + srcs = ["@ape//ape:cat"], + outs = ["stdout.log"], + cmd = "$(location @ape//ape:cat) /etc/os-release > $@", + platform = ":platform", +) + +diff_file_test( + name = "test", + size = "small", + a = ":stdout.log.expected", + b = ":stdout.log", +) diff --git a/e2e/qemu/stdout.log.expected b/e2e/qemu/stdout.log.expected new file mode 100644 index 00000000..33208621 --- /dev/null +++ b/e2e/qemu/stdout.log.expected @@ -0,0 +1,9 @@ +PRETTY_NAME="Debian GNU/Linux 12 (bookworm)" +NAME="Debian GNU/Linux" +VERSION_ID="12" +VERSION="12 (bookworm)" +VERSION_CODENAME=bookworm +ID=debian +HOME_URL="https://www.debian.org/" +SUPPORT_URL="https://www.debian.org/support" +BUG_REPORT_URL="https://bugs.debian.org/" diff --git a/labgrid/toolchain/config/qemu/amd64/BUILD.bazel b/labgrid/toolchain/config/qemu/amd64/BUILD.bazel new file mode 100644 index 00000000..7b326cd4 --- /dev/null +++ b/labgrid/toolchain/config/qemu/amd64/BUILD.bazel @@ -0,0 +1,21 @@ +load("//labgrid/config/toolchain:defs.bzl", "labgrid_config_toolchain") + +labgrid_config_toolchain( + name = "amd64", + src = "config.yaml", + data = [ + "//qemu/debian/image", + "//qemu/seed/image", + ], + env = { + "LG_QEMU_SYSTEM_BIN": "$(QEMU_SYSTEM)", + "LG_QEMU_QCOW2_IMAGE": "$(location //qemu/debian/image)", + "LG_QEMU_VIRT_IMAGE": "$(location //qemu/seed/image)", + }, + target_compatible_with = [ + "@toolchain_utils//toolchain/constraint/os:linux", + "@toolchain_utils//toolchain/constraint/cpu:amd64", + ], + toolchains = ["//labgrid/toolchain/qemu-system:resolved"], + deps = ["//bazel/labgrid/strategy"], +) diff --git a/labgrid/toolchain/config/qemu/amd64/config.yaml b/labgrid/toolchain/config/qemu/amd64/config.yaml new file mode 100644 index 00000000..a8377ee4 --- /dev/null +++ b/labgrid/toolchain/config/qemu/amd64/config.yaml @@ -0,0 +1,27 @@ +targets: + main: + resources: + NetworkService: + address: "localhost" + port: 2222 + username: "labgrid-user" + password: "labgrid" + drivers: + QEMUDriver: + qemu_bin: "qemu" + machine: "pc" + cpu: "max" + memory: "2G" + nic: "user,model=e1000,hostfwd=tcp::2222-:22" + extra_args: !template "-snapshot -drive file=$LG_QEMU_QCOW2_IMAGE,format=qcow2 -cdrom $LG_QEMU_VIRT_IMAGE" + ShellDriver: + prompt: " login: " + login_prompt: " login: " + username: "labgrid-user" + login_timeout: 600 + SSHDriver: {} + QEMUStrategy: {} +tools: + qemu: !template "$LG_QEMU_SYSTEM_BIN" +imports: + - bazel.labgrid.strategy -- GitLab