package entrypoint import ( "bytes" crypticnet "cryptic-net" "cryptic-net/bootstrap" "cryptic-net/garage" "fmt" "io" "net" "os" "path/filepath" "strconv" "time" "github.com/cryptic-io/pmux/pmuxlib" ) func copyBootstrapToDataDir(env *crypticnet.Env, r io.Reader) error { path := env.DataDirBootstrapPath() dirPath := filepath.Dir(path) if err := os.MkdirAll(dirPath, 0700); err != nil { return fmt.Errorf("creating directory %q: %w", dirPath, err) } f, err := os.Create(path) if err != nil { return fmt.Errorf("creating file %q: %w", path, err) } _, err = io.Copy(f, r) f.Close() if err != nil { return fmt.Errorf("copying bootstrap file to %q: %w", path, err) } if err := env.LoadBootstrap(path); err != nil { return fmt.Errorf("loading bootstrap from %q: %w", path, err) } return nil } func mergeDaemonIntoBootstrap(env *crypticnet.Env) error { daemon := env.ThisDaemon() host := env.Bootstrap.ThisHost() host.Nebula.PublicAddr = daemon.VPN.PublicAddr host.Garage = nil if allocs := daemon.Storage.Allocations; len(allocs) > 0 { host.Garage = new(bootstrap.GarageHost) for _, alloc := range allocs { host.Garage.Instances = append(host.Garage.Instances, bootstrap.GarageHostInstance{ RPCPort: alloc.RPCPort, S3APIPort: alloc.S3APIPort, WebPort: alloc.WebPort, }) } } env.Bootstrap.Hosts[host.Name] = host buf := new(bytes.Buffer) if err := env.Bootstrap.WithHosts(env.Bootstrap.Hosts).WriteTo(buf); err != nil { return fmt.Errorf("writing new bootstrap file to buffer: %w", err) } if err := copyBootstrapToDataDir(env, buf); err != nil { return fmt.Errorf("copying new bootstrap file to data dir: %w", err) } return nil } func waitForNebulaArgs(env *crypticnet.Env, args ...string) []string { thisHost := env.Bootstrap.ThisHost() return append([]string{"wait-for-ip", thisHost.Nebula.IP}, args...) } func waitForGarageArgs(env *crypticnet.Env, args ...string) []string { thisHost := env.Bootstrap.ThisHost() allocs := env.ThisDaemon().Storage.Allocations if len(allocs) == 0 { return waitForNebulaArgs(env, args...) } var preArgs []string for _, alloc := range allocs { preArgs = append( preArgs, "wait-for", net.JoinHostPort(thisHost.Nebula.IP, strconv.Itoa(alloc.RPCPort)), "--", ) } return append(preArgs, args...) } func nebulaEntrypointPmuxProcConfig() pmuxlib.ProcessConfig { return pmuxlib.ProcessConfig{ Name: "nebula", Cmd: "cryptic-net-main", Args: []string{ "nebula-entrypoint", }, } } func garageWriteChildConf( env *crypticnet.Env, alloc crypticnet.DaemonYmlStorageAllocation, ) ( string, error, ) { if err := os.MkdirAll(alloc.MetaPath, 0750); err != nil { return "", fmt.Errorf("making directory %q: %w", alloc.MetaPath, err) } thisHost := env.Bootstrap.ThisHost() peer := garage.Peer{ IP: thisHost.Nebula.IP, RPCPort: alloc.RPCPort, S3APIPort: alloc.S3APIPort, } pubKey, privKey := peer.RPCPeerKey() nodeKeyPath := filepath.Join(alloc.MetaPath, "node_key") nodeKeyPubPath := filepath.Join(alloc.MetaPath, "node_keypub") if err := os.WriteFile(nodeKeyPath, privKey, 0400); err != nil { return "", fmt.Errorf("writing private key to %q: %w", nodeKeyPath, err) } else if err := os.WriteFile(nodeKeyPubPath, pubKey, 0440); err != nil { return "", fmt.Errorf("writing public key to %q: %w", nodeKeyPubPath, err) } garageTomlPath := filepath.Join( env.RuntimeDirPath, fmt.Sprintf("garage-%d.toml", alloc.RPCPort), ) err := garage.WriteGarageTomlFile(garageTomlPath, garage.GarageTomlData{ MetaPath: alloc.MetaPath, DataPath: alloc.DataPath, RPCSecret: env.Bootstrap.GarageRPCSecret, RPCAddr: net.JoinHostPort(thisHost.Nebula.IP, strconv.Itoa(alloc.RPCPort)), APIAddr: net.JoinHostPort(thisHost.Nebula.IP, strconv.Itoa(alloc.S3APIPort)), WebAddr: net.JoinHostPort(thisHost.Nebula.IP, strconv.Itoa(alloc.WebPort)), BootstrapPeers: env.Bootstrap.GarageRPCPeerAddrs(), }) if err != nil { return "", fmt.Errorf("creating garage.toml file at %q: %w", garageTomlPath, err) } return garageTomlPath, nil } func garageChildrenPmuxProcConfigs(env *crypticnet.Env) ([]pmuxlib.ProcessConfig, error) { var pmuxProcConfigs []pmuxlib.ProcessConfig for _, alloc := range env.ThisDaemon().Storage.Allocations { childConfPath, err := garageWriteChildConf(env, alloc) if err != nil { return nil, fmt.Errorf("writing child config file for alloc %+v: %w", alloc, err) } pmuxProcConfigs = append(pmuxProcConfigs, pmuxlib.ProcessConfig{ Name: fmt.Sprintf("garage-%d", alloc.RPCPort), Cmd: "garage", Args: []string{"-c", childConfPath, "server"}, SigKillWait: 1 * time.Minute, }) } return pmuxProcConfigs, nil } func garageApplyLayoutDiffPmuxProcConfig(env *crypticnet.Env) pmuxlib.ProcessConfig { return pmuxlib.ProcessConfig{ Name: "garage-apply-layout-diff", Cmd: "bash", Args: waitForGarageArgs(env, "bash", "garage-apply-layout-diff"), NoRestartOn: []int{0}, } }