package entrypoint import ( "cryptic-net/admin" "cryptic-net/bootstrap" "cryptic-net/nebula" "errors" "fmt" "os" ) 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.tgz 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 subCmdAdminMakeBootstrap = subCmd{ name: "make-bootstrap", descr: "Creates a new bootstrap.tgz file for a particular host and writes it to stdout", checkLock: true, do: func(subCmdCtx subCmdCtx) error { flags := subCmdCtx.flagSet(false) name := flags.StringP( "name", "n", "", "Name of the host to generate bootstrap.tgz for", ) adminPath := flags.StringP( "admin-path", "a", "", `Path to admin.tgz 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 *name == "" || *adminPath == "" { return errors.New("--name and --admin-path are required") } env := subCmdCtx.env adm, err := readAdmin(*adminPath) if err != nil { return fmt.Errorf("reading admin.tgz with --admin-path of %q: %w", *adminPath, err) } client, err := env.Bootstrap.GlobalBucketS3APIClient() if err != nil { return fmt.Errorf("creating client for global bucket: %w", err) } // NOTE this isn't _technically_ required, but if the `hosts add` // command for this host has been run recently then it might not have // made it into the bootstrap file yet, and so won't be in // `env.Bootstrap`. hosts, err := bootstrap.GetGarageBootstrapHosts(env.Context, client) if err != nil { return fmt.Errorf("retrieving host info from garage: %w", err) } host, ok := hosts[*name] if !ok { return fmt.Errorf("couldn't find host into for %q in garage, has `cryptic-net hosts add` been run yet?", *name) } nebulaHostCert, err := nebula.NewHostCert(adm.NebulaCACert, host.Name, host.Nebula.IP) if err != nil { return fmt.Errorf("creating new nebula host key/cert: %w", err) } newBootstrap := bootstrap.Bootstrap{ Hosts: hosts, HostName: *name, NebulaHostCert: nebulaHostCert, GarageRPCSecret: adm.GarageRPCSecret, GarageGlobalBucketS3APICredentials: adm.GarageGlobalBucketS3APICredentials, } return newBootstrap.WriteTo(os.Stdout) }, } var subCmdAdmin = subCmd{ name: "admin", descr: "Sub-commands which only admins can run", do: func(subCmdCtx subCmdCtx) error { return subCmdCtx.doSubCmd( subCmdAdminMakeBootstrap, ) }, }