diff --git a/MODULE.bazel b/MODULE.bazel index ce5ce4bbb0ac53961e866fc1cb01619be5a74191..f81d26d06e7a9a3de75776990a9b52cbb2158512 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -21,6 +21,7 @@ bazel_dep(name = "rules_license", version = "1.0.0") bazel_dep(name = "gazelle", version = "0.39.0", dev_dependency = True) bazel_dep(name = "bazel_skylib_gazelle_plugin", version = "1.7.1", dev_dependency = True) +bazel_dep(name = "rules_diff", version = "1.0.0-beta.3", dev_dependency = True) bazel_dep(name = "stardoc", version = "0.7.1", dev_dependency = True) bazel_dep(name = "aspect_rules_lint", version = "1.0.3", dev_dependency = True) bazel_dep(name = "buildifier_prebuilt", version = "7.3.1", dev_dependency = True) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 545f68b3bfb8b6e0cb6878a5b97e377f5a41b3e4..fa8317b3e6a69cd4e3e0193812eaa13a4fc7b9f9 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -121,6 +121,8 @@ "https://bcr.bazel.build/modules/rules_coreutils/1.0.0-beta.6/MODULE.bazel": "d767c0dce8cca10f507ff4df59b6be1023b155e9aa92dc075f564a2ed3713615", "https://bcr.bazel.build/modules/rules_coreutils/1.0.0-beta.7/MODULE.bazel": "7ae2696243d059738d8fdf420ae8ebbe29ff6dccbb4a0467d613cd41f57fd02e", "https://bcr.bazel.build/modules/rules_coreutils/1.0.0-beta.7/source.json": "c6a9bbdbb6d9326ca0023b1aff251f4b6afe0d37f44708011ce8be55a8da076d", + "https://bcr.bazel.build/modules/rules_diff/1.0.0-beta.3/MODULE.bazel": "4bcae1c5e3c7fa1169f9940f548f7b8b3316944b4367771b168f925b7a9ee74e", + "https://bcr.bazel.build/modules/rules_diff/1.0.0-beta.3/source.json": "b5db3fcd469061f2051188da97345162f294fc59e7fdf477beb306dbe950566a", "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", "https://bcr.bazel.build/modules/rules_go/0.33.0/MODULE.bazel": "a2b11b64cd24bf94f57454f53288a5dacfe6cb86453eee7761b7637728c1910c", "https://bcr.bazel.build/modules/rules_go/0.37.0/MODULE.bazel": "7639dae065f071efebbe73c03dc8330c3293206cf073af7c7084add4e0120aba", diff --git a/bazel/labgrid/strategy/BUILD.bazel b/bazel/labgrid/strategy/BUILD.bazel index 2ed17721cedbaef4fe6222c06ad4675d9860d4ec..c5c1180fec23a7a974ac4e97588ad322d1c2b2ae 100644 --- a/bazel/labgrid/strategy/BUILD.bazel +++ b/bazel/labgrid/strategy/BUILD.bazel @@ -6,6 +6,7 @@ py_library( "__init__.py", "localhost.py", "qemu.py", + "ssh.py", "transition.py", ], visibility = ["//visibility:public"], diff --git a/bazel/labgrid/strategy/__init__.py b/bazel/labgrid/strategy/__init__.py index 9c22a21df84d10d35c5e90c19424d5b7b877e5d1..981ab739dd4ee37d2c6423ac72cbdee2d535cb3f 100644 --- a/bazel/labgrid/strategy/__init__.py +++ b/bazel/labgrid/strategy/__init__.py @@ -1,3 +1,4 @@ from .localhost import LocalhostStrategy from .qemu import QEMUStrategy +from .ssh import SSHStrategy from .transition import transition diff --git a/bazel/labgrid/strategy/ssh.py b/bazel/labgrid/strategy/ssh.py new file mode 100644 index 0000000000000000000000000000000000000000..7b4fc189e145b7e4dcbaac44723735a26331e215 --- /dev/null +++ b/bazel/labgrid/strategy/ssh.py @@ -0,0 +1,59 @@ +import enum + +import attr + +from labgrid.driver.qemudriver import QEMUDriver +from labgrid.driver.shelldriver import ShellDriver +from labgrid.driver.sshdriver import SSHDriver +from labgrid.factory import target_factory +from labgrid.step import step +from labgrid.strategy import Strategy, StrategyError +from labgrid.util import get_free_port +from labgrid.exceptions import InvalidConfigError + + +class Status(enum.Enum): + unknown = 0 + off = 1 + shell = 2 + + +@target_factory.reg_driver +@attr.s(eq=False) +class SSHStrategy(Strategy): + bindings = {"ssh": SSHDriver} + + status = attr.ib(default=Status.unknown) + + network_port = attr.ib(default=None, validator=attr.validators.instance_of(str)) + + def __attrs_post_init__(self): + super().__attrs_post_init__() + if self.network_port: + try: + self.ssh.networkservice.port = int(self.network_port) + except ValueError: + raise InvalidConfigError( + f"Value must be convertible to int, it was {self.network_port}" + ) + + @step() + def transition(self, status, *, step): + if not isinstance(status, Status): + status = Status[status] + if status == Status.unknown: + # Unknown is the starting state + raise StrategyError(f"can not transition to {status}") + elif status == self.status: + step.skip("nothing to do") + return + elif status == Status.off: + # Resets shell drivers status + self.target.deactivate(self.ssh) + elif status == Status.shell: + # Resets shell drivers status + self.target.deactivate(self.ssh) + self.target.activate(self.ssh) + else: + raise StrategyError(f"no transition found from {self.status} to {status}") + self.status = status diff --git a/bazel/labgrid/strategy/test.py b/bazel/labgrid/strategy/test.py index 37fb4b15a294fae0382162fe76a93e43ad366e4a..1b71f639ac83ac6a90a699b2eaf41d4368e35485 100644 --- a/bazel/labgrid/strategy/test.py +++ b/bazel/labgrid/strategy/test.py @@ -3,7 +3,12 @@ from unittest import TestCase, main class StrategyTestCase(TestCase): def test_imports(self): - from bazel.labgrid.strategy import LocalhostStrategy, QEMUStrategy, transition + from bazel.labgrid.strategy import ( + LocalhostStrategy, + QEMUStrategy, + SSHStrategy, + transition, + ) if __name__ == "__main__": diff --git a/labgrid/constraint/device/BUILD.bazel b/labgrid/constraint/device/BUILD.bazel index 0eb69f4103fad544ee7aed7679c99eff772a220d..011b63d045224ac4ddf0ba953594d5721f909fff 100644 --- a/labgrid/constraint/device/BUILD.bazel +++ b/labgrid/constraint/device/BUILD.bazel @@ -23,3 +23,9 @@ constraint_value( constraint_setting = ":device", visibility = ["//visibility:public"], ) + +constraint_value( + name = "configurable", + constraint_setting = ":device", + visibility = ["//visibility:public"], +) diff --git a/labgrid/flag/device/BUILD.bazel b/labgrid/flag/device/BUILD.bazel new file mode 100644 index 0000000000000000000000000000000000000000..58c4edd25d34310a4f0f9e41689eded945f1d1c3 --- /dev/null +++ b/labgrid/flag/device/BUILD.bazel @@ -0,0 +1,58 @@ +load("@bazel_skylib//rules:common_settings.bzl", "int_flag", "string_flag") +load("@bazel_skylib//rules:write_file.bzl", "write_file") +load("@rules_diff//diff/file/test:defs.bzl", "diff_file_test") + +genrule( + name = "flags", + outs = ["stdout.log"], + cmd = "echo $(NETWORK_ADDRESS) $(NETWORK_USERNAME) $(NETWORK_PASSWORD) $(NETWORK_PORT) > $@", + toolchains = [ + ":address", + ":username", + ":password", + ":port", + ], +) + +write_file( + name = "default_network_flags", + out = "default_network_flags.txt", + content = ["localhost root root 22\n"], + is_executable = True, +) + +diff_file_test( + name = "default_flags", + size = "small", + a = ":default_network_flags.txt", + b = ":stdout.log", + tags = ["small"], +) + +string_flag( + name = "address", + build_setting_default = "localhost", + make_variable = "NETWORK_ADDRESS", + visibility = ["//visibility:public"], +) + +string_flag( + name = "username", + build_setting_default = "root", + make_variable = "NETWORK_USERNAME", + visibility = ["//visibility:public"], +) + +string_flag( + name = "password", + build_setting_default = "root", + make_variable = "NETWORK_PASSWORD", + visibility = ["//visibility:public"], +) + +int_flag( + name = "port", + build_setting_default = 22, + make_variable = "NETWORK_PORT", + visibility = ["//visibility:public"], +) diff --git a/labgrid/toolchain/config/configurable/BUILD.bazel b/labgrid/toolchain/config/configurable/BUILD.bazel new file mode 100644 index 0000000000000000000000000000000000000000..8027ecf2aa75b577591dfd4f11ee55c91178e894 --- /dev/null +++ b/labgrid/toolchain/config/configurable/BUILD.bazel @@ -0,0 +1,30 @@ +load("//labgrid/config/toolchain:defs.bzl", "labgrid_config_toolchain") + +labgrid_config_toolchain( + name = "configurable", + src = "config.yaml", + env = { + "LG_NETWORK_ADDRESS": "$(NETWORK_ADDRESS)", + "LG_NETWORK_USERNAME": "$(NETWORK_USERNAME)", + "LG_NETWORK_PASSWORD": "$(NETWORK_PASSWORD)", + "LG_NETWORK_PORT": "$(NETWORK_PORT)", + "LG_OPENSSH_SSH": "$(location @openssh//:ssh)", + "LG_OPENSSH_SCP": "$(location @openssh//:scp)", + }, + target_compatible_with = [ + "//labgrid/constraint/device:configurable", + ], + toolchains = [ + "//labgrid/flag/device:address", + "//labgrid/flag/device:password", + "//labgrid/flag/device:port", + "//labgrid/flag/device:username", + ], + tools = [ + "@openssh//:scp", + "@openssh//:ssh", + ], + deps = [ + "//bazel/labgrid/strategy", + ], +) diff --git a/labgrid/toolchain/config/configurable/config.yaml b/labgrid/toolchain/config/configurable/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..91519b8d97d6d16c860f3a9ce8fa5323c135269c --- /dev/null +++ b/labgrid/toolchain/config/configurable/config.yaml @@ -0,0 +1,19 @@ +targets: + main: + resources: + NetworkService: + address: !template "$LG_NETWORK_ADDRESS" + username: !template "$LG_NETWORK_USERNAME" + password: !template "$LG_NETWORK_PASSWORD" + drivers: + SSHDriver: {} + SSHStrategy: { + # Workaround to enable templating + # NetworkService.port is an int so cannot be templated + network_port: !template "$LG_NETWORK_PORT" + } +tools: + ssh: !template "$LG_OPENSSH_SSH" + scp: !template "$LG_OPENSSH_SCP" +imports: + - bazel.labgrid.strategy