cloud: split shepherd up
Change-Id: I8e386d9eaaf17543743e1e8a37a8d71426910d59
Reviewed-on: https://review.monogon.dev/c/monogon/+/2213
Reviewed-by: Serge Bazanski <serge@monogon.tech>
Tested-by: Jenkins CI
diff --git a/cloud/shepherd/provider/equinix/main.go b/cloud/shepherd/provider/equinix/main.go
new file mode 100644
index 0000000..3a402e8
--- /dev/null
+++ b/cloud/shepherd/provider/equinix/main.go
@@ -0,0 +1,154 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+
+ "golang.org/x/crypto/ssh"
+ "k8s.io/klog/v2"
+
+ "source.monogon.dev/cloud/bmaas/bmdb"
+ "source.monogon.dev/cloud/bmaas/bmdb/webug"
+ "source.monogon.dev/cloud/equinix/wrapngo"
+ "source.monogon.dev/cloud/lib/component"
+ "source.monogon.dev/cloud/shepherd/manager"
+ clicontext "source.monogon.dev/metropolis/cli/pkg/context"
+)
+
+type Config struct {
+ Component component.ComponentConfig
+ BMDB bmdb.BMDB
+ WebugConfig webug.Config
+
+ SSHKey manager.SSHKey
+ InitializerConfig manager.InitializerConfig
+ ProvisionerConfig manager.ProvisionerConfig
+ RecovererConfig manager.RecovererConfig
+
+ API wrapngo.Opts
+ Provider providerConfig
+ UpdaterConfig UpdaterConfig
+}
+
+// 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.WebugConfig.RegisterFlags()
+
+ c.SSHKey.RegisterFlags()
+ c.InitializerConfig.RegisterFlags()
+ c.ProvisionerConfig.RegisterFlags()
+ c.RecovererConfig.RegisterFlags()
+
+ c.API.RegisterFlags()
+ c.Provider.RegisterFlags()
+ c.UpdaterConfig.RegisterFlags()
+}
+
+func main() {
+ var c Config
+ c.RegisterFlags()
+
+ flag.Parse()
+ if flag.NArg() > 0 {
+ klog.Exitf("unexpected positional arguments: %v", flag.Args())
+ }
+
+ registry := c.Component.PrometheusRegistry()
+ c.BMDB.EnableMetrics(registry)
+
+ ctx := clicontext.WithInterrupt(context.Background())
+ c.Component.StartPrometheus(ctx)
+
+ if c.API.APIKey == "" || c.API.User == "" {
+ klog.Exitf("-equinix_api_username and -equinix_api_key must be set")
+ }
+ c.API.MetricsRegistry = registry
+ api := wrapngo.New(&c.API)
+
+ provider, err := c.Provider.New(&c.SSHKey, api)
+ if err != nil {
+ klog.Exitf("%v", err)
+ }
+
+ sshSigner, err := c.SSHKey.Signer()
+ if err != nil {
+ klog.Exitf("%v", err)
+ }
+
+ sshClient := &manager.PlainSSHClient{
+ AuthMethod: ssh.PublicKeys(sshSigner),
+ // Equinix OS installations always use root.
+ Username: "root",
+ }
+
+ provisioner, err := manager.NewProvisioner(provider, c.ProvisionerConfig)
+ if err != nil {
+ klog.Exitf("%v", err)
+ }
+
+ initializer, err := manager.NewInitializer(provider, sshClient, c.InitializerConfig)
+ if err != nil {
+ klog.Exitf("%v", err)
+ }
+
+ recoverer, err := manager.NewRecoverer(provider, c.RecovererConfig)
+ if err != nil {
+ klog.Exitf("%v", err)
+ }
+
+ updater, err := c.UpdaterConfig.New(api)
+ 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 = manager.RunControlLoop(ctx, conn, initializer)
+ if err != nil {
+ klog.Exit(err)
+ }
+ }()
+ go func() {
+ err = manager.RunControlLoop(ctx, conn, recoverer)
+ if err != nil {
+ klog.Exit(err)
+ }
+ }()
+ go func() {
+ err = updater.Run(ctx, conn)
+ if err != nil {
+ klog.Exit(err)
+ }
+ }()
+ go func() {
+ if err := c.WebugConfig.Start(ctx, conn); err != nil && err != ctx.Err() {
+ klog.Exitf("Failed to start webug: %v", err)
+ }
+ }()
+
+ <-ctx.Done()
+}