From 41ef3762a8ca71e6c6968d252bf51bbfa1c09a06 Mon Sep 17 00:00:00 2001 From: Pavel Okhlopkov Date: Fri, 13 Feb 2026 10:40:09 +0300 Subject: [PATCH] handle errors correctly Signed-off-by: Pavel Okhlopkov --- go.mod | 1 + go.sum | 2 ++ internal/controller/controller.go | 2 +- pkg/app/root.go | 58 ++++++++++++++++++++++--------- pkg/app/run.go | 2 +- 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index ad3cb884..1dca13c5 100644 --- a/go.mod +++ b/go.mod @@ -75,6 +75,7 @@ require ( github.com/prometheus/procfs v0.12.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/pflag v1.0.6 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/vbatts/tar-split v0.12.1 // indirect diff --git a/go.sum b/go.sum index 60810465..89060c77 100644 --- a/go.sum +++ b/go.sum @@ -166,6 +166,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 03ba79c1..dc8adb7b 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -58,7 +58,7 @@ func (c *HookController) ListHooksMeta() []pkg.HookMetadata { return hooksmetas } -var ErrHookIndexIsNotExists = errors.New("hook index is not exists") +var ErrHookIndexIsNotExists = errors.New("hook index does not exist") func (c *HookController) RunHook(ctx context.Context, idx int) error { hooks := c.registry.Hooks() diff --git a/pkg/app/root.go b/pkg/app/root.go index 114c9cf0..d002b6ec 100644 --- a/pkg/app/root.go +++ b/pkg/app/root.go @@ -8,42 +8,53 @@ import ( "github.com/spf13/cobra" + "github.com/deckhouse/deckhouse/pkg/log" + "github.com/deckhouse/module-sdk/internal/controller" ) -func newCMD(controller *controller.HookController) *cmd { +func newCMD(controller *controller.HookController, logger *log.Logger) *cmd { return &cmd{ controller: controller, + logger: logger, } } type cmd struct { controller *controller.HookController + logger *log.Logger } // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func (c *cmd) Execute() { - rootCmd := c.rootCmd() - rootCmd.AddCommand(c.hooksCmd()) - rootCmd.CompletionOptions.DisableDefaultCmd = true + rootCmd := c.buildCommand() err := rootCmd.Execute() if err != nil { + c.logger.Error("failed to execute root command", "error", err) os.Exit(1) } } -// rootCmd represents the base command when called without any subcommands -func (c *cmd) rootCmd() *cobra.Command { - return &cobra.Command{ +// buildCommand creates the complete command structure with all subcommands +func (c *cmd) buildCommand() *cobra.Command { + rootCmd := &cobra.Command{ Use: filepath.Base(os.Args[0]), Short: "Binary with module hooks inside", Long: `Inside this binary contains list of precompiled hooks to use with corresponding module.`, } + rootCmd.AddCommand(c.hooksCmd()) + rootCmd.CompletionOptions.DisableDefaultCmd = true + // SilenceUsage and SilenceErrors prevent cobra from outputting + // "Error: ..." and "Usage: ..." which would break JSON output parsing + rootCmd.SilenceUsage = true + rootCmd.SilenceErrors = true + return rootCmd } +// NOTE: all of the RunE errors and usage errors are silenced by SilenceUsage and SilenceErrors, to not cause "Invalid character 'E'" error func (c *cmd) hooksCmd() *cobra.Command { hooksCmd := &cobra.Command{ Use: "hooks", @@ -67,21 +78,23 @@ func (c *cmd) hooksCmd() *cobra.Command { }, }) - hooksCmd.AddCommand(&cobra.Command{ + configCmd := &cobra.Command{ Use: "config", Short: "Print hooks configs", Long: `Print list of hooks configs in json format`, RunE: func(_ *cobra.Command, _ []string) error { err := c.controller.PrintHookConfigs() if err != nil { + c.logger.Error("can not print configs", "error", err) return fmt.Errorf("can not print configs: %w", err) } return nil }, - }) + } + hooksCmd.AddCommand(configCmd) - hooksCmd.AddCommand(&cobra.Command{ + dumpCmd := &cobra.Command{ Use: "dump", Short: "Dump hooks configs", Long: `Dump list of hooks configs in config.json file`, @@ -89,6 +102,7 @@ func (c *cmd) hooksCmd() *cobra.Command { RunE: func(_ *cobra.Command, _ []string) error { err := c.controller.WriteHookConfigsInFile() if err != nil { + c.logger.Error("can not write configs to file", "error", err) return fmt.Errorf("can not write configs to file: %w", err) } @@ -96,31 +110,43 @@ func (c *cmd) hooksCmd() *cobra.Command { return nil }, - }) + } + hooksCmd.AddCommand(dumpCmd) - hooksCmd.AddCommand(&cobra.Command{ + runCmd := &cobra.Command{ Use: "run", Short: "Running hook", Long: `Run hook from binary registry`, Hidden: true, - Args: cobra.ExactArgs(1), + Args: func(_ *cobra.Command, args []string) error { + if len(args) != 1 { + c.logger.Error("invalid number of arguments", "expected", 1, "received", len(args)) + + return fmt.Errorf("invalid number of arguments: expected 1, received %d", len(args)) + } + return nil + }, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() idxRaw := args[0] idx, err := strconv.Atoi(idxRaw) if err != nil { - return fmt.Errorf("argument '%s' is not integer", idxRaw) + c.logger.Error("invalid argument", "argument", idxRaw, "error", err) + + return fmt.Errorf("invalid argument: %w", err) } err = c.controller.RunHook(ctx, idx) if err != nil { - return fmt.Errorf("run hook error: %w", err) + c.logger.Warn("hook shutdown", "error", err) + return fmt.Errorf("hook shutdown: %w", err) } return nil }, - }) + } + hooksCmd.AddCommand(runCmd) return hooksCmd } diff --git a/pkg/app/run.go b/pkg/app/run.go index 732459f9..69bc24b4 100644 --- a/pkg/app/run.go +++ b/pkg/app/run.go @@ -47,7 +47,7 @@ func Run() { controller := controller.NewHookController(fConfig, logger.Named("hook-controller")) - c := newCMD(controller) + c := newCMD(controller, logger) c.Execute() }