package daemon import ( "context" "errors" "fmt" "isle/bootstrap" "isle/secrets" "code.betamike.com/micropelago/pmux/pmuxlib" "dev.mediocregopher.com/mediocre-go-lib.git/mlog" ) // Children manages all child processes of a network. Child processes are // comprised of: // - nebula // - dnsmasq // - garage (0 or more, depending on configured storage allocations) type Children struct { logger *mlog.Logger opts Opts pmux *pmuxlib.Pmux } // NewChildren initialized and returns a Children instance. If initialization // fails an error is returned. func NewChildren( ctx context.Context, logger *mlog.Logger, binDirPath string, secretsStore secrets.Store, daemonConfig Config, garageAdminToken string, hostBootstrap bootstrap.Bootstrap, opts *Opts, ) ( *Children, error, ) { opts = opts.withDefaults() logger.Info(ctx, "Loading secrets") garageRPCSecret, err := getGarageRPCSecret(ctx, secretsStore) if err != nil && !errors.Is(err, secrets.ErrNotFound) { return nil, fmt.Errorf("loading garage RPC secret: %w", err) } c := &Children{ logger: logger, opts: *opts, } pmuxConfig, err := c.newPmuxConfig( ctx, garageRPCSecret, binDirPath, daemonConfig, garageAdminToken, hostBootstrap, ) if err != nil { return nil, fmt.Errorf("generating pmux config: %w", err) } c.pmux = pmuxlib.NewPmux(pmuxConfig, c.opts.Stdout, c.opts.Stderr) initErr := c.postPmuxInit( ctx, daemonConfig, garageAdminToken, hostBootstrap, ) if initErr != nil { logger.Warn(ctx, "failed to initialize Children, shutting down child processes", err) if err := c.Shutdown(); err != nil { panic(fmt.Sprintf( "failed to shut down child processes after initialization"+ " error, there may be zombie children leftover."+ " Original error: %v", initErr, )) } return nil, initErr } return c, nil } // Shutdown blocks until all child processes have gracefully shut themselves // down. // // If this returns an error then it's possible that child processes are // still running and are no longer managed. func (c *Children) Shutdown() error { c.pmux.Stop() return nil }