From fe019efc8344a4bc9794fefcf0f264832ad113ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Mon, 28 Nov 2022 09:49:01 +0100 Subject: [PATCH 1/4] Add --dry option to run command This option is useful for validating the Pebble layers without having to actually start the Pebble daemon. --- cmd/pebble/cmd_run.go | 13 ++++++++++++- internal/daemon/daemon.go | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/cmd/pebble/cmd_run.go b/cmd/pebble/cmd_run.go index 78d63f6b..7ca16444 100644 --- a/cmd/pebble/cmd_run.go +++ b/cmd/pebble/cmd_run.go @@ -15,6 +15,7 @@ package main import ( + "errors" "fmt" "os" "os/signal" @@ -40,6 +41,7 @@ type cmdRun struct { clientMixin CreateDirs bool `long:"create-dirs"` + Dry bool `long:"dry"` Hold bool `long:"hold"` HTTP string `long:"http"` Verbose bool `short:"v" long:"verbose"` @@ -49,6 +51,7 @@ func init() { addCommand("run", shortRunHelp, longRunHelp, func() flags.Commander { return &cmdRun{} }, map[string]string{ "create-dirs": "Create pebble directory on startup if it doesn't exist", + "dry": "Don't start the pebble daemon. This option is incompatible with --create-dirs", "hold": "Do not start default services automatically", "http": `Start HTTP API listening on this address (e.g., ":4000")`, "verbose": "Log all output from services to stdout", @@ -60,6 +63,10 @@ func (rcmd *cmdRun) Execute(args []string) error { return ErrExtraArgs } + if rcmd.CreateDirs && rcmd.Dry { + return errors.New("cannot run pebble: --create-dirs and --dry are mutually exclusive") + } + sigs := make(chan os.Signal, 2) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) @@ -126,6 +133,7 @@ func runDaemon(rcmd *cmdRun, ch chan os.Signal) error { dopts := daemon.Options{ Dir: pebbleDir, SocketPath: socketPath, + Dry: rcmd.Dry, } if rcmd.Verbose { dopts.ServiceOutput = os.Stdout @@ -152,10 +160,13 @@ func runDaemon(rcmd *cmdRun, ch chan os.Signal) error { tic = time.NewTicker(checkRunningConditionsRetryDelay) checkTicker = tic.C } - d.Version = cmd.Version d.Start() + if rcmd.Dry { + return nil + } + watchdog, err := runWatchdog(d) if err != nil { return fmt.Errorf("cannot run software watchdog: %v", err) diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index a1bc33ea..cf633290 100644 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -72,6 +72,8 @@ type Options struct { // ServiceOuput is an optional io.Writer for the service log output, if set, all services // log output will be written to the writer. ServiceOutput io.Writer + + Dry bool } // A Daemon listens for requests and routes them to the right command @@ -92,6 +94,7 @@ type Daemon struct { tomb tomb.Tomb router *mux.Router standbyOpinions *standby.StandbyOpinions + dry bool // set to remember we need to restart the system restartSystem bool @@ -354,6 +357,13 @@ func logit(handler http.Handler) http.Handler { // Init sets up the Daemon's internal workings. // Don't call more than once. func (d *Daemon) Init() error { + if _, err := d.overlord.ServiceManager().Plan(); err != nil { + return err + } + if d.dry { + return nil + } + listenerMap := make(map[string]net.Listener) if listener, err := getListener(d.normalSocketPath, listenerMap); err == nil { @@ -453,6 +463,9 @@ func (d *Daemon) initStandbyHandling() { } func (d *Daemon) Start() { + if d.dry { + return + } if d.rebootIsMissing { // we need to schedule and wait for a system restart d.tomb.Kill(nil) @@ -786,6 +799,7 @@ func New(opts *Options) (*Daemon, error) { normalSocketPath: opts.SocketPath, untrustedSocketPath: opts.SocketPath + ".untrusted", httpAddress: opts.HTTPAddress, + dry: opts.Dry, } ovld, err := overlord.New(opts.Dir, d, opts.ServiceOutput) From 90ee9a7e35841c10badc4fe64f8fd8c186c7ef13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Tue, 17 Jan 2023 09:55:23 +0100 Subject: [PATCH 2/4] Don't pass the dry flag to the daemon --- cmd/pebble/cmd_run.go | 15 ++++----------- internal/daemon/daemon.go | 8 -------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/cmd/pebble/cmd_run.go b/cmd/pebble/cmd_run.go index 7ca16444..167dc9ed 100644 --- a/cmd/pebble/cmd_run.go +++ b/cmd/pebble/cmd_run.go @@ -15,7 +15,6 @@ package main import ( - "errors" "fmt" "os" "os/signal" @@ -51,7 +50,7 @@ func init() { addCommand("run", shortRunHelp, longRunHelp, func() flags.Commander { return &cmdRun{} }, map[string]string{ "create-dirs": "Create pebble directory on startup if it doesn't exist", - "dry": "Don't start the pebble daemon. This option is incompatible with --create-dirs", + "dry": "Validate plan without starting the pebble daemon.", "hold": "Do not start default services automatically", "http": `Start HTTP API listening on this address (e.g., ":4000")`, "verbose": "Log all output from services to stdout", @@ -63,10 +62,6 @@ func (rcmd *cmdRun) Execute(args []string) error { return ErrExtraArgs } - if rcmd.CreateDirs && rcmd.Dry { - return errors.New("cannot run pebble: --create-dirs and --dry are mutually exclusive") - } - sigs := make(chan os.Signal, 2) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) @@ -133,7 +128,6 @@ func runDaemon(rcmd *cmdRun, ch chan os.Signal) error { dopts := daemon.Options{ Dir: pebbleDir, SocketPath: socketPath, - Dry: rcmd.Dry, } if rcmd.Verbose { dopts.ServiceOutput = os.Stdout @@ -147,6 +141,9 @@ func runDaemon(rcmd *cmdRun, ch chan os.Signal) error { if err := d.Init(); err != nil { return err } + if rcmd.Dry { + return nil + } // Run sanity check now, if anything goes wrong with the // check we go into "degraded" mode where we always report @@ -163,10 +160,6 @@ func runDaemon(rcmd *cmdRun, ch chan os.Signal) error { d.Version = cmd.Version d.Start() - if rcmd.Dry { - return nil - } - watchdog, err := runWatchdog(d) if err != nil { return fmt.Errorf("cannot run software watchdog: %v", err) diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index cf633290..c0ac23c0 100644 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -94,7 +94,6 @@ type Daemon struct { tomb tomb.Tomb router *mux.Router standbyOpinions *standby.StandbyOpinions - dry bool // set to remember we need to restart the system restartSystem bool @@ -360,9 +359,6 @@ func (d *Daemon) Init() error { if _, err := d.overlord.ServiceManager().Plan(); err != nil { return err } - if d.dry { - return nil - } listenerMap := make(map[string]net.Listener) @@ -463,9 +459,6 @@ func (d *Daemon) initStandbyHandling() { } func (d *Daemon) Start() { - if d.dry { - return - } if d.rebootIsMissing { // we need to schedule and wait for a system restart d.tomb.Kill(nil) @@ -799,7 +792,6 @@ func New(opts *Options) (*Daemon, error) { normalSocketPath: opts.SocketPath, untrustedSocketPath: opts.SocketPath + ".untrusted", httpAddress: opts.HTTPAddress, - dry: opts.Dry, } ovld, err := overlord.New(opts.Dir, d, opts.ServiceOutput) From 22bb1c22ae0216d9a0d23efaf650e386b88e40f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Tue, 17 Jan 2023 10:00:25 +0100 Subject: [PATCH 3/4] Move plan validation logic to a Validate method in Daemon. --- internal/daemon/daemon.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index c0ac23c0..5d001509 100644 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -353,10 +353,18 @@ func logit(handler http.Handler) http.Handler { }) } +// Validate performs the checks needed to ensure that the Pebble daemon can be started. +func (d *Daemon) Validate() error { + if _, err := d.overlord.ServiceManager().Plan(); err != nil { + return err + } + return nil +} + // Init sets up the Daemon's internal workings. // Don't call more than once. func (d *Daemon) Init() error { - if _, err := d.overlord.ServiceManager().Plan(); err != nil { + if err := d.Validate(); err != nil { return err } From 28a22f6313960e08f4e7cc7f6b0d0acdd265775a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81ngel=20P=C3=A9rez?= Date: Wed, 18 Jan 2023 10:58:25 +0100 Subject: [PATCH 4/4] Minor fixes --- cmd/pebble/cmd_run.go | 6 +++++- internal/daemon/daemon.go | 8 ++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/pebble/cmd_run.go b/cmd/pebble/cmd_run.go index 167dc9ed..6e32072c 100644 --- a/cmd/pebble/cmd_run.go +++ b/cmd/pebble/cmd_run.go @@ -138,13 +138,17 @@ func runDaemon(rcmd *cmdRun, ch chan os.Signal) error { if err != nil { return err } - if err := d.Init(); err != nil { + if err := d.Validate(); err != nil { return err } if rcmd.Dry { return nil } + if err := d.Init(); err != nil { + return err + } + // Run sanity check now, if anything goes wrong with the // check we go into "degraded" mode where we always report // the given error to any client. diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index 5d001509..ee59c961 100644 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -72,8 +72,6 @@ type Options struct { // ServiceOuput is an optional io.Writer for the service log output, if set, all services // log output will be written to the writer. ServiceOutput io.Writer - - Dry bool } // A Daemon listens for requests and routes them to the right command @@ -355,10 +353,8 @@ func logit(handler http.Handler) http.Handler { // Validate performs the checks needed to ensure that the Pebble daemon can be started. func (d *Daemon) Validate() error { - if _, err := d.overlord.ServiceManager().Plan(); err != nil { - return err - } - return nil + _, err := d.overlord.ServiceManager().Plan() + return err } // Init sets up the Daemon's internal workings.