Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 docs/commands/vpc-gw.md
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ scw vpc-gw gateway delete <gateway-id ...> [arg=value ...]
| Name | | Description |
|------|---|-------------|
| gateway-id | Required | ID of the gateway to delete |
| delete-ip | | Defines whether the PGW's IP should be deleted |
| with-ip | Default: `prompt`<br />One of: `prompt`, `true`, `false` | Delete the IP attached to the gateway |
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe there is a way to avoid a breaking change here

| zone | Default: `fr-par-1`<br />One of: `fr-par-1`, `fr-par-2`, `nl-ams-1`, `nl-ams-2`, `nl-ams-3`, `pl-waw-1`, `pl-waw-2`, `pl-waw-3` | Zone to target. If none is passed will use default zone from the config |
Comment on lines 368 to 370
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs replace delete-ip with with-ip. If delete-ip is already released, this is a breaking CLI change for users following existing docs/scripts; consider documenting delete-ip as a deprecated alias (or keeping it) to preserve backward compatibility.

Copilot uses AI. Check for mistakes.


Expand Down
1 change: 1 addition & 0 deletions internal/namespaces/vpcgw/v2/custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func GetCommands() *core.Commands {

cmds.MustFind("vpc-gw", "gateway-type", "list").Override(vpcgwGatewayTypeListBuilder)
cmds.MustFind("vpc-gw", "gateway", "create").Override(gatewayCreateBuilder)
cmds.MustFind("vpc-gw", "gateway", "delete").Override(gatewayDeleteBuilder)
cmds.MustFind("vpc-gw", "gateway-network", "create").Override(gatewayNetworkCreateBuilder)
cmds.MustFind("vpc-gw", "gateway-network", "delete").Override(gatewayNetworkDeleteBuilder)

Expand Down
105 changes: 105 additions & 0 deletions internal/namespaces/vpcgw/v2/custom_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package vpcgw

import (
"context"
"reflect"
"time"

"github.com/fatih/color"
"github.com/scaleway/scaleway-cli/v2/core"
"github.com/scaleway/scaleway-cli/v2/core/human"
"github.com/scaleway/scaleway-cli/v2/internal/interactive"
"github.com/scaleway/scaleway-sdk-go/api/vpcgw/v2"
"github.com/scaleway/scaleway-sdk-go/scw"
)
Expand Down Expand Up @@ -63,3 +65,106 @@ func gatewayMarshalerFunc(i any, opt *human.MarshalOpt) (string, error) {

return str, nil
}

// Custom delete gateway command with interactive IP deletion confirmation
type customDeleteGatewayRequest struct {
Zone scw.Zone
GatewayID string
DeleteIP bool
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

customDeleteGatewayRequest defines DeleteIP but the field is never read and there is no ArgSpec for delete-ip, so it is currently dead code. Either remove this field, or reintroduce delete-ip as a deprecated alias (ideally as *bool so you can distinguish “not set” from “set to false”) and map it to the new behavior.

Suggested change
DeleteIP bool

Copilot uses AI. Check for mistakes.
WithIP string // "prompt", "true", "false"
}

const (
withIPPrompt = "prompt"
withIPTrue = "true"
withIPFalse = "false"
)

func gatewayDeleteBuilder(c *core.Command) *core.Command {
c.ArgsType = reflect.TypeOf(customDeleteGatewayRequest{})
c.ArgSpecs = core.ArgSpecs{
{
Name: "gateway-id",
Short: "ID of the gateway to delete",
Required: true,
Positional: true,
},
{
Name: "with-ip",
Short: "Delete the IP attached to the gateway",
Default: core.DefaultValueSetter(withIPPrompt),
EnumValues: []string{
withIPPrompt,
withIPTrue,
withIPFalse,
},
},
Comment on lines +93 to +101
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This override renames the CLI arg from delete-ip (generated command) to with-ip, which will break existing scripts. Consider keeping delete-ip as a deprecated alias (e.g., same OneOfGroup as with-ip to prevent both being set) and translating it to with-ip=true/false behavior internally.

Suggested change
Name: "with-ip",
Short: "Delete the IP attached to the gateway",
Default: core.DefaultValueSetter(withIPPrompt),
EnumValues: []string{
withIPPrompt,
withIPTrue,
withIPFalse,
},
},
Name: "with-ip",
Short: "Delete the IP attached to the gateway",
Default: core.DefaultValueSetter(withIPPrompt),
EnumValues: []string{
withIPPrompt,
withIPTrue,
withIPFalse,
},
OneOfGroup: "gateway-delete-ip-mode",
},
{
Name: "delete-ip",
Short: "Delete the IP attached to the gateway (deprecated, use with-ip instead)",
Deprecated: "use with-ip instead",
OneOfGroup: "gateway-delete-ip-mode",
},

Copilot uses AI. Check for mistakes.
core.ZoneArgSpec(
scw.ZoneFrPar1,
scw.ZoneFrPar2,
scw.ZoneNlAms1,
scw.ZoneNlAms2,
scw.ZoneNlAms3,
scw.ZonePlWaw1,
scw.ZonePlWaw2,
scw.ZonePlWaw3,
),
}
c.Run = func(ctx context.Context, argsI any) (any, error) {
args := argsI.(*customDeleteGatewayRequest)

client := core.ExtractClient(ctx)
api := vpcgw.NewAPI(client)

// Get gateway info to check if it has an IP
gateway, err := api.GetGateway(&vpcgw.GetGatewayRequest{
Zone: args.Zone,
GatewayID: args.GatewayID,
})
if err != nil {
return nil, err
Comment on lines +119 to +125
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetGateway is called unconditionally before deleting. If with-ip is explicitly true or false, this extra API call is unnecessary and can introduce extra latency / permission failures. Consider only fetching the gateway (and prompting) when with-ip=prompt is selected (or when using the deprecated alias, if kept).

Suggested change
// Get gateway info to check if it has an IP
gateway, err := api.GetGateway(&vpcgw.GetGatewayRequest{
Zone: args.Zone,
GatewayID: args.GatewayID,
})
if err != nil {
return nil, err
var gateway *vpcgw.Gateway
var err error
// Only fetch gateway info when we may need to prompt about deleting the IP
if args.WithIP == withIPPrompt {
gateway, err = api.GetGateway(&vpcgw.GetGatewayRequest{
Zone: args.Zone,
GatewayID: args.GatewayID,
})
if err != nil {
return nil, err
}

Copilot uses AI. Check for mistakes.
}

// Determine if we should delete the IP
deleteIP, err := shouldDeleteIP(ctx, gateway, args.WithIP)
if err != nil {
return nil, err
}

request := &vpcgw.DeleteGatewayRequest{
Zone: args.Zone,
GatewayID: args.GatewayID,
DeleteIP: deleteIP,
}

return api.DeleteGateway(request)
}

return c
}

func shouldDeleteIP(
ctx context.Context,
gateway *vpcgw.Gateway,
withIP string,
) (bool, error) {
switch withIP {
case withIPTrue:
return true, nil
case withIPFalse:
return false, nil
case withIPPrompt:
// Only prompt user if gateway has an IP
if gateway.IPv4 == nil {
return false, nil
}

return interactive.PromptBoolWithConfig(&interactive.PromptBoolConfig{
Prompt: "Do you also want to delete the IP attached to this gateway?",
DefaultValue: false,
Ctx: ctx,
})
default:
return false, nil
}
Comment on lines +167 to +169
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In shouldDeleteIP, the default case silently returns (false, nil). This can hide unexpected values and change behavior without surfacing an error. Other tri-state flags in the codebase return an error for unsupported values (e.g. internal/namespaces/instance/v1/custom_server_action.go with-block handling). Return a descriptive error here instead of silently defaulting.

Copilot uses AI. Check for mistakes.
}
Loading