Skip to content

Commit

Permalink
Add VPC2 nodes endpoints (#263)
Browse files Browse the repository at this point in the history
* Add VPC2 nodes endpoints

* Fix linting issues

* Fix linter issues part 2

* Fix linting issue part 3

* Fix linting issue part 4

* Fix the last of the linting issues

* Add tests for new VPC2 endpoints
  • Loading branch information
christhemorse authored Aug 18, 2023
1 parent d82fde3 commit 92f98ac
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 3 deletions.
1 change: 1 addition & 0 deletions instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ type VPC2Info struct {
IPAddress string `json:"ip_address"`
}

// AttachVPC2Req parameters for attaching a VPC 2.0 network
type AttachVPC2Req struct {
VPCID string `json:"vpc_id,omitempty"`
IPAddress *string `json:"ip_address,omitempty"`
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 { //nolint:dupl
type NetworkService interface {
// 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 { //nolint:dupl
type VPCService interface {
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
76 changes: 75 additions & 1 deletion vpc2.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ const vpc2Path = "/v2/vpc2"

// VPC2Service is the interface to interact with the VPC 2.0 endpoints on the Vultr API
// Link : https://www.vultr.com/api/#tag/vpc2
type VPC2Service interface { //nolint:dupl
type VPC2Service interface {
Create(ctx context.Context, createReq *VPC2Req) (*VPC2, *http.Response, error)
Get(ctx context.Context, vpcID string) (*VPC2, *http.Response, error)
Update(ctx context.Context, vpcID string, description string) error
Delete(ctx context.Context, vpcID string) error
List(ctx context.Context, options *ListOptions) ([]VPC2, *Meta, *http.Response, error)
ListNodes(ctx context.Context, vpc2ID string, options *ListOptions) ([]VPC2Node, *Meta, *http.Response, error)
Attach(ctx context.Context, vpcID string, attachReq *VPC2AttachDetachReq) error
Detach(ctx context.Context, vpcID string, detachReq *VPC2AttachDetachReq) error
}

// VPC2ServiceHandler handles interaction with the VPC 2.0 methods for the Vultr API
Expand All @@ -35,6 +38,16 @@ type VPC2 struct {
DateCreated string `json:"date_created"`
}

// VPC2Node represents a node attached to a VPC 2.0 network
type VPC2Node struct {
ID string `json:"id"`
IPAddress string `json:"ip_address"`
MACAddress int `json:"mac_address"`
Description string `json:"description"`
Type string `json:"type"`
NodeStatus string `json:"node_status"`
}

// VPC2Req represents parameters to create or update a VPC 2.0 resource
type VPC2Req struct {
Region string `json:"region"`
Expand All @@ -44,6 +57,11 @@ type VPC2Req struct {
PrefixLength int `json:"prefix_length"`
}

// VPC2AttachDetachReq represents parameters to mass attach or detach nodes from VPC 2.0 networks
type VPC2AttachDetachReq struct {
Nodes []string `json:"nodes"`
}

type vpcs2Base struct {
VPCs []VPC2 `json:"vpcs"`
Meta *Meta `json:"meta"`
Expand All @@ -53,6 +71,11 @@ type vpc2Base struct {
VPC *VPC2 `json:"vpc"`
}

type vpc2NodesBase struct {
Nodes []VPC2Node `json:"nodes"`
Meta *Meta `json:"meta"`
}

// Create creates a new VPC 2.0. A VPC 2.0 can only be used at the location for which it was created.
func (n *VPC2ServiceHandler) Create(ctx context.Context, createReq *VPC2Req) (*VPC2, *http.Response, error) {
req, err := n.client.NewRequest(ctx, http.MethodPost, vpc2Path, createReq)
Expand Down Expand Up @@ -133,3 +156,54 @@ func (n *VPC2ServiceHandler) List(ctx context.Context, options *ListOptions) ([]

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

// ListNodes lists all nodes attached to a VPC 2.0 network
func (n *VPC2ServiceHandler) ListNodes(ctx context.Context, vpc2ID string, options *ListOptions) ([]VPC2Node, *Meta, *http.Response, error) { //nolint:dupl,lll
uri := fmt.Sprintf("%s/%s/nodes", vpc2Path, vpc2ID)

req, err := n.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()

nodes := new(vpc2NodesBase)
resp, err := n.client.DoWithContext(ctx, req, nodes)
if err != nil {
return nil, nil, resp, err
}

return nodes.Nodes, nodes.Meta, resp, nil
}

// Attach attaches nodes to a VPC 2.0 network
func (n *VPC2ServiceHandler) Attach(ctx context.Context, vpcID string, attachReq *VPC2AttachDetachReq) error {
uri := fmt.Sprintf("%s/%s/nodes/attach", vpc2Path, vpcID)

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

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

// Detach detaches nodes from a VPC 2.0 network
func (n *VPC2ServiceHandler) Detach(ctx context.Context, vpcID string, detachReq *VPC2AttachDetachReq) error {
uri := fmt.Sprintf("%s/%s/nodes/detach", vpc2Path, vpcID)

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

_, err = n.client.DoWithContext(ctx, req, nil)
return err
}
107 changes: 107 additions & 0 deletions vpc2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,110 @@ func TestVPC2ServiceHandler_Get(t *testing.T) {
t.Errorf("VPC2.Get returned %+v, expected %+v", vpc, expected)
}
}

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

mux.HandleFunc("/v2/vpc2/84fee086-6691-417a-b2db-e2a71061fa17/nodes", func(writer http.ResponseWriter, request *http.Request) {
response := `
{
"nodes": [
{
"id": "35dbcffe-58bf-46fe-bd68-964d95488dd8",
"ip_address": "10.1.112.5",
"mac_address": 98956121034033,
"description": "bbbbbb-8ac448299844",
"type": "vps",
"node_status": "active"
},
{
"id": "1f5d784a-1011-430c-a2e2-39ba045abe3c",
"ip_address": "10.1.112.6",
"mac_address": 98956121034034,
"description": "bbbbbb-c76d8fc029d6",
"type": "vps",
"node_status": "active"
}
],
"meta": {
"total": 2,
"links": {
"next": "",
"prev": ""
}
}
}
`
fmt.Fprint(writer, response)
})

nodes, _, _, err := client.VPC2.ListNodes(ctx, "84fee086-6691-417a-b2db-e2a71061fa17", nil)

if err != nil {
t.Errorf("VPC2.ListNodes returned error: %v", err)
}

expected := []VPC2Node{
{
ID: "35dbcffe-58bf-46fe-bd68-964d95488dd8",
IPAddress: "10.1.112.5",
MACAddress: 98956121034033,
Description: "bbbbbb-8ac448299844",
Type: "vps",
NodeStatus: "active",
},
{
ID: "1f5d784a-1011-430c-a2e2-39ba045abe3c",
IPAddress: "10.1.112.6",
MACAddress: 98956121034034,
Description: "bbbbbb-c76d8fc029d6",
Type: "vps",
NodeStatus: "active",
},
}

if !reflect.DeepEqual(nodes, expected) {
t.Errorf("VPC2.ListNode returned %+v, expected %+v", nodes, expected)
}
}

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

mux.HandleFunc("/v2/vpc2/84fee086-6691-417a-b2db-e2a71061fa17/nodes/attach", func(writer http.ResponseWriter, request *http.Request) {
fmt.Fprint(writer)
})

nodes := []string{"ce44b37a-bbe7-4e30-bfae-695c2e633bff", "45b794b7-4dd1-48b1-beb7-0b7bf3a16941"}
options := &VPC2AttachDetachReq{
Nodes: nodes,
}

err := client.VPC2.Attach(ctx, "84fee086-6691-417a-b2db-e2a71061fa17", options)

if err != nil {
t.Errorf("VPC2.Attach returned %+v, expected %+v", err, nil)
}
}

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

mux.HandleFunc("/v2/vpc2/84fee086-6691-417a-b2db-e2a71061fa17/nodes/detach", func(writer http.ResponseWriter, request *http.Request) {
fmt.Fprint(writer)
})

nodes := []string{"ce44b37a-bbe7-4e30-bfae-695c2e633bff", "45b794b7-4dd1-48b1-beb7-0b7bf3a16941"}
options := &VPC2AttachDetachReq{
Nodes: nodes,
}

err := client.VPC2.Detach(ctx, "84fee086-6691-417a-b2db-e2a71061fa17", options)

if err != nil {
t.Errorf("VPC2.Detach returned %+v, expected %+v", err, nil)
}
}

0 comments on commit 92f98ac

Please sign in to comment.