131 lines
2.9 KiB
Go
131 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"isle/bootstrap"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
"sort"
|
|
|
|
"github.com/mediocregopher/mediocre-go-lib/v2/mlog"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
var hostNameRegexp = regexp.MustCompile(`^[a-z][a-z0-9\-]*$`)
|
|
|
|
func validateHostName(name string) error {
|
|
|
|
if !hostNameRegexp.MatchString(name) {
|
|
return errors.New("a host's name must start with a letter and only contain letters, numbers, and dashes")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
var subCmdHostsList = subCmd{
|
|
name: "list",
|
|
descr: "Lists all hosts in the network, and their IPs",
|
|
checkLock: true,
|
|
do: func(subCmdCtx subCmdCtx) error {
|
|
|
|
flags := subCmdCtx.flagSet(false)
|
|
|
|
logLevelStr := flags.StringP(
|
|
"log-level", "l", "info",
|
|
`Maximum log level which should be output. Values can be "debug", "info", "warn", "error", "fatal". Does not apply to sub-processes`,
|
|
)
|
|
|
|
if err := flags.Parse(subCmdCtx.args); err != nil {
|
|
return fmt.Errorf("parsing flags: %w", err)
|
|
}
|
|
|
|
ctx := subCmdCtx.ctx
|
|
|
|
logLevel := mlog.LevelFromString(*logLevelStr)
|
|
if logLevel == nil {
|
|
return fmt.Errorf("couldn't parse log level %q", *logLevelStr)
|
|
}
|
|
|
|
logger := subCmdCtx.logger.WithMaxLevel(logLevel.Int())
|
|
|
|
hostBootstrap, err := loadHostBootstrap()
|
|
if err != nil {
|
|
return fmt.Errorf("loading host bootstrap: %w", err)
|
|
}
|
|
|
|
hostsMap, err := hostBootstrap.GetGarageBootstrapHosts(ctx, logger)
|
|
if err != nil {
|
|
return fmt.Errorf("retrieving hosts from garage: %w", err)
|
|
}
|
|
|
|
type host struct {
|
|
Name string `yaml:"name"`
|
|
Nebula struct {
|
|
IP string `yaml:"ip"`
|
|
} `yaml:"nebula"`
|
|
Garage bootstrap.GarageHost `yaml:"garage,omitempty"`
|
|
}
|
|
|
|
hosts := make([]host, 0, len(hostsMap))
|
|
for _, h := range hostsMap {
|
|
|
|
host := host{
|
|
Name: h.Name,
|
|
Garage: h.Garage,
|
|
}
|
|
|
|
host.Nebula.IP = h.IP().String()
|
|
|
|
hosts = append(hosts, host)
|
|
}
|
|
|
|
sort.Slice(hosts, func(i, j int) bool { return hosts[i].Name < hosts[j].Name })
|
|
|
|
return yaml.NewEncoder(os.Stdout).Encode(hosts)
|
|
},
|
|
}
|
|
|
|
var subCmdHostsDelete = subCmd{
|
|
name: "delete",
|
|
descr: "Deletes a host from the network",
|
|
checkLock: true,
|
|
do: func(subCmdCtx subCmdCtx) error {
|
|
|
|
flags := subCmdCtx.flagSet(false)
|
|
|
|
hostName := flags.StringP(
|
|
"hostname", "h", "",
|
|
"Name of the host to delete",
|
|
)
|
|
|
|
if err := flags.Parse(subCmdCtx.args); err != nil {
|
|
return fmt.Errorf("parsing flags: %w", err)
|
|
}
|
|
|
|
if *hostName == "" {
|
|
return errors.New("--hostname is required")
|
|
}
|
|
|
|
hostBootstrap, err := loadHostBootstrap()
|
|
if err != nil {
|
|
return fmt.Errorf("loading host bootstrap: %w", err)
|
|
}
|
|
|
|
client := hostBootstrap.GlobalBucketS3APIClient()
|
|
|
|
return bootstrap.RemoveGarageBootstrapHost(subCmdCtx.ctx, client, *hostName)
|
|
},
|
|
}
|
|
|
|
var subCmdHosts = subCmd{
|
|
name: "hosts",
|
|
descr: "Sub-commands having to do with configuration of hosts in the network",
|
|
do: func(subCmdCtx subCmdCtx) error {
|
|
return subCmdCtx.doSubCmd(
|
|
subCmdHostsDelete,
|
|
subCmdHostsList,
|
|
)
|
|
},
|
|
}
|