isle/go/cmd/entrypoint/admin.go

123 lines
2.6 KiB
Go

package main
import (
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"isle/admin"
"isle/bootstrap"
"isle/nebula"
"net/netip"
"os"
)
func randStr(l int) string {
b := make([]byte, l)
if _, err := rand.Read(b); err != nil {
panic(err)
}
return hex.EncodeToString(b)
}
func readAdmin(path string) (admin.Admin, error) {
if path == "-" {
adm, err := admin.FromReader(os.Stdin)
if err != nil {
return admin.Admin{}, fmt.Errorf("parsing admin.json from stdin: %w", err)
}
return adm, nil
}
f, err := os.Open(path)
if err != nil {
return admin.Admin{}, fmt.Errorf("opening file: %w", err)
}
defer f.Close()
return admin.FromReader(f)
}
var subCmdAdminCreateBootstrap = subCmd{
name: "create-bootstrap",
descr: "Creates a new bootstrap.json file for a particular host and writes it to stdout",
do: func(subCmdCtx subCmdCtx) error {
var (
flags = subCmdCtx.flagSet(false)
hostName nebula.HostName
ip netip.Addr
)
hostNameF := flags.VarPF(
textUnmarshalerFlag{&hostName},
"hostname", "h",
"Name of the host to generate bootstrap.json for",
)
ipF := flags.VarPF(
textUnmarshalerFlag{&ip}, "ip", "i", "IP of the new host",
)
adminPath := flags.StringP(
"admin-path", "a", "",
`Path to admin.json file. If the given path is "-" then stdin is used.`,
)
if err := flags.Parse(subCmdCtx.args); err != nil {
return fmt.Errorf("parsing flags: %w", err)
}
if !hostNameF.Changed ||
!ipF.Changed ||
*adminPath == "" {
return errors.New("--hostname, --ip, and --admin-path are required")
}
adm, err := readAdmin(*adminPath)
if err != nil {
return fmt.Errorf("reading admin.json with --admin-path of %q: %w", *adminPath, err)
}
garageBootstrap := bootstrap.Garage{
RPCSecret: adm.Garage.RPCSecret,
AdminToken: randStr(32),
GlobalBucketS3APICredentials: adm.Garage.GlobalBucketS3APICredentials,
}
newHostBootstrap, err := bootstrap.New(
adm.Nebula.CACredentials,
adm.CreationParams,
garageBootstrap,
hostName,
ip,
)
if err != nil {
return fmt.Errorf("initializing bootstrap data: %w", err)
}
hostsRes, err := subCmdCtx.getHosts()
if err != nil {
return fmt.Errorf("getting hosts: %w", err)
}
for _, host := range hostsRes.Hosts {
newHostBootstrap.Hosts[host.Name] = host
}
return newHostBootstrap.WriteTo(os.Stdout)
},
}
var subCmdAdmin = subCmd{
name: "admin",
descr: "Sub-commands which only admins can run",
do: func(subCmdCtx subCmdCtx) error {
return subCmdCtx.doSubCmd(
subCmdAdminCreateBootstrap,
)
},
}