Skip to content

Commit

Permalink
Merge pull request #381 from linode/proj/vpc
Browse files Browse the repository at this point in the history
Project: Virtual Private Cloud
  • Loading branch information
zliang-akamai committed Nov 7, 2023
2 parents 23b49f0 + d0fbe0f commit 444f59d
Show file tree
Hide file tree
Showing 32 changed files with 11,239 additions and 221 deletions.
8 changes: 8 additions & 0 deletions account_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ const (
ActionVolumeUpdate EventAction = "volume_update"
ActionVolumeDetach EventAction = "volume_detach"
ActionVolumeResize EventAction = "volume_resize"
ActionVPCCreate EventAction = "vpc_create"
ActionVPCDelete EventAction = "vpc_delete"
ActionVPCUpdate EventAction = "vpc_update"
ActionVPCSubnetCreate EventAction = "subnet_create"
ActionVPCSubnetDelete EventAction = "subnet_delete"
ActionVPCSubnetUpdate EventAction = "subnet_update"

// deprecated due to incorrect spelling,
// to be removed in the next major version release.
Expand All @@ -200,6 +206,8 @@ const (
EntityDomain EntityType = "domain"
EntityFirewall EntityType = "firewall"
EntityNodebalancer EntityType = "nodebalancer"
EntityVPC EntityType = "vpc"
EntityVPCSubnet EntityType = "subnet"
)

// EventStatus constants start with Event and include Linode API Event Status values
Expand Down
2 changes: 2 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
Expand Down Expand Up @@ -183,6 +184,7 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
228 changes: 228 additions & 0 deletions instance_config_interfaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
package linodego

import (
"context"
"encoding/json"
"fmt"
)

// InstanceConfigInterface contains information about a configuration's network interface
type InstanceConfigInterface struct {
ID int `json:"id"`
IPAMAddress string `json:"ipam_address"`
Label string `json:"label"`
Purpose ConfigInterfacePurpose `json:"purpose"`
Primary bool `json:"primary"`
Active bool `json:"active"`
VPCID *int `json:"vpc_id"`
SubnetID *int `json:"subnet_id"`
IPv4 VPCIPv4 `json:"ipv4"`
IPRanges []string `json:"ip_ranges"`
}

type VPCIPv4 struct {
VPC string `json:"vpc,omitempty"`
NAT1To1 string `json:"nat_1_1,omitempty"`
}

type InstanceConfigInterfaceCreateOptions struct {
IPAMAddress string `json:"ipam_address,omitempty"`
Label string `json:"label,omitempty"`
Purpose ConfigInterfacePurpose `json:"purpose,omitempty"`
Primary bool `json:"primary,omitempty"`
SubnetID *int `json:"subnet_id,omitempty"`
IPv4 *VPCIPv4 `json:"ipv4,omitempty"`
IPRanges []string `json:"ip_ranges,omitempty"`
}

type InstanceConfigInterfaceUpdateOptions struct {
Primary bool `json:"primary,omitempty"`
IPv4 *VPCIPv4 `json:"ipv4,omitempty"`
IPRanges []string `json:"ip_ranges,omitempty"`
}

type InstanceConfigInterfacesReorderOptions struct {
IDs []int `json:"ids"`
}

func getInstanceConfigInterfacesCreateOptionsList(
interfaces []InstanceConfigInterface,
) []InstanceConfigInterfaceCreateOptions {
interfaceOptsList := make([]InstanceConfigInterfaceCreateOptions, len(interfaces))
for index, configInterface := range interfaces {
interfaceOptsList[index] = configInterface.GetCreateOptions()
}
return interfaceOptsList
}

func (i InstanceConfigInterface) GetCreateOptions() InstanceConfigInterfaceCreateOptions {
opts := InstanceConfigInterfaceCreateOptions{
Label: i.Label,
Purpose: i.Purpose,
Primary: i.Primary,
SubnetID: i.SubnetID,
}

if len(i.IPRanges) > 0 {
opts.IPRanges = i.IPRanges
}

if i.Purpose == InterfacePurposeVPC &&
i.IPv4.NAT1To1 != "" && i.IPv4.VPC != "" {
opts.IPv4 = &VPCIPv4{
VPC: i.IPv4.VPC,
NAT1To1: i.IPv4.NAT1To1,
}
}

// workaround for API issue
if i.IPAMAddress == "222" {
opts.IPAMAddress = ""
} else {
opts.IPAMAddress = i.IPAMAddress
}

return opts
}

func (i InstanceConfigInterface) GetUpdateOptions() InstanceConfigInterfaceUpdateOptions {
opts := InstanceConfigInterfaceUpdateOptions{
Primary: i.Primary,
}

if i.Purpose == InterfacePurposeVPC {
opts.IPv4 = &VPCIPv4{
VPC: i.IPv4.VPC,
NAT1To1: i.IPv4.NAT1To1,
}
}

if len(i.IPRanges) > 0 {
opts.IPRanges = i.IPRanges
}

return opts
}

func (c *Client) AppendInstanceConfigInterface(
ctx context.Context,
linodeID int,
configID int,
opts InstanceConfigInterfaceCreateOptions,
) (*InstanceConfigInterface, error) {
body, err := json.Marshal(opts)
if err != nil {
return nil, err
}

req := c.R(ctx).SetResult(&InstanceConfigInterface{}).SetBody(string(body))
e := fmt.Sprintf("/linode/instances/%d/configs/%d/interfaces", linodeID, configID)
r, err := coupleAPIErrors(req.Post(e))
if err != nil {
return nil, err
}

return r.Result().(*InstanceConfigInterface), nil
}

func (c *Client) GetInstanceConfigInterface(
ctx context.Context,
linodeID int,
configID int,
interfaceID int,
) (*InstanceConfigInterface, error) {
e := fmt.Sprintf(
"linode/instances/%d/configs/%d/interfaces/%d",
linodeID,
configID,
interfaceID,
)
req := c.R(ctx).SetResult(&InstanceConfigInterface{})
r, err := coupleAPIErrors(req.Get(e))
if err != nil {
return nil, err
}
return r.Result().(*InstanceConfigInterface), nil
}

func (c *Client) ListInstanceConfigInterfaces(
ctx context.Context,
linodeID int,
configID int,
) ([]InstanceConfigInterface, error) {
e := fmt.Sprintf(
"linode/instances/%d/configs/%d/interfaces",
linodeID,
configID,
)
req := c.R(ctx).SetResult([]InstanceConfigInterface{})
r, err := coupleAPIErrors(req.Get(e))
if err != nil {
return nil, err
}
return *r.Result().(*[]InstanceConfigInterface), nil
}

func (c *Client) UpdateInstanceConfigInterface(
ctx context.Context,
linodeID int,
configID int,
interfaceID int,
opts InstanceConfigInterfaceUpdateOptions,
) (*InstanceConfigInterface, error) {
body, err := json.Marshal(opts)
if err != nil {
return nil, err
}

e := fmt.Sprintf(
"linode/instances/%d/configs/%d/interfaces/%d",
linodeID,
configID,
interfaceID,
)
req := c.R(ctx).SetResult(&InstanceConfigInterface{}).SetBody(string(body))
r, err := coupleAPIErrors(req.Put(e))
if err != nil {
return nil, err
}
return r.Result().(*InstanceConfigInterface), nil
}

func (c *Client) DeleteInstanceConfigInterface(
ctx context.Context,
linodeID int,
configID int,
interfaceID int,
) error {
e := fmt.Sprintf(
"linode/instances/%d/configs/%d/interfaces/%d",
linodeID,
configID,
interfaceID,
)
_, err := coupleAPIErrors(c.R(ctx).Delete(e))
return err
}

func (c *Client) ReorderInstanceConfigInterfaces(
ctx context.Context,
linodeID int,
configID int,
opts InstanceConfigInterfacesReorderOptions,
) error {
body, err := json.Marshal(opts)
if err != nil {
return err
}
e := fmt.Sprintf(
"linode/instances/%d/configs/%d/interfaces/order",
linodeID,
configID,
)

req := c.R(ctx).SetBody(string(body))
_, err = coupleAPIErrors(req.Post(e))

return err
}
44 changes: 19 additions & 25 deletions instance_configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,9 @@ type ConfigInterfacePurpose string
const (
InterfacePurposePublic ConfigInterfacePurpose = "public"
InterfacePurposeVLAN ConfigInterfacePurpose = "vlan"
InterfacePurposeVPC ConfigInterfacePurpose = "vpc"
)

// InstanceConfigInterface contains information about a configuration's network interface
type InstanceConfigInterface struct {
IPAMAddress string `json:"ipam_address"`
Label string `json:"label"`
Purpose ConfigInterfacePurpose `json:"purpose"`
}

// InstanceConfigsPagedResponse represents a paginated InstanceConfig API response
type InstanceConfigsPagedResponse struct {
*PageOptions
Expand All @@ -78,26 +72,26 @@ type InstanceConfigsPagedResponse struct {

// InstanceConfigCreateOptions are InstanceConfig settings that can be used at creation
type InstanceConfigCreateOptions struct {
Label string `json:"label,omitempty"`
Comments string `json:"comments,omitempty"`
Devices InstanceConfigDeviceMap `json:"devices"`
Helpers *InstanceConfigHelpers `json:"helpers,omitempty"`
Interfaces []InstanceConfigInterface `json:"interfaces"`
MemoryLimit int `json:"memory_limit,omitempty"`
Kernel string `json:"kernel,omitempty"`
InitRD int `json:"init_rd,omitempty"`
RootDevice *string `json:"root_device,omitempty"`
RunLevel string `json:"run_level,omitempty"`
VirtMode string `json:"virt_mode,omitempty"`
Label string `json:"label,omitempty"`
Comments string `json:"comments,omitempty"`
Devices InstanceConfigDeviceMap `json:"devices"`
Helpers *InstanceConfigHelpers `json:"helpers,omitempty"`
Interfaces []InstanceConfigInterfaceCreateOptions `json:"interfaces"`
MemoryLimit int `json:"memory_limit,omitempty"`
Kernel string `json:"kernel,omitempty"`
InitRD int `json:"init_rd,omitempty"`
RootDevice *string `json:"root_device,omitempty"`
RunLevel string `json:"run_level,omitempty"`
VirtMode string `json:"virt_mode,omitempty"`
}

// InstanceConfigUpdateOptions are InstanceConfig settings that can be used in updates
type InstanceConfigUpdateOptions struct {
Label string `json:"label,omitempty"`
Comments string `json:"comments"`
Devices *InstanceConfigDeviceMap `json:"devices,omitempty"`
Helpers *InstanceConfigHelpers `json:"helpers,omitempty"`
Interfaces []InstanceConfigInterface `json:"interfaces"`
Label string `json:"label,omitempty"`
Comments string `json:"comments"`
Devices *InstanceConfigDeviceMap `json:"devices,omitempty"`
Helpers *InstanceConfigHelpers `json:"helpers,omitempty"`
Interfaces []InstanceConfigInterfaceCreateOptions `json:"interfaces"`
// MemoryLimit 0 means unlimitted, this is not omitted
MemoryLimit int `json:"memory_limit"`
Kernel string `json:"kernel,omitempty"`
Expand Down Expand Up @@ -141,7 +135,7 @@ func (i InstanceConfig) GetCreateOptions() InstanceConfigCreateOptions {
Comments: i.Comments,
Devices: *i.Devices,
Helpers: i.Helpers,
Interfaces: i.Interfaces,
Interfaces: getInstanceConfigInterfacesCreateOptionsList(i.Interfaces),
MemoryLimit: i.MemoryLimit,
Kernel: i.Kernel,
InitRD: initrd,
Expand All @@ -158,7 +152,7 @@ func (i InstanceConfig) GetUpdateOptions() InstanceConfigUpdateOptions {
Comments: i.Comments,
Devices: i.Devices,
Helpers: i.Helpers,
Interfaces: i.Interfaces,
Interfaces: getInstanceConfigInterfacesCreateOptionsList(i.Interfaces),
MemoryLimit: i.MemoryLimit,
Kernel: i.Kernel,
InitRD: copyInt(i.InitRD),
Expand Down
27 changes: 18 additions & 9 deletions instance_ips.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@ type InstanceIPv4Response struct {

// InstanceIP represents an Instance IP with additional DNS and networking details
type InstanceIP struct {
Address string `json:"address"`
Gateway string `json:"gateway"`
SubnetMask string `json:"subnet_mask"`
Prefix int `json:"prefix"`
Type InstanceIPType `json:"type"`
Public bool `json:"public"`
RDNS string `json:"rdns"`
LinodeID int `json:"linode_id"`
Region string `json:"region"`
Address string `json:"address"`
Gateway string `json:"gateway"`
SubnetMask string `json:"subnet_mask"`
Prefix int `json:"prefix"`
Type InstanceIPType `json:"type"`
Public bool `json:"public"`
RDNS string `json:"rdns"`
LinodeID int `json:"linode_id"`
Region string `json:"region"`
VPCNAT1To1 *InstanceIPNAT1To1 `json:"vpc_nat_1_1"`
}

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

// InstanceIPNAT1To1 contains information about the NAT 1:1 mapping
// of a public IP address to a VPC subnet.
type InstanceIPNAT1To1 struct {
Address string `json:"address"`
SubnetID int `json:"subnet_id"`
VPCID int `json:"vpc_id"`
}

// IPv6Range represents a range of IPv6 addresses routed to a single Linode in a given Region
type IPv6Range struct {
Range string `json:"range"`
Expand Down
Loading

0 comments on commit 444f59d

Please sign in to comment.