diff --git a/go.mod b/go.mod index c4e7424aea..e0eb5c94ac 100644 --- a/go.mod +++ b/go.mod @@ -38,6 +38,7 @@ require ( github.com/confluentinc/ccloud-sdk-go-v2/networking v0.12.0 github.com/confluentinc/ccloud-sdk-go-v2/networking-access-point v0.3.0 github.com/confluentinc/ccloud-sdk-go-v2/networking-dnsforwarder v0.2.0 + github.com/confluentinc/ccloud-sdk-go-v2/networking-gateway v0.2.0 github.com/confluentinc/ccloud-sdk-go-v2/networking-ip v0.2.0 github.com/confluentinc/ccloud-sdk-go-v2/networking-privatelink v0.2.0 github.com/confluentinc/ccloud-sdk-go-v2/org v0.9.0 diff --git a/go.sum b/go.sum index 44d6cdf51b..105e6aef8f 100644 --- a/go.sum +++ b/go.sum @@ -241,6 +241,8 @@ github.com/confluentinc/ccloud-sdk-go-v2/networking-access-point v0.3.0 h1:8STgb github.com/confluentinc/ccloud-sdk-go-v2/networking-access-point v0.3.0/go.mod h1:HV1xGUwTsGEU3Mgvc+7Ya/0HRpUO69L2rqqxO7LeWMc= github.com/confluentinc/ccloud-sdk-go-v2/networking-dnsforwarder v0.2.0 h1:OdIeCGfy8iQ2Bm+08CDXYttwZOUme0e9FVGrBjBJGx4= github.com/confluentinc/ccloud-sdk-go-v2/networking-dnsforwarder v0.2.0/go.mod h1:472T8ufudvXgXea2BhYxhE/2eowwhoulZzboDh6+ec4= +github.com/confluentinc/ccloud-sdk-go-v2/networking-gateway v0.2.0 h1:a3eTOQy6tlbcZIFzcAKQPoZALi6Csg4phlCQLPyUdsA= +github.com/confluentinc/ccloud-sdk-go-v2/networking-gateway v0.2.0/go.mod h1:zDswAVbulZWmPVEREWPU6jvwi5E7Q95SdY7abYdqVfA= github.com/confluentinc/ccloud-sdk-go-v2/networking-ip v0.2.0 h1:ZHNF2DeqVlNPuKGZ41SBMLGj8GBlvvcwOPnfZLZXA/4= github.com/confluentinc/ccloud-sdk-go-v2/networking-ip v0.2.0/go.mod h1:KTShFBZA7WG8LcxlWjJpoZFdWkJ+uOw3dDuwAHs5eKU= github.com/confluentinc/ccloud-sdk-go-v2/networking-privatelink v0.2.0 h1:3nm/8KnxWeEL4djyGs293g++4xvOGKUNklf5J7MYsas= diff --git a/internal/network/command_access_point_private_link_egress_endpoint_create.go b/internal/network/command_access_point_private_link_egress_endpoint_create.go index 4cdeced9ec..43d487f13e 100644 --- a/internal/network/command_access_point_private_link_egress_endpoint_create.go +++ b/internal/network/command_access_point_private_link_egress_endpoint_create.go @@ -1,7 +1,6 @@ package network import ( - "fmt" "strings" "github.com/spf13/cobra" @@ -11,7 +10,6 @@ import ( pcloud "github.com/confluentinc/cli/v4/pkg/cloud" pcmd "github.com/confluentinc/cli/v4/pkg/cmd" "github.com/confluentinc/cli/v4/pkg/examples" - "github.com/confluentinc/cli/v4/pkg/utils" ) func (c *accessPointCommand) newCreateCommand() *cobra.Command { @@ -32,7 +30,7 @@ func (c *accessPointCommand) newCreateCommand() *cobra.Command { ), } - cmd.Flags().String("cloud", "", fmt.Sprintf("Specify the cloud provider as %s.", utils.ArrayToCommaDelimitedString([]string{"aws", "azure"}, "or"))) + pcmd.AddCloudAwsAzureFlag(cmd) cmd.Flags().String("service", "", "Name of an AWS VPC endpoint service or ID of an Azure Private Link service.") addGatewayFlag(cmd, c.AuthenticatedCLICommand) cmd.Flags().String("subresource", "", "Name of an Azure Private Link subresource.") diff --git a/internal/network/command_gateway.go b/internal/network/command_gateway.go index 0763c4e56f..d56726ffc5 100644 --- a/internal/network/command_gateway.go +++ b/internal/network/command_gateway.go @@ -5,10 +5,31 @@ import ( "github.com/spf13/cobra" - networkingv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking/v1" + networkinggatewayv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-gateway/v1" "github.com/confluentinc/cli/v4/pkg/ccloudv2" pcloud "github.com/confluentinc/cli/v4/pkg/cloud" + pcmd "github.com/confluentinc/cli/v4/pkg/cmd" + "github.com/confluentinc/cli/v4/pkg/errors" + "github.com/confluentinc/cli/v4/pkg/network" + "github.com/confluentinc/cli/v4/pkg/output" + "github.com/confluentinc/cli/v4/pkg/utils" +) + +const ( + awsEgressPrivateLink = "AwsEgressPrivateLink" + awsPeering = "AwsPeering" + azureEgressPrivateLink = "AzureEgressPrivateLink" + azurePeering = "AzurePeering" +) + +var ( + createGatewayTypes = []string{"egress-privatelink"} + listGatewayTypes = []string{"aws-egress-privatelink", "azure-egress-privatelink"} + gatewayTypeMap = map[string]string{ + "aws-egress-privatelink": awsEgressPrivateLink, + "azure-egress-privatelink": azureEgressPrivateLink, + } ) type gatewayOut struct { @@ -16,9 +37,11 @@ type gatewayOut struct { Name string `human:"Name,omitempty" serialized:"name,omitempty"` Environment string `human:"Environment" serialized:"environment"` Region string `human:"Region,omitempty" serialized:"region,omitempty"` + Type string `human:"Type,omitempty" serialized:"type,omitempty"` AwsPrincipalArn string `human:"AWS Principal ARN,omitempty" serialized:"aws_principal_arn,omitempty"` AzureSubscription string `human:"Azure Subscription,omitempty" serialized:"azure_subscription,omitempty"` Phase string `human:"Phase" serialized:"phase"` + ErrorMessage string `human:"Error Message,omitempty" serialized:"error_message,omitempty"` } func (c *command) newGatewayCommand() *cobra.Command { @@ -28,17 +51,49 @@ func (c *command) newGatewayCommand() *cobra.Command { Args: cobra.NoArgs, } + cmd.AddCommand(c.newGatewayCreateCommand()) + cmd.AddCommand(c.newGatewayDeleteCommand()) cmd.AddCommand(c.newGatewayDescribeCommand()) cmd.AddCommand(c.newGatewayListCommand()) + cmd.AddCommand(c.newGatewayUpdateCommand()) return cmd } +func addGatewayTypeFlag(cmd *cobra.Command) { + cmd.Flags().String("type", "", fmt.Sprintf("Specify the gateway type as %s.", utils.ArrayToCommaDelimitedString(createGatewayTypes, "or"))) + pcmd.RegisterFlagCompletionFunc(cmd, "type", func(_ *cobra.Command, _ []string) []string { return createGatewayTypes }) +} + +func (c *command) addRegionFlagGateway(cmd *cobra.Command, command *pcmd.AuthenticatedCLICommand) { + cmd.Flags().String("region", "", "AWS or Azure region of the gateway.") + pcmd.RegisterFlagCompletionFunc(cmd, "region", func(cmd *cobra.Command, args []string) []string { + if err := c.PersistentPreRunE(cmd, args); err != nil { + return nil + } + + cloud, _ := cmd.Flags().GetString("cloud") + regions, err := network.ListRegions(command.Client, cloud) + if err != nil { + return nil + } + + suggestions := make([]string, len(regions)) + for i, region := range regions { + suggestions[i] = region.RegionId + } + return suggestions + }) +} + func (c *command) validGatewayArgs(cmd *cobra.Command, args []string) []string { if len(args) > 0 { return nil } + return c.validGatewayArgsMultiple(cmd, args) +} +func (c *command) validGatewayArgsMultiple(cmd *cobra.Command, args []string) []string { if err := c.PersistentPreRunE(cmd, args); err != nil { return nil } @@ -52,7 +107,7 @@ func (c *command) validGatewayArgs(cmd *cobra.Command, args []string) []string { } func autocompleteGateways(client *ccloudv2.Client, environmentId string) []string { - gateways, err := client.ListGateways(environmentId) + gateways, err := client.ListGateways(environmentId, nil) if err != nil { return nil } @@ -64,7 +119,7 @@ func autocompleteGateways(client *ccloudv2.Client, environmentId string) []strin return suggestions } -func getGatewayCloud(gateway networkingv1.NetworkingV1Gateway) string { +func getGatewayCloud(gateway networkinggatewayv1.NetworkingV1Gateway) string { cloud := gateway.Status.GetCloudGateway() if cloud.NetworkingV1AwsEgressPrivateLinkGatewayStatus != nil { @@ -77,3 +132,48 @@ func getGatewayCloud(gateway networkingv1.NetworkingV1Gateway) string { return "" } + +func printGatewayTable(cmd *cobra.Command, gateway networkinggatewayv1.NetworkingV1Gateway) error { + if gateway.Spec == nil { + return fmt.Errorf(errors.CorruptedNetworkResponseErrorMsg, "spec") + } + if gateway.Status == nil { + return fmt.Errorf(errors.CorruptedNetworkResponseErrorMsg, "status") + } + + out := &gatewayOut{ + Id: gateway.GetId(), + Name: gateway.Spec.GetDisplayName(), + Environment: gateway.Spec.Environment.GetId(), + Phase: gateway.Status.GetPhase(), + ErrorMessage: gateway.Status.GetErrorMessage(), + } + + if gateway.Spec.Config != nil && gateway.Spec.Config.NetworkingV1AwsEgressPrivateLinkGatewaySpec != nil { + out.Region = gateway.Spec.Config.NetworkingV1AwsEgressPrivateLinkGatewaySpec.GetRegion() + out.Type = awsEgressPrivateLink + } + if gateway.Spec.Config != nil && gateway.Spec.Config.NetworkingV1AwsPeeringGatewaySpec != nil { + out.Region = gateway.Spec.Config.NetworkingV1AwsPeeringGatewaySpec.GetRegion() + out.Type = awsPeering + } + if gateway.Spec.Config != nil && gateway.Spec.Config.NetworkingV1AzureEgressPrivateLinkGatewaySpec != nil { + out.Region = gateway.Spec.Config.NetworkingV1AzureEgressPrivateLinkGatewaySpec.GetRegion() + out.Type = azureEgressPrivateLink + } + if gateway.Spec.Config != nil && gateway.Spec.Config.NetworkingV1AzurePeeringGatewaySpec != nil { + out.Region = gateway.Spec.Config.NetworkingV1AzurePeeringGatewaySpec.GetRegion() + out.Type = azurePeering + } + + switch getGatewayCloud(gateway) { + case pcloud.Aws: + out.AwsPrincipalArn = gateway.Status.CloudGateway.NetworkingV1AwsEgressPrivateLinkGatewayStatus.GetPrincipalArn() + case pcloud.Azure: + out.AzureSubscription = gateway.Status.CloudGateway.NetworkingV1AzureEgressPrivateLinkGatewayStatus.GetSubscription() + } + + table := output.NewTable(cmd) + table.Add(out) + return table.Print() +} diff --git a/internal/network/command_gateway_create.go b/internal/network/command_gateway_create.go new file mode 100644 index 0000000000..cc7703c9c6 --- /dev/null +++ b/internal/network/command_gateway_create.go @@ -0,0 +1,102 @@ +package network + +import ( + "strings" + + "github.com/spf13/cobra" + + networkinggatewayv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-gateway/v1" + + pcloud "github.com/confluentinc/cli/v4/pkg/cloud" + pcmd "github.com/confluentinc/cli/v4/pkg/cmd" + "github.com/confluentinc/cli/v4/pkg/examples" +) + +func (c *command) newGatewayCreateCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "create [name]", + Short: "Create a network gateway.", + Args: cobra.MaximumNArgs(1), + RunE: c.gatewayCreate, + Example: examples.BuildExampleString( + examples.Example{ + Text: `Create network gateway "my-gateway".`, + Code: "confluent network gateway create my-gateway --cloud aws --region us-east-1 --type egress-privatelink", + }, + ), + } + + pcmd.AddCloudAwsAzureFlag(cmd) + addGatewayTypeFlag(cmd) + c.addRegionFlagGateway(cmd, c.AuthenticatedCLICommand) + pcmd.AddContextFlag(cmd, c.CLICommand) + pcmd.AddEnvironmentFlag(cmd, c.AuthenticatedCLICommand) + pcmd.AddOutputFlag(cmd) + + cobra.CheckErr(cmd.MarkFlagRequired("cloud")) + cobra.CheckErr(cmd.MarkFlagRequired("type")) + cobra.CheckErr(cmd.MarkFlagRequired("region")) + + return cmd +} + +func (c *command) gatewayCreate(cmd *cobra.Command, args []string) error { + cloud, err := cmd.Flags().GetString("cloud") + if err != nil { + return err + } + cloud = strings.ToUpper(cloud) + + region, err := cmd.Flags().GetString("region") + if err != nil { + return err + } + + gatewayType, err := cmd.Flags().GetString("type") + if err != nil { + return err + } + + environmentId, err := c.Context.EnvironmentId() + if err != nil { + return err + } + + createGateway := networkinggatewayv1.NetworkingV1Gateway{ + Spec: &networkinggatewayv1.NetworkingV1GatewaySpec{ + Environment: &networkinggatewayv1.ObjectReference{Id: environmentId}, + }, + } + + switch cloud { + case pcloud.Aws: + if gatewayType == "egress-privatelink" { + createGateway.Spec.Config = &networkinggatewayv1.NetworkingV1GatewaySpecConfigOneOf{ + NetworkingV1AwsEgressPrivateLinkGatewaySpec: &networkinggatewayv1.NetworkingV1AwsEgressPrivateLinkGatewaySpec{ + Kind: "AwsEgressPrivateLinkGatewaySpec", + Region: region, + }, + } + } + case pcloud.Azure: + if gatewayType == "egress-privatelink" { + createGateway.Spec.Config = &networkinggatewayv1.NetworkingV1GatewaySpecConfigOneOf{ + NetworkingV1AzureEgressPrivateLinkGatewaySpec: &networkinggatewayv1.NetworkingV1AzureEgressPrivateLinkGatewaySpec{ + Kind: "AzureEgressPrivateLinkGatewaySpec", + Region: region, + }, + } + } + } + + if len(args) == 1 { + createGateway.Spec.SetDisplayName(args[0]) + } + + gateway, err := c.V2Client.CreateGateway(createGateway) + if err != nil { + return err + } + + return printGatewayTable(cmd, gateway) +} diff --git a/internal/network/command_gateway_delete.go b/internal/network/command_gateway_delete.go new file mode 100644 index 0000000000..374ebee6c4 --- /dev/null +++ b/internal/network/command_gateway_delete.go @@ -0,0 +1,63 @@ +package network + +import ( + "fmt" + + "github.com/spf13/cobra" + + pcmd "github.com/confluentinc/cli/v4/pkg/cmd" + "github.com/confluentinc/cli/v4/pkg/deletion" + "github.com/confluentinc/cli/v4/pkg/errors" + "github.com/confluentinc/cli/v4/pkg/output" + "github.com/confluentinc/cli/v4/pkg/resource" + "github.com/confluentinc/cli/v4/pkg/utils" +) + +func (c *command) newGatewayDeleteCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "delete [id-2] ... [id-n]", + Short: "Delete one or more gateways.", + Args: cobra.MinimumNArgs(1), + ValidArgsFunction: pcmd.NewValidArgsFunction(c.validGatewayArgsMultiple), + RunE: c.gatewayDelete, + } + + pcmd.AddForceFlag(cmd) + pcmd.AddContextFlag(cmd, c.CLICommand) + pcmd.AddEnvironmentFlag(cmd, c.AuthenticatedCLICommand) + + return cmd +} + +func (c *command) gatewayDelete(cmd *cobra.Command, args []string) error { + environmentId, err := c.Context.EnvironmentId() + if err != nil { + return err + } + + existenceFunc := func(id string) bool { + _, err := c.V2Client.GetGateway(environmentId, id) + return err == nil + } + + if err := deletion.ValidateAndConfirm(cmd, args, existenceFunc, resource.Gateway); err != nil { + return err + } + + deleteFunc := func(id string) error { + if err := c.V2Client.DeleteGateway(environmentId, id); err != nil { + return fmt.Errorf(errors.DeleteResourceErrorMsg, resource.Gateway, id, err) + } + return nil + } + + deletedIds, err := deletion.DeleteWithoutMessage(args, deleteFunc) + deleteMsg := "Requested to delete %s %s.\n" + if len(deletedIds) == 1 { + output.Printf(c.Config.EnableColor, deleteMsg, resource.Gateway, fmt.Sprintf(`"%s"`, deletedIds[0])) + } else if len(deletedIds) > 1 { + output.Printf(c.Config.EnableColor, deleteMsg, resource.Plural(resource.Gateway), utils.ArrayToCommaDelimitedString(deletedIds, "and")) + } + + return err +} diff --git a/internal/network/command_gateway_describe.go b/internal/network/command_gateway_describe.go index 702db23432..ab60e84636 100644 --- a/internal/network/command_gateway_describe.go +++ b/internal/network/command_gateway_describe.go @@ -1,15 +1,10 @@ package network import ( - "fmt" - "github.com/spf13/cobra" - pcloud "github.com/confluentinc/cli/v4/pkg/cloud" pcmd "github.com/confluentinc/cli/v4/pkg/cmd" - "github.com/confluentinc/cli/v4/pkg/errors" "github.com/confluentinc/cli/v4/pkg/examples" - "github.com/confluentinc/cli/v4/pkg/output" ) func (c *command) newGatewayDescribeCommand() *cobra.Command { @@ -45,43 +40,5 @@ func (c *command) gatewayDescribe(cmd *cobra.Command, args []string) error { return err } - if gateway.Spec == nil { - return fmt.Errorf(errors.CorruptedNetworkResponseErrorMsg, "spec") - } - if gateway.Status == nil { - return fmt.Errorf(errors.CorruptedNetworkResponseErrorMsg, "status") - } - - out := &gatewayOut{ - Id: gateway.GetId(), - Name: gateway.Spec.GetDisplayName(), - Environment: gateway.Spec.Environment.GetId(), - Phase: gateway.Status.GetPhase(), - } - - if gateway.Spec.Config != nil && gateway.Spec.Config.NetworkingV1AwsEgressPrivateLinkGatewaySpec != nil { - out.Region = gateway.Spec.Config.NetworkingV1AwsEgressPrivateLinkGatewaySpec.GetRegion() - } - if gateway.Spec.Config != nil && gateway.Spec.Config.NetworkingV1AwsPeeringGatewaySpec != nil { - out.Region = gateway.Spec.Config.NetworkingV1AwsPeeringGatewaySpec.GetRegion() - } - if gateway.Spec.Config != nil && gateway.Spec.Config.NetworkingV1AzureEgressPrivateLinkGatewaySpec != nil { - out.Region = gateway.Spec.Config.NetworkingV1AzureEgressPrivateLinkGatewaySpec.GetRegion() - } - if gateway.Spec.Config != nil && gateway.Spec.Config.NetworkingV1AzurePeeringGatewaySpec != nil { - out.Region = gateway.Spec.Config.NetworkingV1AzurePeeringGatewaySpec.GetRegion() - } - - cloud := getGatewayCloud(gateway) - - switch cloud { - case pcloud.Aws: - out.AwsPrincipalArn = gateway.Status.CloudGateway.NetworkingV1AwsEgressPrivateLinkGatewayStatus.GetPrincipalArn() - case pcloud.Azure: - out.AzureSubscription = gateway.Status.CloudGateway.NetworkingV1AzureEgressPrivateLinkGatewayStatus.GetSubscription() - } - - table := output.NewTable(cmd) - table.Add(out) - return table.Print() + return printGatewayTable(cmd, gateway) } diff --git a/internal/network/command_gateway_list.go b/internal/network/command_gateway_list.go index 314e32e8c9..578908ff5b 100644 --- a/internal/network/command_gateway_list.go +++ b/internal/network/command_gateway_list.go @@ -9,6 +9,7 @@ import ( pcmd "github.com/confluentinc/cli/v4/pkg/cmd" "github.com/confluentinc/cli/v4/pkg/errors" "github.com/confluentinc/cli/v4/pkg/output" + "github.com/confluentinc/cli/v4/pkg/utils" ) func (c *command) newGatewayListCommand() *cobra.Command { @@ -19,6 +20,7 @@ func (c *command) newGatewayListCommand() *cobra.Command { RunE: c.gatewayList, } + cmd.Flags().StringSlice("types", nil, fmt.Sprintf("A comma-separated list of gateway types: %s.", utils.ArrayToCommaDelimitedString(listGatewayTypes, "or"))) pcmd.AddContextFlag(cmd, c.CLICommand) pcmd.AddEnvironmentFlag(cmd, c.AuthenticatedCLICommand) pcmd.AddOutputFlag(cmd) @@ -32,7 +34,17 @@ func (c *command) gatewayList(cmd *cobra.Command, _ []string) error { return nil } - gateways, err := c.V2Client.ListGateways(environmentId) + types, err := cmd.Flags().GetStringSlice("types") + if err != nil { + return err + } + for i, gatewayType := range types { + if val, ok := gatewayTypeMap[gatewayType]; ok { + types[i] = val + } + } + + gateways, err := c.V2Client.ListGateways(environmentId, types) if err != nil { return err } @@ -47,28 +59,31 @@ func (c *command) gatewayList(cmd *cobra.Command, _ []string) error { } out := &gatewayOut{ - Id: gateway.GetId(), - Name: gateway.Spec.GetDisplayName(), - Environment: gateway.Spec.Environment.GetId(), - Phase: gateway.Status.GetPhase(), + Id: gateway.GetId(), + Name: gateway.Spec.GetDisplayName(), + Environment: gateway.Spec.Environment.GetId(), + Phase: gateway.Status.GetPhase(), + ErrorMessage: gateway.Status.GetErrorMessage(), } if gateway.Spec.Config != nil && gateway.Spec.Config.NetworkingV1AwsEgressPrivateLinkGatewaySpec != nil { out.Region = gateway.Spec.Config.NetworkingV1AwsEgressPrivateLinkGatewaySpec.GetRegion() + out.Type = awsEgressPrivateLink } if gateway.Spec.Config != nil && gateway.Spec.Config.NetworkingV1AwsPeeringGatewaySpec != nil { out.Region = gateway.Spec.Config.NetworkingV1AwsPeeringGatewaySpec.GetRegion() + out.Type = awsPeering } if gateway.Spec.Config != nil && gateway.Spec.Config.NetworkingV1AzureEgressPrivateLinkGatewaySpec != nil { out.Region = gateway.Spec.Config.NetworkingV1AzureEgressPrivateLinkGatewaySpec.GetRegion() + out.Type = azureEgressPrivateLink } if gateway.Spec.Config != nil && gateway.Spec.Config.NetworkingV1AzurePeeringGatewaySpec != nil { out.Region = gateway.Spec.Config.NetworkingV1AzurePeeringGatewaySpec.GetRegion() + out.Type = azurePeering } - cloud := getGatewayCloud(gateway) - - switch cloud { + switch getGatewayCloud(gateway) { case pcloud.Aws: out.AwsPrincipalArn = gateway.Status.CloudGateway.NetworkingV1AwsEgressPrivateLinkGatewayStatus.GetPrincipalArn() case pcloud.Azure: diff --git a/internal/network/command_gateway_update.go b/internal/network/command_gateway_update.go new file mode 100644 index 0000000000..e5048a1d05 --- /dev/null +++ b/internal/network/command_gateway_update.go @@ -0,0 +1,60 @@ +package network + +import ( + "github.com/spf13/cobra" + + networkinggatewayv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-gateway/v1" + + pcmd "github.com/confluentinc/cli/v4/pkg/cmd" + "github.com/confluentinc/cli/v4/pkg/examples" +) + +func (c *command) newGatewayUpdateCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "update ", + Short: "Update a gateway.", + Args: cobra.ExactArgs(1), + RunE: c.gatewayUpdate, + Example: examples.BuildExampleString( + examples.Example{ + Text: `Update the name of gateway "gw-abc123".`, + Code: "confluent network gateway update gw-abc123 --name new-name", + }, + ), + } + + cmd.Flags().String("name", "", "Name of the gateway.") + pcmd.AddContextFlag(cmd, c.CLICommand) + pcmd.AddEnvironmentFlag(cmd, c.AuthenticatedCLICommand) + pcmd.AddOutputFlag(cmd) + + cobra.CheckErr(cmd.MarkFlagRequired("name")) + + return cmd +} + +func (c *command) gatewayUpdate(cmd *cobra.Command, args []string) error { + environmentId, err := c.Context.EnvironmentId() + if err != nil { + return err + } + + name, err := cmd.Flags().GetString("name") + if err != nil { + return err + } + + updateGateway := networkinggatewayv1.NetworkingV1GatewayUpdate{ + Spec: &networkinggatewayv1.NetworkingV1GatewaySpecUpdate{ + DisplayName: networkinggatewayv1.PtrString(name), + Environment: &networkinggatewayv1.ObjectReference{Id: environmentId}, + }, + } + + gateway, err := c.V2Client.UpdateGateway(args[0], updateGateway) + if err != nil { + return err + } + + return printGatewayTable(cmd, gateway) +} diff --git a/pkg/ccloudv2/client.go b/pkg/ccloudv2/client.go index fad13795ae..913f9918f6 100644 --- a/pkg/ccloudv2/client.go +++ b/pkg/ccloudv2/client.go @@ -20,6 +20,7 @@ import ( mdsv2 "github.com/confluentinc/ccloud-sdk-go-v2/mds/v2" networkingaccesspointv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-access-point/v1" networkingdnsforwarderv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-dnsforwarder/v1" + networkinggatewayv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-gateway/v1" networkingipv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-ip/v1" networkingprivatelinkv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-privatelink/v1" networkingv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking/v1" @@ -57,9 +58,10 @@ type Client struct { KsqlClient *ksqlv2.APIClient MdsClient *mdsv2.APIClient NetworkingClient *networkingv1.APIClient + NetworkingAccessPointClient *networkingaccesspointv1.APIClient NetworkingDnsForwarderClient *networkingdnsforwarderv1.APIClient + NetworkingGatewayClient *networkinggatewayv1.APIClient NetworkingIpClient *networkingipv1.APIClient - NetworkingAccessPointClient *networkingaccesspointv1.APIClient NetworkingPrivateLinkClient *networkingprivatelinkv1.APIClient OrgClient *orgv2.APIClient ProviderIntegrationClient *pi.APIClient @@ -101,9 +103,10 @@ func NewClient(cfg *config.Config, unsafeTrace bool) *Client { KsqlClient: newKsqlClient(httpClient, url, userAgent, unsafeTrace), MdsClient: newMdsClient(httpClient, url, userAgent, unsafeTrace), NetworkingClient: newNetworkingClient(httpClient, url, userAgent, unsafeTrace), + NetworkingAccessPointClient: newNetworkingAccessPointClient(httpClient, url, userAgent, unsafeTrace), NetworkingDnsForwarderClient: newNetworkingDnsForwarderClient(httpClient, url, userAgent, unsafeTrace), + NetworkingGatewayClient: newNetworkingGatewayClient(httpClient, url, userAgent, unsafeTrace), NetworkingIpClient: newNetworkingIpClient(httpClient, url, userAgent, unsafeTrace), - NetworkingAccessPointClient: newNetworkingAccessPointClient(httpClient, url, userAgent, unsafeTrace), NetworkingPrivateLinkClient: newNetworkingPrivateLinkClient(httpClient, url, userAgent, unsafeTrace), OrgClient: newOrgClient(httpClient, url, userAgent, unsafeTrace), ProviderIntegrationClient: newProviderIntegrationClient(httpClient, url, userAgent, unsafeTrace), diff --git a/pkg/ccloudv2/networking-gateway.go b/pkg/ccloudv2/networking-gateway.go new file mode 100644 index 0000000000..07a014a36c --- /dev/null +++ b/pkg/ccloudv2/networking-gateway.go @@ -0,0 +1,74 @@ +package ccloudv2 + +import ( + "context" + "net/http" + + networkinggatewayv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-gateway/v1" + + "github.com/confluentinc/cli/v4/pkg/errors" +) + +func newNetworkingGatewayClient(httpClient *http.Client, url, userAgent string, unsafeTrace bool) *networkinggatewayv1.APIClient { + cfg := networkinggatewayv1.NewConfiguration() + cfg.Debug = unsafeTrace + cfg.HTTPClient = httpClient + cfg.Servers = networkinggatewayv1.ServerConfigurations{{URL: url}} + cfg.UserAgent = userAgent + + return networkinggatewayv1.NewAPIClient(cfg) +} + +func (c *Client) networkingGatewayApiContext() context.Context { + return context.WithValue(context.Background(), networkinggatewayv1.ContextAccessToken, c.cfg.Context().GetAuthToken()) +} + +func (c *Client) GetGateway(environment, id string) (networkinggatewayv1.NetworkingV1Gateway, error) { + resp, httpResp, err := c.NetworkingGatewayClient.GatewaysNetworkingV1Api.GetNetworkingV1Gateway(c.networkingGatewayApiContext(), id).Environment(environment).Execute() + return resp, errors.CatchCCloudV2Error(err, httpResp) +} + +func (c *Client) DeleteGateway(environment, id string) error { + httpResp, err := c.NetworkingGatewayClient.GatewaysNetworkingV1Api.DeleteNetworkingV1Gateway(c.networkingGatewayApiContext(), id).Environment(environment).Execute() + return errors.CatchCCloudV2Error(err, httpResp) +} + +func (c *Client) CreateGateway(gateway networkinggatewayv1.NetworkingV1Gateway) (networkinggatewayv1.NetworkingV1Gateway, error) { + resp, httpResp, err := c.NetworkingGatewayClient.GatewaysNetworkingV1Api.CreateNetworkingV1Gateway(c.networkingGatewayApiContext()).NetworkingV1Gateway(gateway).Execute() + return resp, errors.CatchCCloudV2Error(err, httpResp) +} + +func (c *Client) UpdateGateway(id string, gatewayUpdate networkinggatewayv1.NetworkingV1GatewayUpdate) (networkinggatewayv1.NetworkingV1Gateway, error) { + resp, httpResp, err := c.NetworkingGatewayClient.GatewaysNetworkingV1Api.UpdateNetworkingV1Gateway(c.networkingGatewayApiContext(), id).NetworkingV1GatewayUpdate(gatewayUpdate).Execute() + return resp, errors.CatchCCloudV2Error(err, httpResp) +} + +func (c *Client) ListGateways(environment string, types []string) ([]networkinggatewayv1.NetworkingV1Gateway, error) { + var list []networkinggatewayv1.NetworkingV1Gateway + + done := false + pageToken := "" + for !done { + page, err := c.executeListGateways(environment, pageToken, types) + if err != nil { + return nil, err + } + list = append(list, page.GetData()...) + + pageToken, done, err = extractNextPageToken(page.GetMetadata().Next) + if err != nil { + return nil, err + } + } + return list, nil +} + +func (c *Client) executeListGateways(environment, pageToken string, types []string) (networkinggatewayv1.NetworkingV1GatewayList, error) { + req := c.NetworkingGatewayClient.GatewaysNetworkingV1Api.ListNetworkingV1Gateways(c.networkingGatewayApiContext()).GatewayType(types).Environment(environment).PageSize(ccloudV2ListPageSize) + if pageToken != "" { + req = req.PageToken(pageToken) + } + + resp, httpResp, err := req.Execute() + return resp, errors.CatchCCloudV2Error(err, httpResp) +} diff --git a/pkg/ccloudv2/networking.go b/pkg/ccloudv2/networking.go index 2fa50a338d..fb5e534a53 100644 --- a/pkg/ccloudv2/networking.go +++ b/pkg/ccloudv2/networking.go @@ -23,41 +23,6 @@ func (c *Client) networkingApiContext() context.Context { return context.WithValue(context.Background(), networkingv1.ContextAccessToken, c.cfg.Context().GetAuthToken()) } -func (c *Client) GetGateway(environment, id string) (networkingv1.NetworkingV1Gateway, error) { - resp, httpResp, err := c.NetworkingClient.GatewaysNetworkingV1Api.GetNetworkingV1Gateway(c.networkingApiContext(), id).Environment(environment).Execute() - return resp, errors.CatchCCloudV2Error(err, httpResp) -} - -func (c *Client) ListGateways(environment string) ([]networkingv1.NetworkingV1Gateway, error) { - var list []networkingv1.NetworkingV1Gateway - - done := false - pageToken := "" - for !done { - page, err := c.executeListGateways(environment, pageToken) - if err != nil { - return nil, err - } - list = append(list, page.GetData()...) - - pageToken, done, err = extractNextPageToken(page.GetMetadata().Next) - if err != nil { - return nil, err - } - } - return list, nil -} - -func (c *Client) executeListGateways(environment, pageToken string) (networkingv1.NetworkingV1GatewayList, error) { - req := c.NetworkingClient.GatewaysNetworkingV1Api.ListNetworkingV1Gateways(c.networkingApiContext()).Environment(environment).PageSize(ccloudV2ListPageSize) - if pageToken != "" { - req = req.PageToken(pageToken) - } - - resp, httpResp, err := req.Execute() - return resp, errors.CatchCCloudV2Error(err, httpResp) -} - func (c *Client) GetNetwork(environment, id string) (networkingv1.NetworkingV1Network, error) { resp, httpResp, err := c.NetworkingClient.NetworksNetworkingV1Api.GetNetworkingV1Network(c.networkingApiContext(), id).Environment(environment).Execute() return resp, errors.CatchCCloudV2Error(err, httpResp) diff --git a/pkg/cmd/flags.go b/pkg/cmd/flags.go index b1a4453cd0..75083362db 100644 --- a/pkg/cmd/flags.go +++ b/pkg/cmd/flags.go @@ -89,6 +89,11 @@ func AddCloudFlag(cmd *cobra.Command) { RegisterFlagCompletionFunc(cmd, "cloud", func(_ *cobra.Command, _ []string) []string { return kafka.Clouds }) } +func AddCloudAwsAzureFlag(cmd *cobra.Command) { + cmd.Flags().String("cloud", "", fmt.Sprintf("Specify the cloud provider as %s.", utils.ArrayToCommaDelimitedString(kafka.Clouds[:2], "or"))) + RegisterFlagCompletionFunc(cmd, "cloud", func(_ *cobra.Command, _ []string) []string { return kafka.Clouds[:2] }) +} + func AddListCloudFlag(cmd *cobra.Command) { cmd.Flags().StringSlice("cloud", nil, "A comma-separated list of cloud providers.") RegisterFlagCompletionFunc(cmd, "cloud", func(_ *cobra.Command, _ []string) []string { return kafka.Clouds }) diff --git a/pkg/resource/resource.go b/pkg/resource/resource.go index 48edeb1867..f212b92ae5 100644 --- a/pkg/resource/resource.go +++ b/pkg/resource/resource.go @@ -41,6 +41,7 @@ const ( FlinkRegion = "Flink region" FlinkStatement = "Flink SQL statement" FlinkConnection = "Flink connection" + Gateway = "gateway" IdentityPool = "identity pool" IdentityProvider = "identity provider" IpGroup = "IP group" diff --git a/test/fixtures/output/network/gateway/create-aws.golden b/test/fixtures/output/network/gateway/create-aws.golden new file mode 100644 index 0000000000..45a5891b6d --- /dev/null +++ b/test/fixtures/output/network/gateway/create-aws.golden @@ -0,0 +1,9 @@ ++-------------------+--------------------------------+ +| ID | gw-abc123 | +| Name | my-gateway | +| Environment | env-596 | +| Region | us-west-2 | +| Type | AwsEgressPrivateLink | +| AWS Principal ARN | arn:aws:iam::123456789012:role | +| Phase | READY | ++-------------------+--------------------------------+ diff --git a/test/fixtures/output/network/gateway/create-help.golden b/test/fixtures/output/network/gateway/create-help.golden new file mode 100644 index 0000000000..24190862e4 --- /dev/null +++ b/test/fixtures/output/network/gateway/create-help.golden @@ -0,0 +1,22 @@ +Create a network gateway. + +Usage: + confluent network gateway create [name] [flags] + +Examples: +Create network gateway "my-gateway". + + $ confluent network gateway create my-gateway --cloud aws --region us-east-1 --type egress-privatelink + +Flags: + --cloud string REQUIRED: Specify the cloud provider as "aws" or "azure". + --type string REQUIRED: Specify the gateway type as "egress-privatelink". + --region string REQUIRED: AWS or Azure region of the gateway. + --context string CLI context name. + --environment string Environment ID. + -o, --output string Specify the output format as "human", "json", or "yaml". (default "human") + +Global Flags: + -h, --help Show help for this command. + --unsafe-trace Equivalent to -vvvv, but also log HTTP requests and responses which might contain plaintext secrets. + -v, --verbose count Increase verbosity (-v for warn, -vv for info, -vvv for debug, -vvvv for trace). diff --git a/test/fixtures/output/network/gateway/create-type-autocomplete.golden b/test/fixtures/output/network/gateway/create-type-autocomplete.golden new file mode 100644 index 0000000000..a5a1897c7a --- /dev/null +++ b/test/fixtures/output/network/gateway/create-type-autocomplete.golden @@ -0,0 +1,3 @@ +egress-privatelink +:4 +Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/test/fixtures/output/network/gateway/delete-fail.golden b/test/fixtures/output/network/gateway/delete-fail.golden new file mode 100644 index 0000000000..ddacadb265 --- /dev/null +++ b/test/fixtures/output/network/gateway/delete-fail.golden @@ -0,0 +1,4 @@ +Error: gateway "gw-invalid" not found + +Suggestions: + List available gateways with `confluent network gateway list`. diff --git a/test/fixtures/output/network/gateway/delete-help.golden b/test/fixtures/output/network/gateway/delete-help.golden new file mode 100644 index 0000000000..440aa21a1c --- /dev/null +++ b/test/fixtures/output/network/gateway/delete-help.golden @@ -0,0 +1,14 @@ +Delete one or more gateways. + +Usage: + confluent network gateway delete [id-2] ... [id-n] [flags] + +Flags: + --force Skip the deletion confirmation prompt. + --context string CLI context name. + --environment string Environment ID. + +Global Flags: + -h, --help Show help for this command. + --unsafe-trace Equivalent to -vvvv, but also log HTTP requests and responses which might contain plaintext secrets. + -v, --verbose count Increase verbosity (-v for warn, -vv for info, -vvv for debug, -vvvv for trace). diff --git a/test/fixtures/output/network/gateway/delete-multiple.golden b/test/fixtures/output/network/gateway/delete-multiple.golden new file mode 100644 index 0000000000..b10c409d4c --- /dev/null +++ b/test/fixtures/output/network/gateway/delete-multiple.golden @@ -0,0 +1 @@ +Are you sure you want to delete gateways "gw-12345" and "gw-54321"? (y/n): Requested to delete gateways "gw-12345" and "gw-54321". diff --git a/test/fixtures/output/network/gateway/delete.golden b/test/fixtures/output/network/gateway/delete.golden new file mode 100644 index 0000000000..6fe2b00776 --- /dev/null +++ b/test/fixtures/output/network/gateway/delete.golden @@ -0,0 +1 @@ +Are you sure you want to delete gateway "gw-12345"? (y/n): Requested to delete gateway "gw-12345". diff --git a/test/fixtures/output/network/gateway/describe-aws-json.golden b/test/fixtures/output/network/gateway/describe-aws-json.golden index c07b9957c8..bd05e8b8c7 100644 --- a/test/fixtures/output/network/gateway/describe-aws-json.golden +++ b/test/fixtures/output/network/gateway/describe-aws-json.golden @@ -3,6 +3,7 @@ "name": "my-aws-gateway", "environment": "env-596", "region": "us-east-1", + "type": "AwsEgressPrivateLink", "aws_principal_arn": "arn:aws:iam::123456789012:role", "phase": "READY" } diff --git a/test/fixtures/output/network/gateway/describe-aws.golden b/test/fixtures/output/network/gateway/describe-aws.golden index e740d0f0f6..6b5a24b4af 100644 --- a/test/fixtures/output/network/gateway/describe-aws.golden +++ b/test/fixtures/output/network/gateway/describe-aws.golden @@ -3,6 +3,7 @@ | Name | my-aws-gateway | | Environment | env-596 | | Region | us-east-1 | +| Type | AwsEgressPrivateLink | | AWS Principal ARN | arn:aws:iam::123456789012:role | | Phase | READY | +-------------------+--------------------------------+ diff --git a/test/fixtures/output/network/gateway/describe-azure.golden b/test/fixtures/output/network/gateway/describe-azure.golden index 73952e7b9a..f742ef8131 100644 --- a/test/fixtures/output/network/gateway/describe-azure.golden +++ b/test/fixtures/output/network/gateway/describe-azure.golden @@ -3,6 +3,7 @@ | Name | my-azure-gateway | | Environment | env-596 | | Region | eastus | +| Type | AzureEgressPrivateLink | | Azure Subscription | aa000000-a000-0a00-00aa-0000aaa0a0a0 | | Phase | READY | +--------------------+--------------------------------------+ diff --git a/test/fixtures/output/network/gateway/help.golden b/test/fixtures/output/network/gateway/help.golden index 5e922ffd85..8910755be9 100644 --- a/test/fixtures/output/network/gateway/help.golden +++ b/test/fixtures/output/network/gateway/help.golden @@ -4,8 +4,11 @@ Usage: confluent network gateway [command] Available Commands: + create Create a network gateway. + delete Delete one or more gateways. describe Describe a gateway. list List gateways. + update Update a gateway. Global Flags: -h, --help Show help for this command. diff --git a/test/fixtures/output/network/gateway/list-help.golden b/test/fixtures/output/network/gateway/list-help.golden index ac94d749f3..b9117d155a 100644 --- a/test/fixtures/output/network/gateway/list-help.golden +++ b/test/fixtures/output/network/gateway/list-help.golden @@ -4,6 +4,7 @@ Usage: confluent network gateway list [flags] Flags: + --types strings A comma-separated list of gateway types: "aws-egress-privatelink" or "azure-egress-privatelink". --context string CLI context name. --environment string Environment ID. -o, --output string Specify the output format as "human", "json", or "yaml". (default "human") diff --git a/test/fixtures/output/network/gateway/list-json.golden b/test/fixtures/output/network/gateway/list-json.golden index d864da0c9b..f3b7c73850 100644 --- a/test/fixtures/output/network/gateway/list-json.golden +++ b/test/fixtures/output/network/gateway/list-json.golden @@ -4,6 +4,7 @@ "name": "my-azure-peering-gateway", "environment": "env-596", "region": "eastus2", + "type": "AzurePeering", "phase": "READY" }, { @@ -11,6 +12,7 @@ "name": "my-aws-gateway", "environment": "env-596", "region": "us-east-1", + "type": "AwsEgressPrivateLink", "aws_principal_arn": "arn:aws:iam::123456789012:role", "phase": "READY" }, @@ -19,6 +21,7 @@ "name": "my-aws-peering-gateway", "environment": "env-596", "region": "us-east-2", + "type": "AwsPeering", "phase": "READY" }, { @@ -26,6 +29,7 @@ "name": "my-azure-gateway", "environment": "env-596", "region": "eastus", + "type": "AzureEgressPrivateLink", "azure_subscription": "aa000000-a000-0a00-00aa-0000aaa0a0a0", "phase": "READY" } diff --git a/test/fixtures/output/network/gateway/list.golden b/test/fixtures/output/network/gateway/list.golden index 9ffbd2b382..2db811ade1 100644 --- a/test/fixtures/output/network/gateway/list.golden +++ b/test/fixtures/output/network/gateway/list.golden @@ -1,6 +1,6 @@ - ID | Name | Environment | Region | AWS Principal ARN | Azure Subscription | Phase ------------+--------------------------+-------------+-----------+--------------------------------+--------------------------------------+-------- - gw-09876 | my-azure-peering-gateway | env-596 | eastus2 | | | READY - gw-12345 | my-aws-gateway | env-596 | us-east-1 | arn:aws:iam::123456789012:role | | READY - gw-67890 | my-aws-peering-gateway | env-596 | us-east-2 | | | READY - gw-67890 | my-azure-gateway | env-596 | eastus | | aa000000-a000-0a00-00aa-0000aaa0a0a0 | READY + ID | Name | Environment | Region | Type | AWS Principal ARN | Azure Subscription | Phase | Error Message +-----------+--------------------------+-------------+-----------+------------------------+--------------------------------+--------------------------------------+-------+---------------- + gw-09876 | my-azure-peering-gateway | env-596 | eastus2 | AzurePeering | | | READY | + gw-12345 | my-aws-gateway | env-596 | us-east-1 | AwsEgressPrivateLink | arn:aws:iam::123456789012:role | | READY | + gw-67890 | my-aws-peering-gateway | env-596 | us-east-2 | AwsPeering | | | READY | + gw-67890 | my-azure-gateway | env-596 | eastus | AzureEgressPrivateLink | | aa000000-a000-0a00-00aa-0000aaa0a0a0 | READY | diff --git a/test/fixtures/output/network/gateway/update-help.golden b/test/fixtures/output/network/gateway/update-help.golden new file mode 100644 index 0000000000..9ee6914036 --- /dev/null +++ b/test/fixtures/output/network/gateway/update-help.golden @@ -0,0 +1,20 @@ +Update a gateway. + +Usage: + confluent network gateway update [flags] + +Examples: +Update the name of gateway "gw-abc123". + + $ confluent network gateway update gw-abc123 --name new-name + +Flags: + --name string REQUIRED: Name of the gateway. + --context string CLI context name. + --environment string Environment ID. + -o, --output string Specify the output format as "human", "json", or "yaml". (default "human") + +Global Flags: + -h, --help Show help for this command. + --unsafe-trace Equivalent to -vvvv, but also log HTTP requests and responses which might contain plaintext secrets. + -v, --verbose count Increase verbosity (-v for warn, -vv for info, -vvv for debug, -vvvv for trace). diff --git a/test/fixtures/output/network/gateway/update.golden b/test/fixtures/output/network/gateway/update.golden new file mode 100644 index 0000000000..1eef138749 --- /dev/null +++ b/test/fixtures/output/network/gateway/update.golden @@ -0,0 +1,9 @@ ++-------------------+--------------------------------+ +| ID | gw-111111 | +| Name | new-name | +| Environment | env-abc123 | +| Region | us-east-1 | +| Type | AwsEgressPrivateLink | +| AWS Principal ARN | arn:aws:iam::123456789012:role | +| Phase | READY | ++-------------------+--------------------------------+ diff --git a/test/network_test.go b/test/network_test.go index 17cac4c517..e3df0c0500 100644 --- a/test/network_test.go +++ b/test/network_test.go @@ -116,6 +116,21 @@ func (s *CLITestSuite) TestNetwork_Autocomplete() { } } +func (s *CLITestSuite) TestNetworkGateway() { + tests := []CLITest{ + {args: "network gateway create my-gateway --cloud aws --type egress-privatelink --region us-west-2", fixture: "network/gateway/create-aws.golden"}, + {args: "network gateway update gw-111111 --name new-name", fixture: "network/gateway/update.golden"}, + {args: "network gateway delete gw-12345", input: "y\n", fixture: "network/gateway/delete.golden"}, + {args: "network gateway delete gw-12345 gw-54321", input: "y\n", fixture: "network/gateway/delete-multiple.golden"}, + {args: "network gateway delete gw-invalid", input: "y\n", fixture: "network/gateway/delete-fail.golden", exitCode: 1}, + } + + for _, test := range tests { + test.login = "cloud" + s.runIntegrationTest(test) + } +} + func (s *CLITestSuite) TestNetworkGatewayDescribe() { tests := []CLITest{ {args: "network gateway describe gw-12345", fixture: "network/gateway/describe-aws.golden"}, @@ -143,7 +158,8 @@ func (s *CLITestSuite) TestNetworkGatewayList() { func (s *CLITestSuite) TestNetworkGateway_Autocomplete() { tests := []CLITest{ - {args: `__complete network gateway describe ""`, login: "cloud", fixture: "network/gateway/describe-autocomplete.golden"}, + {args: `__complete network gateway describe ""`, fixture: "network/gateway/describe-autocomplete.golden"}, + {args: `__complete network gateway create --type ""`, fixture: "network/gateway/create-type-autocomplete.golden"}, } for _, test := range tests { diff --git a/test/test-server/networking_handlers.go b/test/test-server/networking_handlers.go index 53c7fdb8c6..d961efb191 100644 --- a/test/test-server/networking_handlers.go +++ b/test/test-server/networking_handlers.go @@ -14,6 +14,7 @@ import ( networkingaccesspointv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-access-point/v1" networkingdnsforwarderv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-dnsforwarder/v1" + networkinggatewayv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-gateway/v1" networkingipv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-ip/v1" networkingprivatelinkv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking-privatelink/v1" networkingv1 "github.com/confluentinc/ccloud-sdk-go-v2/networking/v1" @@ -51,7 +52,14 @@ func handleNetworkingGateway(t *testing.T) http.HandlerFunc { id := mux.Vars(r)["id"] environment := r.URL.Query().Get("environment") - handleNetworkingGatewayGet(t, id, environment)(w, r) + switch r.Method { + case http.MethodGet: + handleNetworkingGatewayGet(t, id, environment)(w, r) + case http.MethodDelete: + handleNetworkingGatewayDelete(t, id)(w, r) + case http.MethodPatch: + handleNetworkingGatewayPatch(t, id)(w, r) + } } } @@ -61,6 +69,8 @@ func handleNetworkingGateways(t *testing.T) http.HandlerFunc { switch r.Method { case http.MethodGet: handleNetworkingGatewayList(t, environment)(w, r) + case http.MethodPost: + handleNetworkingGatewayPost(t)(w, r) } } } @@ -2131,34 +2141,34 @@ func getIpAddress(ipPrefix, cloud, region string, services []string) networkingi } } -func getGateway(id, environment, name, specConfigKind, statusCloudGatewayKind string) networkingv1.NetworkingV1Gateway { - gateway := networkingv1.NetworkingV1Gateway{ +func getGateway(id, environment, name, specConfigKind, statusCloudGatewayKind string) networkinggatewayv1.NetworkingV1Gateway { + gateway := networkinggatewayv1.NetworkingV1Gateway{ Id: networkingv1.PtrString(id), - Spec: &networkingv1.NetworkingV1GatewaySpec{ + Spec: &networkinggatewayv1.NetworkingV1GatewaySpec{ DisplayName: networkingv1.PtrString(name), - Environment: &networkingv1.ObjectReference{Id: environment}, + Environment: &networkinggatewayv1.ObjectReference{Id: environment}, }, - Status: &networkingv1.NetworkingV1GatewayStatus{Phase: "READY"}, + Status: &networkinggatewayv1.NetworkingV1GatewayStatus{Phase: "READY"}, } switch specConfigKind { case "AwsEgressPrivateLinkGatewaySpec": - gateway.Spec.SetConfig(networkingv1.NetworkingV1AwsEgressPrivateLinkGatewaySpecAsNetworkingV1GatewaySpecConfigOneOf(&networkingv1.NetworkingV1AwsEgressPrivateLinkGatewaySpec{ + gateway.Spec.SetConfig(networkinggatewayv1.NetworkingV1AwsEgressPrivateLinkGatewaySpecAsNetworkingV1GatewaySpecConfigOneOf(&networkinggatewayv1.NetworkingV1AwsEgressPrivateLinkGatewaySpec{ Kind: specConfigKind, Region: "us-east-1", })) case "AwsPeeringGatewaySpec": - gateway.Spec.SetConfig(networkingv1.NetworkingV1AwsPeeringGatewaySpecAsNetworkingV1GatewaySpecConfigOneOf(&networkingv1.NetworkingV1AwsPeeringGatewaySpec{ + gateway.Spec.SetConfig(networkinggatewayv1.NetworkingV1AwsPeeringGatewaySpecAsNetworkingV1GatewaySpecConfigOneOf(&networkinggatewayv1.NetworkingV1AwsPeeringGatewaySpec{ Kind: specConfigKind, Region: "us-east-2", })) case "AzureEgressPrivateLinkGatewaySpec": - gateway.Spec.SetConfig(networkingv1.NetworkingV1AzureEgressPrivateLinkGatewaySpecAsNetworkingV1GatewaySpecConfigOneOf(&networkingv1.NetworkingV1AzureEgressPrivateLinkGatewaySpec{ + gateway.Spec.SetConfig(networkinggatewayv1.NetworkingV1AzureEgressPrivateLinkGatewaySpecAsNetworkingV1GatewaySpecConfigOneOf(&networkinggatewayv1.NetworkingV1AzureEgressPrivateLinkGatewaySpec{ Kind: specConfigKind, Region: "eastus", })) case "AzurePeeringGatewaySpec": - gateway.Spec.SetConfig(networkingv1.NetworkingV1AzurePeeringGatewaySpecAsNetworkingV1GatewaySpecConfigOneOf(&networkingv1.NetworkingV1AzurePeeringGatewaySpec{ + gateway.Spec.SetConfig(networkinggatewayv1.NetworkingV1AzurePeeringGatewaySpecAsNetworkingV1GatewaySpecConfigOneOf(&networkinggatewayv1.NetworkingV1AzurePeeringGatewaySpec{ Kind: specConfigKind, Region: "eastus2", })) @@ -2166,14 +2176,14 @@ func getGateway(id, environment, name, specConfigKind, statusCloudGatewayKind st switch statusCloudGatewayKind { case "AwsEgressPrivateLinkGatewayStatus": - gateway.Status.SetCloudGateway(networkingv1.NetworkingV1AwsEgressPrivateLinkGatewayStatusAsNetworkingV1GatewayStatusCloudGatewayOneOf(&networkingv1.NetworkingV1AwsEgressPrivateLinkGatewayStatus{ + gateway.Status.SetCloudGateway(networkinggatewayv1.NetworkingV1AwsEgressPrivateLinkGatewayStatusAsNetworkingV1GatewayStatusCloudGatewayOneOf(&networkinggatewayv1.NetworkingV1AwsEgressPrivateLinkGatewayStatus{ Kind: statusCloudGatewayKind, - PrincipalArn: networkingv1.PtrString("arn:aws:iam::123456789012:role"), + PrincipalArn: networkinggatewayv1.PtrString("arn:aws:iam::123456789012:role"), })) case "AzureEgressPrivateLinkGatewayStatus": - gateway.Status.SetCloudGateway(networkingv1.NetworkingV1AzureEgressPrivateLinkGatewayStatusAsNetworkingV1GatewayStatusCloudGatewayOneOf(&networkingv1.NetworkingV1AzureEgressPrivateLinkGatewayStatus{ + gateway.Status.SetCloudGateway(networkinggatewayv1.NetworkingV1AzureEgressPrivateLinkGatewayStatusAsNetworkingV1GatewayStatusCloudGatewayOneOf(&networkinggatewayv1.NetworkingV1AzureEgressPrivateLinkGatewayStatus{ Kind: statusCloudGatewayKind, - Subscription: networkingv1.PtrString("aa000000-a000-0a00-00aa-0000aaa0a0a0"), + Subscription: networkinggatewayv1.PtrString("aa000000-a000-0a00-00aa-0000aaa0a0a0"), })) } @@ -2183,6 +2193,10 @@ func getGateway(id, environment, name, specConfigKind, statusCloudGatewayKind st func handleNetworkingGatewayGet(t *testing.T, id, environment string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { switch id { + case "gw-invalid": + w.WriteHeader(http.StatusNotFound) + err := writeErrorJson(w, "The gateway gw-invalid was not found.") + require.NoError(t, err) case "gw-12345": record := getGateway(id, environment, "my-aws-gateway", "AwsEgressPrivateLinkGatewaySpec", "AwsEgressPrivateLinkGatewayStatus") err := json.NewEncoder(w).Encode(record) @@ -2195,6 +2209,47 @@ func handleNetworkingGatewayGet(t *testing.T, id, environment string) http.Handl } } +func handleNetworkingGatewayDelete(_ *testing.T, id string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + switch id { + default: + w.WriteHeader(http.StatusNoContent) + } + } +} + +func handleNetworkingGatewayPost(t *testing.T) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + body := &networkinggatewayv1.NetworkingV1Gateway{} + err := json.NewDecoder(r.Body).Decode(body) + require.NoError(t, err) + + gateway := networkinggatewayv1.NetworkingV1Gateway{ + Id: networkingv1.PtrString("gw-abc123"), + Spec: &networkinggatewayv1.NetworkingV1GatewaySpec{ + DisplayName: body.Spec.DisplayName, + Environment: &networkinggatewayv1.ObjectReference{Id: body.Spec.Environment.GetId()}, + Config: body.Spec.Config, + }, + Status: &networkinggatewayv1.NetworkingV1GatewayStatus{Phase: "READY"}, + } + if body.Spec.Config.NetworkingV1AwsEgressPrivateLinkGatewaySpec != nil { + gateway.Status.SetCloudGateway(networkinggatewayv1.NetworkingV1AwsEgressPrivateLinkGatewayStatusAsNetworkingV1GatewayStatusCloudGatewayOneOf(&networkinggatewayv1.NetworkingV1AwsEgressPrivateLinkGatewayStatus{ + Kind: "AwsEgressPrivateLinkGatewayStatus", + PrincipalArn: networkingv1.PtrString("arn:aws:iam::123456789012:role"), + })) + } else if body.Spec.Config.NetworkingV1AzureEgressPrivateLinkGatewaySpec != nil { + gateway.Status.SetCloudGateway(networkinggatewayv1.NetworkingV1AzureEgressPrivateLinkGatewayStatusAsNetworkingV1GatewayStatusCloudGatewayOneOf(&networkinggatewayv1.NetworkingV1AzureEgressPrivateLinkGatewayStatus{ + Kind: "AzureEgressPrivateLinkGatewayStatus", + Subscription: networkingv1.PtrString("aa000000-a000-0a00-00aa-0000aaa0a0a0"), + })) + } + + err = json.NewEncoder(w).Encode(gateway) + require.NoError(t, err) + } +} + func handleNetworkingGatewayList(t *testing.T, environment string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { gatewayOne := getGateway("gw-12345", environment, "my-aws-gateway", "AwsEgressPrivateLinkGatewaySpec", "AwsEgressPrivateLinkGatewayStatus") @@ -2202,12 +2257,27 @@ func handleNetworkingGatewayList(t *testing.T, environment string) http.HandlerF gatewayThree := getGateway("gw-67890", environment, "my-azure-gateway", "AzureEgressPrivateLinkGatewaySpec", "AzureEgressPrivateLinkGatewayStatus") gatewayFour := getGateway("gw-09876", environment, "my-azure-peering-gateway", "AzurePeeringGatewaySpec", "") - recordList := networkingv1.NetworkingV1GatewayList{Data: []networkingv1.NetworkingV1Gateway{gatewayOne, gatewayTwo, gatewayThree, gatewayFour}} + recordList := networkinggatewayv1.NetworkingV1GatewayList{Data: []networkinggatewayv1.NetworkingV1Gateway{gatewayOne, gatewayTwo, gatewayThree, gatewayFour}} err := json.NewEncoder(w).Encode(recordList) require.NoError(t, err) } } +func handleNetworkingGatewayPatch(t *testing.T, id string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + switch id { + case "gw-111111": + body := &networkinggatewayv1.NetworkingV1GatewayUpdate{} + err := json.NewDecoder(r.Body).Decode(body) + require.NoError(t, err) + + gateway := getGateway("gw-111111", "env-abc123", body.Spec.GetDisplayName(), "AwsEgressPrivateLinkGatewaySpec", "AwsEgressPrivateLinkGatewayStatus") + err = json.NewEncoder(w).Encode(gateway) + require.NoError(t, err) + } + } +} + func getDnsRecord(id, environment, name string) networkingaccesspointv1.NetworkingV1DnsRecord { return networkingaccesspointv1.NetworkingV1DnsRecord{ Id: networkingaccesspointv1.PtrString(id),