blob: 3a402e883597ba4fa95761253b41e6c91ee551e3 [file] [log] [blame] [edit]
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()
}