Skip to content

Commit 444f59d

Browse files
Merge pull request #381 from linode/proj/vpc
Project: Virtual Private Cloud
2 parents 23b49f0 + d0fbe0f commit 444f59d

32 files changed

+11239
-221
lines changed

account_events.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,12 @@ const (
183183
ActionVolumeUpdate EventAction = "volume_update"
184184
ActionVolumeDetach EventAction = "volume_detach"
185185
ActionVolumeResize EventAction = "volume_resize"
186+
ActionVPCCreate EventAction = "vpc_create"
187+
ActionVPCDelete EventAction = "vpc_delete"
188+
ActionVPCUpdate EventAction = "vpc_update"
189+
ActionVPCSubnetCreate EventAction = "subnet_create"
190+
ActionVPCSubnetDelete EventAction = "subnet_delete"
191+
ActionVPCSubnetUpdate EventAction = "subnet_update"
186192

187193
// deprecated due to incorrect spelling,
188194
// to be removed in the next major version release.
@@ -200,6 +206,8 @@ const (
200206
EntityDomain EntityType = "domain"
201207
EntityFirewall EntityType = "firewall"
202208
EntityNodebalancer EntityType = "nodebalancer"
209+
EntityVPC EntityType = "vpc"
210+
EntityVPCSubnet EntityType = "subnet"
203211
)
204212

205213
// EventStatus constants start with Event and include Linode API Event Status values

go.work.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
156156
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
157157
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
158158
github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
159+
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
159160
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
160161
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
161162
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -183,6 +184,7 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
183184
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
184185
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
185186
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
187+
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
186188
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
187189
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
188190
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

instance_config_interfaces.go

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
package linodego
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
)
8+
9+
// InstanceConfigInterface contains information about a configuration's network interface
10+
type InstanceConfigInterface struct {
11+
ID int `json:"id"`
12+
IPAMAddress string `json:"ipam_address"`
13+
Label string `json:"label"`
14+
Purpose ConfigInterfacePurpose `json:"purpose"`
15+
Primary bool `json:"primary"`
16+
Active bool `json:"active"`
17+
VPCID *int `json:"vpc_id"`
18+
SubnetID *int `json:"subnet_id"`
19+
IPv4 VPCIPv4 `json:"ipv4"`
20+
IPRanges []string `json:"ip_ranges"`
21+
}
22+
23+
type VPCIPv4 struct {
24+
VPC string `json:"vpc,omitempty"`
25+
NAT1To1 string `json:"nat_1_1,omitempty"`
26+
}
27+
28+
type InstanceConfigInterfaceCreateOptions struct {
29+
IPAMAddress string `json:"ipam_address,omitempty"`
30+
Label string `json:"label,omitempty"`
31+
Purpose ConfigInterfacePurpose `json:"purpose,omitempty"`
32+
Primary bool `json:"primary,omitempty"`
33+
SubnetID *int `json:"subnet_id,omitempty"`
34+
IPv4 *VPCIPv4 `json:"ipv4,omitempty"`
35+
IPRanges []string `json:"ip_ranges,omitempty"`
36+
}
37+
38+
type InstanceConfigInterfaceUpdateOptions struct {
39+
Primary bool `json:"primary,omitempty"`
40+
IPv4 *VPCIPv4 `json:"ipv4,omitempty"`
41+
IPRanges []string `json:"ip_ranges,omitempty"`
42+
}
43+
44+
type InstanceConfigInterfacesReorderOptions struct {
45+
IDs []int `json:"ids"`
46+
}
47+
48+
func getInstanceConfigInterfacesCreateOptionsList(
49+
interfaces []InstanceConfigInterface,
50+
) []InstanceConfigInterfaceCreateOptions {
51+
interfaceOptsList := make([]InstanceConfigInterfaceCreateOptions, len(interfaces))
52+
for index, configInterface := range interfaces {
53+
interfaceOptsList[index] = configInterface.GetCreateOptions()
54+
}
55+
return interfaceOptsList
56+
}
57+
58+
func (i InstanceConfigInterface) GetCreateOptions() InstanceConfigInterfaceCreateOptions {
59+
opts := InstanceConfigInterfaceCreateOptions{
60+
Label: i.Label,
61+
Purpose: i.Purpose,
62+
Primary: i.Primary,
63+
SubnetID: i.SubnetID,
64+
}
65+
66+
if len(i.IPRanges) > 0 {
67+
opts.IPRanges = i.IPRanges
68+
}
69+
70+
if i.Purpose == InterfacePurposeVPC &&
71+
i.IPv4.NAT1To1 != "" && i.IPv4.VPC != "" {
72+
opts.IPv4 = &VPCIPv4{
73+
VPC: i.IPv4.VPC,
74+
NAT1To1: i.IPv4.NAT1To1,
75+
}
76+
}
77+
78+
// workaround for API issue
79+
if i.IPAMAddress == "222" {
80+
opts.IPAMAddress = ""
81+
} else {
82+
opts.IPAMAddress = i.IPAMAddress
83+
}
84+
85+
return opts
86+
}
87+
88+
func (i InstanceConfigInterface) GetUpdateOptions() InstanceConfigInterfaceUpdateOptions {
89+
opts := InstanceConfigInterfaceUpdateOptions{
90+
Primary: i.Primary,
91+
}
92+
93+
if i.Purpose == InterfacePurposeVPC {
94+
opts.IPv4 = &VPCIPv4{
95+
VPC: i.IPv4.VPC,
96+
NAT1To1: i.IPv4.NAT1To1,
97+
}
98+
}
99+
100+
if len(i.IPRanges) > 0 {
101+
opts.IPRanges = i.IPRanges
102+
}
103+
104+
return opts
105+
}
106+
107+
func (c *Client) AppendInstanceConfigInterface(
108+
ctx context.Context,
109+
linodeID int,
110+
configID int,
111+
opts InstanceConfigInterfaceCreateOptions,
112+
) (*InstanceConfigInterface, error) {
113+
body, err := json.Marshal(opts)
114+
if err != nil {
115+
return nil, err
116+
}
117+
118+
req := c.R(ctx).SetResult(&InstanceConfigInterface{}).SetBody(string(body))
119+
e := fmt.Sprintf("/linode/instances/%d/configs/%d/interfaces", linodeID, configID)
120+
r, err := coupleAPIErrors(req.Post(e))
121+
if err != nil {
122+
return nil, err
123+
}
124+
125+
return r.Result().(*InstanceConfigInterface), nil
126+
}
127+
128+
func (c *Client) GetInstanceConfigInterface(
129+
ctx context.Context,
130+
linodeID int,
131+
configID int,
132+
interfaceID int,
133+
) (*InstanceConfigInterface, error) {
134+
e := fmt.Sprintf(
135+
"linode/instances/%d/configs/%d/interfaces/%d",
136+
linodeID,
137+
configID,
138+
interfaceID,
139+
)
140+
req := c.R(ctx).SetResult(&InstanceConfigInterface{})
141+
r, err := coupleAPIErrors(req.Get(e))
142+
if err != nil {
143+
return nil, err
144+
}
145+
return r.Result().(*InstanceConfigInterface), nil
146+
}
147+
148+
func (c *Client) ListInstanceConfigInterfaces(
149+
ctx context.Context,
150+
linodeID int,
151+
configID int,
152+
) ([]InstanceConfigInterface, error) {
153+
e := fmt.Sprintf(
154+
"linode/instances/%d/configs/%d/interfaces",
155+
linodeID,
156+
configID,
157+
)
158+
req := c.R(ctx).SetResult([]InstanceConfigInterface{})
159+
r, err := coupleAPIErrors(req.Get(e))
160+
if err != nil {
161+
return nil, err
162+
}
163+
return *r.Result().(*[]InstanceConfigInterface), nil
164+
}
165+
166+
func (c *Client) UpdateInstanceConfigInterface(
167+
ctx context.Context,
168+
linodeID int,
169+
configID int,
170+
interfaceID int,
171+
opts InstanceConfigInterfaceUpdateOptions,
172+
) (*InstanceConfigInterface, error) {
173+
body, err := json.Marshal(opts)
174+
if err != nil {
175+
return nil, err
176+
}
177+
178+
e := fmt.Sprintf(
179+
"linode/instances/%d/configs/%d/interfaces/%d",
180+
linodeID,
181+
configID,
182+
interfaceID,
183+
)
184+
req := c.R(ctx).SetResult(&InstanceConfigInterface{}).SetBody(string(body))
185+
r, err := coupleAPIErrors(req.Put(e))
186+
if err != nil {
187+
return nil, err
188+
}
189+
return r.Result().(*InstanceConfigInterface), nil
190+
}
191+
192+
func (c *Client) DeleteInstanceConfigInterface(
193+
ctx context.Context,
194+
linodeID int,
195+
configID int,
196+
interfaceID int,
197+
) error {
198+
e := fmt.Sprintf(
199+
"linode/instances/%d/configs/%d/interfaces/%d",
200+
linodeID,
201+
configID,
202+
interfaceID,
203+
)
204+
_, err := coupleAPIErrors(c.R(ctx).Delete(e))
205+
return err
206+
}
207+
208+
func (c *Client) ReorderInstanceConfigInterfaces(
209+
ctx context.Context,
210+
linodeID int,
211+
configID int,
212+
opts InstanceConfigInterfacesReorderOptions,
213+
) error {
214+
body, err := json.Marshal(opts)
215+
if err != nil {
216+
return err
217+
}
218+
e := fmt.Sprintf(
219+
"linode/instances/%d/configs/%d/interfaces/order",
220+
linodeID,
221+
configID,
222+
)
223+
224+
req := c.R(ctx).SetBody(string(body))
225+
_, err = coupleAPIErrors(req.Post(e))
226+
227+
return err
228+
}

