Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .go-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.24.6
1.24.7
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/confluentinc/cli/v4

go 1.24.6
go 1.24.7

require (
github.com/antihax/optional v1.0.0
Expand All @@ -18,7 +18,7 @@ require (
github.com/confluentinc/ccloud-sdk-go-v2/ai v0.1.0
github.com/confluentinc/ccloud-sdk-go-v2/apikeys v0.4.0
github.com/confluentinc/ccloud-sdk-go-v2/billing v0.3.0
github.com/confluentinc/ccloud-sdk-go-v2/byok v0.0.2
github.com/confluentinc/ccloud-sdk-go-v2/byok v0.0.9
github.com/confluentinc/ccloud-sdk-go-v2/cam v0.3.0
github.com/confluentinc/ccloud-sdk-go-v2/ccl v0.4.0
github.com/confluentinc/ccloud-sdk-go-v2/ccpm v0.0.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ github.com/confluentinc/ccloud-sdk-go-v2/apikeys v0.4.0 h1:8fWyLwMuy8ec0MVF5Avd5
github.com/confluentinc/ccloud-sdk-go-v2/apikeys v0.4.0/go.mod h1:wNa9Qg2e2v/+PQsUyKh+qB22hhLkPR6Ahy6rP+1jmGI=
github.com/confluentinc/ccloud-sdk-go-v2/billing v0.3.0 h1:a2EaPzwLEYkgil7rlsqRUlt994PMGubtdgRrF8Kbo10=
github.com/confluentinc/ccloud-sdk-go-v2/billing v0.3.0/go.mod h1:c7nUjQ5pQCqz4LagF1qatcj5NX4icoiSTaCxfdxAwsY=
github.com/confluentinc/ccloud-sdk-go-v2/byok v0.0.2 h1:BV/dPTFVovJPylrcr9lcSmukCVxBxyUeHBr6hp7zUNk=
github.com/confluentinc/ccloud-sdk-go-v2/byok v0.0.2/go.mod h1:MMtRTfg1g32bQrRwfqvGpe+grS5pQzeq9V+L5GKydV4=
github.com/confluentinc/ccloud-sdk-go-v2/byok v0.0.9 h1:TFz/gJ0tPnTsEE56xJwLtU5ykTpfPv0vZwI1jS1QUMg=
github.com/confluentinc/ccloud-sdk-go-v2/byok v0.0.9/go.mod h1:evP8lAu09jGJMQX54bUaJxmT17eQcN4GsmzjTAZst6w=
github.com/confluentinc/ccloud-sdk-go-v2/cam v0.3.0 h1:9MMm9VeJ8ZVg9A6ofplPPvLZH4OGP56PtrJ/WP18EtY=
github.com/confluentinc/ccloud-sdk-go-v2/cam v0.3.0/go.mod h1:vderFceIQXBEdhkulkwTZ0SPxHz4yZ3uDMne/FA4dJ8=
github.com/confluentinc/ccloud-sdk-go-v2/ccl v0.4.0 h1:dUFB7PM/eQbI/AhRHyMh4Pd7xsDDlhonE3/+kwvXVnY=
Expand Down
18 changes: 12 additions & 6 deletions internal/byok/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,17 @@ type command struct {
}

type out struct {
Id string `human:"ID" serialized:"id"`
Key string `human:"Key" serialized:"key"`
Roles []string `human:"Roles" serialized:"roles"`
Cloud string `human:"Cloud" serialized:"cloud"`
State string `human:"State" serialized:"state"`
CreatedAt string `human:"Created At" serialized:"created_at"`
Id string `human:"ID" serialized:"id"`
DisplayName string `human:"Display Name,omitempty" serialized:"display_name,omitempty"`
Key string `human:"Key" serialized:"key"`
Roles []string `human:"Roles" serialized:"roles"`
Cloud string `human:"Cloud" serialized:"cloud"`
ValidationRegion string `human:"Region,omitempty" serialized:"region,omitempty"`
State string `human:"State" serialized:"state"`
CreatedAt string `human:"Created At" serialized:"created_at"`
ValidationPhase string `human:"Validation Phase" serialized:"validation_phase"`
ValidationSince string `human:"Validation Since" serialized:"validation_since"`
ValidationMessage string `human:"Message,omitempty" serialized:"message,omitempty"`
}

func New(prerunner pcmd.PreRunner) *cobra.Command {
Expand All @@ -34,6 +39,7 @@ func New(prerunner pcmd.PreRunner) *cobra.Command {
cmd.AddCommand(c.newDeleteCommand())
cmd.AddCommand(c.newDescribeCommand())
cmd.AddCommand(c.newListCommand())
cmd.AddCommand(c.newUpdateCommand())

return cmd
}
Expand Down
34 changes: 26 additions & 8 deletions internal/byok/command_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,21 +74,26 @@ func (c *command) newCreateCommand() *cobra.Command {

cmd.Flags().String("key-vault", "", "The ID of the Azure Key Vault where the key is stored.")
cmd.Flags().String("tenant", "", "The ID of the Azure Active Directory tenant that the key vault belongs to.")
cmd.Flags().String("display-name", "", "A human-readable name for the self-managed key.")
pcmd.AddOutputFlag(cmd)

cmd.MarkFlagsRequiredTogether("key-vault", "tenant")

return cmd
}

func (c *command) createAwsKeyRequest(keyArn string) byokv1.ByokV1Key {
return byokv1.ByokV1Key{Key: &byokv1.ByokV1KeyKeyOneOf{ByokV1AwsKey: &byokv1.ByokV1AwsKey{
func (c *command) createAwsKeyRequest(keyArn, displayName string) byokv1.ByokV1Key {
key := byokv1.ByokV1Key{Key: &byokv1.ByokV1KeyKeyOneOf{ByokV1AwsKey: &byokv1.ByokV1AwsKey{
KeyArn: keyArn,
Kind: "AwsKey",
}}}
if displayName != "" {
key.SetDisplayName(displayName)
}
return key
}

func (c *command) createAzureKeyRequest(cmd *cobra.Command, keyString string) (byokv1.ByokV1Key, error) {
func (c *command) createAzureKeyRequest(cmd *cobra.Command, keyString, displayName string) (byokv1.ByokV1Key, error) {
keyVault, err := cmd.Flags().GetString("key-vault")
if err != nil {
return byokv1.ByokV1Key{}, err
Expand All @@ -106,33 +111,46 @@ func (c *command) createAzureKeyRequest(cmd *cobra.Command, keyString string) (b
Kind: "AzureKey",
}}}

if displayName != "" {
keyReq.SetDisplayName(displayName)
}

return keyReq, nil
}

func (c *command) createGcpKeyRequest(keyString string) byokv1.ByokV1Key {
return byokv1.ByokV1Key{Key: &byokv1.ByokV1KeyKeyOneOf{ByokV1GcpKey: &byokv1.ByokV1GcpKey{
func (c *command) createGcpKeyRequest(keyString, displayName string) byokv1.ByokV1Key {
key := byokv1.ByokV1Key{Key: &byokv1.ByokV1KeyKeyOneOf{ByokV1GcpKey: &byokv1.ByokV1GcpKey{
KeyId: keyString,
Kind: "GcpKey",
}}}
if displayName != "" {
key.SetDisplayName(displayName)
}
return key
}

func (c *command) create(cmd *cobra.Command, args []string) error {
keyString := args[0]
var keyReq byokv1.ByokV1Key

displayName, err := cmd.Flags().GetString("display-name")
if err != nil {
return err
}

switch {
case cmd.Flags().Changed("key-vault") && cmd.Flags().Changed("tenant"):
keyString = removeKeyVersionFromAzureKeyId(keyString)

request, err := c.createAzureKeyRequest(cmd, keyString)
request, err := c.createAzureKeyRequest(cmd, keyString, displayName)
if err != nil {
return err
}
keyReq = request
case isAWSKey(keyString):
keyReq = c.createAwsKeyRequest(keyString)
keyReq = c.createAwsKeyRequest(keyString, displayName)
case isGcpKey(keyString):
keyReq = c.createGcpKeyRequest(keyString)
keyReq = c.createGcpKeyRequest(keyString, displayName)
default:
return fmt.Errorf("invalid key format: %s", keyString)
}
Expand Down
17 changes: 11 additions & 6 deletions internal/byok/command_describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,17 @@ func (c *command) outputByokKeyDescription(cmd *cobra.Command, key byokv1.ByokV1

table := output.NewTable(cmd)
table.Add(&out{
Id: key.GetId(),
Key: keyString,
Roles: roles,
Cloud: key.GetProvider(),
State: key.GetState(),
CreatedAt: key.Metadata.CreatedAt.String(),
Id: key.GetId(),
DisplayName: key.GetDisplayName(),
Key: keyString,
Roles: roles,
Cloud: key.GetProvider(),
ValidationRegion: key.Validation.GetRegion(),
State: key.GetState(),
CreatedAt: key.Metadata.CreatedAt.String(),
ValidationPhase: key.Validation.GetPhase(),
ValidationMessage: key.Validation.GetMessage(),
ValidationSince: key.Validation.GetSince().String(),
})
table.Print()

Expand Down
40 changes: 33 additions & 7 deletions internal/byok/command_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ func (c *command) newListCommand() *cobra.Command {

pcmd.AddCloudFlag(cmd)
pcmd.AddByokStateFlag(cmd)
cmd.Flags().String("region", "", "Filter by region.")
pcmd.AddByokValidationPhaseFlag(cmd)
cmd.Flags().String("display-name", "", "Filter by display name.")
cmd.Flags().String("key", "", "Filter by key identifier.")
pcmd.AddOutputFlag(cmd)

return cmd
Expand Down Expand Up @@ -49,7 +53,27 @@ func (c *command) list(cmd *cobra.Command, _ []string) error {
state = "AVAILABLE"
}

keys, err := c.V2Client.ListByokKeys(cloud, state)
region, err := cmd.Flags().GetString("region")
if err != nil {
return err
}

phase, err := cmd.Flags().GetString("validation-phase")
if err != nil {
return err
}

displayName, err := cmd.Flags().GetString("display-name")
if err != nil {
return err
}

key, err := cmd.Flags().GetString("key")
if err != nil {
return err
}

keys, err := c.V2Client.ListByokKeys(cloud, state, region, phase, displayName, key)
if err != nil {
return err
}
Expand All @@ -69,17 +93,19 @@ func (c *command) list(cmd *cobra.Command, _ []string) error {
}

list.Add(&out{
Id: key.GetId(),
Key: keyString,
Cloud: key.GetProvider(),
State: key.GetState(),
CreatedAt: key.Metadata.CreatedAt.String(),
Id: key.GetId(),
DisplayName: key.GetDisplayName(),
Key: keyString,
Cloud: key.GetProvider(),
State: key.GetState(),
CreatedAt: key.Metadata.CreatedAt.String(),
ValidationPhase: key.Validation.GetPhase(),
})
}

// The API returns a list sorted by creation date already
list.Sort(false)
list.Filter([]string{"Id", "Key", "Cloud", "State", "CreatedAt"})
list.Filter([]string{"Id", "DisplayName", "Key", "Cloud", "State", "ValidationPhase", "CreatedAt"})

return list.Print()
}
56 changes: 56 additions & 0 deletions internal/byok/command_update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package byok

import (
"github.com/spf13/cobra"

byokv1 "github.com/confluentinc/ccloud-sdk-go-v2/byok/v1"

pcmd "github.com/confluentinc/cli/v4/pkg/cmd"
"github.com/confluentinc/cli/v4/pkg/errors"
"github.com/confluentinc/cli/v4/pkg/examples"
)

func (c *command) newUpdateCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "update <id>",
Short: "Update a self-managed key.",
Long: "Update a self-managed key in Confluent Cloud.",
Args: cobra.ExactArgs(1),
ValidArgsFunction: pcmd.NewValidArgsFunction(c.validArgs),
RunE: c.update,
Example: examples.BuildExampleString(
examples.Example{
Text: `Update the display name of self-managed key "cck-12345".`,
Code: `confluent byok update cck-12345 --display-name "My production key"`,
},
),
}

cmd.Flags().String("display-name", "", "A human-readable name for the self-managed key.")
pcmd.AddOutputFlag(cmd)

cobra.CheckErr(cmd.MarkFlagRequired("display-name"))

return cmd
}

func (c *command) update(cmd *cobra.Command, args []string) error {
keyId := args[0]

displayName, err := cmd.Flags().GetString("display-name")
if err != nil {
return err
}

// Use dedicated update struct following the pattern from API Keys
updateReq := byokv1.ByokV1KeyUpdate{
DisplayName: byokv1.PtrString(displayName),
}

key, httpResp, err := c.V2Client.UpdateByokKey(keyId, updateReq)
if err != nil {
return errors.CatchByokKeyNotFoundError(err, httpResp)
}

return c.outputByokKeyDescription(cmd, key)
}
22 changes: 19 additions & 3 deletions pkg/ccloudv2/byok.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,21 @@ func (c *Client) GetByokKey(keyId string) (byokv1.ByokV1Key, *http.Response, err
return c.ByokClient.KeysByokV1Api.GetByokV1Key(c.byokApiContext(), keyId).Execute()
}

func (c *Client) UpdateByokKey(keyId string, keyUpdate byokv1.ByokV1KeyUpdate) (byokv1.ByokV1Key, *http.Response, error) {
return c.ByokClient.KeysByokV1Api.UpdateByokV1Key(c.byokApiContext(), keyId).ByokV1KeyUpdate(keyUpdate).Execute()
}

func (c *Client) DeleteByokKey(keyId string) (*http.Response, error) {
return c.ByokClient.KeysByokV1Api.DeleteByokV1Key(c.byokApiContext(), keyId).Execute()
}

func (c *Client) ListByokKeys(provider, state string) ([]byokv1.ByokV1Key, error) {
func (c *Client) ListByokKeys(provider, state, region, phase, displayName, key string) ([]byokv1.ByokV1Key, error) {
var list []byokv1.ByokV1Key

done := false
pageToken := ""
for !done {
page, httpResp, err := c.executeListByokKeys(pageToken, provider, state)
page, httpResp, err := c.executeListByokKeys(pageToken, provider, state, region, phase, displayName, key)
if err != nil {
return nil, errors.CatchCCloudV2Error(err, httpResp)
}
Expand All @@ -55,14 +59,26 @@ func (c *Client) ListByokKeys(provider, state string) ([]byokv1.ByokV1Key, error
return list, nil
}

func (c *Client) executeListByokKeys(pageToken, provider, state string) (byokv1.ByokV1KeyList, *http.Response, error) {
func (c *Client) executeListByokKeys(pageToken, provider, state, region, phase, displayName, key string) (byokv1.ByokV1KeyList, *http.Response, error) {
req := c.ByokClient.KeysByokV1Api.ListByokV1Keys(c.byokApiContext()).PageSize(ccloudV2ListPageSize)
if provider != "" {
req = req.Provider(provider)
}
if state != "" {
req = req.State(state)
}
if region != "" {
req = req.ValidationRegion(region)
}
if phase != "" {
req = req.ValidationPhase(phase)
}
if displayName != "" {
req = req.DisplayName(displayName)
}
if key != "" {
req = req.Key(key)
}
if pageToken != "" {
req = req.PageToken(pageToken)
}
Expand Down
7 changes: 6 additions & 1 deletion pkg/cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func AddByokKeyFlag(cmd *cobra.Command, command *AuthenticatedCLICommand) {
}

func AutocompleteByokKeyIds(client *ccloudv2.Client) []string {
keys, err := client.ListByokKeys("", "")
keys, err := client.ListByokKeys("", "", "", "", "", "")
if err != nil {
return nil
}
Expand All @@ -84,6 +84,11 @@ func AddByokStateFlag(cmd *cobra.Command) {
RegisterFlagCompletionFunc(cmd, "state", func(_ *cobra.Command, _ []string) []string { return []string{"in-use", "available"} })
}

func AddByokValidationPhaseFlag(cmd *cobra.Command) {
cmd.Flags().String("validation-phase", "", fmt.Sprintf("Specify the validation phase as %s.", utils.ArrayToCommaDelimitedString([]string{"valid", "invalid", "initializing"}, "or")))
RegisterFlagCompletionFunc(cmd, "validation-phase", func(_ *cobra.Command, _ []string) []string { return []string{"valid", "invalid", "initializing"} })
}

func AddCloudFlag(cmd *cobra.Command) {
cmd.Flags().String("cloud", "", fmt.Sprintf("Specify the cloud provider as %s.", utils.ArrayToCommaDelimitedString(kafka.Clouds, "or")))
RegisterFlagCompletionFunc(cmd, "cloud", func(_ *cobra.Command, _ []string) []string { return kafka.Clouds })
Expand Down
Loading