Skip to content

Commit

Permalink
Add support for VPC 2.0 (#261)
Browse files Browse the repository at this point in the history
* Copy `vpc.go` to `vpc2.go`

* Add VPC 2.0.

* Add VPC 2.0 for instance, bare_metal.

* Fix lint.

* Fix vpc2 comment.
  • Loading branch information
ogawa0071 authored Aug 10, 2023
1 parent b7f7327 commit 793f45e
Show file tree
Hide file tree
Showing 9 changed files with 548 additions and 4 deletions.
58 changes: 56 additions & 2 deletions bare_metal_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ type BareMetalServerService interface {
MassReboot(ctx context.Context, serverList []string) error

GetUpgrades(ctx context.Context, serverID string) (*Upgrades, *http.Response, error)

ListVPC2Info(ctx context.Context, serverID string) ([]VPC2Info, *http.Response, error)
AttachVPC2(ctx context.Context, serverID string, vpc2Req *AttachVPC2Req) error
DetachVPC2(ctx context.Context, serverID, vpcID string) error
}

// BareMetalServerServiceHandler handles interaction with the Bare Metal methods for the Vultr API
Expand Down Expand Up @@ -92,6 +96,9 @@ type BareMetalCreate struct {
ReservedIPv4 string `json:"reserved_ipv4,omitempty"`
PersistentPxe *bool `json:"persistent_pxe,omitempty"`
Tags []string `json:"tags"`
AttachVPC2 []string `json:"attach_vpc2,omitempty"`
DetachVPC2 []string `json:"detach_vpc2,omitempty"`
EnableVPC2 *bool `json:"enable_vpc2,omitempty"`
}

// BareMetalUpdate represents the optional parameters that can be set when updating a Bare Metal server
Expand All @@ -103,8 +110,11 @@ type BareMetalUpdate struct {
ImageID string `json:"image_id,omitempty"`
UserData string `json:"user_data,omitempty"`
// Deprecated: Tag should no longer be used. Instead, use Tags.
Tag *string `json:"tag,omitempty"`
Tags []string `json:"tags"`
Tag *string `json:"tag,omitempty"`
Tags []string `json:"tags"`
AttachVPC2 []string `json:"attach_vpc2,omitempty"`
DetachVPC2 []string `json:"detach_vpc2,omitempty"`
EnableVPC2 *bool `json:"enable_vpc2,omitempty"`
}

// BareMetalServerBandwidth represents bandwidth information for a Bare Metal server
Expand Down Expand Up @@ -434,3 +444,47 @@ func (b *BareMetalServerServiceHandler) GetUpgrades(ctx context.Context, serverI

return upgrades.Upgrades, resp, nil
}

// ListVPC2Info currently attached to a Bare Metal server.
func (b *BareMetalServerServiceHandler) ListVPC2Info(ctx context.Context, serverID string) ([]VPC2Info, *http.Response, error) {
uri := fmt.Sprintf("%s/%s/vpc2", bmPath, serverID)
req, err := b.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, nil, err
}

vpcs := new(vpc2InfoBase)
resp, err := b.client.DoWithContext(ctx, req, vpcs)
if err != nil {
return nil, resp, err
}

return vpcs.VPCs, resp, nil
}

// AttachVPC2 to a Bare Metal server.
func (b *BareMetalServerServiceHandler) AttachVPC2(ctx context.Context, serverID string, vpc2Req *AttachVPC2Req) error {
uri := fmt.Sprintf("%s/%s/vpc2/attach", bmPath, serverID)

req, err := b.client.NewRequest(ctx, http.MethodPost, uri, vpc2Req)
if err != nil {
return err
}

_, err = b.client.DoWithContext(ctx, req, nil)
return err
}

