From 7e8e8faf9de05e4d8c32799e1c771f2d09301a57 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Fri, 15 May 2026 14:37:50 +0200 Subject: [PATCH 01/26] add kms key show --- cmd/kms/key/key.go | 15 +++++++++++ cmd/kms/key/key_show.go | 59 +++++++++++++++++++++++++++++++++++++++++ cmd/kms/kms.go | 15 +++++++++++ cmd/subcommands/init.go | 2 ++ 4 files changed, 91 insertions(+) create mode 100644 cmd/kms/key/key.go create mode 100644 cmd/kms/key/key_show.go create mode 100644 cmd/kms/kms.go diff --git a/cmd/kms/key/key.go b/cmd/kms/key/key.go new file mode 100644 index 000000000..d1f7969a6 --- /dev/null +++ b/cmd/kms/key/key.go @@ -0,0 +1,15 @@ +package key + +import ( + "github.com/exoscale/cli/cmd/kms" + "github.com/spf13/cobra" +) + +var keyCmd = &cobra.Command{ + Use: "key", + Short: "KMS key", +} + +func init() { + kms.KMSCmd.AddCommand(keyCmd) +} diff --git a/cmd/kms/key/key_show.go b/cmd/kms/key/key_show.go new file mode 100644 index 000000000..c83741b1e --- /dev/null +++ b/cmd/kms/key/key_show.go @@ -0,0 +1,59 @@ +package key + +import ( + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + "github.com/exoscale/cli/pkg/output" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type KeyShowOutput struct { + v3.GetKmsKeyResponse +} + +func (o *KeyShowOutput) Type() string { return "KMS key" } +func (o *KeyShowOutput) ToJSON() { output.JSON(o) } +func (o *KeyShowOutput) ToText() { output.Text(o) } +func (o *KeyShowOutput) ToTable() { output.Table(o) } + +type keyShowCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"show"` + + Key string `cli-arg:"#" cli-usage:"ID"` +} + +func (c *keyShowCmd) CmdAliases() []string { return exocmd.GShowAlias } + +func (c *keyShowCmd) CmdShort() string { + return "Shows details of a KMS key." +} + +func (c *keyShowCmd) CmdLong() string { + return "Shows details of a KMS key." +} + +func (c *keyShowCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *keyShowCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + resp, err := client.GetKmsKey(ctx, v3.UUID(c.Key)) + if err != nil { + return err + } + + out := KeyShowOutput{*resp} + return c.OutputFunc(&out, err) +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyShowCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} diff --git a/cmd/kms/kms.go b/cmd/kms/kms.go new file mode 100644 index 000000000..67791de36 --- /dev/null +++ b/cmd/kms/kms.go @@ -0,0 +1,15 @@ +package kms + +import ( + exocmd "github.com/exoscale/cli/cmd" + "github.com/spf13/cobra" +) + +var KMSCmd = &cobra.Command{ + Use: "kms", + Short: "Key management", +} + +func init() { + exocmd.RootCmd.AddCommand(KMSCmd) +} diff --git a/cmd/subcommands/init.go b/cmd/subcommands/init.go index bdb53bdcd..a39305195 100644 --- a/cmd/subcommands/init.go +++ b/cmd/subcommands/init.go @@ -26,5 +26,7 @@ import ( _ "github.com/exoscale/cli/cmd/dbaas" _ "github.com/exoscale/cli/cmd/dns" _ "github.com/exoscale/cli/cmd/iam" + _ "github.com/exoscale/cli/cmd/kms" + _ "github.com/exoscale/cli/cmd/kms/key" _ "github.com/exoscale/cli/cmd/storage" ) From 209af2ceac3e9d91c062eb8b57806bd859aadddb Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Fri, 15 May 2026 15:34:23 +0200 Subject: [PATCH 02/26] kms key create --- cmd/kms/key/key_create.go | 58 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 cmd/kms/key/key_create.go diff --git a/cmd/kms/key/key_create.go b/cmd/kms/key/key_create.go new file mode 100644 index 000000000..1060459b0 --- /dev/null +++ b/cmd/kms/key/key_create.go @@ -0,0 +1,58 @@ +package key + +import ( + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type keyCreateCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"create"` + + Name string `cli-arg:"#" cli-usage:"NAME"` + + Description string `cli-flag:"description" cli-usage:"key description" cli-short:"desc"` + Usage string `cli-flag:"usage" cli-usage:"symmetric encryption with encrypt-decrypt"` + Multizone bool `cli-flag:"multizone" cli-usage:"allow replication accross zones"` +} + +func (c *keyCreateCmd) CmdAliases() []string { return nil } + +func (c *keyCreateCmd) CmdShort() string { + return "Creates a new KMS key." +} + +func (c *keyCreateCmd) CmdLong() string { + return "Creates a new KMS key." +} + +func (c *keyCreateCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *keyCreateCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + req := v3.CreateKmsKeyRequest{ + Name: c.Name, + Description: c.Description, + Usage: v3.CreateKmsKeyRequestUsage(c.Usage), + MultiZone: &c.Multizone, + } + + if _, err := client.CreateKmsKey(ctx, req); err != nil { + return err + } + + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyCreateCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} From c34983b6e62e850aec8ce5610b9d40c54d51dc3a Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Fri, 15 May 2026 15:34:31 +0200 Subject: [PATCH 03/26] kms key disable --- cmd/kms/key/key_disable.go | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 cmd/kms/key/key_disable.go diff --git a/cmd/kms/key/key_disable.go b/cmd/kms/key/key_disable.go new file mode 100644 index 000000000..5419e278b --- /dev/null +++ b/cmd/kms/key/key_disable.go @@ -0,0 +1,47 @@ +package key + +import ( + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type keyDisableCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"disable"` + + Key string `cli-arg:"#" cli-usage:"ID"` +} + +func (c *keyDisableCmd) CmdAliases() []string { return nil } + +func (c *keyDisableCmd) CmdShort() string { + return "Enables a KMS key." +} + +func (c *keyDisableCmd) CmdLong() string { + return "Enables a KMS key." +} + +func (c *keyDisableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *keyDisableCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + if _, err := client.DisableKmsKey(ctx, v3.UUID(c.Key)); err != nil { + return err + } + + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyDisableCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} From 7c1ddd0b2138733913c72d3a0a4f20470619219e Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Fri, 15 May 2026 15:34:38 +0200 Subject: [PATCH 04/26] kms key enable --- cmd/kms/key/key_enable.go | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 cmd/kms/key/key_enable.go diff --git a/cmd/kms/key/key_enable.go b/cmd/kms/key/key_enable.go new file mode 100644 index 000000000..52b0585a3 --- /dev/null +++ b/cmd/kms/key/key_enable.go @@ -0,0 +1,47 @@ +package key + +import ( + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type keyEnableCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"enable"` + + Key string `cli-arg:"#" cli-usage:"ID"` +} + +func (c *keyEnableCmd) CmdAliases() []string { return nil } + +func (c *keyEnableCmd) CmdShort() string { + return "Enables a KMS key." +} + +func (c *keyEnableCmd) CmdLong() string { + return "Enables a KMS key." +} + +func (c *keyEnableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *keyEnableCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + if _, err := client.EnableKmsKey(ctx, v3.UUID(c.Key)); err != nil { + return err + } + + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyEnableCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} From 77e97be7dcb4a13f0cbb73cf746e8d65dba8448f Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Fri, 15 May 2026 15:34:47 +0200 Subject: [PATCH 05/26] kms key list --- cmd/kms/key/key_list.go | 79 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 cmd/kms/key/key_list.go diff --git a/cmd/kms/key/key_list.go b/cmd/kms/key/key_list.go new file mode 100644 index 000000000..15f0018a7 --- /dev/null +++ b/cmd/kms/key/key_list.go @@ -0,0 +1,79 @@ +package key + +import ( + "os" + "strconv" + "strings" + + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/table" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type keyListOutput struct { + v3.ListKmsKeysResponse +} + +func (o *keyListOutput) ToJSON() { output.JSON(o) } +func (o *keyListOutput) ToText() { output.Text(o) } +func (o *keyListOutput) ToTable() { + t := table.NewTable(os.Stdout) + defer t.Render() + + t.SetHeader([]string{ + "ID", + "NAME", + "ORIGINZONE", + "STATUS", + "MULTIZONE", + "REPLICAS", + }) + + for _, key := range o.KmsKeys { + t.Append([]string{ + string(key.ID), + key.Name, + string(key.OriginZone), + string(key.Status), + strconv.FormatBool(*key.MultiZone), + strings.Join(key.Replicas, ", "), + }) + } +} + +type keyListCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"list"` +} + +func (c *keyListCmd) CmdAliases() []string { return exocmd.GListAlias } + +func (c *keyListCmd) CmdShort() string { + return "List KMS keys." +} + +func (c *keyListCmd) CmdLong() string { + return "List KMS keys." +} + +func (c *keyListCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *keyListCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + keys, err := client.ListKmsKeys(ctx) + if err != nil { + return err + } + + out := keyListOutput{*keys} + + return c.OutputFunc(&out, nil) +} From 5d12ba2ac9dacf6517380f3d792da4c66605e647 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Fri, 15 May 2026 15:39:41 +0200 Subject: [PATCH 06/26] kms key replicate --- cmd/kms/key/key_list.go | 6 +++++ cmd/kms/key/key_replicate.go | 52 ++++++++++++++++++++++++++++++++++++ cmd/kms/key/key_show.go | 2 +- 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 cmd/kms/key/key_replicate.go diff --git a/cmd/kms/key/key_list.go b/cmd/kms/key/key_list.go index 15f0018a7..f8d72d114 100644 --- a/cmd/kms/key/key_list.go +++ b/cmd/kms/key/key_list.go @@ -77,3 +77,9 @@ func (c *keyListCmd) CmdRun(_ *cobra.Command, _ []string) error { return c.OutputFunc(&out, nil) } + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyListCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} diff --git a/cmd/kms/key/key_replicate.go b/cmd/kms/key/key_replicate.go new file mode 100644 index 000000000..17da26b11 --- /dev/null +++ b/cmd/kms/key/key_replicate.go @@ -0,0 +1,52 @@ +package key + +import ( + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type keyReplicateCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"replicate"` + + Key string `cli-arg:"#" cli-usage:"ID"` + Zone v3.ZoneName `cli-short:"z" cli-usage:"zone to replicate the key to"` +} + +func (c *keyReplicateCmd) CmdAliases() []string { return nil } + +func (c *keyReplicateCmd) CmdShort() string { + return "Replicate a KMS key to another zone." +} + +func (c *keyReplicateCmd) CmdLong() string { + return "Replicate a KMS key to another zone." +} + +func (c *keyReplicateCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *keyReplicateCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + req := v3.ReplicateKmsKeyRequest{ + Zone: string(c.Zone), + } + + if _, err := client.ReplicateKmsKey(ctx, v3.UUID(c.Key), req); err != nil { + return err + } + + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyReplicateCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} diff --git a/cmd/kms/key/key_show.go b/cmd/kms/key/key_show.go index c83741b1e..d29a5ba6c 100644 --- a/cmd/kms/key/key_show.go +++ b/cmd/kms/key/key_show.go @@ -49,7 +49,7 @@ func (c *keyShowCmd) CmdRun(_ *cobra.Command, _ []string) error { } out := KeyShowOutput{*resp} - return c.OutputFunc(&out, err) + return c.OutputFunc(&out, nil) } func init() { From c4215e00ff56614c355c4bd04a00d795c7c60926 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Fri, 15 May 2026 16:24:59 +0200 Subject: [PATCH 07/26] kms key encrypt --- cmd/kms/key/key_encrypt.go | 57 ++++++++++++++++++++++++++++++++++++ cmd/kms/key/key_replicate.go | 2 +- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 cmd/kms/key/key_encrypt.go diff --git a/cmd/kms/key/key_encrypt.go b/cmd/kms/key/key_encrypt.go new file mode 100644 index 000000000..ef3c72911 --- /dev/null +++ b/cmd/kms/key/key_encrypt.go @@ -0,0 +1,57 @@ +package key + +import ( + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type keyEncryptCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"encrypt"` + + Key string `cli-arg:"#" cli-usage:"ID"` + Plaintext string `cli-arg:"#" cli-usage:"PLAINTEXT_b64"` + + EncryptionContext string `cli-short:"ec" cli-flag:"encryption-context" cli-usage:"encryption context to use for encryption"` +} + +func (c *keyEncryptCmd) CmdAliases() []string { return nil } + +func (c *keyEncryptCmd) CmdShort() string { + return "Encrypts data using a KMS key." +} + +func (c *keyEncryptCmd) CmdLong() string { + return "Encrypts data using a KMS key." +} + +func (c *keyEncryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *keyEncryptCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + ec := []byte(c.EncryptionContext) + req := v3.EncryptRequest{ + Plaintext: []byte(c.Plaintext), + EncryptionContext: &ec, + } + + _, err := client.Encrypt(ctx, v3.UUID(c.Key), req) + if err != nil { + return err + } + + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyEncryptCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} diff --git a/cmd/kms/key/key_replicate.go b/cmd/kms/key/key_replicate.go index 17da26b11..3b9498c02 100644 --- a/cmd/kms/key/key_replicate.go +++ b/cmd/kms/key/key_replicate.go @@ -13,7 +13,7 @@ type keyReplicateCmd struct { _ bool `cli-cmd:"replicate"` Key string `cli-arg:"#" cli-usage:"ID"` - Zone v3.ZoneName `cli-short:"z" cli-usage:"zone to replicate the key to"` + Zone v3.ZoneName `cli-arg:"#" cli-short:"z" cli-usage:"zone to replicate the key to"` } func (c *keyReplicateCmd) CmdAliases() []string { return nil } From 895d5bcc7cf424b5f7a22a373cdcfffe9b81242b Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Fri, 15 May 2026 16:25:09 +0200 Subject: [PATCH 08/26] kms key decrypt --- cmd/kms/key/key_decrypt.go | 57 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 cmd/kms/key/key_decrypt.go diff --git a/cmd/kms/key/key_decrypt.go b/cmd/kms/key/key_decrypt.go new file mode 100644 index 000000000..7fb693763 --- /dev/null +++ b/cmd/kms/key/key_decrypt.go @@ -0,0 +1,57 @@ +package key + +import ( + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type KeyDecryptCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"decrypt"` + + Key string `cli-arg:"#" cli-usage:"ID"` + Ciphertext string `cli-arg:"#" cli-usage:"CIPHERTEXT_b64"` + + EncryptionContext string `cli-short:"ec" cli-flag:"encryption-context" cli-usage:"encryption context to use for decryption"` +} + +func (c *KeyDecryptCmd) CmdAliases() []string { return nil } + +func (c *KeyDecryptCmd) CmdShort() string { + return "Decrypts data using a KMS key." +} + +func (c *KeyDecryptCmd) CmdLong() string { + return "Decrypts data using a KMS key." +} + +func (c *KeyDecryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *KeyDecryptCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + ec := []byte(c.EncryptionContext) + req := v3.DecryptRequest{ + Ciphertext: []byte(c.Ciphertext), + EncryptionContext: &ec, + } + + _, err := client.Decrypt(ctx, v3.UUID(c.Key), req) + if err != nil { + return err + } + + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &KeyDecryptCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} From b9668b5877ae396ec87db14000cdb8ec493ab98c Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Mon, 18 May 2026 10:56:05 +0200 Subject: [PATCH 09/26] short command uses single char --- cmd/kms/key/key_create.go | 2 +- cmd/kms/key/key_decrypt.go | 2 +- cmd/kms/key/key_encrypt.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/kms/key/key_create.go b/cmd/kms/key/key_create.go index 1060459b0..bce8e23c9 100644 --- a/cmd/kms/key/key_create.go +++ b/cmd/kms/key/key_create.go @@ -14,7 +14,7 @@ type keyCreateCmd struct { Name string `cli-arg:"#" cli-usage:"NAME"` - Description string `cli-flag:"description" cli-usage:"key description" cli-short:"desc"` + Description string `cli-flag:"description" cli-usage:"key description"` Usage string `cli-flag:"usage" cli-usage:"symmetric encryption with encrypt-decrypt"` Multizone bool `cli-flag:"multizone" cli-usage:"allow replication accross zones"` } diff --git a/cmd/kms/key/key_decrypt.go b/cmd/kms/key/key_decrypt.go index 7fb693763..3280f1598 100644 --- a/cmd/kms/key/key_decrypt.go +++ b/cmd/kms/key/key_decrypt.go @@ -15,7 +15,7 @@ type KeyDecryptCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` Ciphertext string `cli-arg:"#" cli-usage:"CIPHERTEXT_b64"` - EncryptionContext string `cli-short:"ec" cli-flag:"encryption-context" cli-usage:"encryption context to use for decryption"` + EncryptionContext string `cli-flag:"encryption-context" cli-usage:"encryption context to use for decryption"` } func (c *KeyDecryptCmd) CmdAliases() []string { return nil } diff --git a/cmd/kms/key/key_encrypt.go b/cmd/kms/key/key_encrypt.go index ef3c72911..57d551dd1 100644 --- a/cmd/kms/key/key_encrypt.go +++ b/cmd/kms/key/key_encrypt.go @@ -15,7 +15,7 @@ type keyEncryptCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` Plaintext string `cli-arg:"#" cli-usage:"PLAINTEXT_b64"` - EncryptionContext string `cli-short:"ec" cli-flag:"encryption-context" cli-usage:"encryption context to use for encryption"` + EncryptionContext string `cli-flag:"encryption-context" cli-usage:"encryption context to use for encryption"` } func (c *keyEncryptCmd) CmdAliases() []string { return nil } From 893077c42c936e96dbd3770d4b37cadada9fee4d Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Mon, 18 May 2026 13:04:36 +0200 Subject: [PATCH 10/26] better formatting --- cmd/kms/key/formatting.go | 67 ++++++++++++++++++++++++++++++++++++ cmd/kms/key/key_create.go | 10 +++++- cmd/kms/key/key_decrypt.go | 39 +++++++++++++++++++-- cmd/kms/key/key_disable.go | 7 ++++ cmd/kms/key/key_enable.go | 7 ++++ cmd/kms/key/key_encrypt.go | 33 +++++++++++++++++- cmd/kms/key/key_replicate.go | 11 ++++-- cmd/kms/key/key_show.go | 30 ++++++++++++++-- 8 files changed, 196 insertions(+), 8 deletions(-) create mode 100644 cmd/kms/key/formatting.go diff --git a/cmd/kms/key/formatting.go b/cmd/kms/key/formatting.go new file mode 100644 index 000000000..a84a54cf7 --- /dev/null +++ b/cmd/kms/key/formatting.go @@ -0,0 +1,67 @@ +package key + +import ( + "fmt" + "os" + "strings" + + "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/table" + v3 "github.com/exoscale/egoscale/v3" +) + +type successResponseOutput v3.SuccessResponse + +func (o *successResponseOutput) ToJSON() { output.JSON(o) } +func (o *successResponseOutput) ToText() { output.Text(o) } +func (o *successResponseOutput) ToTable() { + t := table.NewTable(os.Stdout) + defer t.Render() + + t.SetHeader([]string{ + "STATUS", + }) + + t.Append([]string{ + fmt.Sprintf("%s", o.Status), + }) +} + +func boolPtrToString(b *bool) string { + if b != nil && *b { + return "true" + } + return "false" +} + +func formatKeyRotationConfig(s *v3.KeyRotationConfig) string { + if s == nil { + return "" + } + return fmt.Sprintf("auto: %s\ncount: %d\nnextAt: %s\nrotationPeriod: %d", + boolPtrToString(s.Automatic), + s.ManualCount, + s.NextAT, + s.RotationPeriod) +} + +func formatKeyMaterial(s *v3.KeyMaterial) string { + if s == nil { + return "-" + } + return fmt.Sprintf("auto: %s\ncreatedAt: %s\nversion: %d", + boolPtrToString(s.Automatic), + s.CreatedAT, + s.Version) +} + +func formatReplicaStatus(s []v3.ReplicaState) string { + if len(s) == 0 { + return "-" + } + var res []string + for _, r := range s { + res = append(res, r.Zone) + } + return strings.Join(res, ", ") +} diff --git a/cmd/kms/key/key_create.go b/cmd/kms/key/key_create.go index bce8e23c9..7f884fbe6 100644 --- a/cmd/kms/key/key_create.go +++ b/cmd/kms/key/key_create.go @@ -44,10 +44,18 @@ func (c *keyCreateCmd) CmdRun(_ *cobra.Command, _ []string) error { MultiZone: &c.Multizone, } - if _, err := client.CreateKmsKey(ctx, req); err != nil { + resp, err := client.CreateKmsKey(ctx, req) + if err != nil { return err } + if !globalstate.Quiet { + return (&keyShowCmd{ + CliCommandSettings: c.CliCommandSettings, + Key: resp.ID.String(), + }).CmdRun(nil, nil) + } + return nil } diff --git a/cmd/kms/key/key_decrypt.go b/cmd/kms/key/key_decrypt.go index 3280f1598..fec81166b 100644 --- a/cmd/kms/key/key_decrypt.go +++ b/cmd/kms/key/key_decrypt.go @@ -1,12 +1,36 @@ package key import ( + "encoding/base64" + "os" + exocmd "github.com/exoscale/cli/cmd" "github.com/exoscale/cli/pkg/globalstate" + "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/table" v3 "github.com/exoscale/egoscale/v3" "github.com/spf13/cobra" ) +type keyDecryptOutput struct { + Plaintext string `json:"plaintext"` +} + +func (o *keyDecryptOutput) ToJSON() { output.JSON(o) } +func (o *keyDecryptOutput) ToText() { output.Text(o) } +func (o *keyDecryptOutput) ToTable() { + t := table.NewTable(os.Stdout) + defer t.Render() + + t.SetHeader([]string{ + "PLAINTEXT", + }) + + t.Append([]string{ + o.Plaintext, + }) +} + type KeyDecryptCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` @@ -37,16 +61,27 @@ func (c *KeyDecryptCmd) CmdRun(_ *cobra.Command, _ []string) error { client := globalstate.EgoscaleV3Client ec := []byte(c.EncryptionContext) + decoded, err := base64.StdEncoding.DecodeString(c.Ciphertext) + if err != nil { + return err + } req := v3.DecryptRequest{ - Ciphertext: []byte(c.Ciphertext), + Ciphertext: decoded, EncryptionContext: &ec, } - _, err := client.Decrypt(ctx, v3.UUID(c.Key), req) + resp, err := client.Decrypt(ctx, v3.UUID(c.Key), req) if err != nil { return err } + if !globalstate.Quiet { + out := keyDecryptOutput{ + Plaintext: base64.StdEncoding.EncodeToString(resp.Plaintext), + } + return c.OutputFunc(&out, nil) + } + return nil } diff --git a/cmd/kms/key/key_disable.go b/cmd/kms/key/key_disable.go index 5419e278b..7947b1952 100644 --- a/cmd/kms/key/key_disable.go +++ b/cmd/kms/key/key_disable.go @@ -37,6 +37,13 @@ func (c *keyDisableCmd) CmdRun(_ *cobra.Command, _ []string) error { return err } + if !globalstate.Quiet { + return (&keyShowCmd{ + CliCommandSettings: c.CliCommandSettings, + Key: c.Key, + }).CmdRun(nil, nil) + } + return nil } diff --git a/cmd/kms/key/key_enable.go b/cmd/kms/key/key_enable.go index 52b0585a3..478d288bd 100644 --- a/cmd/kms/key/key_enable.go +++ b/cmd/kms/key/key_enable.go @@ -37,6 +37,13 @@ func (c *keyEnableCmd) CmdRun(_ *cobra.Command, _ []string) error { return err } + if !globalstate.Quiet { + return (&keyShowCmd{ + CliCommandSettings: c.CliCommandSettings, + Key: c.Key, + }).CmdRun(nil, nil) + } + return nil } diff --git a/cmd/kms/key/key_encrypt.go b/cmd/kms/key/key_encrypt.go index 57d551dd1..b2975dde7 100644 --- a/cmd/kms/key/key_encrypt.go +++ b/cmd/kms/key/key_encrypt.go @@ -1,12 +1,36 @@ package key import ( + "encoding/base64" + "os" + exocmd "github.com/exoscale/cli/cmd" "github.com/exoscale/cli/pkg/globalstate" + "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/table" v3 "github.com/exoscale/egoscale/v3" "github.com/spf13/cobra" ) +type keyEncryptOutput struct { + Ciphertext string `json:"ciphertext"` +} + +func (o *keyEncryptOutput) ToJSON() { output.JSON(o) } +func (o *keyEncryptOutput) ToText() { output.Text(o) } +func (o *keyEncryptOutput) ToTable() { + t := table.NewTable(os.Stdout) + defer t.Render() + + t.SetHeader([]string{ + "CIPHERTEXT", + }) + + t.Append([]string{ + o.Ciphertext, + }) +} + type keyEncryptCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` @@ -42,11 +66,18 @@ func (c *keyEncryptCmd) CmdRun(_ *cobra.Command, _ []string) error { EncryptionContext: &ec, } - _, err := client.Encrypt(ctx, v3.UUID(c.Key), req) + resp, err := client.Encrypt(ctx, v3.UUID(c.Key), req) if err != nil { return err } + if !globalstate.Quiet { + out := keyEncryptOutput{ + Ciphertext: base64.StdEncoding.EncodeToString(resp.Ciphertext), + } + c.OutputFunc(&out, nil) + } + return nil } diff --git a/cmd/kms/key/key_replicate.go b/cmd/kms/key/key_replicate.go index 3b9498c02..c23621eee 100644 --- a/cmd/kms/key/key_replicate.go +++ b/cmd/kms/key/key_replicate.go @@ -13,7 +13,7 @@ type keyReplicateCmd struct { _ bool `cli-cmd:"replicate"` Key string `cli-arg:"#" cli-usage:"ID"` - Zone v3.ZoneName `cli-arg:"#" cli-short:"z" cli-usage:"zone to replicate the key to"` + Zone v3.ZoneName `cli-arg:"#" cli-usage:"ZONE"` } func (c *keyReplicateCmd) CmdAliases() []string { return nil } @@ -38,10 +38,17 @@ func (c *keyReplicateCmd) CmdRun(_ *cobra.Command, _ []string) error { Zone: string(c.Zone), } - if _, err := client.ReplicateKmsKey(ctx, v3.UUID(c.Key), req); err != nil { + resp, err := client.ReplicateKmsKey(ctx, v3.UUID(c.Key), req) + if err != nil { return err } + if !globalstate.Quiet { + out := successResponseOutput{ + Status: resp.Status, + } + return c.OutputFunc(&out, nil) + } return nil } diff --git a/cmd/kms/key/key_show.go b/cmd/kms/key/key_show.go index d29a5ba6c..163be5240 100644 --- a/cmd/kms/key/key_show.go +++ b/cmd/kms/key/key_show.go @@ -1,6 +1,8 @@ package key import ( + "time" + exocmd "github.com/exoscale/cli/cmd" "github.com/exoscale/cli/pkg/globalstate" "github.com/exoscale/cli/pkg/output" @@ -9,7 +11,18 @@ import ( ) type KeyShowOutput struct { - v3.GetKmsKeyResponse + ID v3.UUID `json:"id" validate:"required"` + Name string `json:"name" validate:"required"` + CreatedAt time.Time `json:"created-at" validate:"required"` + Multizone bool `json:"multi-zone" validate:"required"` + OriginZone string `json:"origin-zone" validate:"required"` + Status v3.GetKmsKeyResponseStatus `json:"status" validate:"required"` + ReplicasStatus string `json:"replicas-status,omitempty"` + Material string `json:"material" validate:"required"` + Rotation string `json:"rotation" validate:"required"` + Usage string `json:"usage" validate:"required"` + Source v3.GetKmsKeyResponseSource `json:"source" validate:"required"` + Description string `json:"description" validate:"required"` } func (o *KeyShowOutput) Type() string { return "KMS key" } @@ -48,7 +61,20 @@ func (c *keyShowCmd) CmdRun(_ *cobra.Command, _ []string) error { return err } - out := KeyShowOutput{*resp} + out := KeyShowOutput{ + ID: resp.ID, + Name: resp.Name, + CreatedAt: resp.CreatedAT, + Multizone: *resp.MultiZone, + OriginZone: resp.OriginZone, + Status: resp.Status, + ReplicasStatus: formatReplicaStatus(resp.ReplicasStatus), + Material: formatKeyMaterial(resp.Material), + Rotation: formatKeyRotationConfig(resp.Rotation), + Usage: string(resp.Usage), + Source: resp.Source, + Description: resp.Description, + } return c.OutputFunc(&out, nil) } From eb1f56a664a5e96293c22f5d8202d934d7ba3bb1 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Mon, 18 May 2026 13:22:53 +0200 Subject: [PATCH 11/26] add generate dek command --- cmd/kms/key/key_generate_dek.go | 103 ++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 cmd/kms/key/key_generate_dek.go diff --git a/cmd/kms/key/key_generate_dek.go b/cmd/kms/key/key_generate_dek.go new file mode 100644 index 000000000..537260fd1 --- /dev/null +++ b/cmd/kms/key/key_generate_dek.go @@ -0,0 +1,103 @@ +package key + +import ( + "encoding/base64" + "os" + "strconv" + + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/table" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type keyGenerateDEKOutput struct { + Plaintext string `json:"plaintext"` + Ciphertext string `json:"ciphertext"` +} + +func (o *keyGenerateDEKOutput) ToJSON() { output.JSON(o) } +func (o *keyGenerateDEKOutput) ToText() { output.Text(o) } +func (o *keyGenerateDEKOutput) ToTable() { + t := table.NewTable(os.Stdout) + defer t.Render() + + t.SetHeader([]string{ + "PLAINTEXT", + "CIPHERTEXT", + }) + + t.Append([]string{ + o.Plaintext, + o.Ciphertext, + }) +} + +type keyGenerateDEKCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"generate-dek"` + + Key string `cli-arg:"#" cli-usage:"ID"` + KeySpec v3.GenerateDataKeyRequestKeySpec `cli-flag:"key-spec" cli-usage:"key spec for DEK ("AES_256")"` + BytesCount string `cli-flag:"bytes-count" cli-usage:"number of bytes for DEK"` + EncryptionContext string `cli-flag:"encryption-context" cli-usage:"encryption context to use for DEK generation"` +} + +func (c *keyGenerateDEKCmd) CmdAliases() []string { return nil } + +func (c *keyGenerateDEKCmd) CmdShort() string { + return "Generates a data encryption key (DEK) using a KMS key." +} + +func (c *keyGenerateDEKCmd) CmdLong() string { + return "Generates a data encryption key (DEK) using a KMS key." +} + +func (c *keyGenerateDEKCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *keyGenerateDEKCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + ec := []byte(c.EncryptionContext) + + var bytecount int + if c.BytesCount != "" { + n, err := strconv.Atoi(c.BytesCount) + if err != nil { + return err + } + bytecount = n + } + + req := v3.GenerateDataKeyRequest{ + KeySpec: c.KeySpec, + BytesCount: bytecount, + EncryptionContext: &ec, + } + + resp, err := client.GenerateDataKey(ctx, v3.UUID(c.Key), req) + if err != nil { + return err + } + + if !globalstate.Quiet { + out := keyGenerateDEKOutput{ + Ciphertext: base64.StdEncoding.EncodeToString(resp.Ciphertext), + Plaintext: base64.StdEncoding.EncodeToString(resp.Plaintext), + } + return c.OutputFunc(&out, nil) + } + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyGenerateDEKCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} From f47d4d3b46422b33d9074be95218a43959389d4b Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Mon, 18 May 2026 14:39:57 +0200 Subject: [PATCH 12/26] add reencrypt --- cmd/kms/key/formatting.go | 2 +- cmd/kms/key/key_decrypt.go | 16 +++--- cmd/kms/key/key_encrypt.go | 2 +- cmd/kms/key/key_generate_dek.go | 2 +- cmd/kms/key/key_reencrypt.go | 91 +++++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 cmd/kms/key/key_reencrypt.go diff --git a/cmd/kms/key/formatting.go b/cmd/kms/key/formatting.go index a84a54cf7..8beaa8ad4 100644 --- a/cmd/kms/key/formatting.go +++ b/cmd/kms/key/formatting.go @@ -23,7 +23,7 @@ func (o *successResponseOutput) ToTable() { }) t.Append([]string{ - fmt.Sprintf("%s", o.Status), + string(o.Status), }) } diff --git a/cmd/kms/key/key_decrypt.go b/cmd/kms/key/key_decrypt.go index fec81166b..f630bc56c 100644 --- a/cmd/kms/key/key_decrypt.go +++ b/cmd/kms/key/key_decrypt.go @@ -31,32 +31,32 @@ func (o *keyDecryptOutput) ToTable() { }) } -type KeyDecryptCmd struct { +type keyDecryptCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` _ bool `cli-cmd:"decrypt"` Key string `cli-arg:"#" cli-usage:"ID"` - Ciphertext string `cli-arg:"#" cli-usage:"CIPHERTEXT_b64"` + Ciphertext string `cli-arg:"#" cli-usage:"CIPHERTEXT"` EncryptionContext string `cli-flag:"encryption-context" cli-usage:"encryption context to use for decryption"` } -func (c *KeyDecryptCmd) CmdAliases() []string { return nil } +func (c *keyDecryptCmd) CmdAliases() []string { return nil } -func (c *KeyDecryptCmd) CmdShort() string { +func (c *keyDecryptCmd) CmdShort() string { return "Decrypts data using a KMS key." } -func (c *KeyDecryptCmd) CmdLong() string { +func (c *keyDecryptCmd) CmdLong() string { return "Decrypts data using a KMS key." } -func (c *KeyDecryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { +func (c *keyDecryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *KeyDecryptCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *keyDecryptCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext client := globalstate.EgoscaleV3Client @@ -86,7 +86,7 @@ func (c *KeyDecryptCmd) CmdRun(_ *cobra.Command, _ []string) error { } func init() { - cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &KeyDecryptCmd{ + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyDecryptCmd{ CliCommandSettings: exocmd.DefaultCLICmdSettings(), })) } diff --git a/cmd/kms/key/key_encrypt.go b/cmd/kms/key/key_encrypt.go index b2975dde7..48320f03f 100644 --- a/cmd/kms/key/key_encrypt.go +++ b/cmd/kms/key/key_encrypt.go @@ -75,7 +75,7 @@ func (c *keyEncryptCmd) CmdRun(_ *cobra.Command, _ []string) error { out := keyEncryptOutput{ Ciphertext: base64.StdEncoding.EncodeToString(resp.Ciphertext), } - c.OutputFunc(&out, nil) + return c.OutputFunc(&out, nil) } return nil diff --git a/cmd/kms/key/key_generate_dek.go b/cmd/kms/key/key_generate_dek.go index 537260fd1..7ae9d3870 100644 --- a/cmd/kms/key/key_generate_dek.go +++ b/cmd/kms/key/key_generate_dek.go @@ -41,7 +41,7 @@ type keyGenerateDEKCmd struct { _ bool `cli-cmd:"generate-dek"` Key string `cli-arg:"#" cli-usage:"ID"` - KeySpec v3.GenerateDataKeyRequestKeySpec `cli-flag:"key-spec" cli-usage:"key spec for DEK ("AES_256")"` + KeySpec v3.GenerateDataKeyRequestKeySpec `cli-flag:"key-spec" cli-usage:"key spec for DEK (AES_256)"` BytesCount string `cli-flag:"bytes-count" cli-usage:"number of bytes for DEK"` EncryptionContext string `cli-flag:"encryption-context" cli-usage:"encryption context to use for DEK generation"` } diff --git a/cmd/kms/key/key_reencrypt.go b/cmd/kms/key/key_reencrypt.go new file mode 100644 index 000000000..3e13d693f --- /dev/null +++ b/cmd/kms/key/key_reencrypt.go @@ -0,0 +1,91 @@ +package key + +import ( + "encoding/base64" + + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type keyReencryptCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"reencrypt"` + + Key string `cli-arg:"#" cli-usage:"SRC_ID"` + DestinationKey string `cli-arg:"#" cli-usage:"DEST_ID"` + Ciphertext string `cli-arg:"#" cli-usage:"CIPHERTEXT"` + + SourceEncryptionContext string `cli-flag:"source-encryption-context" cli-usage:"encryption context to use for source ciphertext decryption"` + DestEncryptionContext string `cli-flag:"dest-encryption-context" cli-usage:"encryption context to use for destination ciphertext encryption"` +} + +func (c *keyReencryptCmd) CmdAliases() []string { return nil } + +func (c *keyReencryptCmd) CmdShort() string { + return "Re-encrypts data from a KMS key to another KMS key." +} + +func (c *keyReencryptCmd) CmdLong() string { + return "Re-encrypts data from a KMS key to another KMS key." +} + +func (c *keyReencryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *keyReencryptCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + var sourceEC []byte + if c.SourceEncryptionContext != "" { + sourceEC = []byte(c.SourceEncryptionContext) + } + + decodedCipher, err := base64.StdEncoding.DecodeString(c.Ciphertext) + if err != nil { + return err + } + source := &v3.ReEncryptRequestSource{ + Ciphertext: decodedCipher, + EncryptionContext: &sourceEC, + Key: v3.UUID(c.Key), + } + + var destEC []byte + if c.DestEncryptionContext != "" { + destEC = []byte(c.DestEncryptionContext) + } + dest := &v3.ReEncryptRequestDestination{ + Key: v3.UUID(c.DestinationKey), + EncryptionContext: &destEC, + } + + req := v3.ReEncryptRequest{ + Source: source, + Destination: dest, + } + + resp, err := client.ReEncrypt(ctx, v3.UUID(c.Key), req) + if err != nil { + return err + } + + if !globalstate.Quiet { + out := keyEncryptOutput{ + Ciphertext: base64.StdEncoding.EncodeToString(resp.Ciphertext), + } + return c.OutputFunc(&out, nil) + } + + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyReencryptCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} From ef01c89e0c80a6faca143f7188b47fe800e5199d Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Mon, 18 May 2026 15:34:19 +0200 Subject: [PATCH 13/26] add delete --- cmd/kms/key/key_delete.go | 73 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 cmd/kms/key/key_delete.go diff --git a/cmd/kms/key/key_delete.go b/cmd/kms/key/key_delete.go new file mode 100644 index 000000000..2957ba78f --- /dev/null +++ b/cmd/kms/key/key_delete.go @@ -0,0 +1,73 @@ +package key + +import ( + "fmt" + "strconv" + + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type keyDeleteCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"delete"` + + Key string `cli-arg:"#" cli-usage:"ID"` + + DelayDays string `cli-flag:"delay-days" cli-usage:"number of days before deletion (7-30, default 30)"` +} + +func (c *keyDeleteCmd) CmdAliases() []string { return nil } + +func (c *keyDeleteCmd) CmdShort() string { + return "Deletes a KMS key." +} + +func (c *keyDeleteCmd) CmdLong() string { + return "Deletes a KMS key." +} + +func (c *keyDeleteCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *keyDeleteCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + var delayDays int + if c.DelayDays != "" { + n, err := strconv.Atoi(c.DelayDays) + if err != nil { + return fmt.Errorf("invalid delay days: %v", err) + } + delayDays = n + } + + req := v3.ScheduleKmsKeyDeletionRequest{ + DelayDays: delayDays, + } + + _, err := client.ScheduleKmsKeyDeletion(ctx, v3.UUID(c.Key), req) + if err != nil { + return err + } + + if !globalstate.Quiet { + return (&keyShowCmd{ + CliCommandSettings: c.CliCommandSettings, + Key: c.Key, + }).CmdRun(nil, nil) + } + + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyDeleteCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} From 18c866de409d4b7bc40bfbaf667fd7389733f872 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Mon, 18 May 2026 15:34:27 +0200 Subject: [PATCH 14/26] add cancel-delete --- cmd/kms/key/key_cancel_delete.go | 55 ++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 cmd/kms/key/key_cancel_delete.go diff --git a/cmd/kms/key/key_cancel_delete.go b/cmd/kms/key/key_cancel_delete.go new file mode 100644 index 000000000..d7aae0fdc --- /dev/null +++ b/cmd/kms/key/key_cancel_delete.go @@ -0,0 +1,55 @@ +package key + +import ( + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type keyCancelDeleteCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"cancel-delete"` + + Key string `cli-arg:"#" cli-usage:"ID"` +} + +func (c *keyCancelDeleteCmd) CmdAliases() []string { return nil } + +func (c *keyCancelDeleteCmd) CmdShort() string { + return "Cancels the scheduled deletion of a KMS key." +} + +func (c *keyCancelDeleteCmd) CmdLong() string { + return "Cancels the scheduled deletion of a KMS key." +} + +func (c *keyCancelDeleteCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *keyCancelDeleteCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + _, err := client.CancelKmsKeyDeletion(ctx, v3.UUID(c.Key)) + if err != nil { + return err + } + + if !globalstate.Quiet { + return (&keyShowCmd{ + CliCommandSettings: c.CliCommandSettings, + Key: c.Key, + }).CmdRun(nil, nil) + } + + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyCancelDeleteCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} From 445c005febe098298d75c597a3332445feaa5912 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Mon, 18 May 2026 16:36:19 +0200 Subject: [PATCH 15/26] add rotation commands --- cmd/kms/key/formatting.go | 12 ++--- cmd/kms/key/key_cancel_delete.go | 2 +- cmd/kms/key/key_create.go | 2 +- cmd/kms/key/key_delete.go | 2 +- cmd/kms/key/key_disable.go | 2 +- cmd/kms/key/key_enable.go | 2 +- cmd/kms/key/key_rotate.go | 55 +++++++++++++++++++ cmd/kms/key/key_show.go | 14 ++--- cmd/kms/rotation/rotation.go | 15 ++++++ cmd/kms/rotation/rotation_disable.go | 55 +++++++++++++++++++ cmd/kms/rotation/rotation_enable.go | 70 ++++++++++++++++++++++++ cmd/kms/rotation/rotation_list.go | 79 ++++++++++++++++++++++++++++ cmd/subcommands/init.go | 1 + 13 files changed, 290 insertions(+), 21 deletions(-) create mode 100644 cmd/kms/key/key_rotate.go create mode 100644 cmd/kms/rotation/rotation.go create mode 100644 cmd/kms/rotation/rotation_disable.go create mode 100644 cmd/kms/rotation/rotation_enable.go create mode 100644 cmd/kms/rotation/rotation_list.go diff --git a/cmd/kms/key/formatting.go b/cmd/kms/key/formatting.go index 8beaa8ad4..348745867 100644 --- a/cmd/kms/key/formatting.go +++ b/cmd/kms/key/formatting.go @@ -3,6 +3,7 @@ package key import ( "fmt" "os" + "strconv" "strings" "github.com/exoscale/cli/pkg/output" @@ -27,19 +28,12 @@ func (o *successResponseOutput) ToTable() { }) } -func boolPtrToString(b *bool) string { - if b != nil && *b { - return "true" - } - return "false" -} - func formatKeyRotationConfig(s *v3.KeyRotationConfig) string { if s == nil { return "" } return fmt.Sprintf("auto: %s\ncount: %d\nnextAt: %s\nrotationPeriod: %d", - boolPtrToString(s.Automatic), + strconv.FormatBool(*s.Automatic), s.ManualCount, s.NextAT, s.RotationPeriod) @@ -50,7 +44,7 @@ func formatKeyMaterial(s *v3.KeyMaterial) string { return "-" } return fmt.Sprintf("auto: %s\ncreatedAt: %s\nversion: %d", - boolPtrToString(s.Automatic), + strconv.FormatBool(*s.Automatic), s.CreatedAT, s.Version) } diff --git a/cmd/kms/key/key_cancel_delete.go b/cmd/kms/key/key_cancel_delete.go index d7aae0fdc..b1bdd6e98 100644 --- a/cmd/kms/key/key_cancel_delete.go +++ b/cmd/kms/key/key_cancel_delete.go @@ -39,7 +39,7 @@ func (c *keyCancelDeleteCmd) CmdRun(_ *cobra.Command, _ []string) error { } if !globalstate.Quiet { - return (&keyShowCmd{ + return (&KeyShowCmd{ CliCommandSettings: c.CliCommandSettings, Key: c.Key, }).CmdRun(nil, nil) diff --git a/cmd/kms/key/key_create.go b/cmd/kms/key/key_create.go index 7f884fbe6..e83213e10 100644 --- a/cmd/kms/key/key_create.go +++ b/cmd/kms/key/key_create.go @@ -50,7 +50,7 @@ func (c *keyCreateCmd) CmdRun(_ *cobra.Command, _ []string) error { } if !globalstate.Quiet { - return (&keyShowCmd{ + return (&KeyShowCmd{ CliCommandSettings: c.CliCommandSettings, Key: resp.ID.String(), }).CmdRun(nil, nil) diff --git a/cmd/kms/key/key_delete.go b/cmd/kms/key/key_delete.go index 2957ba78f..a960b4645 100644 --- a/cmd/kms/key/key_delete.go +++ b/cmd/kms/key/key_delete.go @@ -57,7 +57,7 @@ func (c *keyDeleteCmd) CmdRun(_ *cobra.Command, _ []string) error { } if !globalstate.Quiet { - return (&keyShowCmd{ + return (&KeyShowCmd{ CliCommandSettings: c.CliCommandSettings, Key: c.Key, }).CmdRun(nil, nil) diff --git a/cmd/kms/key/key_disable.go b/cmd/kms/key/key_disable.go index 7947b1952..a42b938f6 100644 --- a/cmd/kms/key/key_disable.go +++ b/cmd/kms/key/key_disable.go @@ -38,7 +38,7 @@ func (c *keyDisableCmd) CmdRun(_ *cobra.Command, _ []string) error { } if !globalstate.Quiet { - return (&keyShowCmd{ + return (&KeyShowCmd{ CliCommandSettings: c.CliCommandSettings, Key: c.Key, }).CmdRun(nil, nil) diff --git a/cmd/kms/key/key_enable.go b/cmd/kms/key/key_enable.go index 478d288bd..a2a66a1ee 100644 --- a/cmd/kms/key/key_enable.go +++ b/cmd/kms/key/key_enable.go @@ -38,7 +38,7 @@ func (c *keyEnableCmd) CmdRun(_ *cobra.Command, _ []string) error { } if !globalstate.Quiet { - return (&keyShowCmd{ + return (&KeyShowCmd{ CliCommandSettings: c.CliCommandSettings, Key: c.Key, }).CmdRun(nil, nil) diff --git a/cmd/kms/key/key_rotate.go b/cmd/kms/key/key_rotate.go new file mode 100644 index 000000000..45b44b932 --- /dev/null +++ b/cmd/kms/key/key_rotate.go @@ -0,0 +1,55 @@ +package key + +import ( + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type keyRotateCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"rotate"` + + Key string `cli-arg:"#" cli-usage:"ID"` +} + +func (c *keyRotateCmd) CmdAliases() []string { return nil } + +func (c *keyRotateCmd) CmdShort() string { + return "Rotates a KMS key." +} + +func (c *keyRotateCmd) CmdLong() string { + return "Rotates a KMS key." +} + +func (c *keyRotateCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *keyRotateCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + _, err := client.RotateKmsKey(ctx, v3.UUID(c.Key)) + if err != nil { + return err + } + + if !globalstate.Quiet { + return (&KeyShowCmd{ + CliCommandSettings: c.CliCommandSettings, + Key: c.Key, + }).CmdRun(nil, nil) + } + + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyRotateCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} diff --git a/cmd/kms/key/key_show.go b/cmd/kms/key/key_show.go index 163be5240..17b4b5543 100644 --- a/cmd/kms/key/key_show.go +++ b/cmd/kms/key/key_show.go @@ -30,7 +30,7 @@ func (o *KeyShowOutput) ToJSON() { output.JSON(o) } func (o *KeyShowOutput) ToText() { output.Text(o) } func (o *KeyShowOutput) ToTable() { output.Table(o) } -type keyShowCmd struct { +type KeyShowCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` _ bool `cli-cmd:"show"` @@ -38,21 +38,21 @@ type keyShowCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` } -func (c *keyShowCmd) CmdAliases() []string { return exocmd.GShowAlias } +func (c *KeyShowCmd) CmdAliases() []string { return exocmd.GShowAlias } -func (c *keyShowCmd) CmdShort() string { +func (c *KeyShowCmd) CmdShort() string { return "Shows details of a KMS key." } -func (c *keyShowCmd) CmdLong() string { +func (c *KeyShowCmd) CmdLong() string { return "Shows details of a KMS key." } -func (c *keyShowCmd) CmdPreRun(cmd *cobra.Command, args []string) error { +func (c *KeyShowCmd) CmdPreRun(cmd *cobra.Command, args []string) error { return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *keyShowCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *KeyShowCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext client := globalstate.EgoscaleV3Client @@ -79,7 +79,7 @@ func (c *keyShowCmd) CmdRun(_ *cobra.Command, _ []string) error { } func init() { - cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyShowCmd{ + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &KeyShowCmd{ CliCommandSettings: exocmd.DefaultCLICmdSettings(), })) } diff --git a/cmd/kms/rotation/rotation.go b/cmd/kms/rotation/rotation.go new file mode 100644 index 000000000..368e546ea --- /dev/null +++ b/cmd/kms/rotation/rotation.go @@ -0,0 +1,15 @@ +package rotation + +import ( + "github.com/exoscale/cli/cmd/kms" + "github.com/spf13/cobra" +) + +var rotationCmd = &cobra.Command{ + Use: "rotation", + Short: "KMS key rotation", +} + +func init() { + kms.KMSCmd.AddCommand(rotationCmd) +} diff --git a/cmd/kms/rotation/rotation_disable.go b/cmd/kms/rotation/rotation_disable.go new file mode 100644 index 000000000..6036a2fa3 --- /dev/null +++ b/cmd/kms/rotation/rotation_disable.go @@ -0,0 +1,55 @@ +package rotation + +import ( + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/cmd/kms/key" + "github.com/exoscale/cli/pkg/globalstate" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type rotationDisableCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"disable"` + + Key string `cli-arg:"#" cli-usage:"ID"` +} + +func (c *rotationDisableCmd) CmdAliases() []string { return nil } + +func (c *rotationDisableCmd) CmdShort() string { + return "Disable KMS key auto rotation." +} + +func (c *rotationDisableCmd) CmdLong() string { + return "Disable KMS key auto rotation." +} + +func (c *rotationDisableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *rotationDisableCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + if _, err := client.DisableKmsKeyRotation(ctx, v3.UUID(c.Key)); err != nil { + return err + } + + if !globalstate.Quiet { + return (&key.KeyShowCmd{ + CliCommandSettings: c.CliCommandSettings, + Key: c.Key, + }).CmdRun(nil, nil) + } + + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(rotationCmd, &rotationDisableCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} diff --git a/cmd/kms/rotation/rotation_enable.go b/cmd/kms/rotation/rotation_enable.go new file mode 100644 index 000000000..50f645c85 --- /dev/null +++ b/cmd/kms/rotation/rotation_enable.go @@ -0,0 +1,70 @@ +package rotation + +import ( + "strconv" + + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/cmd/kms/key" + "github.com/exoscale/cli/pkg/globalstate" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type rotationEnableCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"enable"` + + Key string `cli-arg:"#" cli-usage:"ID"` + + RotationPeriod string `cli-flag:"rotation-period" cli-usage:"rotation period to use for auto rotation"` +} + +func (c *rotationEnableCmd) CmdAliases() []string { return nil } + +func (c *rotationEnableCmd) CmdShort() string { + return "Enable KMS key auto rotation." +} + +func (c *rotationEnableCmd) CmdLong() string { + return "Enable KMS key auto rotation." +} + +func (c *rotationEnableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *rotationEnableCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + var req v3.EnableKmsKeyRotationRequest + if c.RotationPeriod != "" { + n, err := strconv.Atoi(c.RotationPeriod) + if err != nil { + return err + } + req = v3.EnableKmsKeyRotationRequest{ + RotationPeriod: n, + } + } + + if _, err := client.EnableKmsKeyRotation(ctx, v3.UUID(c.Key), req); err != nil { + return err + } + + if !globalstate.Quiet { + return (&key.KeyShowCmd{ + CliCommandSettings: c.CliCommandSettings, + Key: c.Key, + }).CmdRun(nil, nil) + } + + return nil +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(rotationCmd, &rotationEnableCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} diff --git a/cmd/kms/rotation/rotation_list.go b/cmd/kms/rotation/rotation_list.go new file mode 100644 index 000000000..91c9273c9 --- /dev/null +++ b/cmd/kms/rotation/rotation_list.go @@ -0,0 +1,79 @@ +package rotation + +import ( + "os" + "strconv" + + exocmd "github.com/exoscale/cli/cmd" + "github.com/exoscale/cli/pkg/globalstate" + "github.com/exoscale/cli/pkg/output" + "github.com/exoscale/cli/table" + v3 "github.com/exoscale/egoscale/v3" + "github.com/spf13/cobra" +) + +type rotationListOutput struct { + v3.ListKmsKeyRotationsResponse +} + +func (o *rotationListOutput) ToJSON() { output.JSON(o) } +func (o *rotationListOutput) ToText() { output.Text(o) } +func (o *rotationListOutput) ToTable() { + t := table.NewTable(os.Stdout) + defer t.Render() + + t.SetHeader([]string{ + "VERSION", + "ROTATED_AT", + "AUTOMATIC", + }) + + for _, rotation := range o.Rotations { + t.Append([]string{ + strconv.Itoa(rotation.Version), + rotation.RotatedAT.String(), + strconv.FormatBool(*rotation.Automatic), + }) + } +} + +type rotationListCmd struct { + exocmd.CliCommandSettings `cli-cmd:"-"` + + _ bool `cli-cmd:"list"` + + Key string `cli-arg:"#" cli-usage:"ID"` +} + +func (c *rotationListCmd) CmdAliases() []string { return exocmd.GListAlias } + +func (c *rotationListCmd) CmdShort() string { + return "List KMS key rotations." +} + +func (c *rotationListCmd) CmdLong() string { + return "List KMS key rotations." +} + +func (c *rotationListCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + return exocmd.CliCommandDefaultPreRun(c, cmd, args) +} + +func (c *rotationListCmd) CmdRun(_ *cobra.Command, _ []string) error { + ctx := exocmd.GContext + client := globalstate.EgoscaleV3Client + + resp, err := client.ListKmsKeyRotations(ctx, v3.UUID(c.Key)) + if err != nil { + return err + } + out := rotationListOutput{*resp} + + return c.OutputFunc(&out, nil) +} + +func init() { + cobra.CheckErr(exocmd.RegisterCLICommand(rotationCmd, &rotationListCmd{ + CliCommandSettings: exocmd.DefaultCLICmdSettings(), + })) +} diff --git a/cmd/subcommands/init.go b/cmd/subcommands/init.go index a39305195..d1e3921ba 100644 --- a/cmd/subcommands/init.go +++ b/cmd/subcommands/init.go @@ -28,5 +28,6 @@ import ( _ "github.com/exoscale/cli/cmd/iam" _ "github.com/exoscale/cli/cmd/kms" _ "github.com/exoscale/cli/cmd/kms/key" + _ "github.com/exoscale/cli/cmd/kms/rotation" _ "github.com/exoscale/cli/cmd/storage" ) From 0d69e1bec3ec114dcfa65409715c657f323a6094 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Mon, 18 May 2026 16:47:48 +0200 Subject: [PATCH 16/26] add defaults in description --- cmd/kms/key/key_create.go | 4 ++-- cmd/kms/key/key_delete.go | 2 +- cmd/kms/key/key_encrypt.go | 2 +- cmd/kms/key/key_generate_dek.go | 4 ++-- cmd/kms/rotation/rotation_enable.go | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/kms/key/key_create.go b/cmd/kms/key/key_create.go index e83213e10..abb5a1c5a 100644 --- a/cmd/kms/key/key_create.go +++ b/cmd/kms/key/key_create.go @@ -15,8 +15,8 @@ type keyCreateCmd struct { Name string `cli-arg:"#" cli-usage:"NAME"` Description string `cli-flag:"description" cli-usage:"key description"` - Usage string `cli-flag:"usage" cli-usage:"symmetric encryption with encrypt-decrypt"` - Multizone bool `cli-flag:"multizone" cli-usage:"allow replication accross zones"` + Usage string `cli-flag:"usage" cli-usage:"key usage [encrypt-decrypt]"` + Multizone bool `cli-flag:"multizone" cli-usage:"allow replication accross zones (default: false)"` } func (c *keyCreateCmd) CmdAliases() []string { return nil } diff --git a/cmd/kms/key/key_delete.go b/cmd/kms/key/key_delete.go index a960b4645..fa628e092 100644 --- a/cmd/kms/key/key_delete.go +++ b/cmd/kms/key/key_delete.go @@ -17,7 +17,7 @@ type keyDeleteCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` - DelayDays string `cli-flag:"delay-days" cli-usage:"number of days before deletion (7-30, default 30)"` + DelayDays string `cli-flag:"delay-days" cli-usage:"number of days before deletion (7 - 30, default: 30)"` } func (c *keyDeleteCmd) CmdAliases() []string { return nil } diff --git a/cmd/kms/key/key_encrypt.go b/cmd/kms/key/key_encrypt.go index 48320f03f..07fa152b4 100644 --- a/cmd/kms/key/key_encrypt.go +++ b/cmd/kms/key/key_encrypt.go @@ -37,7 +37,7 @@ type keyEncryptCmd struct { _ bool `cli-cmd:"encrypt"` Key string `cli-arg:"#" cli-usage:"ID"` - Plaintext string `cli-arg:"#" cli-usage:"PLAINTEXT_b64"` + Plaintext string `cli-arg:"#" cli-usage:"PLAINTEXT"` EncryptionContext string `cli-flag:"encryption-context" cli-usage:"encryption context to use for encryption"` } diff --git a/cmd/kms/key/key_generate_dek.go b/cmd/kms/key/key_generate_dek.go index 7ae9d3870..fdd174690 100644 --- a/cmd/kms/key/key_generate_dek.go +++ b/cmd/kms/key/key_generate_dek.go @@ -41,8 +41,8 @@ type keyGenerateDEKCmd struct { _ bool `cli-cmd:"generate-dek"` Key string `cli-arg:"#" cli-usage:"ID"` - KeySpec v3.GenerateDataKeyRequestKeySpec `cli-flag:"key-spec" cli-usage:"key spec for DEK (AES_256)"` - BytesCount string `cli-flag:"bytes-count" cli-usage:"number of bytes for DEK"` + KeySpec v3.GenerateDataKeyRequestKeySpec `cli-flag:"key-spec" cli-usage:"key spec for DEK [AES_256]"` + BytesCount string `cli-flag:"bytes-count" cli-usage:"number of bytes for DEK (1 - 1024)"` EncryptionContext string `cli-flag:"encryption-context" cli-usage:"encryption context to use for DEK generation"` } diff --git a/cmd/kms/rotation/rotation_enable.go b/cmd/kms/rotation/rotation_enable.go index 50f645c85..1b519f613 100644 --- a/cmd/kms/rotation/rotation_enable.go +++ b/cmd/kms/rotation/rotation_enable.go @@ -17,7 +17,7 @@ type rotationEnableCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` - RotationPeriod string `cli-flag:"rotation-period" cli-usage:"rotation period to use for auto rotation"` + RotationPeriod string `cli-flag:"rotation-period" cli-usage:"number of days for auto rotation period (90 - 2560, default: 365)"` } func (c *rotationEnableCmd) CmdAliases() []string { return nil } From d7e58c59ccec4a7ea700ee881c253cdc51c7b7f1 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Tue, 19 May 2026 09:23:57 +0200 Subject: [PATCH 17/26] add cli-short --- cmd/kms/key/key_create.go | 6 +++--- cmd/kms/key/key_decrypt.go | 2 +- cmd/kms/key/key_delete.go | 2 +- cmd/kms/key/key_encrypt.go | 2 +- cmd/kms/key/key_generate_dek.go | 6 +++--- cmd/kms/key/key_reencrypt.go | 4 ++-- cmd/kms/rotation/rotation_enable.go | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cmd/kms/key/key_create.go b/cmd/kms/key/key_create.go index abb5a1c5a..96a112de9 100644 --- a/cmd/kms/key/key_create.go +++ b/cmd/kms/key/key_create.go @@ -14,9 +14,9 @@ type keyCreateCmd struct { Name string `cli-arg:"#" cli-usage:"NAME"` - Description string `cli-flag:"description" cli-usage:"key description"` - Usage string `cli-flag:"usage" cli-usage:"key usage [encrypt-decrypt]"` - Multizone bool `cli-flag:"multizone" cli-usage:"allow replication accross zones (default: false)"` + Description string `cli-short:"d" cli-flag:"description" cli-usage:"key description"` + Usage string `cli-short:"u" cli-flag:"usage" cli-usage:"key usage [encrypt-decrypt]"` + Multizone bool `cli-short:"m" cli-flag:"multizone" cli-usage:"allow replication accross zones (default: false)"` } func (c *keyCreateCmd) CmdAliases() []string { return nil } diff --git a/cmd/kms/key/key_decrypt.go b/cmd/kms/key/key_decrypt.go index f630bc56c..0d60d4c90 100644 --- a/cmd/kms/key/key_decrypt.go +++ b/cmd/kms/key/key_decrypt.go @@ -39,7 +39,7 @@ type keyDecryptCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` Ciphertext string `cli-arg:"#" cli-usage:"CIPHERTEXT"` - EncryptionContext string `cli-flag:"encryption-context" cli-usage:"encryption context to use for decryption"` + EncryptionContext string `cli-short:"e" cli-flag:"encryption-context" cli-usage:"encryption context to use for decryption"` } func (c *keyDecryptCmd) CmdAliases() []string { return nil } diff --git a/cmd/kms/key/key_delete.go b/cmd/kms/key/key_delete.go index fa628e092..aadedbbc1 100644 --- a/cmd/kms/key/key_delete.go +++ b/cmd/kms/key/key_delete.go @@ -17,7 +17,7 @@ type keyDeleteCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` - DelayDays string `cli-flag:"delay-days" cli-usage:"number of days before deletion (7 - 30, default: 30)"` + DelayDays string `cli-short:"d" cli-flag:"delay-days" cli-usage:"number of days before deletion (7 - 30, default: 30)"` } func (c *keyDeleteCmd) CmdAliases() []string { return nil } diff --git a/cmd/kms/key/key_encrypt.go b/cmd/kms/key/key_encrypt.go index 07fa152b4..40b3dece1 100644 --- a/cmd/kms/key/key_encrypt.go +++ b/cmd/kms/key/key_encrypt.go @@ -39,7 +39,7 @@ type keyEncryptCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` Plaintext string `cli-arg:"#" cli-usage:"PLAINTEXT"` - EncryptionContext string `cli-flag:"encryption-context" cli-usage:"encryption context to use for encryption"` + EncryptionContext string `cli-short:"e" cli-flag:"encryption-context" cli-usage:"encryption context to use for encryption"` } func (c *keyEncryptCmd) CmdAliases() []string { return nil } diff --git a/cmd/kms/key/key_generate_dek.go b/cmd/kms/key/key_generate_dek.go index fdd174690..6d8409640 100644 --- a/cmd/kms/key/key_generate_dek.go +++ b/cmd/kms/key/key_generate_dek.go @@ -41,9 +41,9 @@ type keyGenerateDEKCmd struct { _ bool `cli-cmd:"generate-dek"` Key string `cli-arg:"#" cli-usage:"ID"` - KeySpec v3.GenerateDataKeyRequestKeySpec `cli-flag:"key-spec" cli-usage:"key spec for DEK [AES_256]"` - BytesCount string `cli-flag:"bytes-count" cli-usage:"number of bytes for DEK (1 - 1024)"` - EncryptionContext string `cli-flag:"encryption-context" cli-usage:"encryption context to use for DEK generation"` + KeySpec v3.GenerateDataKeyRequestKeySpec `cli-short:"s" cli-flag:"key-spec" cli-usage:"key spec for DEK [AES_256]"` + BytesCount string `cli-short:"b" cli-flag:"bytes-count" cli-usage:"number of bytes for DEK (1 - 1024)"` + EncryptionContext string `cli-short:"e" cli-flag:"encryption-context" cli-usage:"encryption context to use for DEK generation"` } func (c *keyGenerateDEKCmd) CmdAliases() []string { return nil } diff --git a/cmd/kms/key/key_reencrypt.go b/cmd/kms/key/key_reencrypt.go index 3e13d693f..1438bb15d 100644 --- a/cmd/kms/key/key_reencrypt.go +++ b/cmd/kms/key/key_reencrypt.go @@ -18,8 +18,8 @@ type keyReencryptCmd struct { DestinationKey string `cli-arg:"#" cli-usage:"DEST_ID"` Ciphertext string `cli-arg:"#" cli-usage:"CIPHERTEXT"` - SourceEncryptionContext string `cli-flag:"source-encryption-context" cli-usage:"encryption context to use for source ciphertext decryption"` - DestEncryptionContext string `cli-flag:"dest-encryption-context" cli-usage:"encryption context to use for destination ciphertext encryption"` + SourceEncryptionContext string `cli-short:"s" cli-flag:"source-encryption-context" cli-usage:"encryption context to use for source ciphertext decryption"` + DestEncryptionContext string `cli-short:"d" cli-flag:"dest-encryption-context" cli-usage:"encryption context to use for destination ciphertext encryption"` } func (c *keyReencryptCmd) CmdAliases() []string { return nil } diff --git a/cmd/kms/rotation/rotation_enable.go b/cmd/kms/rotation/rotation_enable.go index 1b519f613..a05917ebf 100644 --- a/cmd/kms/rotation/rotation_enable.go +++ b/cmd/kms/rotation/rotation_enable.go @@ -17,7 +17,7 @@ type rotationEnableCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` - RotationPeriod string `cli-flag:"rotation-period" cli-usage:"number of days for auto rotation period (90 - 2560, default: 365)"` + RotationPeriod string `cli-flag:"rotation-period" cli-short:"r" cli-usage:"number of days for auto rotation period (90 - 2560, default: 365)"` } func (c *rotationEnableCmd) CmdAliases() []string { return nil } From 3558ff5350e0100c484fb0439d99b77355bf4ead Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Tue, 19 May 2026 09:40:32 +0200 Subject: [PATCH 18/26] add title to error message --- cmd/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/root.go b/cmd/root.go index d1623e0ed..cc996ab7e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -116,7 +116,7 @@ func formatError(err error) string { return apiErr.Unwrap().Error() } - msg := apiErr.Unwrap().Error() + ": " + lead + msg := apiErr.Unwrap().Error() + ": " + apiErr.Title + ": " + lead for _, e := range apiErr.Errors { field := formatFieldName(e.Location) detail := formatDetail(e.Detail) From 24c758e70d0a3a42a79921a42d29de70c4c1b1ed Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Tue, 19 May 2026 10:15:57 +0200 Subject: [PATCH 19/26] add zone support --- cmd/kms/key/key_cancel_delete.go | 10 ++++++++-- cmd/kms/key/key_create.go | 13 +++++++++---- cmd/kms/key/key_decrypt.go | 9 +++++++-- cmd/kms/key/key_delete.go | 11 ++++++++--- cmd/kms/key/key_disable.go | 8 +++++++- cmd/kms/key/key_enable.go | 8 +++++++- cmd/kms/key/key_encrypt.go | 9 +++++++-- cmd/kms/key/key_generate_dek.go | 10 ++++++++-- cmd/kms/key/key_list.go | 8 +++++++- cmd/kms/key/key_reencrypt.go | 11 ++++++++--- cmd/kms/key/key_replicate.go | 14 ++++++++++---- cmd/kms/key/key_rotate.go | 10 ++++++++-- cmd/kms/key/key_show.go | 8 +++++++- cmd/kms/rotation/rotation_disable.go | 8 +++++++- cmd/kms/rotation/rotation_enable.go | 9 +++++++-- cmd/kms/rotation/rotation_list.go | 9 ++++++++- 16 files changed, 123 insertions(+), 32 deletions(-) diff --git a/cmd/kms/key/key_cancel_delete.go b/cmd/kms/key/key_cancel_delete.go index b1bdd6e98..111172aa6 100644 --- a/cmd/kms/key/key_cancel_delete.go +++ b/cmd/kms/key/key_cancel_delete.go @@ -13,6 +13,8 @@ type keyCancelDeleteCmd struct { _ bool `cli-cmd:"cancel-delete"` Key string `cli-arg:"#" cli-usage:"ID"` + + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyCancelDeleteCmd) CmdAliases() []string { return nil } @@ -26,14 +28,18 @@ func (c *keyCancelDeleteCmd) CmdLong() string { } func (c *keyCancelDeleteCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *keyCancelDeleteCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } - _, err := client.CancelKmsKeyDeletion(ctx, v3.UUID(c.Key)) + _, err = client.CancelKmsKeyDeletion(ctx, v3.UUID(c.Key)) if err != nil { return err } diff --git a/cmd/kms/key/key_create.go b/cmd/kms/key/key_create.go index 96a112de9..bf81c88d9 100644 --- a/cmd/kms/key/key_create.go +++ b/cmd/kms/key/key_create.go @@ -14,9 +14,10 @@ type keyCreateCmd struct { Name string `cli-arg:"#" cli-usage:"NAME"` - Description string `cli-short:"d" cli-flag:"description" cli-usage:"key description"` - Usage string `cli-short:"u" cli-flag:"usage" cli-usage:"key usage [encrypt-decrypt]"` - Multizone bool `cli-short:"m" cli-flag:"multizone" cli-usage:"allow replication accross zones (default: false)"` + Description string `cli-short:"d" cli-flag:"description" cli-usage:"key description"` + Usage string `cli-short:"u" cli-flag:"usage" cli-usage:"key usage [encrypt-decrypt]"` + Multizone bool `cli-short:"m" cli-flag:"multizone" cli-usage:"allow replication accross zones (default: false)"` + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyCreateCmd) CmdAliases() []string { return nil } @@ -30,12 +31,16 @@ func (c *keyCreateCmd) CmdLong() string { } func (c *keyCreateCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *keyCreateCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } req := v3.CreateKmsKeyRequest{ Name: c.Name, diff --git a/cmd/kms/key/key_decrypt.go b/cmd/kms/key/key_decrypt.go index 0d60d4c90..dd6607356 100644 --- a/cmd/kms/key/key_decrypt.go +++ b/cmd/kms/key/key_decrypt.go @@ -39,7 +39,8 @@ type keyDecryptCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` Ciphertext string `cli-arg:"#" cli-usage:"CIPHERTEXT"` - EncryptionContext string `cli-short:"e" cli-flag:"encryption-context" cli-usage:"encryption context to use for decryption"` + EncryptionContext string `cli-short:"e" cli-flag:"encryption-context" cli-usage:"encryption context to use for decryption"` + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyDecryptCmd) CmdAliases() []string { return nil } @@ -53,12 +54,16 @@ func (c *keyDecryptCmd) CmdLong() string { } func (c *keyDecryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *keyDecryptCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } ec := []byte(c.EncryptionContext) decoded, err := base64.StdEncoding.DecodeString(c.Ciphertext) diff --git a/cmd/kms/key/key_delete.go b/cmd/kms/key/key_delete.go index aadedbbc1..ea31cb1ae 100644 --- a/cmd/kms/key/key_delete.go +++ b/cmd/kms/key/key_delete.go @@ -17,7 +17,8 @@ type keyDeleteCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` - DelayDays string `cli-short:"d" cli-flag:"delay-days" cli-usage:"number of days before deletion (7 - 30, default: 30)"` + DelayDays string `cli-short:"d" cli-flag:"delay-days" cli-usage:"number of days before deletion (7 - 30, default: 30)"` + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyDeleteCmd) CmdAliases() []string { return nil } @@ -31,12 +32,16 @@ func (c *keyDeleteCmd) CmdLong() string { } func (c *keyDeleteCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *keyDeleteCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } var delayDays int if c.DelayDays != "" { @@ -51,7 +56,7 @@ func (c *keyDeleteCmd) CmdRun(_ *cobra.Command, _ []string) error { DelayDays: delayDays, } - _, err := client.ScheduleKmsKeyDeletion(ctx, v3.UUID(c.Key), req) + _, err = client.ScheduleKmsKeyDeletion(ctx, v3.UUID(c.Key), req) if err != nil { return err } diff --git a/cmd/kms/key/key_disable.go b/cmd/kms/key/key_disable.go index a42b938f6..059dfbf29 100644 --- a/cmd/kms/key/key_disable.go +++ b/cmd/kms/key/key_disable.go @@ -13,6 +13,8 @@ type keyDisableCmd struct { _ bool `cli-cmd:"disable"` Key string `cli-arg:"#" cli-usage:"ID"` + + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyDisableCmd) CmdAliases() []string { return nil } @@ -26,12 +28,16 @@ func (c *keyDisableCmd) CmdLong() string { } func (c *keyDisableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *keyDisableCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } if _, err := client.DisableKmsKey(ctx, v3.UUID(c.Key)); err != nil { return err diff --git a/cmd/kms/key/key_enable.go b/cmd/kms/key/key_enable.go index a2a66a1ee..7a4ad5065 100644 --- a/cmd/kms/key/key_enable.go +++ b/cmd/kms/key/key_enable.go @@ -13,6 +13,8 @@ type keyEnableCmd struct { _ bool `cli-cmd:"enable"` Key string `cli-arg:"#" cli-usage:"ID"` + + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyEnableCmd) CmdAliases() []string { return nil } @@ -26,12 +28,16 @@ func (c *keyEnableCmd) CmdLong() string { } func (c *keyEnableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *keyEnableCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } if _, err := client.EnableKmsKey(ctx, v3.UUID(c.Key)); err != nil { return err diff --git a/cmd/kms/key/key_encrypt.go b/cmd/kms/key/key_encrypt.go index 40b3dece1..a42f9edd2 100644 --- a/cmd/kms/key/key_encrypt.go +++ b/cmd/kms/key/key_encrypt.go @@ -39,7 +39,8 @@ type keyEncryptCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` Plaintext string `cli-arg:"#" cli-usage:"PLAINTEXT"` - EncryptionContext string `cli-short:"e" cli-flag:"encryption-context" cli-usage:"encryption context to use for encryption"` + EncryptionContext string `cli-short:"e" cli-flag:"encryption-context" cli-usage:"encryption context to use for encryption"` + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyEncryptCmd) CmdAliases() []string { return nil } @@ -53,12 +54,16 @@ func (c *keyEncryptCmd) CmdLong() string { } func (c *keyEncryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *keyEncryptCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } ec := []byte(c.EncryptionContext) req := v3.EncryptRequest{ diff --git a/cmd/kms/key/key_generate_dek.go b/cmd/kms/key/key_generate_dek.go index 6d8409640..c20208c1c 100644 --- a/cmd/kms/key/key_generate_dek.go +++ b/cmd/kms/key/key_generate_dek.go @@ -40,10 +40,12 @@ type keyGenerateDEKCmd struct { _ bool `cli-cmd:"generate-dek"` - Key string `cli-arg:"#" cli-usage:"ID"` + Key string `cli-arg:"#" cli-usage:"ID"` + KeySpec v3.GenerateDataKeyRequestKeySpec `cli-short:"s" cli-flag:"key-spec" cli-usage:"key spec for DEK [AES_256]"` BytesCount string `cli-short:"b" cli-flag:"bytes-count" cli-usage:"number of bytes for DEK (1 - 1024)"` EncryptionContext string `cli-short:"e" cli-flag:"encryption-context" cli-usage:"encryption context to use for DEK generation"` + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyGenerateDEKCmd) CmdAliases() []string { return nil } @@ -57,12 +59,16 @@ func (c *keyGenerateDEKCmd) CmdLong() string { } func (c *keyGenerateDEKCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *keyGenerateDEKCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } ec := []byte(c.EncryptionContext) diff --git a/cmd/kms/key/key_list.go b/cmd/kms/key/key_list.go index f8d72d114..e0b0e536c 100644 --- a/cmd/kms/key/key_list.go +++ b/cmd/kms/key/key_list.go @@ -48,6 +48,8 @@ type keyListCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` _ bool `cli-cmd:"list"` + + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyListCmd) CmdAliases() []string { return exocmd.GListAlias } @@ -61,12 +63,16 @@ func (c *keyListCmd) CmdLong() string { } func (c *keyListCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *keyListCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } keys, err := client.ListKmsKeys(ctx) if err != nil { diff --git a/cmd/kms/key/key_reencrypt.go b/cmd/kms/key/key_reencrypt.go index 1438bb15d..3bbc29481 100644 --- a/cmd/kms/key/key_reencrypt.go +++ b/cmd/kms/key/key_reencrypt.go @@ -18,8 +18,9 @@ type keyReencryptCmd struct { DestinationKey string `cli-arg:"#" cli-usage:"DEST_ID"` Ciphertext string `cli-arg:"#" cli-usage:"CIPHERTEXT"` - SourceEncryptionContext string `cli-short:"s" cli-flag:"source-encryption-context" cli-usage:"encryption context to use for source ciphertext decryption"` - DestEncryptionContext string `cli-short:"d" cli-flag:"dest-encryption-context" cli-usage:"encryption context to use for destination ciphertext encryption"` + SourceEncryptionContext string `cli-short:"s" cli-flag:"source-encryption-context" cli-usage:"encryption context to use for source ciphertext decryption"` + DestEncryptionContext string `cli-short:"d" cli-flag:"dest-encryption-context" cli-usage:"encryption context to use for destination ciphertext encryption"` + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyReencryptCmd) CmdAliases() []string { return nil } @@ -33,12 +34,16 @@ func (c *keyReencryptCmd) CmdLong() string { } func (c *keyReencryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *keyReencryptCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } var sourceEC []byte if c.SourceEncryptionContext != "" { diff --git a/cmd/kms/key/key_replicate.go b/cmd/kms/key/key_replicate.go index c23621eee..54894817f 100644 --- a/cmd/kms/key/key_replicate.go +++ b/cmd/kms/key/key_replicate.go @@ -12,8 +12,10 @@ type keyReplicateCmd struct { _ bool `cli-cmd:"replicate"` - Key string `cli-arg:"#" cli-usage:"ID"` - Zone v3.ZoneName `cli-arg:"#" cli-usage:"ZONE"` + Key string `cli-arg:"#" cli-usage:"ID"` + TargetZone v3.ZoneName `cli-arg:"#" cli-usage:"TARGET_ZONE"` + + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyReplicateCmd) CmdAliases() []string { return nil } @@ -27,15 +29,19 @@ func (c *keyReplicateCmd) CmdLong() string { } func (c *keyReplicateCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *keyReplicateCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } req := v3.ReplicateKmsKeyRequest{ - Zone: string(c.Zone), + Zone: string(c.TargetZone), } resp, err := client.ReplicateKmsKey(ctx, v3.UUID(c.Key), req) diff --git a/cmd/kms/key/key_rotate.go b/cmd/kms/key/key_rotate.go index 45b44b932..ad3c80034 100644 --- a/cmd/kms/key/key_rotate.go +++ b/cmd/kms/key/key_rotate.go @@ -13,6 +13,8 @@ type keyRotateCmd struct { _ bool `cli-cmd:"rotate"` Key string `cli-arg:"#" cli-usage:"ID"` + + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyRotateCmd) CmdAliases() []string { return nil } @@ -26,14 +28,18 @@ func (c *keyRotateCmd) CmdLong() string { } func (c *keyRotateCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *keyRotateCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } - _, err := client.RotateKmsKey(ctx, v3.UUID(c.Key)) + _, err = client.RotateKmsKey(ctx, v3.UUID(c.Key)) if err != nil { return err } diff --git a/cmd/kms/key/key_show.go b/cmd/kms/key/key_show.go index 17b4b5543..28cac50f8 100644 --- a/cmd/kms/key/key_show.go +++ b/cmd/kms/key/key_show.go @@ -36,6 +36,8 @@ type KeyShowCmd struct { _ bool `cli-cmd:"show"` Key string `cli-arg:"#" cli-usage:"ID"` + + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *KeyShowCmd) CmdAliases() []string { return exocmd.GShowAlias } @@ -49,12 +51,16 @@ func (c *KeyShowCmd) CmdLong() string { } func (c *KeyShowCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *KeyShowCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } resp, err := client.GetKmsKey(ctx, v3.UUID(c.Key)) if err != nil { diff --git a/cmd/kms/rotation/rotation_disable.go b/cmd/kms/rotation/rotation_disable.go index 6036a2fa3..9736cbc89 100644 --- a/cmd/kms/rotation/rotation_disable.go +++ b/cmd/kms/rotation/rotation_disable.go @@ -14,6 +14,8 @@ type rotationDisableCmd struct { _ bool `cli-cmd:"disable"` Key string `cli-arg:"#" cli-usage:"ID"` + + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *rotationDisableCmd) CmdAliases() []string { return nil } @@ -27,12 +29,16 @@ func (c *rotationDisableCmd) CmdLong() string { } func (c *rotationDisableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *rotationDisableCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } if _, err := client.DisableKmsKeyRotation(ctx, v3.UUID(c.Key)); err != nil { return err diff --git a/cmd/kms/rotation/rotation_enable.go b/cmd/kms/rotation/rotation_enable.go index a05917ebf..b26f50d95 100644 --- a/cmd/kms/rotation/rotation_enable.go +++ b/cmd/kms/rotation/rotation_enable.go @@ -17,7 +17,8 @@ type rotationEnableCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` - RotationPeriod string `cli-flag:"rotation-period" cli-short:"r" cli-usage:"number of days for auto rotation period (90 - 2560, default: 365)"` + RotationPeriod string `cli-flag:"rotation-period" cli-short:"r" cli-usage:"number of days for auto rotation period (90 - 2560, default: 365)"` + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *rotationEnableCmd) CmdAliases() []string { return nil } @@ -31,12 +32,16 @@ func (c *rotationEnableCmd) CmdLong() string { } func (c *rotationEnableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *rotationEnableCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } var req v3.EnableKmsKeyRotationRequest if c.RotationPeriod != "" { diff --git a/cmd/kms/rotation/rotation_list.go b/cmd/kms/rotation/rotation_list.go index 91c9273c9..acd7f9969 100644 --- a/cmd/kms/rotation/rotation_list.go +++ b/cmd/kms/rotation/rotation_list.go @@ -43,6 +43,8 @@ type rotationListCmd struct { _ bool `cli-cmd:"list"` Key string `cli-arg:"#" cli-usage:"ID"` + + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *rotationListCmd) CmdAliases() []string { return exocmd.GListAlias } @@ -56,12 +58,17 @@ func (c *rotationListCmd) CmdLong() string { } func (c *rotationListCmd) CmdPreRun(cmd *cobra.Command, args []string) error { + exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } func (c *rotationListCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext - client := globalstate.EgoscaleV3Client + + client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) + if err != nil { + return err + } resp, err := client.ListKmsKeyRotations(ctx, v3.UUID(c.Key)) if err != nil { From cb24b0c72c9af01bf0801e13e7b9ed72a5a526d7 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Tue, 19 May 2026 10:23:06 +0200 Subject: [PATCH 20/26] add --ignore-replica --status filter --- cmd/kms/key/key_list.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/cmd/kms/key/key_list.go b/cmd/kms/key/key_list.go index e0b0e536c..a06c1741f 100644 --- a/cmd/kms/key/key_list.go +++ b/cmd/kms/key/key_list.go @@ -49,7 +49,9 @@ type keyListCmd struct { _ bool `cli-cmd:"list"` - Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` + IgnoreReplicas bool `cli-short:"i" cli-flag:"ignore-replica" cli-usage:"filter out replicas"` + Status string `cli-short:"s" cli-flag:"status" cli-usage:"filter by key status [enabled|disabled|pending-deletion]"` + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyListCmd) CmdAliases() []string { return exocmd.GListAlias } @@ -79,7 +81,18 @@ func (c *keyListCmd) CmdRun(_ *cobra.Command, _ []string) error { return err } - out := keyListOutput{*keys} + filtered := make([]v3.ListKmsKeysResponseEntry, 0, len(keys.KmsKeys)) + for _, key := range keys.KmsKeys { + if c.IgnoreReplicas && key.OriginZone != string(c.Zone) { + continue + } + if c.Status != "" && string(key.Status) != c.Status { + continue + } + filtered = append(filtered, key) + } + + out := keyListOutput{v3.ListKmsKeysResponse{KmsKeys: filtered}} return c.OutputFunc(&out, nil) } From 5928dd2ab2bf5c20d58149fcc53067e1e140499c Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Tue, 19 May 2026 10:24:25 +0200 Subject: [PATCH 21/26] typo --- cmd/kms/key/key_list.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/kms/key/key_list.go b/cmd/kms/key/key_list.go index a06c1741f..a648896e3 100644 --- a/cmd/kms/key/key_list.go +++ b/cmd/kms/key/key_list.go @@ -49,9 +49,9 @@ type keyListCmd struct { _ bool `cli-cmd:"list"` - IgnoreReplicas bool `cli-short:"i" cli-flag:"ignore-replica" cli-usage:"filter out replicas"` - Status string `cli-short:"s" cli-flag:"status" cli-usage:"filter by key status [enabled|disabled|pending-deletion]"` - Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` + IgnoreReplica bool `cli-short:"i" cli-flag:"ignore-replica" cli-usage:"filter out replicas"` + Status string `cli-short:"s" cli-flag:"status" cli-usage:"filter by key status [enabled|disabled|pending-deletion]"` + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } func (c *keyListCmd) CmdAliases() []string { return exocmd.GListAlias } @@ -83,7 +83,7 @@ func (c *keyListCmd) CmdRun(_ *cobra.Command, _ []string) error { filtered := make([]v3.ListKmsKeysResponseEntry, 0, len(keys.KmsKeys)) for _, key := range keys.KmsKeys { - if c.IgnoreReplicas && key.OriginZone != string(c.Zone) { + if c.IgnoreReplica && key.OriginZone != string(c.Zone) { continue } if c.Status != "" && string(key.Status) != c.Status { From b28ffee0f3ec53a9e43738906b95f5ec0440a595 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Tue, 26 May 2026 15:07:35 +0200 Subject: [PATCH 22/26] renaming --- ...nerate_dek.go => key_generate_data_key.go} | 30 +++++++++---------- ...key_delete.go => key_schedule_deletion.go} | 20 ++++++------- 2 files changed, 25 insertions(+), 25 deletions(-) rename cmd/kms/key/{key_generate_dek.go => key_generate_data_key.go} (70%) rename cmd/kms/key/{key_delete.go => key_schedule_deletion.go} (69%) diff --git a/cmd/kms/key/key_generate_dek.go b/cmd/kms/key/key_generate_data_key.go similarity index 70% rename from cmd/kms/key/key_generate_dek.go rename to cmd/kms/key/key_generate_data_key.go index c20208c1c..4814ea71a 100644 --- a/cmd/kms/key/key_generate_dek.go +++ b/cmd/kms/key/key_generate_data_key.go @@ -13,14 +13,14 @@ import ( "github.com/spf13/cobra" ) -type keyGenerateDEKOutput struct { +type keyGenerateDataKeyOutput struct { Plaintext string `json:"plaintext"` Ciphertext string `json:"ciphertext"` } -func (o *keyGenerateDEKOutput) ToJSON() { output.JSON(o) } -func (o *keyGenerateDEKOutput) ToText() { output.Text(o) } -func (o *keyGenerateDEKOutput) ToTable() { +func (o *keyGenerateDataKeyOutput) ToJSON() { output.JSON(o) } +func (o *keyGenerateDataKeyOutput) ToText() { output.Text(o) } +func (o *keyGenerateDataKeyOutput) ToTable() { t := table.NewTable(os.Stdout) defer t.Render() @@ -35,10 +35,10 @@ func (o *keyGenerateDEKOutput) ToTable() { }) } -type keyGenerateDEKCmd struct { +type keyGenerateDataKeyCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` - _ bool `cli-cmd:"generate-dek"` + _ bool `cli-cmd:"generate-data-key"` Key string `cli-arg:"#" cli-usage:"ID"` @@ -48,22 +48,22 @@ type keyGenerateDEKCmd struct { Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } -func (c *keyGenerateDEKCmd) CmdAliases() []string { return nil } +func (c *keyGenerateDataKeyCmd) CmdAliases() []string { return nil } -func (c *keyGenerateDEKCmd) CmdShort() string { - return "Generates a data encryption key (DEK) using a KMS key." +func (c *keyGenerateDataKeyCmd) CmdShort() string { + return "Generates a data encryption key using a KMS key." } -func (c *keyGenerateDEKCmd) CmdLong() string { - return "Generates a data encryption key (DEK) using a KMS key." +func (c *keyGenerateDataKeyCmd) CmdLong() string { + return "Generates a data encryption key using a KMS key." } -func (c *keyGenerateDEKCmd) CmdPreRun(cmd *cobra.Command, args []string) error { +func (c *keyGenerateDataKeyCmd) CmdPreRun(cmd *cobra.Command, args []string) error { exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *keyGenerateDEKCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *keyGenerateDataKeyCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) if err != nil { @@ -93,7 +93,7 @@ func (c *keyGenerateDEKCmd) CmdRun(_ *cobra.Command, _ []string) error { } if !globalstate.Quiet { - out := keyGenerateDEKOutput{ + out := keyGenerateDataKeyOutput{ Ciphertext: base64.StdEncoding.EncodeToString(resp.Ciphertext), Plaintext: base64.StdEncoding.EncodeToString(resp.Plaintext), } @@ -103,7 +103,7 @@ func (c *keyGenerateDEKCmd) CmdRun(_ *cobra.Command, _ []string) error { } func init() { - cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyGenerateDEKCmd{ + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyGenerateDataKeyCmd{ CliCommandSettings: exocmd.DefaultCLICmdSettings(), })) } diff --git a/cmd/kms/key/key_delete.go b/cmd/kms/key/key_schedule_deletion.go similarity index 69% rename from cmd/kms/key/key_delete.go rename to cmd/kms/key/key_schedule_deletion.go index ea31cb1ae..ff115610c 100644 --- a/cmd/kms/key/key_delete.go +++ b/cmd/kms/key/key_schedule_deletion.go @@ -10,10 +10,10 @@ import ( "github.com/spf13/cobra" ) -type keyDeleteCmd struct { +type keyScheduleDeletionCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` - _ bool `cli-cmd:"delete"` + _ bool `cli-cmd:"schedule-deletion"` Key string `cli-arg:"#" cli-usage:"ID"` @@ -21,22 +21,22 @@ type keyDeleteCmd struct { Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } -func (c *keyDeleteCmd) CmdAliases() []string { return nil } +func (c *keyScheduleDeletionCmd) CmdAliases() []string { return nil } -func (c *keyDeleteCmd) CmdShort() string { - return "Deletes a KMS key." +func (c *keyScheduleDeletionCmd) CmdShort() string { + return "Schedules deletion of a KMS key." } -func (c *keyDeleteCmd) CmdLong() string { - return "Deletes a KMS key." +func (c *keyScheduleDeletionCmd) CmdLong() string { + return "Schedules deletion of a KMS key." } -func (c *keyDeleteCmd) CmdPreRun(cmd *cobra.Command, args []string) error { +func (c *keyScheduleDeletionCmd) CmdPreRun(cmd *cobra.Command, args []string) error { exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *keyDeleteCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *keyScheduleDeletionCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) if err != nil { @@ -72,7 +72,7 @@ func (c *keyDeleteCmd) CmdRun(_ *cobra.Command, _ []string) error { } func init() { - cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyDeleteCmd{ + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyScheduleDeletionCmd{ CliCommandSettings: exocmd.DefaultCLICmdSettings(), })) } From db989b491250fb1eb980ddf97a28d8c2efb6a604 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Tue, 26 May 2026 16:02:30 +0200 Subject: [PATCH 23/26] renaming --- cmd/kms/crypto/crypto.go | 15 ++++++++++ .../crypto_decrypt.go} | 28 +++++++++---------- .../crypto_encrypt.go} | 26 ++++++++--------- .../crypto_generate_data_key.go} | 26 ++++++++--------- .../crypto_reencrypt.go} | 18 ++++++------ ...ancel_delete.go => key_cancel_deletion.go} | 16 +++++------ .../key_rotation_disable.go} | 21 +++++++------- .../key_rotation_enable.go} | 21 +++++++------- .../key_rotation_list.go} | 28 +++++++++---------- cmd/kms/rotation/rotation.go | 15 ---------- cmd/subcommands/init.go | 2 +- 11 files changed, 107 insertions(+), 109 deletions(-) create mode 100644 cmd/kms/crypto/crypto.go rename cmd/kms/{key/key_decrypt.go => crypto/crypto_decrypt.go} (71%) rename cmd/kms/{key/key_encrypt.go => crypto/crypto_encrypt.go} (71%) rename cmd/kms/{key/key_generate_data_key.go => crypto/crypto_generate_data_key.go} (74%) rename cmd/kms/{key/key_reencrypt.go => crypto/crypto_reencrypt.go} (82%) rename cmd/kms/key/{key_cancel_delete.go => key_cancel_deletion.go} (72%) rename cmd/kms/{rotation/rotation_disable.go => key/key_rotation_disable.go} (63%) rename cmd/kms/{rotation/rotation_enable.go => key/key_rotation_enable.go} (71%) rename cmd/kms/{rotation/rotation_list.go => key/key_rotation_list.go} (63%) delete mode 100644 cmd/kms/rotation/rotation.go diff --git a/cmd/kms/crypto/crypto.go b/cmd/kms/crypto/crypto.go new file mode 100644 index 000000000..55275920a --- /dev/null +++ b/cmd/kms/crypto/crypto.go @@ -0,0 +1,15 @@ +package crypto + +import ( + "github.com/exoscale/cli/cmd/kms" + "github.com/spf13/cobra" +) + +var cryptoCmd = &cobra.Command{ + Use: "crypto", + Short: "KMS key cryptographic operations", +} + +func init() { + kms.KMSCmd.AddCommand(cryptoCmd) +} diff --git a/cmd/kms/key/key_decrypt.go b/cmd/kms/crypto/crypto_decrypt.go similarity index 71% rename from cmd/kms/key/key_decrypt.go rename to cmd/kms/crypto/crypto_decrypt.go index dd6607356..d10db3ae1 100644 --- a/cmd/kms/key/key_decrypt.go +++ b/cmd/kms/crypto/crypto_decrypt.go @@ -1,4 +1,4 @@ -package key +package crypto import ( "encoding/base64" @@ -12,13 +12,13 @@ import ( "github.com/spf13/cobra" ) -type keyDecryptOutput struct { +type cryptoDecryptOutput struct { Plaintext string `json:"plaintext"` } -func (o *keyDecryptOutput) ToJSON() { output.JSON(o) } -func (o *keyDecryptOutput) ToText() { output.Text(o) } -func (o *keyDecryptOutput) ToTable() { +func (o *cryptoDecryptOutput) ToJSON() { output.JSON(o) } +func (o *cryptoDecryptOutput) ToText() { output.Text(o) } +func (o *cryptoDecryptOutput) ToTable() { t := table.NewTable(os.Stdout) defer t.Render() @@ -31,7 +31,7 @@ func (o *keyDecryptOutput) ToTable() { }) } -type keyDecryptCmd struct { +type cryptoDecryptCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` _ bool `cli-cmd:"decrypt"` @@ -40,25 +40,25 @@ type keyDecryptCmd struct { Ciphertext string `cli-arg:"#" cli-usage:"CIPHERTEXT"` EncryptionContext string `cli-short:"e" cli-flag:"encryption-context" cli-usage:"encryption context to use for decryption"` - Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` + Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"crypto zone"` } -func (c *keyDecryptCmd) CmdAliases() []string { return nil } +func (c *cryptoDecryptCmd) CmdAliases() []string { return nil } -func (c *keyDecryptCmd) CmdShort() string { +func (c *cryptoDecryptCmd) CmdShort() string { return "Decrypts data using a KMS key." } -func (c *keyDecryptCmd) CmdLong() string { +func (c *cryptoDecryptCmd) CmdLong() string { return "Decrypts data using a KMS key." } -func (c *keyDecryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { +func (c *cryptoDecryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *keyDecryptCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *cryptoDecryptCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) if err != nil { @@ -81,7 +81,7 @@ func (c *keyDecryptCmd) CmdRun(_ *cobra.Command, _ []string) error { } if !globalstate.Quiet { - out := keyDecryptOutput{ + out := cryptoDecryptOutput{ Plaintext: base64.StdEncoding.EncodeToString(resp.Plaintext), } return c.OutputFunc(&out, nil) @@ -91,7 +91,7 @@ func (c *keyDecryptCmd) CmdRun(_ *cobra.Command, _ []string) error { } func init() { - cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyDecryptCmd{ + cobra.CheckErr(exocmd.RegisterCLICommand(cryptoCmd, &cryptoDecryptCmd{ CliCommandSettings: exocmd.DefaultCLICmdSettings(), })) } diff --git a/cmd/kms/key/key_encrypt.go b/cmd/kms/crypto/crypto_encrypt.go similarity index 71% rename from cmd/kms/key/key_encrypt.go rename to cmd/kms/crypto/crypto_encrypt.go index a42f9edd2..d0f0e01bf 100644 --- a/cmd/kms/key/key_encrypt.go +++ b/cmd/kms/crypto/crypto_encrypt.go @@ -1,4 +1,4 @@ -package key +package crypto import ( "encoding/base64" @@ -12,13 +12,13 @@ import ( "github.com/spf13/cobra" ) -type keyEncryptOutput struct { +type cryptoEncryptOutput struct { Ciphertext string `json:"ciphertext"` } -func (o *keyEncryptOutput) ToJSON() { output.JSON(o) } -func (o *keyEncryptOutput) ToText() { output.Text(o) } -func (o *keyEncryptOutput) ToTable() { +func (o *cryptoEncryptOutput) ToJSON() { output.JSON(o) } +func (o *cryptoEncryptOutput) ToText() { output.Text(o) } +func (o *cryptoEncryptOutput) ToTable() { t := table.NewTable(os.Stdout) defer t.Render() @@ -31,7 +31,7 @@ func (o *keyEncryptOutput) ToTable() { }) } -type keyEncryptCmd struct { +type cryptoEncryptCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` _ bool `cli-cmd:"encrypt"` @@ -43,22 +43,22 @@ type keyEncryptCmd struct { Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } -func (c *keyEncryptCmd) CmdAliases() []string { return nil } +func (c *cryptoEncryptCmd) CmdAliases() []string { return nil } -func (c *keyEncryptCmd) CmdShort() string { +func (c *cryptoEncryptCmd) CmdShort() string { return "Encrypts data using a KMS key." } -func (c *keyEncryptCmd) CmdLong() string { +func (c *cryptoEncryptCmd) CmdLong() string { return "Encrypts data using a KMS key." } -func (c *keyEncryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { +func (c *cryptoEncryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *keyEncryptCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *cryptoEncryptCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) if err != nil { @@ -77,7 +77,7 @@ func (c *keyEncryptCmd) CmdRun(_ *cobra.Command, _ []string) error { } if !globalstate.Quiet { - out := keyEncryptOutput{ + out := cryptoEncryptOutput{ Ciphertext: base64.StdEncoding.EncodeToString(resp.Ciphertext), } return c.OutputFunc(&out, nil) @@ -87,7 +87,7 @@ func (c *keyEncryptCmd) CmdRun(_ *cobra.Command, _ []string) error { } func init() { - cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyEncryptCmd{ + cobra.CheckErr(exocmd.RegisterCLICommand(cryptoCmd, &cryptoEncryptCmd{ CliCommandSettings: exocmd.DefaultCLICmdSettings(), })) } diff --git a/cmd/kms/key/key_generate_data_key.go b/cmd/kms/crypto/crypto_generate_data_key.go similarity index 74% rename from cmd/kms/key/key_generate_data_key.go rename to cmd/kms/crypto/crypto_generate_data_key.go index 4814ea71a..5225b137d 100644 --- a/cmd/kms/key/key_generate_data_key.go +++ b/cmd/kms/crypto/crypto_generate_data_key.go @@ -1,4 +1,4 @@ -package key +package crypto import ( "encoding/base64" @@ -13,14 +13,14 @@ import ( "github.com/spf13/cobra" ) -type keyGenerateDataKeyOutput struct { +type cryptoGenerateDataKeyOutput struct { Plaintext string `json:"plaintext"` Ciphertext string `json:"ciphertext"` } -func (o *keyGenerateDataKeyOutput) ToJSON() { output.JSON(o) } -func (o *keyGenerateDataKeyOutput) ToText() { output.Text(o) } -func (o *keyGenerateDataKeyOutput) ToTable() { +func (o *cryptoGenerateDataKeyOutput) ToJSON() { output.JSON(o) } +func (o *cryptoGenerateDataKeyOutput) ToText() { output.Text(o) } +func (o *cryptoGenerateDataKeyOutput) ToTable() { t := table.NewTable(os.Stdout) defer t.Render() @@ -35,7 +35,7 @@ func (o *keyGenerateDataKeyOutput) ToTable() { }) } -type keyGenerateDataKeyCmd struct { +type cryptoGenerateDataKeyCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` _ bool `cli-cmd:"generate-data-key"` @@ -48,22 +48,22 @@ type keyGenerateDataKeyCmd struct { Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } -func (c *keyGenerateDataKeyCmd) CmdAliases() []string { return nil } +func (c *cryptoGenerateDataKeyCmd) CmdAliases() []string { return nil } -func (c *keyGenerateDataKeyCmd) CmdShort() string { +func (c *cryptoGenerateDataKeyCmd) CmdShort() string { return "Generates a data encryption key using a KMS key." } -func (c *keyGenerateDataKeyCmd) CmdLong() string { +func (c *cryptoGenerateDataKeyCmd) CmdLong() string { return "Generates a data encryption key using a KMS key." } -func (c *keyGenerateDataKeyCmd) CmdPreRun(cmd *cobra.Command, args []string) error { +func (c *cryptoGenerateDataKeyCmd) CmdPreRun(cmd *cobra.Command, args []string) error { exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *keyGenerateDataKeyCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *cryptoGenerateDataKeyCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) if err != nil { @@ -93,7 +93,7 @@ func (c *keyGenerateDataKeyCmd) CmdRun(_ *cobra.Command, _ []string) error { } if !globalstate.Quiet { - out := keyGenerateDataKeyOutput{ + out := cryptoGenerateDataKeyOutput{ Ciphertext: base64.StdEncoding.EncodeToString(resp.Ciphertext), Plaintext: base64.StdEncoding.EncodeToString(resp.Plaintext), } @@ -103,7 +103,7 @@ func (c *keyGenerateDataKeyCmd) CmdRun(_ *cobra.Command, _ []string) error { } func init() { - cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyGenerateDataKeyCmd{ + cobra.CheckErr(exocmd.RegisterCLICommand(cryptoCmd, &cryptoGenerateDataKeyCmd{ CliCommandSettings: exocmd.DefaultCLICmdSettings(), })) } diff --git a/cmd/kms/key/key_reencrypt.go b/cmd/kms/crypto/crypto_reencrypt.go similarity index 82% rename from cmd/kms/key/key_reencrypt.go rename to cmd/kms/crypto/crypto_reencrypt.go index 3bbc29481..b62924183 100644 --- a/cmd/kms/key/key_reencrypt.go +++ b/cmd/kms/crypto/crypto_reencrypt.go @@ -1,4 +1,4 @@ -package key +package crypto import ( "encoding/base64" @@ -9,7 +9,7 @@ import ( "github.com/spf13/cobra" ) -type keyReencryptCmd struct { +type cryptoReencryptCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` _ bool `cli-cmd:"reencrypt"` @@ -23,22 +23,22 @@ type keyReencryptCmd struct { Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } -func (c *keyReencryptCmd) CmdAliases() []string { return nil } +func (c *cryptoReencryptCmd) CmdAliases() []string { return nil } -func (c *keyReencryptCmd) CmdShort() string { +func (c *cryptoReencryptCmd) CmdShort() string { return "Re-encrypts data from a KMS key to another KMS key." } -func (c *keyReencryptCmd) CmdLong() string { +func (c *cryptoReencryptCmd) CmdLong() string { return "Re-encrypts data from a KMS key to another KMS key." } -func (c *keyReencryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { +func (c *cryptoReencryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *keyReencryptCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *cryptoReencryptCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) if err != nil { @@ -80,7 +80,7 @@ func (c *keyReencryptCmd) CmdRun(_ *cobra.Command, _ []string) error { } if !globalstate.Quiet { - out := keyEncryptOutput{ + out := cryptoEncryptOutput{ Ciphertext: base64.StdEncoding.EncodeToString(resp.Ciphertext), } return c.OutputFunc(&out, nil) @@ -90,7 +90,7 @@ func (c *keyReencryptCmd) CmdRun(_ *cobra.Command, _ []string) error { } func init() { - cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyReencryptCmd{ + cobra.CheckErr(exocmd.RegisterCLICommand(cryptoCmd, &cryptoReencryptCmd{ CliCommandSettings: exocmd.DefaultCLICmdSettings(), })) } diff --git a/cmd/kms/key/key_cancel_delete.go b/cmd/kms/key/key_cancel_deletion.go similarity index 72% rename from cmd/kms/key/key_cancel_delete.go rename to cmd/kms/key/key_cancel_deletion.go index 111172aa6..3d7cdef5d 100644 --- a/cmd/kms/key/key_cancel_delete.go +++ b/cmd/kms/key/key_cancel_deletion.go @@ -7,32 +7,32 @@ import ( "github.com/spf13/cobra" ) -type keyCancelDeleteCmd struct { +type keyCancelDeletionCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` - _ bool `cli-cmd:"cancel-delete"` + _ bool `cli-cmd:"cancel-deletion"` Key string `cli-arg:"#" cli-usage:"ID"` Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } -func (c *keyCancelDeleteCmd) CmdAliases() []string { return nil } +func (c *keyCancelDeletionCmd) CmdAliases() []string { return nil } -func (c *keyCancelDeleteCmd) CmdShort() string { +func (c *keyCancelDeletionCmd) CmdShort() string { return "Cancels the scheduled deletion of a KMS key." } -func (c *keyCancelDeleteCmd) CmdLong() string { +func (c *keyCancelDeletionCmd) CmdLong() string { return "Cancels the scheduled deletion of a KMS key." } -func (c *keyCancelDeleteCmd) CmdPreRun(cmd *cobra.Command, args []string) error { +func (c *keyCancelDeletionCmd) CmdPreRun(cmd *cobra.Command, args []string) error { exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *keyCancelDeleteCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *keyCancelDeletionCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) if err != nil { @@ -55,7 +55,7 @@ func (c *keyCancelDeleteCmd) CmdRun(_ *cobra.Command, _ []string) error { } func init() { - cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyCancelDeleteCmd{ + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyCancelDeletionCmd{ CliCommandSettings: exocmd.DefaultCLICmdSettings(), })) } diff --git a/cmd/kms/rotation/rotation_disable.go b/cmd/kms/key/key_rotation_disable.go similarity index 63% rename from cmd/kms/rotation/rotation_disable.go rename to cmd/kms/key/key_rotation_disable.go index 9736cbc89..28b4218e5 100644 --- a/cmd/kms/rotation/rotation_disable.go +++ b/cmd/kms/key/key_rotation_disable.go @@ -1,39 +1,38 @@ -package rotation +package key import ( exocmd "github.com/exoscale/cli/cmd" - "github.com/exoscale/cli/cmd/kms/key" "github.com/exoscale/cli/pkg/globalstate" v3 "github.com/exoscale/egoscale/v3" "github.com/spf13/cobra" ) -type rotationDisableCmd struct { +type keyRotationDisableCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` - _ bool `cli-cmd:"disable"` + _ bool `cli-cmd:"disable-rotation"` Key string `cli-arg:"#" cli-usage:"ID"` Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } -func (c *rotationDisableCmd) CmdAliases() []string { return nil } +func (c *keyRotationDisableCmd) CmdAliases() []string { return nil } -func (c *rotationDisableCmd) CmdShort() string { +func (c *keyRotationDisableCmd) CmdShort() string { return "Disable KMS key auto rotation." } -func (c *rotationDisableCmd) CmdLong() string { +func (c *keyRotationDisableCmd) CmdLong() string { return "Disable KMS key auto rotation." } -func (c *rotationDisableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { +func (c *keyRotationDisableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *rotationDisableCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *keyRotationDisableCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) if err != nil { @@ -45,7 +44,7 @@ func (c *rotationDisableCmd) CmdRun(_ *cobra.Command, _ []string) error { } if !globalstate.Quiet { - return (&key.KeyShowCmd{ + return (&KeyShowCmd{ CliCommandSettings: c.CliCommandSettings, Key: c.Key, }).CmdRun(nil, nil) @@ -55,7 +54,7 @@ func (c *rotationDisableCmd) CmdRun(_ *cobra.Command, _ []string) error { } func init() { - cobra.CheckErr(exocmd.RegisterCLICommand(rotationCmd, &rotationDisableCmd{ + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyRotationDisableCmd{ CliCommandSettings: exocmd.DefaultCLICmdSettings(), })) } diff --git a/cmd/kms/rotation/rotation_enable.go b/cmd/kms/key/key_rotation_enable.go similarity index 71% rename from cmd/kms/rotation/rotation_enable.go rename to cmd/kms/key/key_rotation_enable.go index b26f50d95..7bb90f578 100644 --- a/cmd/kms/rotation/rotation_enable.go +++ b/cmd/kms/key/key_rotation_enable.go @@ -1,19 +1,18 @@ -package rotation +package key import ( "strconv" exocmd "github.com/exoscale/cli/cmd" - "github.com/exoscale/cli/cmd/kms/key" "github.com/exoscale/cli/pkg/globalstate" v3 "github.com/exoscale/egoscale/v3" "github.com/spf13/cobra" ) -type rotationEnableCmd struct { +type keyRotationEnableCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` - _ bool `cli-cmd:"enable"` + _ bool `cli-cmd:"enable-rotation"` Key string `cli-arg:"#" cli-usage:"ID"` @@ -21,22 +20,22 @@ type rotationEnableCmd struct { Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } -func (c *rotationEnableCmd) CmdAliases() []string { return nil } +func (c *keyRotationEnableCmd) CmdAliases() []string { return nil } -func (c *rotationEnableCmd) CmdShort() string { +func (c *keyRotationEnableCmd) CmdShort() string { return "Enable KMS key auto rotation." } -func (c *rotationEnableCmd) CmdLong() string { +func (c *keyRotationEnableCmd) CmdLong() string { return "Enable KMS key auto rotation." } -func (c *rotationEnableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { +func (c *keyRotationEnableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *rotationEnableCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *keyRotationEnableCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) if err != nil { @@ -59,7 +58,7 @@ func (c *rotationEnableCmd) CmdRun(_ *cobra.Command, _ []string) error { } if !globalstate.Quiet { - return (&key.KeyShowCmd{ + return (&KeyShowCmd{ CliCommandSettings: c.CliCommandSettings, Key: c.Key, }).CmdRun(nil, nil) @@ -69,7 +68,7 @@ func (c *rotationEnableCmd) CmdRun(_ *cobra.Command, _ []string) error { } func init() { - cobra.CheckErr(exocmd.RegisterCLICommand(rotationCmd, &rotationEnableCmd{ + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyRotationEnableCmd{ CliCommandSettings: exocmd.DefaultCLICmdSettings(), })) } diff --git a/cmd/kms/rotation/rotation_list.go b/cmd/kms/key/key_rotation_list.go similarity index 63% rename from cmd/kms/rotation/rotation_list.go rename to cmd/kms/key/key_rotation_list.go index acd7f9969..e95bf3890 100644 --- a/cmd/kms/rotation/rotation_list.go +++ b/cmd/kms/key/key_rotation_list.go @@ -1,4 +1,4 @@ -package rotation +package key import ( "os" @@ -12,13 +12,13 @@ import ( "github.com/spf13/cobra" ) -type rotationListOutput struct { +type keyRotationListOutput struct { v3.ListKmsKeyRotationsResponse } -func (o *rotationListOutput) ToJSON() { output.JSON(o) } -func (o *rotationListOutput) ToText() { output.Text(o) } -func (o *rotationListOutput) ToTable() { +func (o *keyRotationListOutput) ToJSON() { output.JSON(o) } +func (o *keyRotationListOutput) ToText() { output.Text(o) } +func (o *keyRotationListOutput) ToTable() { t := table.NewTable(os.Stdout) defer t.Render() @@ -37,32 +37,32 @@ func (o *rotationListOutput) ToTable() { } } -type rotationListCmd struct { +type keyRotationListCmd struct { exocmd.CliCommandSettings `cli-cmd:"-"` - _ bool `cli-cmd:"list"` + _ bool `cli-cmd:"list-rotation"` Key string `cli-arg:"#" cli-usage:"ID"` Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"` } -func (c *rotationListCmd) CmdAliases() []string { return exocmd.GListAlias } +func (c *keyRotationListCmd) CmdAliases() []string { return exocmd.GListAlias } -func (c *rotationListCmd) CmdShort() string { +func (c *keyRotationListCmd) CmdShort() string { return "List KMS key rotations." } -func (c *rotationListCmd) CmdLong() string { +func (c *keyRotationListCmd) CmdLong() string { return "List KMS key rotations." } -func (c *rotationListCmd) CmdPreRun(cmd *cobra.Command, args []string) error { +func (c *keyRotationListCmd) CmdPreRun(cmd *cobra.Command, args []string) error { exocmd.CmdSetZoneFlagFromDefault(cmd) return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *rotationListCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *keyRotationListCmd) CmdRun(_ *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) @@ -74,13 +74,13 @@ func (c *rotationListCmd) CmdRun(_ *cobra.Command, _ []string) error { if err != nil { return err } - out := rotationListOutput{*resp} + out := keyRotationListOutput{*resp} return c.OutputFunc(&out, nil) } func init() { - cobra.CheckErr(exocmd.RegisterCLICommand(rotationCmd, &rotationListCmd{ + cobra.CheckErr(exocmd.RegisterCLICommand(keyCmd, &keyRotationListCmd{ CliCommandSettings: exocmd.DefaultCLICmdSettings(), })) } diff --git a/cmd/kms/rotation/rotation.go b/cmd/kms/rotation/rotation.go deleted file mode 100644 index 368e546ea..000000000 --- a/cmd/kms/rotation/rotation.go +++ /dev/null @@ -1,15 +0,0 @@ -package rotation - -import ( - "github.com/exoscale/cli/cmd/kms" - "github.com/spf13/cobra" -) - -var rotationCmd = &cobra.Command{ - Use: "rotation", - Short: "KMS key rotation", -} - -func init() { - kms.KMSCmd.AddCommand(rotationCmd) -} diff --git a/cmd/subcommands/init.go b/cmd/subcommands/init.go index d1e3921ba..d54545275 100644 --- a/cmd/subcommands/init.go +++ b/cmd/subcommands/init.go @@ -27,7 +27,7 @@ import ( _ "github.com/exoscale/cli/cmd/dns" _ "github.com/exoscale/cli/cmd/iam" _ "github.com/exoscale/cli/cmd/kms" + _ "github.com/exoscale/cli/cmd/kms/crypto" _ "github.com/exoscale/cli/cmd/kms/key" - _ "github.com/exoscale/cli/cmd/kms/rotation" _ "github.com/exoscale/cli/cmd/storage" ) From 038fb69094053248e748d98357978d2462b1951b Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Fri, 29 May 2026 17:24:22 +0200 Subject: [PATCH 24/26] same description for commands as api doc --- cmd/kms/crypto/crypto_decrypt.go | 4 ++-- cmd/kms/crypto/crypto_encrypt.go | 4 ++-- cmd/kms/crypto/crypto_generate_data_key.go | 4 ++-- cmd/kms/crypto/crypto_reencrypt.go | 4 ++-- cmd/kms/key/key_cancel_deletion.go | 4 ++-- cmd/kms/key/key_create.go | 4 ++-- cmd/kms/key/key_disable.go | 4 ++-- cmd/kms/key/key_enable.go | 4 ++-- cmd/kms/key/key_list.go | 4 ++-- cmd/kms/key/key_replicate.go | 4 ++-- cmd/kms/key/key_rotate.go | 4 ++-- cmd/kms/key/key_rotation_disable.go | 4 ++-- cmd/kms/key/key_rotation_enable.go | 4 ++-- cmd/kms/key/key_rotation_list.go | 4 ++-- cmd/kms/key/key_schedule_deletion.go | 4 ++-- cmd/kms/key/key_show.go | 4 ++-- 16 files changed, 32 insertions(+), 32 deletions(-) diff --git a/cmd/kms/crypto/crypto_decrypt.go b/cmd/kms/crypto/crypto_decrypt.go index d10db3ae1..90f7f44f2 100644 --- a/cmd/kms/crypto/crypto_decrypt.go +++ b/cmd/kms/crypto/crypto_decrypt.go @@ -46,11 +46,11 @@ type cryptoDecryptCmd struct { func (c *cryptoDecryptCmd) CmdAliases() []string { return nil } func (c *cryptoDecryptCmd) CmdShort() string { - return "Decrypts data using a KMS key." + return "Decrypt a ciphertext." } func (c *cryptoDecryptCmd) CmdLong() string { - return "Decrypts data using a KMS key." + return "Decrypt a ciphertext." } func (c *cryptoDecryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/crypto/crypto_encrypt.go b/cmd/kms/crypto/crypto_encrypt.go index d0f0e01bf..6e2493fd9 100644 --- a/cmd/kms/crypto/crypto_encrypt.go +++ b/cmd/kms/crypto/crypto_encrypt.go @@ -46,11 +46,11 @@ type cryptoEncryptCmd struct { func (c *cryptoEncryptCmd) CmdAliases() []string { return nil } func (c *cryptoEncryptCmd) CmdShort() string { - return "Encrypts data using a KMS key." + return "Encrypt a plaintext." } func (c *cryptoEncryptCmd) CmdLong() string { - return "Encrypts data using a KMS key." + return "Encrypt a plaintext." } func (c *cryptoEncryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/crypto/crypto_generate_data_key.go b/cmd/kms/crypto/crypto_generate_data_key.go index 5225b137d..5f5150867 100644 --- a/cmd/kms/crypto/crypto_generate_data_key.go +++ b/cmd/kms/crypto/crypto_generate_data_key.go @@ -51,11 +51,11 @@ type cryptoGenerateDataKeyCmd struct { func (c *cryptoGenerateDataKeyCmd) CmdAliases() []string { return nil } func (c *cryptoGenerateDataKeyCmd) CmdShort() string { - return "Generates a data encryption key using a KMS key." + return "Generate a Data Encryption Key from a given KMS Key." } func (c *cryptoGenerateDataKeyCmd) CmdLong() string { - return "Generates a data encryption key using a KMS key." + return "Generate a Data Encryption Key from a given KMS Key." } func (c *cryptoGenerateDataKeyCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/crypto/crypto_reencrypt.go b/cmd/kms/crypto/crypto_reencrypt.go index b62924183..7df7e2ad2 100644 --- a/cmd/kms/crypto/crypto_reencrypt.go +++ b/cmd/kms/crypto/crypto_reencrypt.go @@ -26,11 +26,11 @@ type cryptoReencryptCmd struct { func (c *cryptoReencryptCmd) CmdAliases() []string { return nil } func (c *cryptoReencryptCmd) CmdShort() string { - return "Re-encrypts data from a KMS key to another KMS key." + return "Decrypts and encrypts an exisiting ciphertext with newest key material or a different KMS key." } func (c *cryptoReencryptCmd) CmdLong() string { - return "Re-encrypts data from a KMS key to another KMS key." + return "Decrypts an existing ciphertext using its original key material and re-encrypts the underlying plaintext using a specified KMS key or the latest key material of the same KMS Key." } func (c *cryptoReencryptCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/key/key_cancel_deletion.go b/cmd/kms/key/key_cancel_deletion.go index 3d7cdef5d..3e512f1a7 100644 --- a/cmd/kms/key/key_cancel_deletion.go +++ b/cmd/kms/key/key_cancel_deletion.go @@ -20,11 +20,11 @@ type keyCancelDeletionCmd struct { func (c *keyCancelDeletionCmd) CmdAliases() []string { return nil } func (c *keyCancelDeletionCmd) CmdShort() string { - return "Cancels the scheduled deletion of a KMS key." + return "Cancel the scheduled deletion of a KMS Key." } func (c *keyCancelDeletionCmd) CmdLong() string { - return "Cancels the scheduled deletion of a KMS key." + return "Cancel the scheduled deletion of a KMS Key." } func (c *keyCancelDeletionCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/key/key_create.go b/cmd/kms/key/key_create.go index bf81c88d9..83f91f984 100644 --- a/cmd/kms/key/key_create.go +++ b/cmd/kms/key/key_create.go @@ -23,11 +23,11 @@ type keyCreateCmd struct { func (c *keyCreateCmd) CmdAliases() []string { return nil } func (c *keyCreateCmd) CmdShort() string { - return "Creates a new KMS key." + return "Create a KMS Key in a given zone with a given name." } func (c *keyCreateCmd) CmdLong() string { - return "Creates a new KMS key." + return "Create a KMS Key in a given zone with a given name." } func (c *keyCreateCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/key/key_disable.go b/cmd/kms/key/key_disable.go index 059dfbf29..edce33b55 100644 --- a/cmd/kms/key/key_disable.go +++ b/cmd/kms/key/key_disable.go @@ -20,11 +20,11 @@ type keyDisableCmd struct { func (c *keyDisableCmd) CmdAliases() []string { return nil } func (c *keyDisableCmd) CmdShort() string { - return "Enables a KMS key." + return "Disables a KMS Key." } func (c *keyDisableCmd) CmdLong() string { - return "Enables a KMS key." + return "Disables a KMS Key." } func (c *keyDisableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/key/key_enable.go b/cmd/kms/key/key_enable.go index 7a4ad5065..9d4fed4e8 100644 --- a/cmd/kms/key/key_enable.go +++ b/cmd/kms/key/key_enable.go @@ -20,11 +20,11 @@ type keyEnableCmd struct { func (c *keyEnableCmd) CmdAliases() []string { return nil } func (c *keyEnableCmd) CmdShort() string { - return "Enables a KMS key." + return "Enables a KMS Key." } func (c *keyEnableCmd) CmdLong() string { - return "Enables a KMS key." + return "Enables a KMS Key." } func (c *keyEnableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/key/key_list.go b/cmd/kms/key/key_list.go index a648896e3..2b92c35de 100644 --- a/cmd/kms/key/key_list.go +++ b/cmd/kms/key/key_list.go @@ -57,11 +57,11 @@ type keyListCmd struct { func (c *keyListCmd) CmdAliases() []string { return exocmd.GListAlias } func (c *keyListCmd) CmdShort() string { - return "List KMS keys." + return "List KMS Keys details for an organization in a given zone." } func (c *keyListCmd) CmdLong() string { - return "List KMS keys." + return "List KMS Keys details for an organization in a given zone." } func (c *keyListCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/key/key_replicate.go b/cmd/kms/key/key_replicate.go index 54894817f..79e8e4e19 100644 --- a/cmd/kms/key/key_replicate.go +++ b/cmd/kms/key/key_replicate.go @@ -21,11 +21,11 @@ type keyReplicateCmd struct { func (c *keyReplicateCmd) CmdAliases() []string { return nil } func (c *keyReplicateCmd) CmdShort() string { - return "Replicate a KMS key to another zone." + return "Replicate a KMS key to a target zone." } func (c *keyReplicateCmd) CmdLong() string { - return "Replicate a KMS key to another zone." + return "Replicate a KMS key to a target zone." } func (c *keyReplicateCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/key/key_rotate.go b/cmd/kms/key/key_rotate.go index ad3c80034..509bcb0ea 100644 --- a/cmd/kms/key/key_rotate.go +++ b/cmd/kms/key/key_rotate.go @@ -20,11 +20,11 @@ type keyRotateCmd struct { func (c *keyRotateCmd) CmdAliases() []string { return nil } func (c *keyRotateCmd) CmdShort() string { - return "Rotates a KMS key." + return "Perform a manual rotation of the key material for a symmetric key." } func (c *keyRotateCmd) CmdLong() string { - return "Rotates a KMS key." + return "Perform a manual rotation of the key material for a symmetric key." } func (c *keyRotateCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/key/key_rotation_disable.go b/cmd/kms/key/key_rotation_disable.go index 28b4218e5..8166bb4c0 100644 --- a/cmd/kms/key/key_rotation_disable.go +++ b/cmd/kms/key/key_rotation_disable.go @@ -20,11 +20,11 @@ type keyRotationDisableCmd struct { func (c *keyRotationDisableCmd) CmdAliases() []string { return nil } func (c *keyRotationDisableCmd) CmdShort() string { - return "Disable KMS key auto rotation." + return "Disable the periodic rotation of a KMS Key." } func (c *keyRotationDisableCmd) CmdLong() string { - return "Disable KMS key auto rotation." + return "Disable the periodic rotation of a KMS Key." } func (c *keyRotationDisableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/key/key_rotation_enable.go b/cmd/kms/key/key_rotation_enable.go index 7bb90f578..ca67840d2 100644 --- a/cmd/kms/key/key_rotation_enable.go +++ b/cmd/kms/key/key_rotation_enable.go @@ -23,11 +23,11 @@ type keyRotationEnableCmd struct { func (c *keyRotationEnableCmd) CmdAliases() []string { return nil } func (c *keyRotationEnableCmd) CmdShort() string { - return "Enable KMS key auto rotation." + return "Enable the periodic rotation of a KMS Key." } func (c *keyRotationEnableCmd) CmdLong() string { - return "Enable KMS key auto rotation." + return "Enable the periodic rotation of a KMS Key." } func (c *keyRotationEnableCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/key/key_rotation_list.go b/cmd/kms/key/key_rotation_list.go index e95bf3890..94621b5ad 100644 --- a/cmd/kms/key/key_rotation_list.go +++ b/cmd/kms/key/key_rotation_list.go @@ -50,11 +50,11 @@ type keyRotationListCmd struct { func (c *keyRotationListCmd) CmdAliases() []string { return exocmd.GListAlias } func (c *keyRotationListCmd) CmdShort() string { - return "List KMS key rotations." + return "List all the key material versions of a KMS Key." } func (c *keyRotationListCmd) CmdLong() string { - return "List KMS key rotations." + return "List all the key material versions of a KMS Key." } func (c *keyRotationListCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/key/key_schedule_deletion.go b/cmd/kms/key/key_schedule_deletion.go index ff115610c..4256fdedf 100644 --- a/cmd/kms/key/key_schedule_deletion.go +++ b/cmd/kms/key/key_schedule_deletion.go @@ -24,11 +24,11 @@ type keyScheduleDeletionCmd struct { func (c *keyScheduleDeletionCmd) CmdAliases() []string { return nil } func (c *keyScheduleDeletionCmd) CmdShort() string { - return "Schedules deletion of a KMS key." + return "Schedule a KMS key for deletion after a delay." } func (c *keyScheduleDeletionCmd) CmdLong() string { - return "Schedules deletion of a KMS key." + return "Schedule a KMS key for deletion after a delay." } func (c *keyScheduleDeletionCmd) CmdPreRun(cmd *cobra.Command, args []string) error { diff --git a/cmd/kms/key/key_show.go b/cmd/kms/key/key_show.go index 28cac50f8..4755321e8 100644 --- a/cmd/kms/key/key_show.go +++ b/cmd/kms/key/key_show.go @@ -43,11 +43,11 @@ type KeyShowCmd struct { func (c *KeyShowCmd) CmdAliases() []string { return exocmd.GShowAlias } func (c *KeyShowCmd) CmdShort() string { - return "Shows details of a KMS key." + return "Retrieve KMS Key details." } func (c *KeyShowCmd) CmdLong() string { - return "Shows details of a KMS key." + return "Retrieve KMS Key details." } func (c *KeyShowCmd) CmdPreRun(cmd *cobra.Command, args []string) error { From ac6c904be8d66f3cc2887a0a030aeae520ed3903 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Wed, 17 Jun 2026 15:02:37 +0200 Subject: [PATCH 25/26] only set fields in request if provided --- cmd/kms/key/key_create.go | 19 +- cmd/kms/key/key_rotation_enable.go | 8 +- cmd/kms/key/key_schedule_deletion.go | 15 +- go.mod | 2 +- go.sum | 4 +- .../exoscale/egoscale/v3/operations.go | 685 ++++++++++++++---- .../exoscale/egoscale/v3/schemas.go | 415 +++++++++-- .../exoscale/egoscale/v3/version.go | 2 +- vendor/modules.txt | 4 +- 9 files changed, 916 insertions(+), 238 deletions(-) diff --git a/cmd/kms/key/key_create.go b/cmd/kms/key/key_create.go index 83f91f984..b2f6af2cb 100644 --- a/cmd/kms/key/key_create.go +++ b/cmd/kms/key/key_create.go @@ -35,7 +35,7 @@ func (c *keyCreateCmd) CmdPreRun(cmd *cobra.Command, args []string) error { return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *keyCreateCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *keyCreateCmd) CmdRun(cmd *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) if err != nil { @@ -43,10 +43,19 @@ func (c *keyCreateCmd) CmdRun(_ *cobra.Command, _ []string) error { } req := v3.CreateKmsKeyRequest{ - Name: c.Name, - Description: c.Description, - Usage: v3.CreateKmsKeyRequestUsage(c.Usage), - MultiZone: &c.Multizone, + Name: c.Name, + } + + if cmd.Flags().Changed("usage") { + req.Usage = v3.CreateKmsKeyRequestUsage(c.Usage) + } + + if cmd.Flags().Changed("description") { + req.Description = c.Description + } + + if cmd.Flags().Changed("multizone") { + req.MultiZone = &c.Multizone } resp, err := client.CreateKmsKey(ctx, req) diff --git a/cmd/kms/key/key_rotation_enable.go b/cmd/kms/key/key_rotation_enable.go index ca67840d2..012a4f97f 100644 --- a/cmd/kms/key/key_rotation_enable.go +++ b/cmd/kms/key/key_rotation_enable.go @@ -35,7 +35,7 @@ func (c *keyRotationEnableCmd) CmdPreRun(cmd *cobra.Command, args []string) erro return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *keyRotationEnableCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *keyRotationEnableCmd) CmdRun(cmd *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) if err != nil { @@ -43,14 +43,12 @@ func (c *keyRotationEnableCmd) CmdRun(_ *cobra.Command, _ []string) error { } var req v3.EnableKmsKeyRotationRequest - if c.RotationPeriod != "" { + if cmd.Flags().Changed("rotation-period") { n, err := strconv.Atoi(c.RotationPeriod) if err != nil { return err } - req = v3.EnableKmsKeyRotationRequest{ - RotationPeriod: n, - } + req.RotationPeriod = n } if _, err := client.EnableKmsKeyRotation(ctx, v3.UUID(c.Key), req); err != nil { diff --git a/cmd/kms/key/key_schedule_deletion.go b/cmd/kms/key/key_schedule_deletion.go index 4256fdedf..5bb9394e8 100644 --- a/cmd/kms/key/key_schedule_deletion.go +++ b/cmd/kms/key/key_schedule_deletion.go @@ -1,7 +1,6 @@ package key import ( - "fmt" "strconv" exocmd "github.com/exoscale/cli/cmd" @@ -36,24 +35,20 @@ func (c *keyScheduleDeletionCmd) CmdPreRun(cmd *cobra.Command, args []string) er return exocmd.CliCommandDefaultPreRun(c, cmd, args) } -func (c *keyScheduleDeletionCmd) CmdRun(_ *cobra.Command, _ []string) error { +func (c *keyScheduleDeletionCmd) CmdRun(cmd *cobra.Command, _ []string) error { ctx := exocmd.GContext client, err := exocmd.SwitchClientZoneV3(ctx, globalstate.EgoscaleV3Client, c.Zone) if err != nil { return err } - var delayDays int - if c.DelayDays != "" { + var req v3.ScheduleKmsKeyDeletionRequest + if cmd.Flags().Changed("delay-days") { n, err := strconv.Atoi(c.DelayDays) if err != nil { - return fmt.Errorf("invalid delay days: %v", err) + return err } - delayDays = n - } - - req := v3.ScheduleKmsKeyDeletionRequest{ - DelayDays: delayDays, + req.DelayDays = n } _, err = client.ScheduleKmsKeyDeletion(ctx, v3.UUID(c.Key), req) diff --git a/go.mod b/go.mod index bd99f2e61..47c4760f4 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/s3 v1.2.0 github.com/aws/smithy-go v1.1.0 github.com/dustin/go-humanize v1.0.1 - github.com/exoscale/egoscale/v3 v3.1.36-0.20260424083744-33446130ebd9 + github.com/exoscale/egoscale/v3 v3.1.38 github.com/exoscale/openapi-cli-generator v1.2.0 github.com/fatih/camelcase v1.0.0 github.com/hashicorp/go-multierror v1.1.1 diff --git a/go.sum b/go.sum index 7591ae72c..984c81abe 100644 --- a/go.sum +++ b/go.sum @@ -161,8 +161,8 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= -github.com/exoscale/egoscale/v3 v3.1.36-0.20260424083744-33446130ebd9 h1:3fQP3zqWwhhiWflStd1Ns1DPXx2yxpN0fhlqEZ/vYgI= -github.com/exoscale/egoscale/v3 v3.1.36-0.20260424083744-33446130ebd9/go.mod h1:/1RTNibUdltIdzBbFxMMewNAkB6KKdxzRE/Icu8K5RU= +github.com/exoscale/egoscale/v3 v3.1.38 h1:Xu/eZa8gGgBcS3eJ05PTOGR6/CvGy4I5z19LGyYyxOg= +github.com/exoscale/egoscale/v3 v3.1.38/go.mod h1:DUTgeubl5msPAo3SKFed04AxNhyTNOrCTJHZDRYLR10= github.com/exoscale/openapi-cli-generator v1.2.0 h1:xgTff1bInBP+JZCauD7Jq9GNBFoKK31Cnv5FIAcxtrk= github.com/exoscale/openapi-cli-generator v1.2.0/go.mod h1:TZBnbT7f3hJ5ImyUphJwRM+X5xF/zCQZ6o8a42gQeTs= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= diff --git a/vendor/github.com/exoscale/egoscale/v3/operations.go b/vendor/github.com/exoscale/egoscale/v3/operations.go index 40661f6be..043c873bb 100644 --- a/vendor/github.com/exoscale/egoscale/v3/operations.go +++ b/vendor/github.com/exoscale/egoscale/v3/operations.go @@ -12,9 +12,9 @@ import ( "time" ) -// FindAIAPIKey attempts to find an AIAPIKey by nameOrID. -func (l ListAIAPIKeysResponse) FindAIAPIKey(nameOrID string) (AIAPIKey, error) { - var result []AIAPIKey +// FindListAIAPIKeysResponseEntry attempts to find an ListAIAPIKeysResponseEntry by nameOrID. +func (l ListAIAPIKeysResponse) FindListAIAPIKeysResponseEntry(nameOrID string) (ListAIAPIKeysResponseEntry, error) { + var result []ListAIAPIKeysResponseEntry for i, elem := range l.AIAPIKeys { if string(elem.Name) == nameOrID || string(elem.ID) == nameOrID { result = append(result, l.AIAPIKeys[i]) @@ -25,15 +25,15 @@ func (l ListAIAPIKeysResponse) FindAIAPIKey(nameOrID string) (AIAPIKey, error) { } if len(result) > 1 { - return AIAPIKey{}, fmt.Errorf("%q too many found in ListAIAPIKeysResponse: %w", nameOrID, ErrConflict) + return ListAIAPIKeysResponseEntry{}, fmt.Errorf("%q too many found in ListAIAPIKeysResponse: %w", nameOrID, ErrConflict) } - return AIAPIKey{}, fmt.Errorf("%q not found in ListAIAPIKeysResponse: %w", nameOrID, ErrNotFound) + return ListAIAPIKeysResponseEntry{}, fmt.Errorf("%q not found in ListAIAPIKeysResponse: %w", nameOrID, ErrNotFound) } // List AI API keys for an organization func (c Client) ListAIAPIKeys(ctx context.Context) (*ListAIAPIKeysResponse, error) { - path := "/ai/ai-api-key" + path := "/ai/api-key" request, err := http.NewRequestWithContext(ctx, "GET", c.serverEndpoint+path, nil) if err != nil { @@ -76,8 +76,8 @@ func (c Client) ListAIAPIKeys(ctx context.Context) (*ListAIAPIKeysResponse, erro } // Create a new AI API key -func (c Client) CreateAIAPIKey(ctx context.Context, req CreateAIAPIKeyRequest) (*AIAPIKeyWithValue, error) { - path := "/ai/ai-api-key" +func (c Client) CreateAIAPIKey(ctx context.Context, req CreateAIAPIKeyRequest) (*CreateAIAPIKeyResponse, error) { + path := "/ai/api-key" body, err := prepareJSONBody(req) if err != nil { @@ -118,7 +118,7 @@ func (c Client) CreateAIAPIKey(ctx context.Context, req CreateAIAPIKeyRequest) ( return nil, fmt.Errorf("CreateAIAPIKey: http response: %w", err) } - bodyresp := new(AIAPIKeyWithValue) + bodyresp := new(CreateAIAPIKeyResponse) if err := prepareJSONResponse(response, bodyresp); err != nil { return nil, fmt.Errorf("CreateAIAPIKey: prepare Json response: %w", err) } @@ -126,36 +126,32 @@ func (c Client) CreateAIAPIKey(ctx context.Context, req CreateAIAPIKeyRequest) ( return bodyresp, nil } -type DeleteAIAPIKeyResponse struct { - Deleted *bool `json:"deleted" validate:"required"` -} - -// Delete AI API key -func (c Client) DeleteAIAPIKey(ctx context.Context, id UUID) (*DeleteAIAPIKeyResponse, error) { - path := fmt.Sprintf("/ai/ai-api-key/%v", id) +// Get AI API key metadata +func (c Client) GetAIAPIKey(ctx context.Context, id UUID) (*GetAIAPIKeyResponse, error) { + path := fmt.Sprintf("/ai/api-key/%v", id) - request, err := http.NewRequestWithContext(ctx, "DELETE", c.serverEndpoint+path, nil) + request, err := http.NewRequestWithContext(ctx, "GET", c.serverEndpoint+path, nil) if err != nil { - return nil, fmt.Errorf("DeleteAIAPIKey: new request: %w", err) + return nil, fmt.Errorf("GetAIAPIKey: new request: %w", err) } request.Header.Add("User-Agent", c.getUserAgent()) if err := c.executeRequestInterceptors(ctx, request); err != nil { - return nil, fmt.Errorf("DeleteAIAPIKey: execute request editors: %w", err) + return nil, fmt.Errorf("GetAIAPIKey: execute request editors: %w", err) } if err := c.signRequest(request); err != nil { - return nil, fmt.Errorf("DeleteAIAPIKey: sign request: %w", err) + return nil, fmt.Errorf("GetAIAPIKey: sign request: %w", err) } if c.trace { - dumpRequest(request, "delete-ai-api-key") + dumpRequest(request, "get-ai-api-key") } response, err := c.httpClient.Do(request) if err != nil { - return nil, fmt.Errorf("DeleteAIAPIKey: http client do: %w", err) + return nil, fmt.Errorf("GetAIAPIKey: http client do: %w", err) } if c.trace { @@ -163,43 +159,50 @@ func (c Client) DeleteAIAPIKey(ctx context.Context, id UUID) (*DeleteAIAPIKeyRes } if err := handleHTTPErrorResp(response); err != nil { - return nil, fmt.Errorf("DeleteAIAPIKey: http response: %w", err) + return nil, fmt.Errorf("GetAIAPIKey: http response: %w", err) } - bodyresp := new(DeleteAIAPIKeyResponse) + bodyresp := new(GetAIAPIKeyResponse) if err := prepareJSONResponse(response, bodyresp); err != nil { - return nil, fmt.Errorf("DeleteAIAPIKey: prepare Json response: %w", err) + return nil, fmt.Errorf("GetAIAPIKey: prepare Json response: %w", err) } return bodyresp, nil } -// Get AI API key metadata -func (c Client) GetAIAPIKey(ctx context.Context, id UUID) (*AIAPIKey, error) { - path := fmt.Sprintf("/ai/ai-api-key/%v", id) +// Update AI API key name and/or scope +func (c Client) UpdateAIAPIKey(ctx context.Context, id UUID, req UpdateAIAPIKeyRequest) (*UpdateAIAPIKeyResponse, error) { + path := fmt.Sprintf("/ai/api-key/%v", id) - request, err := http.NewRequestWithContext(ctx, "GET", c.serverEndpoint+path, nil) + body, err := prepareJSONBody(req) if err != nil { - return nil, fmt.Errorf("GetAIAPIKey: new request: %w", err) + return nil, fmt.Errorf("UpdateAIAPIKey: prepare Json body: %w", err) + } + + request, err := http.NewRequestWithContext(ctx, "PATCH", c.serverEndpoint+path, body) + if err != nil { + return nil, fmt.Errorf("UpdateAIAPIKey: new request: %w", err) } request.Header.Add("User-Agent", c.getUserAgent()) + request.Header.Add("Content-Type", "application/json") + if err := c.executeRequestInterceptors(ctx, request); err != nil { - return nil, fmt.Errorf("GetAIAPIKey: execute request editors: %w", err) + return nil, fmt.Errorf("UpdateAIAPIKey: execute request editors: %w", err) } if err := c.signRequest(request); err != nil { - return nil, fmt.Errorf("GetAIAPIKey: sign request: %w", err) + return nil, fmt.Errorf("UpdateAIAPIKey: sign request: %w", err) } if c.trace { - dumpRequest(request, "get-ai-api-key") + dumpRequest(request, "update-ai-api-key") } response, err := c.httpClient.Do(request) if err != nil { - return nil, fmt.Errorf("GetAIAPIKey: http client do: %w", err) + return nil, fmt.Errorf("UpdateAIAPIKey: http client do: %w", err) } if c.trace { @@ -207,50 +210,43 @@ func (c Client) GetAIAPIKey(ctx context.Context, id UUID) (*AIAPIKey, error) { } if err := handleHTTPErrorResp(response); err != nil { - return nil, fmt.Errorf("GetAIAPIKey: http response: %w", err) + return nil, fmt.Errorf("UpdateAIAPIKey: http response: %w", err) } - bodyresp := new(AIAPIKey) + bodyresp := new(UpdateAIAPIKeyResponse) if err := prepareJSONResponse(response, bodyresp); err != nil { - return nil, fmt.Errorf("GetAIAPIKey: prepare Json response: %w", err) + return nil, fmt.Errorf("UpdateAIAPIKey: prepare Json response: %w", err) } return bodyresp, nil } -// Update AI API key name and/or scope -func (c Client) UpdateAIAPIKey(ctx context.Context, id UUID, req UpdateAIAPIKeyRequest) (*AIAPIKey, error) { - path := fmt.Sprintf("/ai/ai-api-key/%v", id) +// Reveal AI API key plaintext value +func (c Client) RevealAIAPIKey(ctx context.Context, id UUID) (*RevealAIAPIKeyResponse, error) { + path := fmt.Sprintf("/ai/api-key/%v/reveal", id) - body, err := prepareJSONBody(req) + request, err := http.NewRequestWithContext(ctx, "GET", c.serverEndpoint+path, nil) if err != nil { - return nil, fmt.Errorf("UpdateAIAPIKey: prepare Json body: %w", err) - } - - request, err := http.NewRequestWithContext(ctx, "PATCH", c.serverEndpoint+path, body) - if err != nil { - return nil, fmt.Errorf("UpdateAIAPIKey: new request: %w", err) + return nil, fmt.Errorf("RevealAIAPIKey: new request: %w", err) } request.Header.Add("User-Agent", c.getUserAgent()) - request.Header.Add("Content-Type", "application/json") - if err := c.executeRequestInterceptors(ctx, request); err != nil { - return nil, fmt.Errorf("UpdateAIAPIKey: execute request editors: %w", err) + return nil, fmt.Errorf("RevealAIAPIKey: execute request editors: %w", err) } if err := c.signRequest(request); err != nil { - return nil, fmt.Errorf("UpdateAIAPIKey: sign request: %w", err) + return nil, fmt.Errorf("RevealAIAPIKey: sign request: %w", err) } if c.trace { - dumpRequest(request, "update-ai-api-key") + dumpRequest(request, "reveal-ai-api-key") } response, err := c.httpClient.Do(request) if err != nil { - return nil, fmt.Errorf("UpdateAIAPIKey: http client do: %w", err) + return nil, fmt.Errorf("RevealAIAPIKey: http client do: %w", err) } if c.trace { @@ -258,20 +254,20 @@ func (c Client) UpdateAIAPIKey(ctx context.Context, id UUID, req UpdateAIAPIKeyR } if err := handleHTTPErrorResp(response); err != nil { - return nil, fmt.Errorf("UpdateAIAPIKey: http response: %w", err) + return nil, fmt.Errorf("RevealAIAPIKey: http response: %w", err) } - bodyresp := new(AIAPIKey) + bodyresp := new(RevealAIAPIKeyResponse) if err := prepareJSONResponse(response, bodyresp); err != nil { - return nil, fmt.Errorf("UpdateAIAPIKey: prepare Json response: %w", err) + return nil, fmt.Errorf("RevealAIAPIKey: prepare Json response: %w", err) } return bodyresp, nil } // Rotate AI API key value -func (c Client) RotateAIAPIKey(ctx context.Context, id UUID) (*AIAPIKeyWithValue, error) { - path := fmt.Sprintf("/ai/ai-api-key/%v/rotate", id) +func (c Client) RotateAIAPIKey(ctx context.Context, id UUID) (*RotateAIAPIKeyResponse, error) { + path := fmt.Sprintf("/ai/api-key/%v/rotate", id) request, err := http.NewRequestWithContext(ctx, "POST", c.serverEndpoint+path, nil) if err != nil { @@ -305,7 +301,7 @@ func (c Client) RotateAIAPIKey(ctx context.Context, id UUID) (*AIAPIKeyWithValue return nil, fmt.Errorf("RotateAIAPIKey: http response: %w", err) } - bodyresp := new(AIAPIKeyWithValue) + bodyresp := new(RotateAIAPIKeyResponse) if err := prepareJSONResponse(response, bodyresp); err != nil { return nil, fmt.Errorf("RotateAIAPIKey: prepare Json response: %w", err) } @@ -1067,6 +1063,50 @@ func (c Client) GetModel(ctx context.Context, id UUID) (*GetModelResponse, error return bodyresp, nil } +// Get per-org Unit Of Measurement (UOM) consumption quota (UOM/min). Null means unlimited. UOM represents weighted units across different AI workloads (e.g., tokens for LLMs, minutes for TTS, pages for OCR). +func (c Client) GetUserOrgConsumptionQuota(ctx context.Context) (*OrgConsumptionQuotaResponse, error) { + path := "/ai/quota" + + request, err := http.NewRequestWithContext(ctx, "GET", c.serverEndpoint+path, nil) + if err != nil { + return nil, fmt.Errorf("GetUserOrgConsumptionQuota: new request: %w", err) + } + + request.Header.Add("User-Agent", c.getUserAgent()) + + if err := c.executeRequestInterceptors(ctx, request); err != nil { + return nil, fmt.Errorf("GetUserOrgConsumptionQuota: execute request editors: %w", err) + } + + if err := c.signRequest(request); err != nil { + return nil, fmt.Errorf("GetUserOrgConsumptionQuota: sign request: %w", err) + } + + if c.trace { + dumpRequest(request, "get-user-org-consumption-quota") + } + + response, err := c.httpClient.Do(request) + if err != nil { + return nil, fmt.Errorf("GetUserOrgConsumptionQuota: http client do: %w", err) + } + + if c.trace { + dumpResponse(response) + } + + if err := handleHTTPErrorResp(response); err != nil { + return nil, fmt.Errorf("GetUserOrgConsumptionQuota: http response: %w", err) + } + + bodyresp := new(OrgConsumptionQuotaResponse) + if err := prepareJSONResponse(response, bodyresp); err != nil { + return nil, fmt.Errorf("GetUserOrgConsumptionQuota: prepare Json response: %w", err) + } + + return bodyresp, nil +} + type ListAntiAffinityGroupsResponse struct { AntiAffinityGroups []AntiAffinityGroup `json:"anti-affinity-groups,omitempty"` } @@ -6864,6 +6904,8 @@ type CreateDBAASServicePGRequest struct { Migration *CreateDBAASServicePGRequestMigration `json:"migration,omitempty"` // postgresql.conf configuration values PGSettings *JSONSchemaPG `json:"pg-settings,omitempty"` + // System-wide settings for the pgaudit extension. + PgauditSettings *JSONSchemaPgaudit `json:"pgaudit-settings,omitempty"` // System-wide settings for pgbouncer. PgbouncerSettings *JSONSchemaPgbouncer `json:"pgbouncer-settings,omitempty"` // System-wide settings for pglookout. @@ -6992,6 +7034,8 @@ type UpdateDBAASServicePGRequest struct { Migration *UpdateDBAASServicePGRequestMigration `json:"migration,omitempty"` // postgresql.conf configuration values PGSettings *JSONSchemaPG `json:"pg-settings,omitempty"` + // System-wide settings for the pgaudit extension. + PgauditSettings *JSONSchemaPgaudit `json:"pgaudit-settings,omitempty"` // System-wide settings for pgbouncer. PgbouncerSettings *JSONSchemaPgbouncer `json:"pgbouncer-settings,omitempty"` // System-wide settings for pglookout. @@ -11115,8 +11159,8 @@ func (c Client) ListIAMRoles(ctx context.Context) (*ListIAMRolesResponse, error) } type CreateIAMRoleRequest struct { - // Policy - AssumeRolePolicy *IAMPolicy `json:"assume-role-policy,omitempty"` + // Assume Role Policy + AssumeRolePolicy *IAMAssumeRolePolicy `json:"assume-role-policy,omitempty"` // IAM Role description Description string `json:"description,omitempty" validate:"omitempty,gte=1,lte=255"` // Sets if the IAM Role Policy is editable or not (default: true). This setting cannot be changed after creation @@ -11272,6 +11316,8 @@ func (c Client) GetIAMRole(ctx context.Context, id UUID) (*IAMRole, error) { } type UpdateIAMRoleRequest struct { + // Assume Role Policy + AssumeRolePolicy *IAMAssumeRolePolicy `json:"assume-role-policy,omitempty"` // IAM Role description Description string `json:"description,omitempty" validate:"omitempty,gte=1,lte=255"` Labels Labels `json:"labels,omitempty"` @@ -11332,18 +11378,32 @@ func (c Client) UpdateIAMRole(ctx context.Context, id UUID, req UpdateIAMRoleReq return bodyresp, nil } -// Update IAM Assume role Policy -func (c Client) UpdateIAMRoleAssumePolicy(ctx context.Context, id UUID, req IAMPolicy) (*Operation, error) { - path := fmt.Sprintf("/iam-role/%v:assume-role-policy", id) +type AssumeIAMRoleResponse struct { + ExpiresAT string `json:"expires-at,omitempty"` + Key string `json:"key,omitempty"` + Name string `json:"name,omitempty"` + OrgID string `json:"org-id,omitempty"` + RoleID string `json:"role-id,omitempty"` + Secret string `json:"secret,omitempty"` +} + +type AssumeIAMRoleRequest struct { + // TTL in seconds for the generated access key (cannot exceed the max TTL defined in the targeted assume role) + Ttl int64 `json:"ttl" validate:"required,gt=0"` +} + +// [BETA] Request generation of key/secret that allow caller to assume target role +func (c Client) AssumeIAMRole(ctx context.Context, id UUID, req AssumeIAMRoleRequest) (*AssumeIAMRoleResponse, error) { + path := fmt.Sprintf("/iam-role/%v/assume", id) body, err := prepareJSONBody(req) if err != nil { - return nil, fmt.Errorf("UpdateIAMRoleAssumePolicy: prepare Json body: %w", err) + return nil, fmt.Errorf("AssumeIAMRole: prepare Json body: %w", err) } - request, err := http.NewRequestWithContext(ctx, "PUT", c.serverEndpoint+path, body) + request, err := http.NewRequestWithContext(ctx, "POST", c.serverEndpoint+path, body) if err != nil { - return nil, fmt.Errorf("UpdateIAMRoleAssumePolicy: new request: %w", err) + return nil, fmt.Errorf("AssumeIAMRole: new request: %w", err) } request.Header.Add("User-Agent", c.getUserAgent()) @@ -11351,20 +11411,20 @@ func (c Client) UpdateIAMRoleAssumePolicy(ctx context.Context, id UUID, req IAMP request.Header.Add("Content-Type", "application/json") if err := c.executeRequestInterceptors(ctx, request); err != nil { - return nil, fmt.Errorf("UpdateIAMRoleAssumePolicy: execute request editors: %w", err) + return nil, fmt.Errorf("AssumeIAMRole: execute request editors: %w", err) } if err := c.signRequest(request); err != nil { - return nil, fmt.Errorf("UpdateIAMRoleAssumePolicy: sign request: %w", err) + return nil, fmt.Errorf("AssumeIAMRole: sign request: %w", err) } if c.trace { - dumpRequest(request, "update-iam-role-assume-policy") + dumpRequest(request, "assume-iam-role") } response, err := c.httpClient.Do(request) if err != nil { - return nil, fmt.Errorf("UpdateIAMRoleAssumePolicy: http client do: %w", err) + return nil, fmt.Errorf("AssumeIAMRole: http client do: %w", err) } if c.trace { @@ -11372,12 +11432,12 @@ func (c Client) UpdateIAMRoleAssumePolicy(ctx context.Context, id UUID, req IAMP } if err := handleHTTPErrorResp(response); err != nil { - return nil, fmt.Errorf("UpdateIAMRoleAssumePolicy: http response: %w", err) + return nil, fmt.Errorf("AssumeIAMRole: http response: %w", err) } - bodyresp := new(Operation) + bodyresp := new(AssumeIAMRoleResponse) if err := prepareJSONResponse(response, bodyresp); err != nil { - return nil, fmt.Errorf("UpdateIAMRoleAssumePolicy: prepare Json response: %w", err) + return nil, fmt.Errorf("AssumeIAMRole: prepare Json response: %w", err) } return bodyresp, nil @@ -11434,70 +11494,6 @@ func (c Client) UpdateIAMRolePolicy(ctx context.Context, id UUID, req IAMPolicy) return bodyresp, nil } -type AssumeIAMRoleResponse struct { - Key string `json:"key,omitempty"` - Name string `json:"name,omitempty"` - OrgID string `json:"org-id,omitempty"` - RoleID string `json:"role-id,omitempty"` - Secret string `json:"secret,omitempty"` -} - -type AssumeIAMRoleRequest struct { - // TTL in seconds for the generated access key (cannot exceed the max TTL defined in the targeted assume role) - Ttl int64 `json:"ttl,omitempty" validate:"omitempty,gt=0"` -} - -// [BETA] Request generation of key/secret that allow caller to assume target role -func (c Client) AssumeIAMRole(ctx context.Context, targetRoleID UUID, req AssumeIAMRoleRequest) (*AssumeIAMRoleResponse, error) { - path := fmt.Sprintf("/iam-role/%v/assume", targetRoleID) - - body, err := prepareJSONBody(req) - if err != nil { - return nil, fmt.Errorf("AssumeIAMRole: prepare Json body: %w", err) - } - - request, err := http.NewRequestWithContext(ctx, "POST", c.serverEndpoint+path, body) - if err != nil { - return nil, fmt.Errorf("AssumeIAMRole: new request: %w", err) - } - - request.Header.Add("User-Agent", c.getUserAgent()) - - request.Header.Add("Content-Type", "application/json") - - if err := c.executeRequestInterceptors(ctx, request); err != nil { - return nil, fmt.Errorf("AssumeIAMRole: execute request editors: %w", err) - } - - if err := c.signRequest(request); err != nil { - return nil, fmt.Errorf("AssumeIAMRole: sign request: %w", err) - } - - if c.trace { - dumpRequest(request, "assume-iam-role") - } - - response, err := c.httpClient.Do(request) - if err != nil { - return nil, fmt.Errorf("AssumeIAMRole: http client do: %w", err) - } - - if c.trace { - dumpResponse(response) - } - - if err := handleHTTPErrorResp(response); err != nil { - return nil, fmt.Errorf("AssumeIAMRole: http response: %w", err) - } - - bodyresp := new(AssumeIAMRoleResponse) - if err := prepareJSONResponse(response, bodyresp); err != nil { - return nil, fmt.Errorf("AssumeIAMRole: prepare Json response: %w", err) - } - - return bodyresp, nil -} - // Private Network type ListInstancesResponseInstancesPrivateNetworks struct { // Private Network ID @@ -13992,6 +13988,50 @@ func (c Client) ScheduleKmsKeyDeletion(ctx context.Context, id UUID, req Schedul return bodyresp, nil } +// [BETA] Returns the live-balance of the current organization. +func (c Client) GetLiveBalance(ctx context.Context) (*LiveBalance, error) { + path := "/live-balance" + + request, err := http.NewRequestWithContext(ctx, "GET", c.serverEndpoint+path, nil) + if err != nil { + return nil, fmt.Errorf("GetLiveBalance: new request: %w", err) + } + + request.Header.Add("User-Agent", c.getUserAgent()) + + if err := c.executeRequestInterceptors(ctx, request); err != nil { + return nil, fmt.Errorf("GetLiveBalance: execute request editors: %w", err) + } + + if err := c.signRequest(request); err != nil { + return nil, fmt.Errorf("GetLiveBalance: sign request: %w", err) + } + + if c.trace { + dumpRequest(request, "get-live-balance") + } + + response, err := c.httpClient.Do(request) + if err != nil { + return nil, fmt.Errorf("GetLiveBalance: http client do: %w", err) + } + + if c.trace { + dumpResponse(response) + } + + if err := handleHTTPErrorResp(response); err != nil { + return nil, fmt.Errorf("GetLiveBalance: http response: %w", err) + } + + bodyresp := new(LiveBalance) + if err := prepareJSONResponse(response, bodyresp); err != nil { + return nil, fmt.Errorf("GetLiveBalance: prepare Json response: %w", err) + } + + return bodyresp, nil +} + type ListLoadBalancersResponse struct { LoadBalancers []LoadBalancer `json:"load-balancers,omitempty"` } @@ -16752,6 +16792,102 @@ func (c Client) GetSKSClusterAuthorityCert(ctx context.Context, id UUID, authori return bodyresp, nil } +type GenerateSKSKarpenterExoscaleNodeclassResponse struct { + ExoscaleNodeclass string `json:"exoscale-nodeclass,omitempty"` +} + +// Generate a Karpenter ExoscaleNodeClass manifest for an SKS cluster, including its default security group and feature flags if present +func (c Client) GenerateSKSKarpenterExoscaleNodeclass(ctx context.Context, id UUID) (*GenerateSKSKarpenterExoscaleNodeclassResponse, error) { + path := fmt.Sprintf("/sks-cluster/%v/generate-karpenter-exoscale-nodeclass", id) + + request, err := http.NewRequestWithContext(ctx, "PUT", c.serverEndpoint+path, nil) + if err != nil { + return nil, fmt.Errorf("GenerateSKSKarpenterExoscaleNodeclass: new request: %w", err) + } + + request.Header.Add("User-Agent", c.getUserAgent()) + + if err := c.executeRequestInterceptors(ctx, request); err != nil { + return nil, fmt.Errorf("GenerateSKSKarpenterExoscaleNodeclass: execute request editors: %w", err) + } + + if err := c.signRequest(request); err != nil { + return nil, fmt.Errorf("GenerateSKSKarpenterExoscaleNodeclass: sign request: %w", err) + } + + if c.trace { + dumpRequest(request, "generate-sks-karpenter-exoscale-nodeclass") + } + + response, err := c.httpClient.Do(request) + if err != nil { + return nil, fmt.Errorf("GenerateSKSKarpenterExoscaleNodeclass: http client do: %w", err) + } + + if c.trace { + dumpResponse(response) + } + + if err := handleHTTPErrorResp(response); err != nil { + return nil, fmt.Errorf("GenerateSKSKarpenterExoscaleNodeclass: http response: %w", err) + } + + bodyresp := new(GenerateSKSKarpenterExoscaleNodeclassResponse) + if err := prepareJSONResponse(response, bodyresp); err != nil { + return nil, fmt.Errorf("GenerateSKSKarpenterExoscaleNodeclass: prepare Json response: %w", err) + } + + return bodyresp, nil +} + +type GenerateSKSKarpenterNodepoolResponse struct { + Nodepool string `json:"nodepool,omitempty"` +} + +// Generate a Karpenter NodePool manifest with minimal configuration for an SKS cluster +func (c Client) GenerateSKSKarpenterNodepool(ctx context.Context, id UUID) (*GenerateSKSKarpenterNodepoolResponse, error) { + path := fmt.Sprintf("/sks-cluster/%v/generate-karpenter-nodepool", id) + + request, err := http.NewRequestWithContext(ctx, "PUT", c.serverEndpoint+path, nil) + if err != nil { + return nil, fmt.Errorf("GenerateSKSKarpenterNodepool: new request: %w", err) + } + + request.Header.Add("User-Agent", c.getUserAgent()) + + if err := c.executeRequestInterceptors(ctx, request); err != nil { + return nil, fmt.Errorf("GenerateSKSKarpenterNodepool: execute request editors: %w", err) + } + + if err := c.signRequest(request); err != nil { + return nil, fmt.Errorf("GenerateSKSKarpenterNodepool: sign request: %w", err) + } + + if c.trace { + dumpRequest(request, "generate-sks-karpenter-nodepool") + } + + response, err := c.httpClient.Do(request) + if err != nil { + return nil, fmt.Errorf("GenerateSKSKarpenterNodepool: http client do: %w", err) + } + + if c.trace { + dumpResponse(response) + } + + if err := handleHTTPErrorResp(response); err != nil { + return nil, fmt.Errorf("GenerateSKSKarpenterNodepool: http response: %w", err) + } + + bodyresp := new(GenerateSKSKarpenterNodepoolResponse) + if err := prepareJSONResponse(response, bodyresp); err != nil { + return nil, fmt.Errorf("GenerateSKSKarpenterNodepool: prepare Json response: %w", err) + } + + return bodyresp, nil +} + type GetSKSClusterInspectionResponse map[string]any // Helps troubleshoot common problems when deploying a kubernetes cluster. Inspections run every couple of minutes. @@ -18801,6 +18937,279 @@ func (c Client) UpdateUserRole(ctx context.Context, id UUID, req UpdateUserRoleR return bodyresp, nil } +type ListVpcsResponse struct { + Vpcs []ListVpcResponseEntry `json:"vpcs,omitempty"` +} + +// FindListVpcResponseEntry attempts to find an ListVpcResponseEntry by nameOrID. +func (l ListVpcsResponse) FindListVpcResponseEntry(nameOrID string) (ListVpcResponseEntry, error) { + var result []ListVpcResponseEntry + for i, elem := range l.Vpcs { + if string(elem.Name) == nameOrID || string(elem.ID) == nameOrID { + result = append(result, l.Vpcs[i]) + } + } + if len(result) == 1 { + return result[0], nil + } + + if len(result) > 1 { + return ListVpcResponseEntry{}, fmt.Errorf("%q too many found in ListVpcsResponse: %w", nameOrID, ErrConflict) + } + + return ListVpcResponseEntry{}, fmt.Errorf("%q not found in ListVpcsResponse: %w", nameOrID, ErrNotFound) +} + +// [BETA] List VPCs +func (c Client) ListVpcs(ctx context.Context) (*ListVpcsResponse, error) { + path := "/vpc" + + request, err := http.NewRequestWithContext(ctx, "GET", c.serverEndpoint+path, nil) + if err != nil { + return nil, fmt.Errorf("ListVpcs: new request: %w", err) + } + + request.Header.Add("User-Agent", c.getUserAgent()) + + if err := c.executeRequestInterceptors(ctx, request); err != nil { + return nil, fmt.Errorf("ListVpcs: execute request editors: %w", err) + } + + if err := c.signRequest(request); err != nil { + return nil, fmt.Errorf("ListVpcs: sign request: %w", err) + } + + if c.trace { + dumpRequest(request, "list-vpcs") + } + + response, err := c.httpClient.Do(request) + if err != nil { + return nil, fmt.Errorf("ListVpcs: http client do: %w", err) + } + + if c.trace { + dumpResponse(response) + } + + if err := handleHTTPErrorResp(response); err != nil { + return nil, fmt.Errorf("ListVpcs: http response: %w", err) + } + + bodyresp := new(ListVpcsResponse) + if err := prepareJSONResponse(response, bodyresp); err != nil { + return nil, fmt.Errorf("ListVpcs: prepare Json response: %w", err) + } + + return bodyresp, nil +} + +type CreateVpcRequest struct { + // VPC description + Description string `json:"description,omitempty" validate:"omitempty,lte=4096"` + Labels Labels `json:"labels,omitempty"` + // VPC name + Name string `json:"name" validate:"required,gte=1,lte=255"` +} + +// [BETA] Create a VPC +func (c Client) CreateVpc(ctx context.Context, req CreateVpcRequest) (*Operation, error) { + path := "/vpc" + + body, err := prepareJSONBody(req) + if err != nil { + return nil, fmt.Errorf("CreateVpc: prepare Json body: %w", err) + } + + request, err := http.NewRequestWithContext(ctx, "POST", c.serverEndpoint+path, body) + if err != nil { + return nil, fmt.Errorf("CreateVpc: new request: %w", err) + } + + request.Header.Add("User-Agent", c.getUserAgent()) + + request.Header.Add("Content-Type", "application/json") + + if err := c.executeRequestInterceptors(ctx, request); err != nil { + return nil, fmt.Errorf("CreateVpc: execute request editors: %w", err) + } + + if err := c.signRequest(request); err != nil { + return nil, fmt.Errorf("CreateVpc: sign request: %w", err) + } + + if c.trace { + dumpRequest(request, "create-vpc") + } + + response, err := c.httpClient.Do(request) + if err != nil { + return nil, fmt.Errorf("CreateVpc: http client do: %w", err) + } + + if c.trace { + dumpResponse(response) + } + + if err := handleHTTPErrorResp(response); err != nil { + return nil, fmt.Errorf("CreateVpc: http response: %w", err) + } + + bodyresp := new(Operation) + if err := prepareJSONResponse(response, bodyresp); err != nil { + return nil, fmt.Errorf("CreateVpc: prepare Json response: %w", err) + } + + return bodyresp, nil +} + +// [BETA] Delete a VPC +func (c Client) DeleteVpc(ctx context.Context, id UUID) (*Operation, error) { + path := fmt.Sprintf("/vpc/%v", id) + + request, err := http.NewRequestWithContext(ctx, "DELETE", c.serverEndpoint+path, nil) + if err != nil { + return nil, fmt.Errorf("DeleteVpc: new request: %w", err) + } + + request.Header.Add("User-Agent", c.getUserAgent()) + + if err := c.executeRequestInterceptors(ctx, request); err != nil { + return nil, fmt.Errorf("DeleteVpc: execute request editors: %w", err) + } + + if err := c.signRequest(request); err != nil { + return nil, fmt.Errorf("DeleteVpc: sign request: %w", err) + } + + if c.trace { + dumpRequest(request, "delete-vpc") + } + + response, err := c.httpClient.Do(request) + if err != nil { + return nil, fmt.Errorf("DeleteVpc: http client do: %w", err) + } + + if c.trace { + dumpResponse(response) + } + + if err := handleHTTPErrorResp(response); err != nil { + return nil, fmt.Errorf("DeleteVpc: http response: %w", err) + } + + bodyresp := new(Operation) + if err := prepareJSONResponse(response, bodyresp); err != nil { + return nil, fmt.Errorf("DeleteVpc: prepare Json response: %w", err) + } + + return bodyresp, nil +} + +// [BETA] Retrieve VPC details +func (c Client) GetVpc(ctx context.Context, id UUID) (*Vpc, error) { + path := fmt.Sprintf("/vpc/%v", id) + + request, err := http.NewRequestWithContext(ctx, "GET", c.serverEndpoint+path, nil) + if err != nil { + return nil, fmt.Errorf("GetVpc: new request: %w", err) + } + + request.Header.Add("User-Agent", c.getUserAgent()) + + if err := c.executeRequestInterceptors(ctx, request); err != nil { + return nil, fmt.Errorf("GetVpc: execute request editors: %w", err) + } + + if err := c.signRequest(request); err != nil { + return nil, fmt.Errorf("GetVpc: sign request: %w", err) + } + + if c.trace { + dumpRequest(request, "get-vpc") + } + + response, err := c.httpClient.Do(request) + if err != nil { + return nil, fmt.Errorf("GetVpc: http client do: %w", err) + } + + if c.trace { + dumpResponse(response) + } + + if err := handleHTTPErrorResp(response); err != nil { + return nil, fmt.Errorf("GetVpc: http response: %w", err) + } + + bodyresp := new(Vpc) + if err := prepareJSONResponse(response, bodyresp); err != nil { + return nil, fmt.Errorf("GetVpc: prepare Json response: %w", err) + } + + return bodyresp, nil +} + +type UpdateVpcRequest struct { + // VPC description + Description *string `json:"description,omitempty" validate:"omitempty,lte=4096"` + Labels Labels `json:"labels"` + // VPC name + Name *string `json:"name,omitempty" validate:"omitempty,gte=1,lte=255"` +} + +// [BETA] Update a VPC +func (c Client) UpdateVpc(ctx context.Context, id UUID, req UpdateVpcRequest) (*Vpc, error) { + path := fmt.Sprintf("/vpc/%v", id) + + body, err := prepareJSONBody(req) + if err != nil { + return nil, fmt.Errorf("UpdateVpc: prepare Json body: %w", err) + } + + request, err := http.NewRequestWithContext(ctx, "PUT", c.serverEndpoint+path, body) + if err != nil { + return nil, fmt.Errorf("UpdateVpc: new request: %w", err) + } + + request.Header.Add("User-Agent", c.getUserAgent()) + + request.Header.Add("Content-Type", "application/json") + + if err := c.executeRequestInterceptors(ctx, request); err != nil { + return nil, fmt.Errorf("UpdateVpc: execute request editors: %w", err) + } + + if err := c.signRequest(request); err != nil { + return nil, fmt.Errorf("UpdateVpc: sign request: %w", err) + } + + if c.trace { + dumpRequest(request, "update-vpc") + } + + response, err := c.httpClient.Do(request) + if err != nil { + return nil, fmt.Errorf("UpdateVpc: http client do: %w", err) + } + + if c.trace { + dumpResponse(response) + } + + if err := handleHTTPErrorResp(response); err != nil { + return nil, fmt.Errorf("UpdateVpc: http response: %w", err) + } + + bodyresp := new(Vpc) + if err := prepareJSONResponse(response, bodyresp); err != nil { + return nil, fmt.Errorf("UpdateVpc: prepare Json response: %w", err) + } + + return bodyresp, nil +} + type ListZonesResponse struct { Zones []Zone `json:"zones,omitempty"` } diff --git a/vendor/github.com/exoscale/egoscale/v3/schemas.go b/vendor/github.com/exoscale/egoscale/v3/schemas.go index d6562f8a6..a058509d0 100644 --- a/vendor/github.com/exoscale/egoscale/v3/schemas.go +++ b/vendor/github.com/exoscale/egoscale/v3/schemas.go @@ -74,24 +74,26 @@ type AccessKeyResource struct { ResourceType AccessKeyResourceResourceType `json:"resource-type,omitempty"` } -// AI API key metadata (without value) +// AI API key metadata type AIAPIKey struct { // Creation timestamp - CreatedAT time.Time `json:"created-at,omitempty"` + CreatedAT time.Time `json:"created-at" validate:"required"` // AI API key ID - ID UUID `json:"id,omitempty"` + ID UUID `json:"id" validate:"required"` // Human-readable name for the AI API key - Name string `json:"name,omitempty"` + Name string `json:"name" validate:"required"` // Organization UUID that owns this key - OrgUuid UUID `json:"org-uuid,omitempty"` + OrgUuid UUID `json:"org-uuid" validate:"required"` // Key scope: 'public' for all deployments, or a specific deployment UUID - Scope string `json:"scope,omitempty"` + Scope string `json:"scope" validate:"required"` // Last update timestamp - UpdatedAT time.Time `json:"updated-at,omitempty"` + UpdatedAT time.Time `json:"updated-at" validate:"required"` } -// AI API key with plaintext value -type AIAPIKeyWithValue struct { +// AI API key plaintext value +type AIAPIKeyValue struct { + // Plaintext AI API key value + Value string `json:"value" validate:"required"` } // Anti-affinity Group @@ -112,6 +114,14 @@ type AntiAffinityGroupRef struct { ID UUID `json:"id,omitempty"` } +// Usage breakdown for one API key, grouped by model +type APIKeyUsageEntry struct { + // Map of model-uuid to accumulated counters. Keys are model UUIDs. + Models map[string]ModelUsageCounters `json:"models" validate:"required"` + // Organization that owns this API key + OrganizationID UUID `json:"organization-id" validate:"required"` +} + type BlockStorageSnapshotState string const ( @@ -172,6 +182,8 @@ type BlockStorageVolume struct { Blocksize int64 `json:"blocksize,omitempty" validate:"omitempty,gte=0"` // Volume creation date CreatedAT time.Time `json:"created-at,omitempty"` + // Indicates if the block-storage volume is encrypted + Encrypted *bool `json:"encrypted,omitempty"` // Volume ID ID UUID `json:"id,omitempty"` // Target Instance @@ -199,7 +211,23 @@ type CreateAIAPIKeyRequest struct { Scope string `json:"scope" validate:"required"` } -// Deployment an AI model onto a set of GPUs +// Create AI API key response +type CreateAIAPIKeyResponse struct { + // Creation timestamp + CreatedAT time.Time `json:"created-at" validate:"required"` + // AI API key ID + ID UUID `json:"id" validate:"required"` + // Human-readable name for the AI API key + Name string `json:"name" validate:"required"` + // Organization UUID that owns this key + OrgUuid UUID `json:"org-uuid" validate:"required"` + // Key scope: 'public' for all deployments, or a specific deployment UUID + Scope string `json:"scope" validate:"required"` + // Last update timestamp + UpdatedAT time.Time `json:"updated-at" validate:"required"` +} + +// Deploy an AI model onto a set of GPUs type CreateDeploymentRequest struct { // Number of GPUs (1-8) GpuCount int64 `json:"gpu-count" validate:"required,gte=1"` @@ -209,7 +237,8 @@ type CreateDeploymentRequest struct { InferenceEngineParameters []string `json:"inference-engine-parameters,omitempty"` // Inference engine version InferenceEngineVersion InferenceEngineVersion `json:"inference-engine-version,omitempty"` - Model *ModelRef `json:"model" validate:"required"` + // Model reference. Provide either id or name. + Model *ModelRef `json:"model" validate:"required"` // Deployment name Name string `json:"name" validate:"required,gte=1"` // Number of replicas (>=1) @@ -223,10 +252,10 @@ const ( ) type CreateKmsKeyRequest struct { - Description string `json:"description" validate:"required"` - MultiZone *bool `json:"multi-zone" validate:"required"` + Description string `json:"description,omitempty"` + MultiZone *bool `json:"multi-zone,omitempty"` Name string `json:"name" validate:"required"` - Usage CreateKmsKeyRequestUsage `json:"usage" validate:"required"` + Usage CreateKmsKeyRequestUsage `json:"usage,omitempty"` } type CreateKmsKeyResponseSource string @@ -253,6 +282,7 @@ type CreateKmsKeyResponse struct { Revision *RevisionStamp `json:"revision" validate:"required"` Source CreateKmsKeyResponseSource `json:"source" validate:"required"` Status CreateKmsKeyResponseStatus `json:"status" validate:"required"` + StatusSince time.Time `json:"status-since" validate:"required"` Usage string `json:"usage" validate:"required"` } @@ -1297,6 +1327,8 @@ type DBAASServiceMysql struct { BackupSchedule *DBAASServiceMysqlBackupSchedule `json:"backup-schedule,omitempty"` // List of backups for the service Backups []DBAASServiceBackup `json:"backups,omitempty"` + // The minimum amount of time in seconds to keep binlog entries before deletion. This may be extended for services that require binlog entries for longer than the default for example if using the MySQL Debezium Kafka connector. + BinlogRetentionPeriod int64 `json:"binlog-retention-period,omitempty" validate:"omitempty,gt=0"` // Service component information objects Components []DBAASServiceMysqlComponents `json:"components,omitempty"` // MySQL connection information properties @@ -1599,6 +1631,8 @@ type DBAASServicePG struct { Notifications []DBAASServiceNotification `json:"notifications,omitempty"` // postgresql.conf configuration values PGSettings *JSONSchemaPG `json:"pg-settings,omitempty"` + // System-wide settings for the pgaudit extension. + PgauditSettings *JSONSchemaPgaudit `json:"pgaudit-settings,omitempty"` // System-wide settings for pgbouncer. PgbouncerSettings *JSONSchemaPgbouncer `json:"pgbouncer-settings,omitempty"` // System-wide settings for pglookout. @@ -2387,25 +2421,41 @@ type GenerateDataKeyResponse struct { Plaintext []byte `json:"plaintext" validate:"required"` } +// Get AI API key response +type GetAIAPIKeyResponse struct { + // Creation timestamp + CreatedAT time.Time `json:"created-at" validate:"required"` + // AI API key ID + ID UUID `json:"id" validate:"required"` + // Human-readable name for the AI API key + Name string `json:"name" validate:"required"` + // Organization UUID that owns this key + OrgUuid UUID `json:"org-uuid" validate:"required"` + // Key scope: 'public' for all deployments, or a specific deployment UUID + Scope string `json:"scope" validate:"required"` + // Last update timestamp + UpdatedAT time.Time `json:"updated-at" validate:"required"` +} + // GPU usage for all organizations type GetConfederatioUsageResponse struct { - OrganizationsUsages map[string]OrganizationUsage `json:"organizations_usages" validate:"required"` + OrganizationsUsages map[string]OrganizationUsage `json:"organizations-usages" validate:"required"` } // A single log entry type GetDeploymentLogsEntry struct { // Log message content - Message string `json:"message,omitempty"` + Message string `json:"message" validate:"required"` // Node identifier - Node string `json:"node,omitempty"` + Node string `json:"node" validate:"required"` // Timestamp of the log entry - Time string `json:"time,omitempty"` + Time time.Time `json:"time" validate:"required"` } // Deployment logs type GetDeploymentLogsResponse struct { // List of log entries - Logs []GetDeploymentLogsEntry `json:"logs,omitempty"` + Logs []GetDeploymentLogsEntry `json:"logs" validate:"required"` } type GetDeploymentResponseState string @@ -2413,44 +2463,48 @@ type GetDeploymentResponseState string const ( GetDeploymentResponseStateReady GetDeploymentResponseState = "ready" GetDeploymentResponseStateCreating GetDeploymentResponseState = "creating" + GetDeploymentResponseStatePreparing GetDeploymentResponseState = "preparing" GetDeploymentResponseStateError GetDeploymentResponseState = "error" GetDeploymentResponseStateDeploying GetDeploymentResponseState = "deploying" + GetDeploymentResponseStateScaling GetDeploymentResponseState = "scaling" + GetDeploymentResponseStateUpdating GetDeploymentResponseState = "updating" ) // AI deployment type GetDeploymentResponse struct { // Creation time - CreatedAT time.Time `json:"created-at,omitempty"` - // Deployment URL (nullable) - DeploymentURL string `json:"deployment-url,omitempty"` + CreatedAT time.Time `json:"created-at" validate:"required"` + // Deployment inference endpoint URL + DeploymentURL string `json:"deployment-url" validate:"required"` // Number of GPUs - GpuCount int64 `json:"gpu-count,omitempty" validate:"omitempty,gte=1"` + GpuCount int64 `json:"gpu-count" validate:"required,gte=1"` // GPU type family - GpuType string `json:"gpu-type,omitempty" validate:"omitempty,gte=1"` + GpuType string `json:"gpu-type" validate:"required,gte=1"` // Deployment ID - ID UUID `json:"id,omitempty"` + ID UUID `json:"id" validate:"required"` // Optional extra inference engine server CLI args - InferenceEngineParameters []string `json:"inference-engine-parameters,omitempty"` + InferenceEngineParameters []string `json:"inference-engine-parameters" validate:"required"` // Inference engine version - InferenceEngineVersion InferenceEngineVersion `json:"inference-engine-version,omitempty"` - Model *ModelRef `json:"model,omitempty"` + InferenceEngineVersion InferenceEngineVersion `json:"inference-engine-version" validate:"required"` + // Model reference. Provide either id or name. + Model *ModelRef `json:"model" validate:"required"` // Deployment name - Name string `json:"name,omitempty" validate:"omitempty,gte=1"` + Name string `json:"name" validate:"required,gte=1"` // Number of replicas (>=0) - Replicas int64 `json:"replicas,omitempty" validate:"omitempty,gte=0"` + Replicas int64 `json:"replicas" validate:"required,gte=0"` // Service level - ServiceLevel string `json:"service-level,omitempty" validate:"omitempty,gte=1"` + ServiceLevel string `json:"service-level" validate:"required,gte=1"` // Deployment state - State GetDeploymentResponseState `json:"state,omitempty"` + State GetDeploymentResponseState `json:"state" validate:"required"` // Deployment state details - StateDetails string `json:"state-details,omitempty"` + StateDetails string `json:"state-details" validate:"required"` // Update time - UpdatedAT time.Time `json:"updated-at,omitempty"` + UpdatedAT time.Time `json:"updated-at" validate:"required"` } // List of allowed inference-engine parameters type GetInferenceEngineHelpResponse struct { - Parameters []InferenceEngineParameterEntry `json:"parameters,omitempty"` + Parameters []InferenceEngineParameterEntry `json:"parameters" validate:"required"` } type GetKmsKeyResponseSource string @@ -2498,23 +2552,23 @@ const ( // AI model type GetModelResponse struct { // Creation time - CreatedAT time.Time `json:"created-at,omitempty"` + CreatedAT time.Time `json:"created-at" validate:"required"` // Model ID - ID UUID `json:"id,omitempty"` - // Model size (nullable) - ModelSize int64 `json:"model-size,omitempty" validate:"omitempty,gte=0"` + ID UUID `json:"id" validate:"required"` + // Model size in bytes + ModelSize int64 `json:"model-size" validate:"required,gte=0"` // Model name - Name string `json:"name,omitempty" validate:"omitempty,gte=1"` + Name string `json:"name" validate:"required,gte=1"` // Model state - State GetModelResponseState `json:"state,omitempty"` + State GetModelResponseState `json:"state" validate:"required"` // Update time - UpdatedAT time.Time `json:"updated-at,omitempty"` + UpdatedAT time.Time `json:"updated-at" validate:"required"` } // GPU usage for an organization type GetOrganizationUsageResponse struct { // Total GPU count - Gpu int64 `json:"gpu,omitempty" validate:"omitempty,gte=0"` + Gpu int64 `json:"gpu" validate:"required,gte=0"` } // IAM API Key @@ -2539,6 +2593,12 @@ type IAMAPIKeyCreated struct { Secret string `json:"secret,omitempty"` } +// Assume Role Policy +type IAMAssumeRolePolicy struct { + // IAM Assume Role Policy rules + Rules []IAMServicePolicyRule `json:"rules,omitempty"` +} + type IAMPolicyDefaultServiceStrategy string const ( @@ -2556,8 +2616,8 @@ type IAMPolicy struct { // IAM Role type IAMRole struct { - // Policy - AssumeRolePolicy *IAMPolicy `json:"assume-role-policy,omitempty"` + // Assume Role Policy + AssumeRolePolicy *IAMAssumeRolePolicy `json:"assume-role-policy,omitempty"` // IAM Role description Description string `json:"description,omitempty" validate:"omitempty,gte=1,lte=255"` // IAM Role mutability @@ -2630,8 +2690,35 @@ const ( InferenceEngineVersion0180 InferenceEngineVersion = "0.18.0" InferenceEngineVersion0181 InferenceEngineVersion = "0.18.1" InferenceEngineVersion0190 InferenceEngineVersion = "0.19.0" + InferenceEngineVersion0191 InferenceEngineVersion = "0.19.1" + InferenceEngineVersion0200 InferenceEngineVersion = "0.20.0" + InferenceEngineVersion0201 InferenceEngineVersion = "0.20.1" + InferenceEngineVersion0202 InferenceEngineVersion = "0.20.2" + InferenceEngineVersion0210 InferenceEngineVersion = "0.21.0" + InferenceEngineVersion0220 InferenceEngineVersion = "0.22.0" + InferenceEngineVersion0221 InferenceEngineVersion = "0.22.1" ) +// Router flush payload: the router's full in-memory usage map with flush identity fields +type IngestMeteringRequest struct { + // ISO-8601 UTC timestamp when the flush snapshot was created (truncated to minute boundary for bucketing) + CreatedAT time.Time `json:"created-at" validate:"required"` + // UUID identifying this flush; used for idempotent deduplication + FlushID UUID `json:"flush-id" validate:"required"` + // Router instance identifier that produced this flush + RouterID string `json:"router-id" validate:"required,gte=1"` + // Map of api-key-uuid to usage entry. Keys are API key UUIDs. Mirrors the router's in-memory accumulator structure directly. + Usage map[string]APIKeyUsageEntry `json:"usage" validate:"required"` +} + +// Result of a metering ingest operation +type IngestMeteringResponse struct { + // True if flush-id was already processed (idempotent retry) + Duplicate *bool `json:"duplicate,omitempty"` + // Number of rows affected (inserted or updated) in usage_minutely; 0 if duplicate flush-id + Upserted int `json:"upserted" validate:"required"` +} + // Private Network type InstancePrivateNetworks struct { // Private Network ID @@ -2650,6 +2737,8 @@ type Instance struct { CreatedAT time.Time `json:"created-at,omitempty"` // Deploy target reference DeployTarget *DeployTarget `json:"deploy-target,omitempty"` + // Indicates if the root volume of the instance is encrypted + DiskEncrypted *bool `json:"disk-encrypted,omitempty"` // Instance disk size in GiB DiskSize int64 `json:"disk-size,omitempty" validate:"omitempty,gte=10,lte=51200"` // Instance Elastic IPs @@ -2795,6 +2884,7 @@ const ( InstanceTypeFamilyGpu InstanceTypeFamily = "gpu" InstanceTypeFamilyMemory InstanceTypeFamily = "memory" InstanceTypeFamilyGpua5000 InstanceTypeFamily = "gpua5000" + InstanceTypeFamilyGpub300 InstanceTypeFamily = "gpub300" InstanceTypeFamilyGpurtx6000pro InstanceTypeFamily = "gpurtx6000pro" InstanceTypeFamilyStorage InstanceTypeFamily = "storage" InstanceTypeFamilyStandard InstanceTypeFamily = "standard" @@ -2842,9 +2932,9 @@ type InstanceType struct { // Instance type with authorization status type InstanceTypeEntry struct { // Whether this instance type is authorized based on server availability - Authorized *bool `json:"authorized,omitempty"` + Authorized *bool `json:"authorized" validate:"required"` // GPU family name - Family string `json:"family,omitempty"` + Family string `json:"family" validate:"required"` } // Instance type reference @@ -3875,6 +3965,58 @@ type JSONSchemaPG struct { Wal *JSONSchemaPGWal `json:"wal,omitempty"` } +type JSONSchemaPgauditLogLevel string + +const ( + JSONSchemaPgauditLogLevelDebug1 JSONSchemaPgauditLogLevel = "debug1" + JSONSchemaPgauditLogLevelDebug2 JSONSchemaPgauditLogLevel = "debug2" + JSONSchemaPgauditLogLevelDebug3 JSONSchemaPgauditLogLevel = "debug3" + JSONSchemaPgauditLogLevelDebug4 JSONSchemaPgauditLogLevel = "debug4" + JSONSchemaPgauditLogLevelDebug5 JSONSchemaPgauditLogLevel = "debug5" + JSONSchemaPgauditLogLevelInfo JSONSchemaPgauditLogLevel = "info" + JSONSchemaPgauditLogLevelNotice JSONSchemaPgauditLogLevel = "notice" + JSONSchemaPgauditLogLevelWarning JSONSchemaPgauditLogLevel = "warning" + JSONSchemaPgauditLogLevelLog JSONSchemaPgauditLogLevel = "log" +) + +// System-wide settings for the pgaudit extension. +type JSONSchemaPgaudit struct { + // Enable pgaudit extension. When enabled, pgaudit extension will be automatically installed.Otherwise, extension will be uninstalled but auditing configurations will be preserved. + FeatureEnabled *bool `json:"feature_enabled,omitempty"` + // Specifies which classes of statements will be logged by session audit logging. + Log []string `json:"log,omitempty"` + // Specifies that session logging should be enabled in the case where all relations + // in a statement are in pg_catalog. + LogCatalog *bool `json:"log_catalog,omitempty"` + // Specifies whether log messages will be visible to a client process such as psql. + LogClient *bool `json:"log_client,omitempty"` + // Specifies the log level that will be used for log entries. + LogLevel JSONSchemaPgauditLogLevel `json:"log_level,omitempty"` + // Crop parameters representation and whole statements if they exceed this threshold. + // A (default) value of -1 disable the truncation. + LogMaxStringLength int `json:"log_max_string_length,omitempty" validate:"omitempty,gte=-1,lte=102400"` + // This GUC allows to turn off logging nested statements, that is, statements that are + // executed as part of another ExecutorRun. + LogNestedStatements *bool `json:"log_nested_statements,omitempty"` + // Specifies that audit logging should include the parameters that were passed with the statement. + LogParameter *bool `json:"log_parameter,omitempty"` + // Specifies that parameter values longer than this setting (in bytes) should not be logged, + // but replaced with . + LogParameterMaxSize int `json:"log_parameter_max_size,omitempty"` + // Specifies whether session audit logging should create a separate log entry + // for each relation (TABLE, VIEW, etc.) referenced in a SELECT or DML statement. + LogRelation *bool `json:"log_relation,omitempty"` + // Log Rows + LogRows *bool `json:"log_rows,omitempty"` + // Specifies whether logging will include the statement text and parameters (if enabled). + LogStatement *bool `json:"log_statement,omitempty"` + // Specifies whether logging will include the statement text and parameters with + // the first log entry for a statement/substatement combination or with every entry. + LogStatementOnce *bool `json:"log_statement_once,omitempty"` + // Specifies the master role to use for object audit logging. + Role string `json:"role,omitempty" validate:"omitempty,lte=64"` +} + type JSONSchemaPgbouncerAutodbPoolMode string const ( @@ -4042,17 +4184,33 @@ type Labels map[string]string // List of AI API keys type ListAIAPIKeysResponse struct { - AIAPIKeys []AIAPIKey `json:"ai-api-keys" validate:"required"` + AIAPIKeys []ListAIAPIKeysResponseEntry `json:"ai-api-keys" validate:"required"` +} + +// AI API key list entry +type ListAIAPIKeysResponseEntry struct { + // Creation timestamp + CreatedAT time.Time `json:"created-at" validate:"required"` + // AI API key ID + ID UUID `json:"id" validate:"required"` + // Human-readable name for the AI API key + Name string `json:"name" validate:"required"` + // Organization UUID that owns this key + OrgUuid UUID `json:"org-uuid" validate:"required"` + // Key scope: 'public' for all deployments, or a specific deployment UUID + Scope string `json:"scope" validate:"required"` + // Last update timestamp + UpdatedAT time.Time `json:"updated-at" validate:"required"` } // List of available instance types with authorization status type ListAIInstanceTypesResponse struct { - InstanceTypes []InstanceTypeEntry `json:"instance-types,omitempty"` + InstanceTypes []InstanceTypeEntry `json:"instance-types" validate:"required"` } -// AI model list +// AI deployment list type ListDeploymentsResponse struct { - Deployments []ListDeploymentsResponseEntry `json:"deployments,omitempty"` + Deployments []ListDeploymentsResponseEntry `json:"deployments" validate:"required"` } type ListDeploymentsResponseEntryState string @@ -4060,33 +4218,37 @@ type ListDeploymentsResponseEntryState string const ( ListDeploymentsResponseEntryStateReady ListDeploymentsResponseEntryState = "ready" ListDeploymentsResponseEntryStateCreating ListDeploymentsResponseEntryState = "creating" + ListDeploymentsResponseEntryStatePreparing ListDeploymentsResponseEntryState = "preparing" ListDeploymentsResponseEntryStateError ListDeploymentsResponseEntryState = "error" ListDeploymentsResponseEntryStateDeploying ListDeploymentsResponseEntryState = "deploying" + ListDeploymentsResponseEntryStateScaling ListDeploymentsResponseEntryState = "scaling" + ListDeploymentsResponseEntryStateUpdating ListDeploymentsResponseEntryState = "updating" ) // AI deployment type ListDeploymentsResponseEntry struct { // Creation time - CreatedAT time.Time `json:"created-at,omitempty"` - // Deployment URL (nullable) - DeploymentURL string `json:"deployment-url,omitempty"` + CreatedAT time.Time `json:"created-at" validate:"required"` + // Deployment inference endpoint URL + DeploymentURL string `json:"deployment-url" validate:"required"` // Number of GPUs - GpuCount int64 `json:"gpu-count,omitempty" validate:"omitempty,gte=1"` + GpuCount int64 `json:"gpu-count" validate:"required,gte=1"` // GPU type family - GpuType string `json:"gpu-type,omitempty" validate:"omitempty,gte=1"` + GpuType string `json:"gpu-type" validate:"required,gte=1"` // Deployment ID - ID UUID `json:"id,omitempty"` - Model *ModelRef `json:"model,omitempty"` + ID UUID `json:"id" validate:"required"` + // Model reference. Provide either id or name. + Model *ModelRef `json:"model" validate:"required"` // Deployment name - Name string `json:"name,omitempty" validate:"omitempty,gte=1"` + Name string `json:"name" validate:"required,gte=1"` // Number of replicas (>=0) - Replicas int64 `json:"replicas,omitempty" validate:"omitempty,gte=0"` + Replicas int64 `json:"replicas" validate:"required,gte=0"` // Service level - ServiceLevel string `json:"service-level,omitempty" validate:"omitempty,gte=1"` + ServiceLevel string `json:"service-level" validate:"required,gte=1"` // Deployment state - State ListDeploymentsResponseEntryState `json:"state,omitempty"` + State ListDeploymentsResponseEntryState `json:"state" validate:"required"` // Update time - UpdatedAT time.Time `json:"updated-at,omitempty"` + UpdatedAT time.Time `json:"updated-at" validate:"required"` } type ListKmsKeyRotationsResponse struct { @@ -4136,7 +4298,7 @@ type ListKmsKeysResponseEntry struct { // AI model list type ListModelsResponse struct { - Models []ListModelsResponseEntry `json:"models,omitempty"` + Models []ListModelsResponseEntry `json:"models" validate:"required"` } type ListModelsResponseEntryState string @@ -4152,17 +4314,38 @@ const ( // AI model type ListModelsResponseEntry struct { // Creation time - CreatedAT time.Time `json:"created-at,omitempty"` + CreatedAT time.Time `json:"created-at" validate:"required"` // Model ID - ID UUID `json:"id,omitempty"` - // Model size (nullable) - ModelSize int64 `json:"model-size,omitempty" validate:"omitempty,gte=0"` + ID UUID `json:"id" validate:"required"` + // Model size in bytes + ModelSize int64 `json:"model-size" validate:"required,gte=0"` // Model name - Name string `json:"name,omitempty" validate:"omitempty,gte=1"` + Name string `json:"name" validate:"required,gte=1"` // Model state - State ListModelsResponseEntryState `json:"state,omitempty"` + State ListModelsResponseEntryState `json:"state" validate:"required"` // Update time - UpdatedAT time.Time `json:"updated-at,omitempty"` + UpdatedAT time.Time `json:"updated-at" validate:"required"` +} + +// VPC +type ListVpcResponseEntry struct { + // VPC creation date + CreatedAT time.Time `json:"created-at,omitempty"` + // VPC description + Description string `json:"description,omitempty" validate:"omitempty,lte=4096"` + // VPC ID + ID UUID `json:"id,omitempty"` + Labels Labels `json:"labels,omitempty"` + // VPC name + Name string `json:"name,omitempty" validate:"omitempty,gte=1,lte=255"` +} + +// Live balance +type LiveBalance struct { + // Organization live balance + Balance float64 `json:"balance,omitempty"` + // Organization currency + Currency string `json:"currency,omitempty"` } type LoadBalancerState string @@ -4302,6 +4485,7 @@ type Manager struct { Type ManagerType `json:"type,omitempty"` } +// Model reference. Provide either id or name. type ModelRef struct { // Associated model ID ID UUID `json:"id,omitempty"` @@ -4309,6 +4493,16 @@ type ModelRef struct { Name string `json:"name,omitempty" validate:"omitempty,gte=1"` } +// Accumulated Unit Of Measurement (UOM) counters for one model over a flush window +type ModelUsageCounters struct { + // Number of inference calls in this flush window + CallCount int `json:"call-count" validate:"required,gte=1"` + // Total prompt/input Unit Of Measurement (UOM) across all calls in this flush window (e.g., tokens for LLMs, minutes for TTS, pages for OCR) + InputUom int `json:"input-uom" validate:"required,gte=0"` + // Total completion/output Unit Of Measurement (UOM) across all calls in this flush window (e.g., tokens for LLMs, minutes for TTS, pages for OCR) + OutputUom int `json:"output-uom" validate:"required,gte=0"` +} + // Cluster networking configuration. type Networking struct { // CIDR Range for Pods in cluster. This must not overlap with any IP ranges assigned to pods. Max of two, comma-separated, dual-stack CIDRs is allowed. @@ -4378,11 +4572,17 @@ type OperationResourceRef struct { Link string `json:"link,omitempty"` } +// Per-org Unit Of Measurement (UOM) consumption quota response +type OrgConsumptionQuotaResponse struct { + // Per-org Unit Of Measurement (UOM) consumption quota (UOM/min). Null means unlimited. UOM represents weighted units across different AI workloads (e.g., tokens for LLMs, minutes for TTS, pages for OCR). + QuotaUomPerMinute int `json:"quota-uom-per-minute,omitempty" validate:"omitempty,gte=0"` +} + // Organization type Organization struct { // Organization address Address string `json:"address,omitempty"` - // Organization balance + // Organization balance. DEPRECATED: use the dedicated `live-balance` endpoint Balance float64 `json:"balance,omitempty"` // Organization city City string `json:"city,omitempty"` @@ -4400,8 +4600,18 @@ type Organization struct { // Organization GPU usage type OrganizationUsage struct { - // Total GPU count + // Total GPU count (sum of all GPU types) Gpu int64 `json:"gpu" validate:"required,gte=0"` + // GPU3 count + Gpu3 int64 `json:"gpu3,omitempty" validate:"omitempty,gte=0"` + // GPU3080TI count + Gpu3080ti int64 `json:"gpu3080ti,omitempty" validate:"omitempty,gte=0"` + // GPUA30 count + Gpua30 int64 `json:"gpua30,omitempty" validate:"omitempty,gte=0"` + // GPUA5000 count + Gpua5000 int64 `json:"gpua5000,omitempty" validate:"omitempty,gte=0"` + // GPURTX6000PRO count + Gpurtx6000pro int64 `json:"gpurtx6000pro,omitempty" validate:"omitempty,gte=0"` } // Private Network @@ -4471,6 +4681,14 @@ type Quota struct { Usage int64 `json:"usage,omitempty"` } +// Rate Limit +type RateLimited struct { + // The error message + Error string `json:"error,omitempty"` + // The time in seconds to wait before the next request + RetryAfter float64 `json:"retry_after,omitempty"` +} + type ReEncryptRequestDestination struct { // Optional encryption context appended to the AAD. EncryptionContext *[]byte `json:"encryption-context,omitempty"` @@ -4525,9 +4743,16 @@ type Resource struct { Name string `json:"name,omitempty"` } +// Reveal AI API key response +type RevealAIAPIKeyResponse struct { + // Plaintext AI API key value + Value string `json:"value" validate:"required"` +} + // AI deployment inference endpoint authentication key type RevealDeploymentAPIKeyResponse struct { - APIKey string `json:"api-key,omitempty"` + // Inference endpoint authentication key + APIKey string `json:"api-key" validate:"required"` } type ReverseDNSRecord struct { @@ -4539,6 +4764,12 @@ type RevisionStamp struct { Seq int `json:"seq" validate:"required,gte=0"` } +// Rotate AI API key response +type RotateAIAPIKeyResponse struct { + // Plaintext AI API key value + Value string `json:"value" validate:"required"` +} + type RotateKmsKeyResponse struct { Rotation *KeyRotationConfig `json:"rotation" validate:"required"` } @@ -4640,6 +4871,12 @@ type SecurityGroupRule struct { StartPort int64 `json:"start-port,omitempty" validate:"omitempty,gte=1,lte=65535"` } +// Request to set per-org Unit Of Measurement (UOM) consumption quota +type SetOrgConsumptionQuotaRequest struct { + // Per-org Unit Of Measurement (UOM) consumption quota (UOM/min). Pass null to remove the limit. UOM represents weighted units across different AI workloads (e.g., tokens for LLMs, minutes for TTS, pages for OCR). + QuotaUomPerMinute int `json:"quota-uom-per-minute,omitempty" validate:"omitempty,gte=0"` +} + // Kubernetes Audit parameters type SKSAudit struct { // Enabled @@ -4944,6 +5181,7 @@ type SuccessResponseStatus string const ( SuccessResponseStatusSuccess SuccessResponseStatus = "success" SuccessResponseStatusTargetRegistered SuccessResponseStatus = "target-registered" + SuccessResponseStatusAlreadyApplied SuccessResponseStatus = "already-applied" ) type SuccessResponse struct { @@ -5018,6 +5256,22 @@ type UpdateAIAPIKeyRequest struct { Scope string `json:"scope,omitempty"` } +// Update AI API key response +type UpdateAIAPIKeyResponse struct { + // Creation timestamp + CreatedAT time.Time `json:"created-at" validate:"required"` + // AI API key ID + ID UUID `json:"id" validate:"required"` + // Human-readable name for the AI API key + Name string `json:"name" validate:"required"` + // Organization UUID that owns this key + OrgUuid UUID `json:"org-uuid" validate:"required"` + // Key scope: 'public' for all deployments, or a specific deployment UUID + Scope string `json:"scope" validate:"required"` + // Last update timestamp + UpdatedAT time.Time `json:"updated-at" validate:"required"` +} + // Update AI deployment type UpdateDeploymentRequest struct { // Optional extra inference engine server CLI args @@ -5044,6 +5298,19 @@ type User struct { TwoFactorAuthentication *bool `json:"two-factor-authentication,omitempty"` } +// VPC +type Vpc struct { + // VPC creation date + CreatedAT time.Time `json:"created-at,omitempty"` + // VPC description + Description string `json:"description,omitempty" validate:"omitempty,lte=4096"` + // VPC ID + ID UUID `json:"id,omitempty"` + Labels Labels `json:"labels,omitempty"` + // VPC name + Name string `json:"name,omitempty" validate:"omitempty,gte=1,lte=255"` +} + // Zone type Zone struct { // Zone API endpoint diff --git a/vendor/github.com/exoscale/egoscale/v3/version.go b/vendor/github.com/exoscale/egoscale/v3/version.go index 6611bd70a..2b80947e4 100644 --- a/vendor/github.com/exoscale/egoscale/v3/version.go +++ b/vendor/github.com/exoscale/egoscale/v3/version.go @@ -1,4 +1,4 @@ package v3 // Version represents the current egoscale v3 version. -const Version = "v3.1.36" +const Version = "v3.1.38" diff --git a/vendor/modules.txt b/vendor/modules.txt index e7c5ceb8a..16eb2a538 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -154,8 +154,8 @@ github.com/dlclark/regexp2/syntax # github.com/dustin/go-humanize v1.0.1 ## explicit; go 1.16 github.com/dustin/go-humanize -# github.com/exoscale/egoscale/v3 v3.1.36-0.20260424083744-33446130ebd9 -## explicit; go 1.26 +# github.com/exoscale/egoscale/v3 v3.1.38 +## explicit; go 1.25 github.com/exoscale/egoscale/v3 github.com/exoscale/egoscale/v3/credentials # github.com/exoscale/openapi-cli-generator v1.2.0 From 76e73a877269feffa7c9fe77906b3aa116a4e154 Mon Sep 17 00:00:00 2001 From: Leo Loch Date: Thu, 18 Jun 2026 10:42:46 +0200 Subject: [PATCH 26/26] typo in comment --- cmd/kms/crypto/crypto_generate_data_key.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/kms/crypto/crypto_generate_data_key.go b/cmd/kms/crypto/crypto_generate_data_key.go index 5f5150867..1d230ee30 100644 --- a/cmd/kms/crypto/crypto_generate_data_key.go +++ b/cmd/kms/crypto/crypto_generate_data_key.go @@ -42,7 +42,7 @@ type cryptoGenerateDataKeyCmd struct { Key string `cli-arg:"#" cli-usage:"ID"` - KeySpec v3.GenerateDataKeyRequestKeySpec `cli-short:"s" cli-flag:"key-spec" cli-usage:"key spec for DEK [AES_256]"` + KeySpec v3.GenerateDataKeyRequestKeySpec `cli-short:"s" cli-flag:"key-spec" cli-usage:"key spec for DEK [AES-256]"` BytesCount string `cli-short:"b" cli-flag:"bytes-count" cli-usage:"number of bytes for DEK (1 - 1024)"` EncryptionContext string `cli-short:"e" cli-flag:"encryption-context" cli-usage:"encryption context to use for DEK generation"` Zone v3.ZoneName `cli-short:"z" cli-flag:"zone" cli-usage:"key zone"`