From ead38f66ad09279b34cffd26f1bef7451bada0db Mon Sep 17 00:00:00 2001 From: Natalie Perret <11332444+natalie-o-perret@users.noreply.github.com> Date: Thu, 2 Jul 2026 11:31:37 +0200 Subject: [PATCH] storage(lifecycle): move to subpackage, use RegisterCLICommand pattern --- cmd/storage/lifecycle/lifecycle.go | 9 +++ cmd/storage/lifecycle/lifecycle_delete.go | 50 ++++++++++++ cmd/storage/lifecycle/lifecycle_set.go | 78 +++++++++++++++++++ cmd/storage/lifecycle/lifecycle_show.go | 55 +++++++++++++ cmd/storage/storage_bucket.go | 2 + cmd/storage/storage_bucket_lifecycle.go | 21 ----- .../storage_bucket_lifecycle_delete.go | 48 ------------ cmd/storage/storage_bucket_lifecycle_set.go | 78 ------------------- cmd/storage/storage_bucket_lifecycle_show.go | 53 ------------- 9 files changed, 194 insertions(+), 200 deletions(-) create mode 100644 cmd/storage/lifecycle/lifecycle.go create mode 100644 cmd/storage/lifecycle/lifecycle_delete.go create mode 100644 cmd/storage/lifecycle/lifecycle_set.go create mode 100644 cmd/storage/lifecycle/lifecycle_show.go delete mode 100644 cmd/storage/storage_bucket_lifecycle.go delete mode 100644 cmd/storage/storage_bucket_lifecycle_delete.go delete mode 100644 cmd/storage/storage_bucket_lifecycle_set.go delete mode 100644 cmd/storage/storage_bucket_lifecycle_show.go diff --git a/cmd/storage/lifecycle/lifecycle.go b/cmd/storage/lifecycle/lifecycle.go new file mode 100644 index 000000000..9b31961e7 --- /dev/null +++ b/cmd/storage/lifecycle/lifecycle.go @@ -0,0 +1,9 @@ +package lifecycle + +import "github.com/spf13/cobra" + +var Cmd = &cobra.Command{ + Use: "lifecycle", + Short: "Object Storage Bucket lifecycle management", + Long: "Object Storage Bucket lifecycle management", +} diff --git a/cmd/storage/lifecycle/lifecycle_delete.go b/cmd/storage/lifecycle/lifecycle_delete.go new file mode 100644 index 000000000..4289966b2 --- /dev/null +++ b/cmd/storage/lifecycle/lifecycle_delete.go @@ -0,0 +1,50 @@ +package lifecycle + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" + + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/storage/sos" +) + +type deleteCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"delete"` + + Bucket string `cli-arg:"#" cli-usage:"sos://BUCKET"` + + Zone string `cli-short:"z" cli-usage:"zone"` +} + +func (c *deleteCmd) CmdAliases() []string { return exocmd.GDeleteAlias } +func (c *deleteCmd) CmdShort() string { return "Delete lifecycle configuration" } +func (c *deleteCmd) CmdLong() string { return "Delete lifecycle configuration" } + +func (c *deleteCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *deleteCmd) CmdRun(_ *cobra.Command, _ []string) error { + bucket := strings.TrimPrefix(c.Bucket, sos.BucketPrefix) + + storage, err := sos.NewStorageClient( + exocmd.GContext, + sos.ClientOptWithZone(c.Zone), + ) + if err != nil { + return fmt.Errorf("unable to initialize storage client: %w", err) + } + + return storage.DeleteBucketLifecycle(exocmd.GContext, bucket) +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(Cmd, &deleteCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} diff --git a/cmd/storage/lifecycle/lifecycle_set.go b/cmd/storage/lifecycle/lifecycle_set.go new file mode 100644 index 000000000..14bb2437a --- /dev/null +++ b/cmd/storage/lifecycle/lifecycle_set.go @@ -0,0 +1,78 @@ +package lifecycle + +import ( + "encoding/json" + "fmt" + "os" + "strings" + + "github.com/spf13/cobra" + + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/storage/sos" +) + +type setCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"set"` + + Bucket string `cli-arg:"#" cli-usage:"sos://BUCKET"` + File string `cli-arg:"#" cli-usage:"path/to/lifecycle.json"` + + Zone string `cli-short:"z" cli-usage:"zone"` +} + +func (c *setCmd) CmdAliases() []string { return nil } +func (c *setCmd) CmdShort() string { return "Set lifecycle configuration" } +func (c *setCmd) CmdLong() string { + return `Set a lifecycle configuration for a bucket. + +Example of a valid lifecycle configuration: +{ + "Rules": [ + { + "Status": "Enabled", + "Expiration": { "Days": 30 }, + "Filter": { "Prefix": "" }, + "ID": "expire-after-30-days" + } + ] +}` +} + +func (c *setCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *setCmd) CmdRun(_ *cobra.Command, _ []string) error { + bucket := strings.TrimPrefix(c.Bucket, sos.BucketPrefix) + + confFile, err := os.Open(c.File) + if err != nil { + return err + } + defer func() { _ = confFile.Close() }() + + var configuration sos.BucketLifecycleConf + if err = json.NewDecoder(confFile).Decode(&configuration); err != nil { + return err + } + + storage, err := sos.NewStorageClient( + exocmd.GContext, + sos.ClientOptWithZone(c.Zone), + ) + if err != nil { + return fmt.Errorf("unable to initialize storage client: %w", err) + } + + return storage.PutBucketLifecycle(exocmd.GContext, bucket, configuration.ToS3()) +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(Cmd, &setCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} diff --git a/cmd/storage/lifecycle/lifecycle_show.go b/cmd/storage/lifecycle/lifecycle_show.go new file mode 100644 index 000000000..b73f80b80 --- /dev/null +++ b/cmd/storage/lifecycle/lifecycle_show.go @@ -0,0 +1,55 @@ +package lifecycle + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" + + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/storage/sos" +) + +type showCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"show"` + + Bucket string `cli-arg:"#" cli-usage:"sos://BUCKET"` + + Zone string `cli-short:"z" cli-usage:"zone"` +} + +func (c *showCmd) CmdAliases() []string { return exocmd.GShowAlias } +func (c *showCmd) CmdShort() string { return "Retrieve lifecycle configuration" } +func (c *showCmd) CmdLong() string { return "Retrieve lifecycle configuration" } + +func (c *showCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *showCmd) CmdRun(_ *cobra.Command, _ []string) error { + bucket := strings.TrimPrefix(c.Bucket, sos.BucketPrefix) + + storage, err := sos.NewStorageClient( + exocmd.GContext, + sos.ClientOptWithZone(c.Zone), + ) + if err != nil { + return fmt.Errorf("unable to initialize storage client: %w", err) + } + + o, err := storage.GetBucketLifecycle(exocmd.GContext, bucket) + if err != nil { + return err + } + + return c.OutputFunc(o, nil) +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(Cmd, &showCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} diff --git a/cmd/storage/storage_bucket.go b/cmd/storage/storage_bucket.go index 57ed75d1f..b4e32f8c6 100644 --- a/cmd/storage/storage_bucket.go +++ b/cmd/storage/storage_bucket.go @@ -1,11 +1,13 @@ package storage import ( + "github.com/exoscale/cli/cmd/storage/lifecycle" "github.com/spf13/cobra" ) func init() { storageCmd.AddCommand(storageBucketCmd) + storageBucketCmd.AddCommand(lifecycle.Cmd) } var storageBucketCmd = &cobra.Command{ diff --git a/cmd/storage/storage_bucket_lifecycle.go b/cmd/storage/storage_bucket_lifecycle.go deleted file mode 100644 index af48a5925..000000000 --- a/cmd/storage/storage_bucket_lifecycle.go +++ /dev/null @@ -1,21 +0,0 @@ -package storage - -import ( - exocmd "github.com/exoscale/cli/cmd" - "github.com/spf13/cobra" -) - -func init() { - storageBucketLifecycleCmd.Flags().StringP(exocmd.ZoneFlagLong, exocmd.ZoneFlagShort, "", exocmd.ZoneFlagMsg) - storageBucketCmd.AddCommand(storageBucketLifecycleCmd) -} - -var storageBucketLifecycleCmd = &cobra.Command{ - Use: "lifecycle", - Short: "Object Storage Bucket lifecycle management", - Long: storageBucketLifecycleCmdLongHelp(), -} - -var storageBucketLifecycleCmdLongHelp = func() string { - return "Object Storage Bucket lifecycle management" -} diff --git a/cmd/storage/storage_bucket_lifecycle_delete.go b/cmd/storage/storage_bucket_lifecycle_delete.go deleted file mode 100644 index b1f0fce48..000000000 --- a/cmd/storage/storage_bucket_lifecycle_delete.go +++ /dev/null @@ -1,48 +0,0 @@ -package storage - -import ( - "fmt" - "strings" - - "github.com/exoscale/cli/pkg/storage/sos" - - exocmd "github.com/exoscale/cli/cmd" - "github.com/spf13/cobra" -) - -func init() { - storageBucketLifecycleDeleteCmd.Flags().StringP(exocmd.ZoneFlagLong, exocmd.ZoneFlagShort, "", exocmd.ZoneFlagMsg) - storageBucketLifecycleCmd.AddCommand(storageBucketLifecycleDeleteCmd) -} - -var storageBucketLifecycleDeleteCmd = &cobra.Command{ - Use: "delete sos://BUCKET", - Short: "Delete lifecycle configuration", - Args: cobra.ExactArgs(1), - PreRunE: func(c *cobra.Command, args []string) error { - - args[0] = strings.TrimPrefix(args[0], sos.BucketPrefix) - - exocmd.CmdSetZoneFlagFromDefault(c) - return exocmd.CmdCheckRequiredFlags(c, []string{exocmd.ZoneFlagLong}) - }, - RunE: func(c *cobra.Command, args []string) error { - bucket := args[0] - - zone, err := c.Flags().GetString(exocmd.ZoneFlagLong) - if err != nil { - return err - } - - storage, err := sos.NewStorageClient( - exocmd.GContext, - sos.ClientOptWithZone(zone), - ) - if err != nil { - return fmt.Errorf("unable to initialize storage client: %w", err) - } - - err = storage.DeleteBucketLifecycle(exocmd.GContext, bucket) - return err - }, -} diff --git a/cmd/storage/storage_bucket_lifecycle_set.go b/cmd/storage/storage_bucket_lifecycle_set.go deleted file mode 100644 index 3b867b706..000000000 --- a/cmd/storage/storage_bucket_lifecycle_set.go +++ /dev/null @@ -1,78 +0,0 @@ -package storage - -import ( - "encoding/json" - "fmt" - "os" - "strings" - - exocmd "github.com/exoscale/cli/cmd" - "github.com/exoscale/cli/pkg/storage/sos" - "github.com/spf13/cobra" -) - -func init() { - storageBucketLifecycleSetCmd.Flags().StringP(exocmd.ZoneFlagLong, exocmd.ZoneFlagShort, "", exocmd.ZoneFlagMsg) - storageBucketLifecycleCmd.AddCommand(storageBucketLifecycleSetCmd) -} - -var storageBucketLifecycleSetCmd = &cobra.Command{ - Use: "set sos://BUCKET path/to/lifecycle.json", - Short: "Set lifecycle configuration", - Long: `Set a lifecycle configuration for a bucket. - -Example of a valid lifecycle configuration: -{ - "Rules": [ - { - "Status": "Enabled", - "Expiration": { "Days": 30 }, - "Filter": { "Prefix": "" }, - "ID": "expire-after-30-days" - } - ] -}`, - Args: cobra.ExactArgs(2), - PreRunE: func(cmd *cobra.Command, args []string) error { - - args[0] = strings.TrimPrefix(args[0], sos.BucketPrefix) - - exocmd.CmdSetZoneFlagFromDefault(cmd) - return exocmd.CmdCheckRequiredFlags(cmd, []string{exocmd.ZoneFlagLong}) - }, - RunE: func(cmd *cobra.Command, args []string) error { - - var configuration sos.BucketLifecycleConf - - confFile, err := os.Open(args[1]) - if err != nil { - return err - } - - jsonParsr := json.NewDecoder(confFile) - if err = jsonParsr.Decode(&configuration); err != nil { - return err - } - - bucket := args[0] - - zone, err := cmd.Flags().GetString(exocmd.ZoneFlagLong) - if err != nil { - return err - } - - storage, err := sos.NewStorageClient( - exocmd.GContext, - sos.ClientOptWithZone(zone), - ) - if err != nil { - return fmt.Errorf("unable to initialize storage client: %w", err) - } - - s3conf := configuration.ToS3() - - err = storage.PutBucketLifecycle(exocmd.GContext, bucket, s3conf) - - return err - }, -} diff --git a/cmd/storage/storage_bucket_lifecycle_show.go b/cmd/storage/storage_bucket_lifecycle_show.go deleted file mode 100644 index a60c18ea4..000000000 --- a/cmd/storage/storage_bucket_lifecycle_show.go +++ /dev/null @@ -1,53 +0,0 @@ -package storage - -import ( - "fmt" - "strings" - - exocmd "github.com/exoscale/cli/cmd" - "github.com/exoscale/cli/pkg/storage/sos" - "github.com/exoscale/cli/utils" - "github.com/spf13/cobra" -) - -func init() { - storageBucketLifecycleShowCmd.Flags().StringP(exocmd.ZoneFlagLong, exocmd.ZoneFlagShort, "", exocmd.ZoneFlagMsg) - storageBucketLifecycleCmd.AddCommand(storageBucketLifecycleShowCmd) -} - -var storageBucketLifecycleShowCmd = &cobra.Command{ - Use: "show sos://BUCKET", - Short: "Retrieve lifecycle configuration", - Args: cobra.ExactArgs(1), - PreRunE: func(cmd *cobra.Command, args []string) error { - - args[0] = strings.TrimPrefix(args[0], sos.BucketPrefix) - - exocmd.CmdSetZoneFlagFromDefault(cmd) - return exocmd.CmdCheckRequiredFlags(cmd, []string{exocmd.ZoneFlagLong}) - }, - RunE: func(cmd *cobra.Command, args []string) error { - - bucket := args[0] - - zone, err := cmd.Flags().GetString(exocmd.ZoneFlagLong) - if err != nil { - return err - } - - storage, err := sos.NewStorageClient( - exocmd.GContext, - sos.ClientOptWithZone(zone), - ) - if err != nil { - return fmt.Errorf("unable to initialize storage client: %w", err) - } - - o, err := storage.GetBucketLifecycle(exocmd.GContext, bucket) - if err != nil { - return err - } - - return utils.PrintOutput(o, nil) - }, -}