cloud/shepherd/equinix/manager: init
This adds implementation managing Equinix Metal server lifecycle as
part of the BMaaS project.
Co-authored-by: Mateusz Zalega <mateusz@monogon.tech>
Supersedes: https://review.monogon.dev/c/monogon/+/990
Change-Id: I5537b2d07763985ad27aecac544ed19f933d6727
Reviewed-on: https://review.monogon.dev/c/monogon/+/1129
Reviewed-by: Leopold Schabel <leo@monogon.tech>
Reviewed-by: Mateusz Zalega <mateusz@monogon.tech>
Tested-by: Jenkins CI
diff --git a/cloud/shepherd/equinix/manager/test_agent/BUILD.bazel b/cloud/shepherd/equinix/manager/test_agent/BUILD.bazel
new file mode 100644
index 0000000..8f03070
--- /dev/null
+++ b/cloud/shepherd/equinix/manager/test_agent/BUILD.bazel
@@ -0,0 +1,20 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+
+go_binary(
+ name = "test_agent",
+ embed = [":test_agent_lib"],
+ visibility = [
+ "//cloud/shepherd/equinix/manager:__pkg__",
+ ],
+)
+
+go_library(
+ name = "test_agent_lib",
+ srcs = ["main.go"],
+ importpath = "source.monogon.dev/cloud/shepherd/equinix/manager/test_agent",
+ visibility = ["//visibility:private"],
+ deps = [
+ "//cloud/agent/api",
+ "@org_golang_google_protobuf//proto",
+ ],
+)
diff --git a/cloud/shepherd/equinix/manager/test_agent/main.go b/cloud/shepherd/equinix/manager/test_agent/main.go
new file mode 100644
index 0000000..5dd5ccd
--- /dev/null
+++ b/cloud/shepherd/equinix/manager/test_agent/main.go
@@ -0,0 +1,52 @@
+// test_agent is used by the Equinix Metal Manager test code. Its only role
+// is to ensure successful delivery of the BMaaS agent executable to the test
+// hosts, together with its subsequent execution.
+package main
+
+import (
+ "crypto/ed25519"
+ "crypto/rand"
+ "fmt"
+ "io"
+ "os"
+
+ "google.golang.org/protobuf/proto"
+
+ apb "source.monogon.dev/cloud/agent/api"
+)
+
+func main() {
+ // The agent initialization message will arrive from Shepherd on Agent's
+ // standard input.
+ aimb, err := io.ReadAll(os.Stdin)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "while reading AgentInit message: %v\n", err)
+ return
+ }
+ var aim apb.TakeoverInit
+ if err := proto.Unmarshal(aimb, &aim); err != nil {
+ fmt.Fprintf(os.Stderr, "while unmarshaling TakeoverInit message: %v\n", err)
+ return
+ }
+
+ // Agent should send back apb.TakeoverResponse on its standard output.
+ pub, _, err := ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "while generating agent public key: %v\n", err)
+ return
+ }
+ arsp := apb.TakeoverResponse{
+ InitMessage: &aim,
+ Key: pub,
+ }
+ arspb, err := proto.Marshal(&arsp)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "while marshaling TakeoverResponse message: %v\n", err)
+ return
+ }
+ if _, err := os.Stdout.Write(arspb); err != nil {
+ fmt.Fprintf(os.Stderr, "while writing TakeoverResponse message: %v\n", err)
+ }
+ // The agent must detach and/or terminate after sending back the reply.
+ // Failure to do so will leave the session hanging.
+}