2021-04-20 21:31:37 +00:00
|
|
|
package entrypoint
|
|
|
|
|
|
|
|
import (
|
|
|
|
"cryptic-net/bootstrap"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"regexp"
|
2022-10-15 16:41:07 +00:00
|
|
|
"sort"
|
2021-04-20 21:31:37 +00:00
|
|
|
|
|
|
|
"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 subCmdHostsAdd = subCmd{
|
|
|
|
name: "add",
|
|
|
|
descr: "Adds a host to the network",
|
|
|
|
checkLock: true,
|
|
|
|
do: func(subCmdCtx subCmdCtx) error {
|
|
|
|
|
|
|
|
flags := subCmdCtx.flagSet(false)
|
|
|
|
|
|
|
|
name := flags.StringP(
|
|
|
|
"name", "n", "",
|
|
|
|
"Name of the new host",
|
|
|
|
)
|
|
|
|
|
|
|
|
ip := flags.StringP(
|
|
|
|
"ip", "i", "",
|
|
|
|
"IP of the new host",
|
|
|
|
)
|
|
|
|
|
|
|
|
if err := flags.Parse(subCmdCtx.args); err != nil {
|
|
|
|
return fmt.Errorf("parsing flags: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if *name == "" || *ip == "" {
|
|
|
|
return errors.New("--name and --ip are required")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := validateHostName(*name); err != nil {
|
|
|
|
return fmt.Errorf("invalid hostname %q: %w", *name, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if net.ParseIP(*ip) == nil {
|
|
|
|
return fmt.Errorf("invalid ip %q", *ip)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO validate that the IP is in the correct CIDR
|
|
|
|
|
|
|
|
env := subCmdCtx.env
|
|
|
|
|
2022-10-16 13:38:15 +00:00
|
|
|
client, err := env.Bootstrap.GlobalBucketS3APIClient()
|
2021-04-20 21:31:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("creating client for global bucket: %w", err)
|
|
|
|
}
|
|
|
|
|
2022-10-15 16:41:07 +00:00
|
|
|
host := bootstrap.Host{
|
2021-04-20 21:31:37 +00:00
|
|
|
Name: *name,
|
2022-10-15 16:41:07 +00:00
|
|
|
Nebula: bootstrap.NebulaHost{
|
|
|
|
IP: *ip,
|
|
|
|
},
|
2021-04-20 21:31:37 +00:00
|
|
|
}
|
|
|
|
|
2022-10-15 16:41:07 +00:00
|
|
|
return bootstrap.PutGarageBoostrapHost(env.Context, client, host)
|
2021-04-20 21:31:37 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var subCmdHostsList = subCmd{
|
|
|
|
name: "list",
|
|
|
|
descr: "Lists all hosts in the network, and their IPs",
|
|
|
|
checkLock: true,
|
|
|
|
do: func(subCmdCtx subCmdCtx) error {
|
|
|
|
|
|
|
|
env := subCmdCtx.env
|
|
|
|
|
2022-10-16 13:38:15 +00:00
|
|
|
client, err := env.Bootstrap.GlobalBucketS3APIClient()
|
2021-04-20 21:31:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("creating client for global bucket: %w", err)
|
|
|
|
}
|
|
|
|
|
2022-10-15 16:41:07 +00:00
|
|
|
hostsMap, err := bootstrap.GetGarageBootstrapHosts(env.Context, client)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("retrieving hosts from garage: %w", err)
|
|
|
|
}
|
2021-04-20 21:31:37 +00:00
|
|
|
|
2022-10-15 16:41:07 +00:00
|
|
|
hosts := make([]bootstrap.Host, 0, len(hostsMap))
|
|
|
|
for _, host := range hostsMap {
|
|
|
|
hosts = append(hosts, host)
|
2021-04-20 21:31:37 +00:00
|
|
|
}
|
|
|
|
|
2022-10-15 16:41:07 +00:00
|
|
|
sort.Slice(hosts, func(i, j int) bool { return hosts[i].Name < hosts[j].Name })
|
|
|
|
|
|
|
|
return yaml.NewEncoder(os.Stdout).Encode(hosts)
|
2021-04-20 21:31:37 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var subCmdHostsDelete = subCmd{
|
|
|
|
name: "delete",
|
|
|
|
descr: "Deletes a host from the network",
|
|
|
|
checkLock: true,
|
|
|
|
do: func(subCmdCtx subCmdCtx) error {
|
|
|
|
|
|
|
|
flags := subCmdCtx.flagSet(false)
|
|
|
|
|
|
|
|
name := flags.StringP(
|
|
|
|
"name", "n", "",
|
2022-10-15 16:41:07 +00:00
|
|
|
"Name of the host to delete",
|
2021-04-20 21:31:37 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
if err := flags.Parse(subCmdCtx.args); err != nil {
|
|
|
|
return fmt.Errorf("parsing flags: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if *name == "" {
|
|
|
|
return errors.New("--name is required")
|
|
|
|
}
|
|
|
|
|
|
|
|
env := subCmdCtx.env
|
|
|
|
|
2022-10-16 13:38:15 +00:00
|
|
|
client, err := env.Bootstrap.GlobalBucketS3APIClient()
|
2021-04-20 21:31:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("creating client for global bucket: %w", err)
|
|
|
|
}
|
|
|
|
|
2022-10-15 16:41:07 +00:00
|
|
|
return bootstrap.RemoveGarageBootstrapHost(env.Context, client, *name)
|
2021-04-20 21:31:37 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
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(
|
|
|
|
subCmdHostsAdd,
|
|
|
|
subCmdHostsDelete,
|
2022-10-16 15:18:50 +00:00
|
|
|
subCmdHostsList,
|
2021-04-20 21:31:37 +00:00
|
|
|
)
|
|
|
|
},
|
|
|
|
}
|