Skip to content

Commit

Permalink
Resell V2 - add cross-region subnets Get method (#116)
Browse files Browse the repository at this point in the history
* Resell V2 - add cross-region subnets Get method

* Resell V2 - add cross-region subnets Get method

Add crossregionsubnets package with Get method and basic CrossRegionSubnet structure.
Provide tests and doc example.

* Readme: add cross-region subnets link

Add link to the "crossregionsubnets" package documentation.

* Resell V2 - fix comments in crossregionsubnets

Add spaces between // and comment messages.

* Resell V2 - update schemas in subnets package

Add VLANID and VTEPIPAddress fields to Subnet structure.

* Resell V2 - fix schemas in crossregionsubnets

Fix Subnets field in CrossRegionSubnets structure.
Rename VlanID field to VLANID.
Fix test fixtures.
  • Loading branch information
kolsean authored and ozerovandrei committed Jan 8, 2019
1 parent 8839192 commit ee5acdd
Show file tree
Hide file tree
Showing 7 changed files with 315 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ You can use this library to work with the following objects of the Selectel VPC
* [tokens](https://godoc.org/github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/tokens)
* [subnets](https://godoc.org/github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/subnets)
* [vrrp_subnets](https://godoc.org/github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/vrrpsubnets)
* [cross_region_subnets](https://godoc.org/github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/crossregionsubnets)
* [floating ips](https://godoc.org/github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/floatingips)
* [licenses](https://godoc.org/github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/licenses)
* [keypairs](https://godoc.org/github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/keypairs)
Expand Down
13 changes: 13 additions & 0 deletions selvpcclient/resell/v2/crossregionsubnets/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
Package crossregionsubnets provides the ability to retrieve and manage cross-region subnets
through the Resell v2 API.
Example of getting a single cross-region subnet referenced by its id
crossRegionSubnet, _, err := crossregionsubnets.Get(context, resellClient, crossRegionSubnetID)
if err != nil {
log.Fatal(err)
}
fmt.Println(crossRegionSubnet)
*/
package crossregionsubnets
34 changes: 34 additions & 0 deletions selvpcclient/resell/v2/crossregionsubnets/requests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package crossregionsubnets

import (
"context"
"net/http"
"strings"

"github.com/selectel/go-selvpcclient/selvpcclient"
)

const resourceURL = "cross_region_subnets"

// Get returns a single cross-region subnet by its id.
func Get(ctx context.Context, client *selvpcclient.ServiceClient, id string) (*CrossRegionSubnet, *selvpcclient.ResponseResult, error) {
url := strings.Join([]string{client.Endpoint, resourceURL, id}, "/")
responseResult, err := client.DoRequest(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, nil, err
}
if responseResult.Err != nil {
return nil, responseResult, responseResult.Err
}

// Extract a cross-region subnet from the response body.
var result struct {
CrossRegionSubnet *CrossRegionSubnet `json:"cross_region_subnet"`
}
err = responseResult.ExtractResult(&result)
if err != nil {
return nil, responseResult, err
}

return result.CrossRegionSubnet, responseResult, nil
}
27 changes: 27 additions & 0 deletions selvpcclient/resell/v2/crossregionsubnets/schemas.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package crossregionsubnets

import (
"github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/servers"
"github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/subnets"
)

// CrossRegionSubnet represents a single Resell cross-region subnet.
type CrossRegionSubnet struct {
// ID is a unique id of a cross-region subnet.
ID int `json:"id"`

// CIDR is a cross-region subnet prefix in CIDR notation.
CIDR string `json:"cidr"`

// VLANID represents id of the associated VLAN in the Networking service.
VLANID int `json:"vlan_id"`

// Status shows if cross-region subnet is used.
Status string `json:"status"`

// Servers contains info about servers to which cross-region subnet is associated to.
Servers []servers.Server `json:"servers"`

// Subnets contains standard subnets in every region that cross-region subnet is attached to.
Subnets []subnets.Subnet `json:"subnets"`
}
113 changes: 113 additions & 0 deletions selvpcclient/resell/v2/crossregionsubnets/testing/fixtures.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package testing

import (
"time"

"github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/crossregionsubnets"
"github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/servers"
"github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/subnets"
)

// TestGetCrossRegionSubnetResponseRaw represents a raw response from the Get request.
const TestGetCrossRegionSubnetResponseRaw = `
{
"cross_region_subnet": {
"id": 12,
"cidr": "192.168.200.0/24",
"vlan_id": 1003,
"status": "ACTIVE",
"servers": [
{
"status": "ACTIVE",
"updated": "2019-01-04T08:09:43Z",
"id": "22170dcf-2e58-49b7-9115-951b84d366f6",
"name": "Node01"
},
{
"status": "ACTIVE",
"updated": "2019-01-04T08:09:43Z",
"id": "df842202-fdcc-490e-b92a-6e252e5577c7",
"name": "Node02"
}
],
"subnets": [
{
"id": 10,
"vlan_id": 1003,
"cidr": "192.168.200.0/24",
"project_id": "b63ab68796e34858befb8fa2a8b1e12a",
"network_id": "78c1cbe1-c34d-4685-be2d-a877a1b1dec4",
"subnet_id": "7db1255f-2545-4b8a-9446-22608c0f6cb8",
"region": "ru-1",
"vtep_ip_address": "10.10.0.101"
},
{
"id": 20,
"vlan_id": 1003,
"cidr": "192.168.200.0/24",
"project_id": "b63ab68796e34858befb8fa2a8b1e12a",
"network_id": "67f7ab15-9424-4b50-999a-1c4de12372ec",
"subnet_id": "66ee047b-c699-4d62-9b64-363d2d77f021",
"region": "ru-3",
"vtep_ip_address": "10.10.0.201"
}
]
}
}
`

var crossregionSubnetServerTimeStamp, _ = time.Parse(time.RFC3339, "2019-01-04T08:09:43Z")

// TestGetCrossRegionSubnetResponse represents an unmarshalled TestGetCrossRegionSubnetResponseRaw.
var TestGetCrossRegionSubnetResponse = &crossregionsubnets.CrossRegionSubnet{
ID: 12,
CIDR: "192.168.200.0/24",
VLANID: 1003,
Status: "ACTIVE",
Servers: []servers.Server{
{
Status: "ACTIVE",
Updated: crossregionSubnetServerTimeStamp,
ID: "22170dcf-2e58-49b7-9115-951b84d366f6",
Name: "Node01",
},
{
Status: "ACTIVE",
Updated: crossregionSubnetServerTimeStamp,
ID: "df842202-fdcc-490e-b92a-6e252e5577c7",
Name: "Node02",
},
},
Subnets: []subnets.Subnet{
{
ID: 10,
CIDR: "192.168.200.0/24",
ProjectID: "b63ab68796e34858befb8fa2a8b1e12a",
NetworkID: "78c1cbe1-c34d-4685-be2d-a877a1b1dec4",
SubnetID: "7db1255f-2545-4b8a-9446-22608c0f6cb8",
Region: "ru-1",
VLANID: 1003,
VTEPIPAddress: "10.10.0.101",
},
{
ID: 20,
CIDR: "192.168.200.0/24",
ProjectID: "b63ab68796e34858befb8fa2a8b1e12a",
NetworkID: "67f7ab15-9424-4b50-999a-1c4de12372ec",
SubnetID: "66ee047b-c699-4d62-9b64-363d2d77f021",
Region: "ru-3",
VLANID: 1003,
VTEPIPAddress: "10.10.0.201",
},
},
}

// TestSingleCrossRegionSubnetInvalidResponseRaw represents a raw invalid response with
// a single cross-region subnet.
const TestSingleCrossRegionSubnetInvalidResponseRaw = `
{
"cross_region_subnet": {
"id": "b63ab68796e34858befb8fa2a8b1e12a"
}
}
`
121 changes: 121 additions & 0 deletions selvpcclient/resell/v2/crossregionsubnets/testing/requests_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package testing

import (
"context"
"net/http"
"reflect"
"testing"

"github.com/selectel/go-selvpcclient/selvpcclient/resell/v2/crossregionsubnets"
"github.com/selectel/go-selvpcclient/selvpcclient/testutils"
)

func TestGetCrossRegionSubnet(t *testing.T) {
endpointCalled := false

testEnv := testutils.SetupTestEnv()
defer testEnv.TearDownTestEnv()
testEnv.NewTestResellV2Client()
testutils.HandleReqWithoutBody(t, &testutils.HandleReqOpts{
Mux: testEnv.Mux,
URL: "/resell/v2/cross_region_subnets/12",
RawResponse: TestGetCrossRegionSubnetResponseRaw,
Method: http.MethodGet,
Status: http.StatusOK,
CallFlag: &endpointCalled,
})

ctx := context.Background()
actual, _, err := crossregionsubnets.Get(ctx, testEnv.Client, "12")
if err != nil {
t.Fatal(err)
}

expected := TestGetCrossRegionSubnetResponse

if !endpointCalled {
t.Fatal("endpoint wasn't called")
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("expected %#v, but got %#v", expected, actual)
}
}

func TestGetCrossRegionSubnetHTTPError(t *testing.T) {
endpointCalled := false

testEnv := testutils.SetupTestEnv()
defer testEnv.TearDownTestEnv()
testEnv.NewTestResellV2Client()
testutils.HandleReqWithoutBody(t, &testutils.HandleReqOpts{
Mux: testEnv.Mux,
URL: "/resell/v2/cross_region_subnets/12",
RawResponse: TestGetCrossRegionSubnetResponseRaw,
Method: http.MethodGet,
Status: http.StatusBadGateway,
CallFlag: &endpointCalled,
})

ctx := context.Background()
crossRegionSubnet, httpResponse, err := crossregionsubnets.Get(ctx, testEnv.Client, "12")

if !endpointCalled {
t.Fatal("endpoint wasn't called")
}
if crossRegionSubnet != nil {
t.Fatal("expected no cross-region subnet from the Get method")
}
if err == nil {
t.Fatal("expected error from the Get method")
}
if httpResponse.StatusCode != http.StatusBadGateway {
t.Fatalf("expected %d status in the HTTP response, but got %d",
http.StatusBadGateway, httpResponse.StatusCode)
}
}

func TestGetCrossRegionSubnetTimeoutError(t *testing.T) {
testEnv := testutils.SetupTestEnv()
testEnv.Server.Close()
defer testEnv.TearDownTestEnv()
testEnv.NewTestResellV2Client()

ctx := context.Background()
crossRegionSubnet, _, err := crossregionsubnets.Get(ctx, testEnv.Client, "12")

if crossRegionSubnet != nil {
t.Fatal("expected no cross-region subnet from the Get method")
}
if err == nil {
t.Fatal("expected error from the Get method")
}
}

func TestGetCrossRegionSubnetUnmarshalError(t *testing.T) {
endpointCalled := false

testEnv := testutils.SetupTestEnv()
defer testEnv.TearDownTestEnv()
testEnv.NewTestResellV2Client()
testutils.HandleReqWithoutBody(t, &testutils.HandleReqOpts{
Mux: testEnv.Mux,
URL: "/resell/v2/cross_region_subnets/12",
RawResponse: TestSingleCrossRegionSubnetInvalidResponseRaw,
Method: http.MethodGet,
Status: http.StatusOK,
CallFlag: &endpointCalled,
})

ctx := context.Background()
crossRegionSubnet, _, err := crossregionsubnets.Get(ctx, testEnv.Client, "12")

if !endpointCalled {
t.Fatal("endpoint wasn't called")
}
if crossRegionSubnet != nil {
t.Fatal("expected no cross-region subnets from the Get method")
}
if err == nil {
t.Fatal("expected error from the Get method")
}
}
6 changes: 6 additions & 0 deletions selvpcclient/resell/v2/subnets/schemas.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,10 @@ type Subnet struct {

// ProjectID represents an associated Identity service project.
ProjectID string `json:"project_id"`

// VLANID represents id of the associated VLAN in the Networking service.
VLANID int `json:"vlan_id"`

// VTEPIPAddress represents an ip address of the associated VTEP in the Networking service.
VTEPIPAddress string `json:"vtep_ip_address"`
}

0 comments on commit ee5acdd

Please sign in to comment.