// DetachVPC2 from a Bare Metal server.
func (b *BareMetalServerServiceHandler) DetachVPC2(ctx context.Context, serverID, vpcID string) error {
uri := fmt.Sprintf("%s/%s/vpc2/detach", bmPath, serverID)
body := RequestBody{"vpc_id": vpcID}

req, err := b.client.NewRequest(ctx, http.MethodPost, uri, body)
if err != nil {
return err
}

_, err = b.client.DoWithContext(ctx, req, nil)
return err
}
53 changes: 53 additions & 0 deletions bare_metal_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -799,3 +799,56 @@ func TestBareMetalServerServiceHandler_CreateMarketplaceImage(t *testing.T) {
t.Errorf("BareMetalServer.Create returned %+v, expected %+v", bm, expected)
}
}

func TestBareMetalServerServiceHandler_ListVPC2Info(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/v2/bare-metals/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/vpc2", func(writer http.ResponseWriter, request *http.Request) {
response := `{"vpcs": [{"id": "v1-net539626f0798d7","mac_address": "5a:02:00:00:24:e9","ip_address": "10.99.0.3"}]}`
fmt.Fprint(writer, response)
})

vpc, _, err := client.BareMetalServer.ListVPC2Info(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33")
if err != nil {
t.Errorf("BareMetalServer.ListVPC2Info returned %+v, ", err)
}

expected := []VPC2Info{
{
ID: "v1-net539626f0798d7",
MacAddress: "5a:02:00:00:24:e9",
IPAddress: "10.99.0.3",
},
}

if !reflect.DeepEqual(vpc, expected) {
t.Errorf("BareMetalServer.ListVPC2Info returned %+v, expected %+v", vpc, expected)
}
}

func TestBareMetalServerServiceHandler_AttachVPC2(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/v2/bare-metals/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/vpc2/attach", func(writer http.ResponseWriter, request *http.Request) {
fmt.Fprint(writer)
})

if err := client.BareMetalServer.AttachVPC2(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", &AttachVPC2Req{VPCID: "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"}); err != nil {
t.Errorf("BareMetalServer.AttachVPC2 returned %+v", err)
}
}

func TestBareMetalServerServiceHandler_DetachVPC2(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/v2/bare-metals/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/vpc2/detach", func(writer http.ResponseWriter, request *http.Request) {
fmt.Fprint(writer)
})

