Skip to content

Commit 7d0ba5f

Browse files
authored
Introduce vpc nat gateways api (#1698)
* Support vpc nat gateways api * Default as public gateway type * Mark command as hidden
1 parent c20b49e commit 7d0ba5f

File tree

10 files changed

+690
-0
lines changed

10 files changed

+690
-0
lines changed

args.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,23 @@ const (
118118
// ArgAutoscaleTargetInstances is an autoscale target instance argument.
119119
ArgAutoscaleTargetInstances = "target-instances"
120120

121+
// ArgVPCNATGatewayName is a vpc nat gateway name argument.
122+
ArgVPCNATGatewayName = "name"
123+
// ArgVPCNATGatewayType is a vpc nat gateway type argument.
124+
ArgVPCNATGatewayType = "type"
125+
// ArgVPCNATGatewayRegion is a vpc nat gateway region argument.
126+
ArgVPCNATGatewayRegion = "region"
127+
// ArgVPCNATGatewaySize is a vpc nat gateway region argument.
128+
ArgVPCNATGatewaySize = "size"
129+
// ArgVPCNATGatewayVPCs is a vpc nat gateway vpcs argument.
130+
ArgVPCNATGatewayVPCs = "vpcs"
131+
// ArgVPCNATGatewayUDPTimeout is a vpc nat gateway udp-timeout argument.
132+
ArgVPCNATGatewayUDPTimeout = "udp-timeout"
133+
// ArgVPCNATGatewayICMPTimeout is a vpc nat gateway icmp-timeout argument.
134+
ArgVPCNATGatewayICMPTimeout = "icmp-timeout"
135+
// ArgVPCNATGatewayTCPTimeout is a vpc nat gateway tcp-timeout argument.
136+
ArgVPCNATGatewayTCPTimeout = "tcp-timeout"
137+
121138
// ArgHA is a cluster's highly available control plane argument.
122139
ArgHA = "ha"
123140
// ArgEnableControlPlaneFirewall enable control plane firewall.

commands/command_config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ type CmdConfig struct {
5252
DropletActions func() do.DropletActionsService
5353
DropletAutoscale func() do.DropletAutoscaleService
5454
Domains func() do.DomainsService
55+
VPCNATGateways func() do.VPCNATGatewaysService
5556
Actions func() do.ActionsService
5657
Account func() do.AccountService
5758
Balance func() do.BalanceService
@@ -108,6 +109,7 @@ func NewCmdConfig(ns string, dc doctl.Config, out io.Writer, args []string, init
108109
c.DropletActions = func() do.DropletActionsService { return do.NewDropletActionsService(godoClient) }
109110
c.DropletAutoscale = func() do.DropletAutoscaleService { return do.NewDropletAutoscaleService(godoClient) }
110111
c.Domains = func() do.DomainsService { return do.NewDomainsService(godoClient) }
112+
c.VPCNATGateways = func() do.VPCNATGatewaysService { return do.NewVPCNATGatewaysService(godoClient) }
111113
c.Actions = func() do.ActionsService { return do.NewActionsService(godoClient) }
112114
c.Account = func() do.AccountService { return do.NewAccountService(godoClient) }
113115
c.Balance = func() do.BalanceService { return do.NewBalanceService(godoClient) }

commands/commands_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ type tcMocks struct {
246246
registry *domocks.MockRegistryService
247247
sshRunner *domocks.MockRunner
248248
vpcs *domocks.MockVPCsService
249+
vpcNatGateways *domocks.MockVPCNATGatewaysService
249250
oneClick *domocks.MockOneClickService
250251
listen *domocks.MockListenerService
251252
terminal *domocks.MockTerminal
@@ -287,6 +288,7 @@ func withTestClient(t *testing.T, tFn testFn) {
287288
uptimeChecks: domocks.NewMockUptimeChecksService(ctrl),
288289
volumes: domocks.NewMockVolumesService(ctrl),
289290
volumeActions: domocks.NewMockVolumeActionsService(ctrl),
291+
vpcNatGateways: domocks.NewMockVPCNATGatewaysService(ctrl),
290292
snapshots: domocks.NewMockSnapshotsService(ctrl),
291293
certificates: domocks.NewMockCertificatesService(ctrl),
292294
loadBalancers: domocks.NewMockLoadBalancersService(ctrl),
@@ -352,6 +354,7 @@ func withTestClient(t *testing.T, tFn testFn) {
352354
UptimeChecks: func() do.UptimeChecksService { return tm.uptimeChecks },
353355
Volumes: func() do.VolumesService { return tm.volumes },
354356
VolumeActions: func() do.VolumeActionsService { return tm.volumeActions },
357+
VPCNATGateways: func() do.VPCNATGatewaysService { return tm.vpcNatGateways },
355358
Snapshots: func() do.SnapshotsService { return tm.snapshots },
356359
Certificates: func() do.CertificatesService { return tm.certificates },
357360
LoadBalancers: func() do.LoadBalancersService { return tm.loadBalancers },
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package displayers
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"strings"
7+
8+
"github.com/digitalocean/godo"
9+
)
10+
11+
type VPCNATGateways struct {
12+
VPCNATGateways []*godo.VPCNATGateway `json:"vpc_nat_gateways"`
13+
}
14+
15+
var _ Displayable = &VPCNATGateways{}
16+
17+
func (e *VPCNATGateways) Cols() []string {
18+
return []string{
19+
"ID",
20+
"Name",
21+
"Type",
22+
"State",
23+
"Region",
24+
"VPCs",
25+
"Egresses",
26+
"Timeouts",
27+
}
28+
}
29+
30+
func (e *VPCNATGateways) ColMap() map[string]string {
31+
return map[string]string{
32+
"ID": "ID",
33+
"Name": "Name",
34+
"Type": "Type",
35+
"State": "State",
36+
"Region": "Region",
37+
"VPCs": "VPCs",
38+
"Egresses": "Egresses",
39+
"Timeouts": "Timeouts",
40+
}
41+
}
42+
43+
func (e *VPCNATGateways) KV() []map[string]any {
44+
out := make([]map[string]any, 0, len(e.VPCNATGateways))
45+
for _, gateway := range e.VPCNATGateways {
46+
out = append(out, map[string]any{
47+
"ID": gateway.ID,
48+
"Name": gateway.Name,
49+
"Type": gateway.Type,
50+
"State": gateway.State,
51+
"Region": gateway.Region,
52+
"VPCs": func() string {
53+
var vpcs []string
54+
for _, vpc := range gateway.VPCs {
55+
vpcs = append(vpcs, fmt.Sprintf("%s:%s", vpc.VpcUUID, vpc.GatewayIP))
56+
}
57+
return strings.Join(vpcs, ",")
58+
}(),
59+
"Egresses": func() string {
60+
var egresses []string
61+
if gateway.Egresses != nil {
62+
for _, egress := range gateway.Egresses.PublicGateways {
63+
egresses = append(egresses, egress.IPv4)
64+
}
65+
}
66+
return strings.Join(egresses, ",")
67+
}(),
68+
"Timeouts": func() string {
69+
return fmt.Sprintf("udp:%ds,icmp:%ds,tcp:%ds",
70+
gateway.UDPTimeoutSeconds,
71+
gateway.ICMPTimeoutSeconds,
72+
gateway.TCPTimeoutSeconds)
73+
}(),
74+
})
75+
}
76+
return out
77+
}
78+
79+
func (e *VPCNATGateways) JSON(out io.Writer) error {
80+
return writeJSON(e.VPCNATGateways, out)
81+
}

commands/doit.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ func computeCmd() *Command {
210210
cmd.AddCommand(Droplet())
211211
cmd.AddCommand(DropletAutoscale())
212212
cmd.AddCommand(Domain())
213+
cmd.AddCommand(VPCNATGateway())
213214
cmd.AddCommand(Firewall())
214215
cmd.AddCommand(ReservedIP())
215216
cmd.AddCommand(ReservedIPAction())

commands/vpc_nat_gateways.go

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
package commands
2+
3+
import (
4+
"github.com/digitalocean/doctl"
5+
"github.com/digitalocean/doctl/commands/displayers"
6+
"github.com/digitalocean/godo"
7+
"github.com/spf13/cobra"
8+
)
9+
10+
func VPCNATGateway() *Command {
11+
cmd := &Command{
12+
Command: &cobra.Command{
13+
Use: "vpc-nat-gateway",
14+
Aliases: []string{"vng"},
15+
Short: "Display commands to manage VPC NAT Gateways",
16+
Long: `Use the subcommands of ` + "`" + `doctl compute vpc-nat-gateway` + "`" + ` to perform actions on VPC NAT Gateways.
17+
18+
You can use vpc-nat-gateway to perform CRUD operations on a VPC NAT Gateway.`,
19+
Hidden: true,
20+
},
21+
}
22+
23+
cmdVPCNATGatewayCreate := CmdBuilder(cmd, RunVPCNATGatewayCreate, "create", "Create a new VPC NAT Gateway", "", Writer, displayerType(&displayers.VPCNATGateways{}), aliasOpt("c"))
24+
25+
cmdVPCNATGatewayUpdate := CmdBuilder(cmd, RunVPCNATGatewayUpdate, "update <gateway-id>", "Update an active VPC NAT Gateway", "", Writer, displayerType(&displayers.VPCNATGateways{}), aliasOpt("u"))
26+
27+
for _, c := range []*Command{
28+
cmdVPCNATGatewayCreate,
29+
cmdVPCNATGatewayUpdate,
30+
} {
31+
AddStringFlag(c, doctl.ArgVPCNATGatewayName, "", "", "Name of the VPC NAT Gateway", requiredOpt())
32+
AddStringFlag(c, doctl.ArgVPCNATGatewayType, "", "PUBLIC", "Gateway type", requiredOpt())
33+
AddStringFlag(c, doctl.ArgVPCNATGatewayRegion, "", "", "Gateway region", requiredOpt())
34+
AddIntFlag(c, doctl.ArgVPCNATGatewaySize, "", 1, "Gateway size")
35+
// Ingress VPCs is not a required arg for update cmd
36+
var opts []flagOpt
37+
if c.HasAlias("c") {
38+
opts = append(opts, requiredOpt())
39+
}
40+
AddStringSliceFlag(c, doctl.ArgVPCNATGatewayVPCs, "", []string{}, "Ingress VPCs", opts...)
41+
AddIntFlag(c, doctl.ArgVPCNATGatewayUDPTimeout, "", 30, "UDP connection timeout (seconds)")
42+
AddIntFlag(c, doctl.ArgVPCNATGatewayICMPTimeout, "", 30, "ICMP connection timeout (seconds)")
43+
AddIntFlag(c, doctl.ArgVPCNATGatewayTCPTimeout, "", 30, "TCP connection timeout (seconds)")
44+
}
45+
46+
CmdBuilder(cmd, RunVPCNATGatewayGet, "get <gateway-id>", "Get a VPC NAT Gateway", "", Writer, displayerType(&displayers.VPCNATGateways{}))
47+
48+
CmdBuilder(cmd, RunVPCNATGatewayList, "list", "List all active VPC NAT Gateways", "", Writer, displayerType(&displayers.VPCNATGateways{}), aliasOpt("ls"))
49+
50+
cmdVPCNATGatewayDelete := CmdBuilder(cmd, RunVPCNATGatewayDelete, "delete <gateway-id>", "Delete a VPC NAT Gateway", "", Writer, aliasOpt("d", "rm"))
51+
AddBoolFlag(cmdVPCNATGatewayDelete, doctl.ArgForce, "", false, "Force delete without a confirmation prompt")
52+
53+
return cmd
54+
}
55+
56+
func buildVPCNATGatewayRequestFromArgs(c *CmdConfig, r *godo.VPCNATGatewayRequest) error {
57+
var hydrators = []func() error{
58+
func() error {
59+
name, err := c.Doit.GetString(c.NS, doctl.ArgVPCNATGatewayName)
60+
if err != nil {
61+
return err
62+
}
63+
r.Name = name
64+
return nil
65+
},
66+
func() error {
67+
gatewayType, err := c.Doit.GetString(c.NS, doctl.ArgVPCNATGatewayType)
68+
if err != nil {
69+
return err
70+
}
71+
r.Type = gatewayType
72+
return nil
73+
},
74+
func() error {
75+
region, err := c.Doit.GetString(c.NS, doctl.ArgVPCNATGatewayRegion)
76+
if err != nil {
77+
return err
78+
}
79+
r.Region = region
80+
return nil
81+
},
82+
func() error {
83+
size, err := c.Doit.GetInt(c.NS, doctl.ArgVPCNATGatewaySize)
84+
if err != nil {
85+
return err
86+
}
87+
r.Size = uint32(size)
88+
return nil
89+
},
90+
func() error {
91+
vpcs, err := c.Doit.GetStringSlice(c.NS, doctl.ArgVPCNATGatewayVPCs)
92+
if err != nil {
93+
return err
94+
}
95+
for _, vpc := range vpcs {
96+
r.VPCs = append(r.VPCs, &godo.IngressVPC{VpcUUID: vpc})
97+
}
98+
return nil
99+
},
100+
func() error {
101+
timeout, err := c.Doit.GetInt(c.NS, doctl.ArgVPCNATGatewayUDPTimeout)
102+
if err != nil {
103+
return err
104+
}
105+
r.UDPTimeoutSeconds = uint32(timeout)
106+
return nil
107+
},
108+
func() error {
109+
timeout, err := c.Doit.GetInt(c.NS, doctl.ArgVPCNATGatewayICMPTimeout)
110+
if err != nil {
111+
return err
112+
}
113+
r.ICMPTimeoutSeconds = uint32(timeout)
114+
return nil
115+
},
116+
func() error {
117+
timeout, err := c.Doit.GetInt(c.NS, doctl.ArgVPCNATGatewayTCPTimeout)
118+
if err != nil {
119+
return err
120+
}
121+
r.TCPTimeoutSeconds = uint32(timeout)
122+
return nil
123+
},
124+
}
125+
for _, hydrate := range hydrators {
126+
if err := hydrate(); err != nil {
127+
return err
128+
}
129+
}
130+
return nil
131+
}
132+
133+
// RunVPCNATGatewayCreate creates a VPC NAT Gateway
134+
func RunVPCNATGatewayCreate(c *CmdConfig) error {
135+
createReq := new(godo.VPCNATGatewayRequest)
136+
if err := buildVPCNATGatewayRequestFromArgs(c, createReq); err != nil {
137+
return err
138+
}
139+
gateway, err := c.VPCNATGateways().Create(createReq)
140+
if err != nil {
141+
return err
142+
}
143+
item := &displayers.VPCNATGateways{VPCNATGateways: []*godo.VPCNATGateway{gateway}}
144+
return c.Display(item)
145+
}
146+
147+
// RunVPCNATGatewayUpdate updates a VPC NAT Gateway
148+
func RunVPCNATGatewayUpdate(c *CmdConfig) error {
149+
err := ensureOneArg(c)
150+
if err != nil {
151+
return err
152+
}
153+
id := c.Args[0]
154+
updateReq := new(godo.VPCNATGatewayRequest)
155+
if err = buildVPCNATGatewayRequestFromArgs(c, updateReq); err != nil {
156+
return err
157+
}
158+
gateway, err := c.VPCNATGateways().Update(id, updateReq)
159+
if err != nil {
160+
return err
161+
}
162+
item := &displayers.VPCNATGateways{VPCNATGateways: []*godo.VPCNATGateway{gateway}}
163+
return c.Display(item)
164+
}
165+
166+
// RunVPCNATGatewayGet retrieves a VPC NAT Gateway
167+
func RunVPCNATGatewayGet(c *CmdConfig) error {
168+
err := ensureOneArg(c)
169+
if err != nil {
170+
return err
171+
}
172+
id := c.Args[0]
173+
gateway, err := c.VPCNATGateways().Get(id)
174+
if err != nil {
175+
return err
176+
}
177+
item := &displayers.VPCNATGateways{VPCNATGateways: []*godo.VPCNATGateway{gateway}}
178+
return c.Display(item)
179+
}
180+
181+
// RunVPCNATGatewayList lists all VPC NAT Gateways
182+
func RunVPCNATGatewayList(c *CmdConfig) error {
183+
gateways, err := c.VPCNATGateways().List()
184+
if err != nil {
185+
return err
186+
}
187+
item := &displayers.VPCNATGateways{VPCNATGateways: gateways}
188+
return c.Display(item)
189+
}
190+
191+
// RunVPCNATGatewayDelete deletes a VPC NAT Gateway
192+
func RunVPCNATGatewayDelete(c *CmdConfig) error {
193+
err := ensureOneArg(c)
194+
if err != nil {
195+
return err
196+
}
197+
id := c.Args[0]
198+
force, err := c.Doit.GetBool(c.NS, doctl.ArgForce)
199+
if err != nil {
200+
return err
201+
}
202+
if force || AskForConfirmDelete("vpc nat gateway", 1) == nil {
203+
if err = c.VPCNATGateways().Delete(id); err != nil {
204+
return err
205+
}
206+
} else {
207+
return errOperationAborted
208+
}
209+
return nil
210+
}

0 commit comments

Comments
 (0)