instance_configs.go

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,9 @@ type ConfigInterfacePurpose string
6161
const (
6262
InterfacePurposePublic ConfigInterfacePurpose = "public"
6363
InterfacePurposeVLAN ConfigInterfacePurpose = "vlan"
64+
InterfacePurposeVPC ConfigInterfacePurpose = "vpc"
6465
)
6566

66-
// InstanceConfigInterface contains information about a configuration's network interface
67-
type InstanceConfigInterface struct {
68-
IPAMAddress string `json:"ipam_address"`
69-
Label string `json:"label"`
70-
Purpose ConfigInterfacePurpose `json:"purpose"`
71-
}
72-
7367
// InstanceConfigsPagedResponse represents a paginated InstanceConfig API response
7468
type InstanceConfigsPagedResponse struct {
7569
*PageOptions
@@ -78,26 +72,26 @@ type InstanceConfigsPagedResponse struct {
7872

7973
// InstanceConfigCreateOptions are InstanceConfig settings that can be used at creation
8074
type InstanceConfigCreateOptions struct {
81-
Label string `json:"label,omitempty"`
82-
Comments string `json:"comments,omitempty"`
83-
Devices InstanceConfigDeviceMap `json:"devices"`
84-
Helpers *InstanceConfigHelpers `json:"helpers,omitempty"`
85-
Interfaces []InstanceConfigInterface `json:"interfaces"`
86-
MemoryLimit int `json:"memory_limit,omitempty"`
87-
Kernel string `json:"kernel,omitempty"`
88-
InitRD int `json:"init_rd,omitempty"`
89-
RootDevice *string `json:"root_device,omitempty"`
90-
RunLevel string `json:"run_level,omitempty"`
91-
VirtMode string `json:"virt_mode,omitempty"`
75+
Label string `json:"label,omitempty"`
76+
Comments string `json:"comments,omitempty"`
77+
Devices InstanceConfigDeviceMap `json:"devices"`
78+
Helpers *InstanceConfigHelpers `json:"helpers,omitempty"`
79+
Interfaces []InstanceConfigInterfaceCreateOptions `json:"interfaces"`
80+
MemoryLimit int `json:"memory_limit,omitempty"`
81+
Kernel string `json:"kernel,omitempty"`
82+
InitRD int `json:"init_rd,omitempty"`
83+
RootDevice *string `json:"root_device,omitempty"`
84+
RunLevel string `json:"run_level,omitempty"`
85+
VirtMode string `json:"virt_mode,omitempty"`
9286
}
9387

9488
// InstanceConfigUpdateOptions are InstanceConfig settings that can be used in updates
9589
type InstanceConfigUpdateOptions struct {
96-
Label string `json:"label,omitempty"`
97-
Comments string `json:"comments"`
98-
Devices *InstanceConfigDeviceMap `json:"devices,omitempty"`
99-
Helpers *InstanceConfigHelpers `json:"helpers,omitempty"`
100-
Interfaces []InstanceConfigInterface `json:"interfaces"`
90+
Label string `json:"label,omitempty"`
91+
Comments string `json:"comments"`
92+
Devices *InstanceConfigDeviceMap `json:"devices,omitempty"`
93+
Helpers *InstanceConfigHelpers `json:"helpers,omitempty"`
94+
Interfaces []InstanceConfigInterfaceCreateOptions `json:"interfaces"`
10195
// MemoryLimit 0 means unlimitted, this is not omitted
10296
MemoryLimit int `json:"memory_limit"`
10397
Kernel string `json:"kernel,omitempty"`
@@ -141,7 +135,7 @@ func (i InstanceConfig) GetCreateOptions() InstanceConfigCreateOptions {
141135
Comments: i.Comments,
142136
Devices: *i.Devices,
143137
Helpers: i.Helpers,
144-
Interfaces: i.Interfaces,
138+
Interfaces: getInstanceConfigInterfacesCreateOptionsList(i.Interfaces),
145139
MemoryLimit: i.MemoryLimit,
146140
Kernel: i.Kernel,
147141
InitRD: initrd,
@@ -158,7 +152,7 @@ func (i InstanceConfig) GetUpdateOptions() InstanceConfigUpdateOptions {
158152
Comments: i.Comments,
159153
Devices: i.Devices,
160154
Helpers: i.Helpers,
161-
Interfaces: i.Interfaces,
155+
Interfaces: getInstanceConfigInterfacesCreateOptionsList(i.Interfaces),
162156
MemoryLimit: i.MemoryLimit,
163157
Kernel: i.Kernel,
164158
InitRD: copyInt(i.InitRD),

instance_ips.go

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@ type InstanceIPv4Response struct {
2323

2424
// InstanceIP represents an Instance IP with additional DNS and networking details
2525
type InstanceIP struct {
26-
Address string `json:"address"`
27-
Gateway string `json:"gateway"`
28-
SubnetMask string `json:"subnet_mask"`
29-
Prefix int `json:"prefix"`
30-
Type InstanceIPType `json:"type"`
31-
Public bool `json:"public"`
32-
RDNS string `json:"rdns"`
33-
LinodeID int `json:"linode_id"`
34-
Region string `json:"region"`
26+
Address string `json:"address"`
27+
Gateway string `json:"gateway"`
28+
SubnetMask string `json:"subnet_mask"`
29+
Prefix int `json:"prefix"`
30+
Type InstanceIPType `json:"type"`
31+
Public bool `json:"public"`
32+
RDNS string `json:"rdns"`
33+
LinodeID int `json:"linode_id"`
34+
Region string `json:"region"`
35+
VPCNAT1To1 *InstanceIPNAT1To1 `json:"vpc_nat_1_1"`
3536
}
3637

3738
// InstanceIPv6Response contains the IPv6 addresses and ranges for an Instance
@@ -41,6 +42,14 @@ type InstanceIPv6Response struct {
4142
Global []IPv6Range `json:"global"`
4243
}
4344

45+
// InstanceIPNAT1To1 contains information about the NAT 1:1 mapping
46+
// of a public IP address to a VPC subnet.
47+
type InstanceIPNAT1To1 struct {
48+
Address string `json:"address"`
49+
SubnetID int `json:"subnet_id"`
50+
VPCID int `json:"vpc_id"`
51+
}
52+
4453
// IPv6Range represents a range of IPv6 addresses routed to a single Linode in a given Region
4554
type IPv6Range struct {
4655
Range string `json:"range"`

0 commit comments

Comments
 (0)