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/server/main.go b/cloud/shepherd/equinix/manager/server/main.go
new file mode 100644
index 0000000..567ebd7
--- /dev/null
+++ b/cloud/shepherd/equinix/manager/server/main.go
@@ -0,0 +1,107 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+
+ "k8s.io/klog"
+
+ "source.monogon.dev/cloud/bmaas/bmdb"
+ "source.monogon.dev/cloud/lib/component"
+ "source.monogon.dev/cloud/shepherd/equinix/manager"
+ "source.monogon.dev/cloud/shepherd/equinix/wrapngo"
+ clicontext "source.monogon.dev/metropolis/cli/pkg/context"
+)
+
+type Config struct {
+ Component component.ComponentConfig
+ BMDB bmdb.BMDB
+
+ SharedConfig manager.SharedConfig
+ AgentConfig manager.AgentConfig
+ ProvisionerConfig manager.ProvisionerConfig
+ InitializerConfig manager.InitializerConfig
+ API wrapngo.Opts
+}
+
+// TODO(q3k): factor this out to BMDB library?
+func runtimeInfo() string {
+ hostname, _ := os.Hostname()
+ if hostname == "" {
+ hostname = "UNKNOWN"
+ }
+ return fmt.Sprintf("host %s", hostname)
+}
+
+func (c *Config) RegisterFlags() {
+ c.Component.RegisterFlags("shepherd")
+ c.BMDB.ComponentName = "shepherd-equinix"
+ c.BMDB.RuntimeInfo = runtimeInfo()
+ c.BMDB.Database.RegisterFlags("bmdb")
+
+ c.SharedConfig.RegisterFlags("")
+ c.AgentConfig.RegisterFlags()
+ c.ProvisionerConfig.RegisterFlags()
+ c.InitializerConfig.RegisterFlags()
+ c.API.RegisterFlags()
+}
+
+func main() {
+ c := &Config{}
+ c.RegisterFlags()
+ flag.Parse()
+
+ ctx := clicontext.WithInterrupt(context.Background())
+
+ if c.API.APIKey == "" || c.API.User == "" {
+ klog.Exitf("-equinix_api_username and -equinix_api_key must be set")
+ }
+ api := wrapngo.New(&c.API)
+
+ // These variables are _very_ important to configure correctly, otherwise someone
+ // running this locally with prod creds will actually destroy production
+ // data.
+ if strings.Contains(c.SharedConfig.KeyLabel, "FIXME") {
+ klog.Exitf("refusing to run with -equinix_ssh_key_label %q, please set it to something unique", c.SharedConfig.KeyLabel)
+ }
+ if strings.Contains(c.SharedConfig.DevicePrefix, "FIXME") {
+ klog.Exitf("refusing to run with -equinix_device_prefix %q, please set it to something unique", c.SharedConfig.DevicePrefix)
+ }
+
+ klog.Infof("Ensuring our SSH key is configured...")
+ if err := c.SharedConfig.SSHEquinixEnsure(ctx, api); err != nil {
+ klog.Exitf("Ensuring SSH key failed: %v", err)
+ }
+
+ provisioner, err := c.ProvisionerConfig.New(api, &c.SharedConfig)
+ if err != nil {
+ klog.Exitf("%v", err)
+ }
+
+ initializer, err := c.InitializerConfig.New(api, &c.SharedConfig, &c.AgentConfig)
+ if err != nil {
+ klog.Exitf("%v", err)
+ }
+
+ conn, err := c.BMDB.Open(true)
+ if err != nil {
+ klog.Exitf("Failed to open BMDB connection: %v", err)
+ }
+ go func() {
+ err = provisioner.Run(ctx, conn)
+ if err != nil {
+ klog.Exit(err)
+ }
+ }()
+ go func() {
+ err = initializer.Run(ctx, conn)
+ if err != nil {
+ klog.Exit(err)
+ }
+ }()
+
+ <-ctx.Done()
+}