if err := client.BareMetalServer.DetachVPC2(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"); err != nil {
t.Errorf("BareMetalServer.DetachVPC2 returned %+v", err)
}
}
2 changes: 2 additions & 0 deletions govultr.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ type Client struct {
StartupScript StartupScriptService
User UserService
VPC VPCService
VPC2 VPC2Service

// Optional function called after every successful request made to the Vultr API
onRequestCompleted RequestCompletionCallback
Expand Down Expand Up @@ -135,6 +136,7 @@ func NewClient(httpClient *http.Client) *Client {
client.StartupScript = &StartupScriptServiceHandler{client}
client.User = &UserServiceHandler{client}
client.VPC = &VPCServiceHandler{client}
client.VPC2 = &VPC2ServiceHandler{client}

return client
}
Expand Down
77 changes: 77 additions & 0 deletions instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ type InstanceService interface {
AttachVPC(ctx context.Context, instanceID, vpcID string) error
DetachVPC(ctx context.Context, instanceID, vpcID string) error

ListVPC2Info(ctx context.Context, instanceID string, options *ListOptions) ([]VPC2Info, *Meta, *http.Response, error)
AttachVPC2(ctx context.Context, instanceID string, vpc2Req *AttachVPC2Req) error
DetachVPC2(ctx context.Context, instanceID, vpcID string) error

ISOStatus(ctx context.Context, instanceID string) (*Iso, *http.Response, error)
AttachISO(ctx context.Context, instanceID, isoID string) (*http.Response, error)
DetachISO(ctx context.Context, instanceID string) (*http.Response, error)
Expand Down Expand Up @@ -159,6 +163,23 @@ type VPCInfo struct {
IPAddress string `json:"ip_address"`
}

type vpc2InfoBase struct {
VPCs []VPC2Info `json:"vpcs"`
Meta *Meta `json:"meta"`
}

// VPC2Info information for a given instance.
type VPC2Info struct {
ID string `json:"id"`
MacAddress string `json:"mac_address"`
IPAddress string `json:"ip_address"`
}

type AttachVPC2Req struct {
VPCID string `json:"vpc_id,omitempty"`
IPAddress *string `json:"ip_address,omitempty"`
}

type isoStatusBase struct {
IsoStatus *Iso `json:"iso_status"`
}
Expand Down Expand Up @@ -253,6 +274,8 @@ type InstanceCreateReq struct {
AttachPrivateNetwork []string `json:"attach_private_network,omitempty"`
EnableVPC *bool `json:"enable_vpc,omitempty"`
AttachVPC []string `json:"attach_vpc,omitempty"`
EnableVPC2 *bool `json:"enable_vpc2,omitempty"`
AttachVPC2 []string `json:"attach_vpc2,omitempty"`
SSHKeys []string `json:"sshkey_id,omitempty"`
Backups string `json:"backups,omitempty"`
DDOSProtection *bool `json:"ddos_protection,omitempty"`
Expand Down Expand Up @@ -281,6 +304,9 @@ type InstanceUpdateReq struct {
EnableVPC *bool `json:"enable_vpc,omitempty"`
AttachVPC []string `json:"attach_vpc,omitempty"`
DetachVPC []string `json:"detach_vpc,omitempty"`
EnableVPC2 *bool `json:"enable_vpc2,omitempty"`
AttachVPC2 []string `json:"attach_vpc2,omitempty"`
DetachVPC2 []string `json:"detach_vpc2,omitempty"`
Backups string `json:"backups,omitempty"`
DDOSProtection *bool `json:"ddos_protection"`
UserData string `json:"user_data,omitempty"`
Expand Down Expand Up @@ -624,6 +650,57 @@ func (i *InstanceServiceHandler) DetachVPC(ctx context.Context, instanceID, vpcI
return err
}

// ListVPC2Info currently attached to an instance.
func (i *InstanceServiceHandler) ListVPC2Info(ctx context.Context, instanceID string, options *ListOptions) ([]VPC2Info, *Meta, *http.Response, error) { //nolint:lll,dupl
uri := fmt.Sprintf("%s/%s/vpc2", instancePath, instanceID)
req, err := i.client.NewRequest(ctx, http.MethodGet, uri, nil)
if err != nil {
return nil, nil, nil, err
}

newValues, err := query.Values(options)
if err != nil {
return nil, nil, nil, err
}

req.URL.RawQuery = newValues.Encode()

vpcs := new(vpc2InfoBase)
resp, err := i.client.DoWithContext(ctx, req, vpcs)
if err != nil {
return nil, nil, resp, err
}

return vpcs.VPCs, vpcs.Meta, resp, nil
}

// AttachVPC2 to an instance
func (i *InstanceServiceHandler) AttachVPC2(ctx context.Context, instanceID string, vpc2Req *AttachVPC2Req) error {
uri := fmt.Sprintf("%s/%s/vpc2/attach", instancePath, instanceID)

req, err := i.client.NewRequest(ctx, http.MethodPost, uri, vpc2Req)
if err != nil {
return err
}

_, err = i.client.DoWithContext(ctx, req, nil)
return err
}

// DetachVPC2 from an instance.
func (i *InstanceServiceHandler) DetachVPC2(ctx context.Context, instanceID, vpcID string) error {
uri := fmt.Sprintf("%s/%s/vpc2/detach", instancePath, instanceID)
body := RequestBody{"vpc_id": vpcID}

req, err := i.client.NewRequest(ctx, http.MethodPost, uri, body)
if err != nil {
return err
}

_, err = i.client.DoWithContext(ctx, req, nil)
return err
}

// ISOStatus retrieves the current ISO state for a given VPS.
// The returned state may be one of: ready | isomounting | isomounted.
func (i *InstanceServiceHandler) ISOStatus(ctx context.Context, instanceID string) (*Iso, *http.Response, error) {
Expand Down
69 changes: 69 additions & 0 deletions instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,49 @@ func TestServerServiceHandler_ListVPCInfo(t *testing.T) {
}
}

func TestServerServiceHandler_ListVPC2Info(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/vpc2", func(writer http.ResponseWriter, request *http.Request) {
response := `{"vpcs": [{"id": "v1-net539626f0798d7","mac_address": "5a:02:00:00:24:e9","ip_address": "10.99.0.3"}],"meta":{"total":1,"links":{"next":"thisismycusror","prev":""}}}`
fmt.Fprint(writer, response)
})

options := &ListOptions{
PerPage: 1,
Cursor: "",
}
vpc, meta, _, err := client.Instance.ListVPC2Info(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", options)
if err != nil {
t.Errorf("Instance.ListVPC2Info returned %+v, ", err)
}

expected := []VPC2Info{
{
ID: "v1-net539626f0798d7",
MacAddress: "5a:02:00:00:24:e9",
IPAddress: "10.99.0.3",
},
}

if !reflect.DeepEqual(vpc, expected) {
t.Errorf("Instance.ListVPC2Info returned %+v, expected %+v", vpc, expected)
}

expectedMeta := &Meta{
Total: 1,
Links: &Links{
Next: "thisismycusror",
Prev: "",
},
}

if !reflect.DeepEqual(meta, expectedMeta) {
t.Errorf("Instance.ListVPC2Info meta returned %+v, expected %+v", meta, expectedMeta)
}
}

func TestServerServiceHandler_GetUserData(t *testing.T) {
setup()
defer teardown()
Expand Down Expand Up @@ -989,6 +1032,32 @@ func TestServerServiceHandler_DetachVPC(t *testing.T) {
}
}

func TestServerServiceHandler_AttachVPC2(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/vpc2/attach", func(writer http.ResponseWriter, request *http.Request) {
fmt.Fprint(writer)
})

if err := client.Instance.AttachVPC2(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", &AttachVPC2Req{VPCID: "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"}); err != nil {
t.Errorf("Instance.AttachVPC2 returned %+v", err)
}
}

func TestServerServiceHandler_DetachVPC2(t *testing.T) {
setup()
defer teardown()

mux.HandleFunc("/v2/instances/14b3e7d6-ffb5-4994-8502-57fcd9db3b33/vpc2/detach", func(writer http.ResponseWriter, request *http.Request) {
fmt.Fprint(writer)
})

if err := client.Instance.DetachVPC2(ctx, "14b3e7d6-ffb5-4994-8502-57fcd9db3b33", "14b3e7d6-ffb5-4994-8502-57fcd9db3b33"); err != nil {
t.Errorf("Instance.DetachVPC2 returned %+v", err)
}
}

func TestServerServiceHandler_ISOAttach(t *testing.T) {
setup()
defer teardown()
Expand Down
2 changes: 1 addition & 1 deletion network.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const netPath = "/v2/private-networks"
// NetworkService is the interface to interact with the network endpoints on the Vultr API
// Link : https://www.vultr.com/api/#tag/private-Networks
// Deprecated: NetworkService should no longer be used. Instead, use VPCService.
type NetworkService interface {
type NetworkService interface { //nolint:dupl
// Deprecated: NetworkService Create should no longer be used. Instead, use VPCService Create.
Create(ctx context.Context, createReq *NetworkReq) (*Network, *http.Response, error)
// Deprecated: NetworkService Get should no longer be used. Instead, use VPCService Get.
Expand Down
2 changes: 1 addition & 1 deletion vpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const vpcPath = "/v2/vpcs"

// VPCService is the interface to interact with the VPC endpoints on the Vultr API
// Link : https://www.vultr.com/api/#tag/vpcs
type VPCService interface {
type VPCService interface { //nolint:dupl
Create(ctx context.Context, createReq *VPCReq) (*VPC, *http.Response, error)
Get(ctx context.Context, vpcID string) (*VPC, *http.Response, error)
Update(ctx context.Context, vpcID string, description string) error
Expand Down
Loading

0 comments on commit 793f45e

Please sign in to comment.