From 175a0ad6730b5663c428b9ddd0d3b98b742a05a4 Mon Sep 17 00:00:00 2001 From: savasw Date: Tue, 27 Mar 2018 16:21:02 +0530 Subject: [PATCH 01/10] added vpc module with unit and acceptance tests --- acceptance/clients/clients.go | 19 ++ acceptance/openstack/networking/v1/vpc.go | 40 +++ .../openstack/networking/v1/vpcs_test.go | 57 ++++ .../networking/v1/common/common_tests.go | 18 ++ openstack/networking/v1/vpcs/doc.go | 52 ++++ openstack/networking/v1/vpcs/requests.go | 178 +++++++++++++ openstack/networking/v1/vpcs/results.go | 115 ++++++++ openstack/networking/v1/vpcs/testing/doc.go | 2 + .../v1/vpcs/testing/requests_test.go | 246 ++++++++++++++++++ openstack/networking/v1/vpcs/urls.go | 13 + 10 files changed, 740 insertions(+) create mode 100644 acceptance/openstack/networking/v1/vpc.go create mode 100644 acceptance/openstack/networking/v1/vpcs_test.go create mode 100644 openstack/networking/v1/common/common_tests.go create mode 100644 openstack/networking/v1/vpcs/doc.go create mode 100644 openstack/networking/v1/vpcs/requests.go create mode 100644 openstack/networking/v1/vpcs/results.go create mode 100644 openstack/networking/v1/vpcs/testing/doc.go create mode 100644 openstack/networking/v1/vpcs/testing/requests_test.go create mode 100644 openstack/networking/v1/vpcs/urls.go diff --git a/acceptance/clients/clients.go b/acceptance/clients/clients.go index 8a43a4ee5..1476533c5 100644 --- a/acceptance/clients/clients.go +++ b/acceptance/clients/clients.go @@ -333,6 +333,25 @@ func NewImageServiceV2Client() (*golangsdk.ServiceClient, error) { }) } +// NewNetworkV1Client returns a *ServiceClient for making calls to the +// OpenStack Networking v1 API. An error will be returned if authentication +// or client creation was not possible. +func NewNetworkV1Client() (*golangsdk.ServiceClient, error) { + ao, err := openstack.AuthOptionsFromEnv() + if err != nil { + return nil, err + } + + client, err := openstack.AuthenticatedClient(ao) + if err != nil { + return nil, err + } + + return openstack.NewNetworkV1(client, golangsdk.EndpointOpts{ + Region: os.Getenv("OS_REGION_NAME"), + }) +} + // NewNetworkV2Client returns a *ServiceClient for making calls to the // OpenStack Networking v2 API. An error will be returned if authentication // or client creation was not possible. diff --git a/acceptance/openstack/networking/v1/vpc.go b/acceptance/openstack/networking/v1/vpc.go new file mode 100644 index 000000000..a1255c372 --- /dev/null +++ b/acceptance/openstack/networking/v1/vpc.go @@ -0,0 +1,40 @@ +package v1 + +import ( + "testing" + + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/acceptance/tools" + "github.com/huaweicloud/golangsdk/openstack/networking/v1/vpcs" +) + +func CreateVpc(t *testing.T, client *golangsdk.ServiceClient) (*vpcs.Vpc, error) { + + vpcName := tools.RandomString("TESTACC-", 8) + + createOpts := vpcs.CreateOpts{ + Name: vpcName, + CIDR: "192.168.20.0/24", + } + + t.Logf("Attempting to create vpc: %s", vpcName) + + vpc, err := vpcs.Create(client, createOpts).Extract() + if err != nil { + return vpc, err + } + t.Logf("Created vpc: %s", vpcName) + + return vpc, nil +} + +func DeleteVpc(t *testing.T, client *golangsdk.ServiceClient, vpcID string) { + t.Logf("Attempting to delete vpc: %s", vpcID) + + err := vpcs.Delete(client, vpcID).ExtractErr() + if err != nil { + t.Fatalf("Error deleting vpc: %v", err) + } + + t.Logf("Deleted vpc: %s", vpcID) +} diff --git a/acceptance/openstack/networking/v1/vpcs_test.go b/acceptance/openstack/networking/v1/vpcs_test.go new file mode 100644 index 000000000..f6a9e5d48 --- /dev/null +++ b/acceptance/openstack/networking/v1/vpcs_test.go @@ -0,0 +1,57 @@ +package v1 + +import ( + "github.com/huaweicloud/golangsdk/acceptance/clients" + "github.com/huaweicloud/golangsdk/acceptance/tools" + "github.com/huaweicloud/golangsdk/openstack/networking/v1/vpcs" + "testing" +) + +func TestVpcList(t *testing.T) { + client, err := clients.NewNetworkV1Client() + if err != nil { + t.Fatalf("Unable to create a vpc client: %v", err) + } + + listOpts := vpcs.ListOpts{} + allVpcs, err := vpcs.List(client, listOpts) + if err != nil { + t.Fatalf("Unable to list vpcs: %v", err) + } + for _, vpc := range allVpcs { + tools.PrintResource(t, vpc) + } +} + +func TestVpcsCRUD(t *testing.T) { + client, err := clients.NewNetworkV1Client() + if err != nil { + t.Fatalf("Unable to create a vpc client: %v", err) + } + + // Create a vpc + vpc, err := CreateVpc(t, client) + if err != nil { + t.Fatalf("Unable to create create: %v", err) + } + defer DeleteVpc(t, client, vpc.ID) + + tools.PrintResource(t, vpc) + + newName := tools.RandomString("TESTACC-", 8) + updateOpts := &vpcs.UpdateOpts{ + Name: newName, + } + + _, err = vpcs.Update(client, vpc.ID, updateOpts).Extract() + if err != nil { + t.Fatalf("Unable to update vpc: %v", err) + } + + newVpc, err := vpcs.Get(client, vpc.ID).Extract() + if err != nil { + t.Fatalf("Unable to retrieve vpc: %v", err) + } + + tools.PrintResource(t, newVpc) +} diff --git a/openstack/networking/v1/common/common_tests.go b/openstack/networking/v1/common/common_tests.go new file mode 100644 index 000000000..bab798e5f --- /dev/null +++ b/openstack/networking/v1/common/common_tests.go @@ -0,0 +1,18 @@ +package common + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/testhelper/client" +) + +const TokenID = client.TokenID + +// Fake project id to use. +const ProjectID = "85636478b0bd8e67e89469c7749d4127" + +func ServiceClient() *golangsdk.ServiceClient { + sc := client.ServiceClient() + sc.ResourceBase = sc.Endpoint + "v1/" + sc.ProjectID = ProjectID + return sc +} diff --git a/openstack/networking/v1/vpcs/doc.go b/openstack/networking/v1/vpcs/doc.go new file mode 100644 index 000000000..87dc6dded --- /dev/null +++ b/openstack/networking/v1/vpcs/doc.go @@ -0,0 +1,52 @@ +/* +Package vpcs enables management and retrieval of Vpcs from the Open Telekom Cloud +VPC service. + +Example to List Vpcs + + listOpts := vpcs.ListOpts{} + allVpcs, err := vpcs.List(vpcClient, listOpts) + if err != nil { + panic(err) + } + + for _, vpc := range allVpcs { + fmt.Printf("%+v\n", vpc) + } + +Example to Create a Vpc + + createOpts := vpcs.CreateOpts{ + Name: "vpc_1", + CIDR: "192.168.0.0/24" + + } + + vpc, err := vpcs.Create(vpcClient, createOpts).Extract() + if err != nil { + panic(err) + } + +Example to Update a Vpc + + vpcID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + + updateOpts := vpcs.UpdateOpts{ + Name: "vpc_2", + CIDR: "192.168.0.0/23" + } + + vpc, err := vpcs.Update(vpcClient, vpcID, updateOpts).Extract() + if err != nil { + panic(err) + } + +Example to Delete a Vpc + + vpcID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + err := vpcs.Delete(vpcClient, vpcID).ExtractErr() + if err != nil { + panic(err) + } +*/ +package vpcs diff --git a/openstack/networking/v1/vpcs/requests.go b/openstack/networking/v1/vpcs/requests.go new file mode 100644 index 000000000..a9539b9ce --- /dev/null +++ b/openstack/networking/v1/vpcs/requests.go @@ -0,0 +1,178 @@ +package vpcs + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" + "reflect" +) + +// ListOpts allows the filtering and sorting of paginated collections through +// the API. Filtering is achieved by passing in struct field values that map to +// the floating IP attributes you want to see returned. SortKey allows you to +// sort by a particular network attribute. SortDir sets the direction, and is +// either `asc' or `desc'. Marker and Limit are used for pagination. + +type ListOpts struct { + // ID is the unique identifier for the vpc. + ID string `json:"id"` + + // Name is the human readable name for the vpc. It does not have to be + // unique. + Name string `json:"name"` + + //Specifies the range of available subnets in the VPC. + CIDR string `json:"cidr"` + + // Status indicates whether or not a vpc is currently operational. + Status string `json:"status"` +} + +// List returns collection of +// vpcs. It accepts a ListOpts struct, which allows you to filter and sort +// the returned collection for greater efficiency. +// +// Default policy settings return only those vpcs that are owned by the +// tenant who submits the request, unless an admin user submits the request. +func List(c *golangsdk.ServiceClient, opts ListOpts) ([]Vpc, error) { + u := rootURL(c) + pages, err := pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page { + return VpcPage{pagination.LinkedPageBase{PageResult: r}} + }).AllPages() + + allVpcs, err := ExtractVpcs(pages) + if err != nil { + return nil, err + } + + return FilterVPCs(allVpcs, opts) +} + +func FilterVPCs(vpcs []Vpc, opts ListOpts) ([]Vpc, error) { + + var refinedVPCs []Vpc + var matched bool + m := map[string]interface{}{} + + if opts.ID != "" { + m["ID"] = opts.ID + } + if opts.Name != "" { + m["Name"] = opts.Name + } + if opts.Status != "" { + m["Status"] = opts.Status + } + if opts.CIDR != "" { + m["CIDR"] = opts.CIDR + } + + if len(m) > 0 && len(vpcs) > 0 { + for _, vpc := range vpcs { + matched = true + + for key, value := range m { + if sVal := getStructField(&vpc, key); !(sVal == value) { + matched = false + } + } + + if matched { + refinedVPCs = append(refinedVPCs, vpc) + } + } + + } else { + refinedVPCs = vpcs + } + + return refinedVPCs, nil +} + +func getStructField(v *Vpc, field string) string { + r := reflect.ValueOf(v) + f := reflect.Indirect(r).FieldByName(field) + return string(f.String()) +} + +// CreateOptsBuilder allows extensions to add additional parameters to the +// Create request. +type CreateOptsBuilder interface { + ToVpcCreateMap() (map[string]interface{}, error) +} + +// CreateOpts contains all the values needed to create a new vpc. There are +// no required values. +type CreateOpts struct { + Name string `json:"name,omitempty"` + CIDR string `json:"cidr,omitempty"` +} + +// ToVpcCreateMap builds a create request body from CreateOpts. +func (opts CreateOpts) ToVpcCreateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "vpc") +} + +// Create accepts a CreateOpts struct and uses the values to create a new +// logical vpc. When it is created, the vpc does not have an internal +// interface - it is not associated to any subnet. +// +// You can optionally specify an external gateway for a vpc using the +// GatewayInfo struct. The external gateway for the vpc must be plugged into +// an external network (it is external if its `vpc:external' field is set to +// true). +func Create(c *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToVpcCreateMap() + if err != nil { + r.Err = err + return + } + reqOpt := &golangsdk.RequestOpts{OkCodes: []int{200}} + _, r.Err = c.Post(rootURL(c), b, &r.Body, reqOpt) + return +} + +// Get retrieves a particular vpc based on its unique ID. +func Get(c *golangsdk.ServiceClient, id string) (r GetResult) { + _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) + return +} + +// UpdateOptsBuilder allows extensions to add additional parameters to the +// Update request. +type UpdateOptsBuilder interface { + ToVpcUpdateMap() (map[string]interface{}, error) +} + +// UpdateOpts contains the values used when updating a vpc. +type UpdateOpts struct { + CIDR string `json:"cidr,omitempty"` + Name string `json:"name,omitempty"` +} + +// ToVpcUpdateMap builds an update body based on UpdateOpts. +func (opts UpdateOpts) ToVpcUpdateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "vpc") +} + +// Update allows vpcs to be updated. You can update the name, administrative +// state, and the external gateway. For more information about how to set the +// external gateway for a vpc, see Create. This operation does not enable +// the update of vpc interfaces. To do this, use the AddInterface and +// RemoveInterface functions. +func Update(c *golangsdk.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToVpcUpdateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = c.Put(resourceURL(c, id), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +// Delete will permanently delete a particular vpc based on its unique ID. +func Delete(c *golangsdk.ServiceClient, id string) (r DeleteResult) { + _, r.Err = c.Delete(resourceURL(c, id), nil) + return +} diff --git a/openstack/networking/v1/vpcs/results.go b/openstack/networking/v1/vpcs/results.go new file mode 100644 index 000000000..411aa0dfb --- /dev/null +++ b/openstack/networking/v1/vpcs/results.go @@ -0,0 +1,115 @@ +package vpcs + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +// Route is a possible route in a vpc. +type Route struct { + NextHop string `json:"nexthop"` + DestinationCIDR string `json:"destination"` +} + +// Vpc represents a Neutron vpc. A vpc is a logical entity that +// forwards packets across internal subnets and NATs (network address +// translation) them on external networks through an appropriate gateway. +// +// A vpc has an interface for each subnet with which it is associated. By +// default, the IP address of such interface is the subnet's gateway IP. Also, +// whenever a vpc is associated with a subnet, a port for that vpc +// interface is added to the subnet's network. +type Vpc struct { + // ID is the unique identifier for the vpc. + ID string `json:"id"` + + // Name is the human readable name for the vpc. It does not have to be + // unique. + Name string `json:"name"` + + //Specifies the range of available subnets in the VPC. + CIDR string `json:"cidr"` + + // Status indicates whether or not a vpc is currently operational. + Status string `json:"status"` + + // Routes are a collection of static routes that the vpc will host. + Routes []Route `json:"routes"` + + //Provides informaion about shared snat + EnableSharedSnat bool `json:"enable_shared_snat"` +} + +// VpcPage is the page returned by a pager when traversing over a +// collection of vpcs. +type VpcPage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of vpcs has reached +// the end of a page and the pager seeks to traverse over a new one. In order +// to do this, it needs to construct the next page's URL. +func (r VpcPage) NextPageURL() (string, error) { + var s struct { + Links []golangsdk.Link `json:"vpcs_links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return golangsdk.ExtractNextURL(s.Links) +} + +// IsEmpty checks whether a VpcPage struct is empty. +func (r VpcPage) IsEmpty() (bool, error) { + is, err := ExtractVpcs(r) + return len(is) == 0, err +} + +// ExtractVpcs accepts a Page struct, specifically a VpcPage struct, +// and extracts the elements into a slice of Vpc structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractVpcs(r pagination.Page) ([]Vpc, error) { + var s struct { + Vpcs []Vpc `json:"vpcs"` + } + err := (r.(VpcPage)).ExtractInto(&s) + return s.Vpcs, err +} + +type commonResult struct { + golangsdk.Result +} + +// Extract is a function that accepts a result and extracts a vpc. +func (r commonResult) Extract() (*Vpc, error) { + var s struct { + Vpc *Vpc `json:"vpc"` + } + err := r.ExtractInto(&s) + return s.Vpc, err +} + +// CreateResult represents the result of a create operation. Call its Extract +// method to interpret it as a Vpc. +type CreateResult struct { + commonResult +} + +// GetResult represents the result of a get operation. Call its Extract +// method to interpret it as a Vpc. +type GetResult struct { + commonResult +} + +// UpdateResult represents the result of an update operation. Call its Extract +// method to interpret it as a Vpc. +type UpdateResult struct { + commonResult +} + +// DeleteResult represents the result of a delete operation. Call its ExtractErr +// method to determine if the request succeeded or failed. +type DeleteResult struct { + golangsdk.ErrResult +} diff --git a/openstack/networking/v1/vpcs/testing/doc.go b/openstack/networking/v1/vpcs/testing/doc.go new file mode 100644 index 000000000..77f41573c --- /dev/null +++ b/openstack/networking/v1/vpcs/testing/doc.go @@ -0,0 +1,2 @@ +// vpcs unit tests +package testing diff --git a/openstack/networking/v1/vpcs/testing/requests_test.go b/openstack/networking/v1/vpcs/testing/requests_test.go new file mode 100644 index 000000000..c2bc2565d --- /dev/null +++ b/openstack/networking/v1/vpcs/testing/requests_test.go @@ -0,0 +1,246 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + fake "github.com/huaweicloud/golangsdk/openstack/networking/v1/common" + "github.com/huaweicloud/golangsdk/openstack/networking/v1/vpcs" + th "github.com/huaweicloud/golangsdk/testhelper" +) + +func TestListVpc(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v1/85636478b0bd8e67e89469c7749d4127/vpcs", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` +{ + "vpcs": [ + { + "id": "14ece7d0-a8d4-4317-982a-041e4f10f442", + "name": "vpc-elb-l00379969", + "cidr": "192.168.0.0/16", + "status": "OK", + "routes": [], + "enable_shared_snat": false + }, + { + "id": "1e5618c3-89f0-4f58-a14e-33536074ec88", + "name": "vpc-ops", + "cidr": "192.168.0.0/16", + "status": "OK", + "routes": [], + "enable_shared_snat": false + }, + { + "id": "2140264c-d313-4363-9874-9a5e18aeb516", + "name": "test", + "cidr": "192.168.0.0/16", + "status": "OK", + "routes": [], + "enable_shared_snat": false + } + ] +} + `) + }) + + //count := 0 + + actual, err := vpcs.List(fake.ServiceClient(), vpcs.ListOpts{}) + if err != nil { + t.Errorf("Failed to extract vpcs: %v", err) + } + + expected := []vpcs.Vpc{ + { + Status: "OK", + CIDR: "192.168.0.0/16", + EnableSharedSnat: false, + Name: "vpc-elb-l00379969", + ID: "14ece7d0-a8d4-4317-982a-041e4f10f442", + Routes: []vpcs.Route{}, + }, + { + Status: "OK", + CIDR: "192.168.0.0/16", + EnableSharedSnat: false, + Name: "vpc-ops", + ID: "1e5618c3-89f0-4f58-a14e-33536074ec88", + Routes: []vpcs.Route{}, + }, + { + Status: "OK", + CIDR: "192.168.0.0/16", + EnableSharedSnat: false, + Name: "test", + ID: "2140264c-d313-4363-9874-9a5e18aeb516", + Routes: []vpcs.Route{}, + }, + } + + th.AssertDeepEquals(t, expected, actual) +} + +func TestGetVpc(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v1/85636478b0bd8e67e89469c7749d4127/vpcs/abda1f6e-ae7c-4ff5-8d06-53425dc11f34", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` +{ + "vpc": { + "id": "abda1f6e-ae7c-4ff5-8d06-53425dc11f34", + "name": "terraform-provider-test-l90006937", + "cidr": "192.168.0.0/16", + "status": "OK", + "routes": [ + { + "destination": "0.0.0.0/0", + "nexthop": "192.168.0.5" + } + ], + "enable_shared_snat": false + } +} + `) + }) + + n, err := vpcs.Get(fake.ServiceClient(), "abda1f6e-ae7c-4ff5-8d06-53425dc11f34").Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, "abda1f6e-ae7c-4ff5-8d06-53425dc11f34", n.ID) + th.AssertEquals(t, "terraform-provider-test-l90006937", n.Name) + th.AssertEquals(t, "192.168.0.0/16", n.CIDR) + th.AssertEquals(t, "OK", n.Status) + th.AssertDeepEquals(t, []vpcs.Route{{DestinationCIDR: "0.0.0.0/0", NextHop: "192.168.0.5"}}, n.Routes) + th.AssertEquals(t, false, n.EnableSharedSnat) + +} + +func TestCreateVpc(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v1/85636478b0bd8e67e89469c7749d4127/vpcs", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "vpc": + { + "name": "terraform-provider-vpctestcreate", + "cidr": "192.168.0.0/16" + } +} + `) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` +{ + "vpc": { + "id": "97e01fc2-e39e-4cfc-abf6-1d0886d120af", + "name": "terraform-provider-vpctestcreate", + "cidr": "192.168.0.0/16", + "status": "CREATING" + } +} `) + }) + + options := vpcs.CreateOpts{ + Name: "terraform-provider-vpctestcreate", + CIDR: "192.168.0.0/16", + } + n, err := vpcs.Create(fake.ServiceClient(), options).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, "terraform-provider-vpctestcreate", n.Name) + th.AssertEquals(t, "97e01fc2-e39e-4cfc-abf6-1d0886d120af", n.ID) + th.AssertEquals(t, "192.168.0.0/16", n.CIDR) + th.AssertEquals(t, "CREATING", n.Status) + th.AssertEquals(t, false, n.EnableSharedSnat) +} + +func TestUpdateVpc(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v1/85636478b0bd8e67e89469c7749d4127/vpcs/97e01fc2-e39e-4cfc-abf6-1d0886d120af", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ +"vpc": + { + "name": "terraform-provider-new-name", + "cidr": "192.168.0.0/16" + + } +} + `) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` +{ + "vpc": { + "id": "97e01fc2-e39e-4cfc-abf6-1d0886d120af", + "name": "terraform-provider-new-name", + "cidr": "192.168.0.0/16", + "status": "OK", + "routes": [ + { + "destination": "0.0.0.0/4", + "nexthop": "192.168.0.4" + } + ], + "enable_shared_snat": false + } +} + `) + }) + + options := vpcs.UpdateOpts{Name: "terraform-provider-new-name", CIDR: "192.168.0.0/16"} + + n, err := vpcs.Update(fake.ServiceClient(), "97e01fc2-e39e-4cfc-abf6-1d0886d120af", options).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, "terraform-provider-new-name", n.Name) + th.AssertEquals(t, "97e01fc2-e39e-4cfc-abf6-1d0886d120af", n.ID) + th.AssertEquals(t, "192.168.0.0/16", n.CIDR) + th.AssertEquals(t, "OK", n.Status) + th.AssertDeepEquals(t, []vpcs.Route{{DestinationCIDR: "0.0.0.0/4", NextHop: "192.168.0.4"}}, n.Routes) + th.AssertEquals(t, false, n.EnableSharedSnat) +} + +func TestDeleteVpc(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v1/85636478b0bd8e67e89469c7749d4127/vpcs/abda1f6e-ae7c-4ff5-8d06-53425dc11f34", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + w.WriteHeader(http.StatusNoContent) + }) + + res := vpcs.Delete(fake.ServiceClient(), "abda1f6e-ae7c-4ff5-8d06-53425dc11f34") + th.AssertNoErr(t, res.Err) +} diff --git a/openstack/networking/v1/vpcs/urls.go b/openstack/networking/v1/vpcs/urls.go new file mode 100644 index 000000000..d4293720f --- /dev/null +++ b/openstack/networking/v1/vpcs/urls.go @@ -0,0 +1,13 @@ +package vpcs + +import "github.com/huaweicloud/golangsdk" + +const resourcePath = "vpcs" + +func rootURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL(c.ProjectID, resourcePath) +} + +func resourceURL(c *golangsdk.ServiceClient, id string) string { + return c.ServiceURL(c.ProjectID, resourcePath, id) +} From baad8776fea019478d5d048c3d303dfd0b9b2b46 Mon Sep 17 00:00:00 2001 From: savasw Date: Tue, 27 Mar 2018 16:29:04 +0530 Subject: [PATCH 02/10] added vpc peering connection interface and unit acceptance tests --- acceptance/clients/clients.go | 65 ++++ .../networking/v2/peerings/peerings.go | 132 ++++++++ .../networking/v2/peerings/peerings_test.go | 79 +++++ openstack/networking/v2/peerings/doc.go | 88 +++++ openstack/networking/v2/peerings/requests.go | 221 +++++++++++++ openstack/networking/v2/peerings/results.go | 144 ++++++++ .../networking/v2/peerings/testing/doc.go | 2 + .../v2/peerings/testing/requests_test.go | 311 ++++++++++++++++++ openstack/networking/v2/peerings/urls.go | 24 ++ 9 files changed, 1066 insertions(+) create mode 100644 acceptance/openstack/networking/v2/peerings/peerings.go create mode 100644 acceptance/openstack/networking/v2/peerings/peerings_test.go create mode 100644 openstack/networking/v2/peerings/doc.go create mode 100644 openstack/networking/v2/peerings/requests.go create mode 100644 openstack/networking/v2/peerings/results.go create mode 100644 openstack/networking/v2/peerings/testing/doc.go create mode 100644 openstack/networking/v2/peerings/testing/requests_test.go create mode 100644 openstack/networking/v2/peerings/urls.go diff --git a/acceptance/clients/clients.go b/acceptance/clients/clients.go index 1476533c5..92645c863 100644 --- a/acceptance/clients/clients.go +++ b/acceptance/clients/clients.go @@ -352,6 +352,30 @@ func NewNetworkV1Client() (*golangsdk.ServiceClient, error) { }) } +// NewPeerNetworkV1Client returns a *ServiceClient for making calls to the +// OpenStack Networking v1 API for VPC peer. An error will be returned if authentication +// or client creation was not possible. +func NewPeerNetworkV1Client() (*golangsdk.ServiceClient, error) { + ao, err := openstack.AuthOptionsFromEnv() + if err != nil { + return nil, err + } + + err = UpdatePeerTenantDetails(&ao) + if err != nil { + return nil, err + } + + client, err := openstack.AuthenticatedClient(ao) + if err != nil { + return nil, err + } + + return openstack.NewNetworkV1(client, golangsdk.EndpointOpts{ + Region: os.Getenv("OS_REGION_NAME"), + }) +} + // NewNetworkV2Client returns a *ServiceClient for making calls to the // OpenStack Networking v2 API. An error will be returned if authentication // or client creation was not possible. @@ -371,6 +395,30 @@ func NewNetworkV2Client() (*golangsdk.ServiceClient, error) { }) } +// NewPeerNetworkV2Client returns a *ServiceClient for making calls to the +// OpenStack Networking v2 API for Peer. An error will be returned if authentication +// or client creation was not possible. +func NewPeerNetworkV2Client() (*golangsdk.ServiceClient, error) { + ao, err := openstack.AuthOptionsFromEnv() + if err != nil { + return nil, err + } + + err = UpdatePeerTenantDetails(&ao) + if err != nil { + return nil, err + } + + client, err := openstack.AuthenticatedClient(ao) + if err != nil { + return nil, err + } + + return openstack.NewNetworkV2(client, golangsdk.EndpointOpts{ + Region: os.Getenv("OS_REGION_NAME"), + }) +} + // NewObjectStorageV1Client returns a *ServiceClient for making calls to the // OpenStack Object Storage v1 API. An error will be returned if authentication // or client creation was not possible. @@ -408,3 +456,20 @@ func NewSharedFileSystemV2Client() (*golangsdk.ServiceClient, error) { Region: os.Getenv("OS_REGION_NAME"), }) } + +func UpdatePeerTenantDetails(ao *golangsdk.AuthOptions) error { + + if peerTenantID := os.Getenv("OS_Peer_Tenant_ID"); peerTenantID != "" { + ao.TenantID = peerTenantID + ao.TenantName = "" + return nil + + } else if peerTenantName := os.Getenv("OS_Peer_Tenant_Name"); peerTenantName != "" { + ao.TenantID = "" + ao.TenantName = peerTenantName + return nil + + } else { + return fmt.Errorf("You're missing some important setup:\n OS_Peer_Tenant_ID or OS_Peer_Tenant_Name env variables must be provided.") + } +} diff --git a/acceptance/openstack/networking/v2/peerings/peerings.go b/acceptance/openstack/networking/v2/peerings/peerings.go new file mode 100644 index 000000000..efd615919 --- /dev/null +++ b/acceptance/openstack/networking/v2/peerings/peerings.go @@ -0,0 +1,132 @@ +package v2 + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/acceptance/clients" + "github.com/huaweicloud/golangsdk/acceptance/tools" + "github.com/huaweicloud/golangsdk/openstack/networking/v1/vpcs" + "github.com/huaweicloud/golangsdk/openstack/networking/v2/peerings" + "testing" +) + +func CreatePeeringResourcesNConn(t *testing.T, clientV2 *golangsdk.ServiceClient, peerClientV2 *golangsdk.ServiceClient, + clientV1 *golangsdk.ServiceClient, peerClientV1 *golangsdk.ServiceClient) (*peerings.Peering, error) { + + vpcName := tools.RandomString("TESTACC-vpc", 8) + peerVpcName := tools.RandomString("TESTACC-peervpc", 8) + + createOpts := vpcs.CreateOpts{ + Name: vpcName, + CIDR: "192.168.20.0/24", + } + + t.Logf("Attempting to create vpc: %s and peer vpc: %s", vpcName, peerVpcName) + + vpc, err := vpcs.Create(clientV1, createOpts).Extract() + if err != nil { + return nil, err + } + + peerVpc, err := vpcs.Create(peerClientV1, createOpts).Extract() + if err != nil { + return nil, err + } + + t.Logf("Created vpcs: %s %s", vpcName, peerVpcName) + + peeringConnName := tools.RandomString("TESTACC-", 8) + + peerCreateOpts := peerings.CreateOpts{ + Name: peeringConnName, + RequestVpcInfo: peerings.VpcInfo{VpcId: vpc.ID}, + AcceptVpcInfo: peerings.VpcInfo{peerVpc.ID, peerClientV2.ProjectID}, + } + + t.Logf("Attempting to create vpc peering connection: %s", peeringConnName) + + peeringConns, err := peerings.Create(clientV2, peerCreateOpts).Extract() + if err != nil { + return peeringConns, err + } + + if err := WaitForPeeringConnToCreate(clientV2, peeringConns.ID, 60); err != nil { + return peeringConns, err + } + + t.Logf("Created vpc peering connection: %s", peeringConnName) + + return peeringConns, nil +} + +func DeletePeeringConnNResources(t *testing.T, clientV2 *golangsdk.ServiceClient, clientV1 *golangsdk.ServiceClient, + peerClientV1 *golangsdk.ServiceClient, peeringConn *peerings.Peering) { + t.Logf("Attempting to delete vpc peering connection: %s", peeringConn.ID) + + err := peerings.Delete(clientV2, peeringConn.ID).ExtractErr() + if err != nil { + t.Fatalf("Error deleting vpc peering connection: %v", err) + } + + t.Logf("Deleted vpc peering connection: %s", peeringConn.ID) + + t.Logf("Attempting to delete vpc: %s", peeringConn.RequestVpcInfo.VpcId) + + err = vpcs.Delete(clientV1, peeringConn.RequestVpcInfo.VpcId).ExtractErr() + if err != nil { + t.Fatalf("Error deleting vpc: %v", err) + } + + err = vpcs.Delete(peerClientV1, peeringConn.AcceptVpcInfo.VpcId).ExtractErr() + if err != nil { + t.Fatalf("Error deleting vpc: %v", err) + } + + t.Logf("Deleted vpcs: %s and %s", peeringConn.RequestVpcInfo.VpcId, peeringConn.AcceptVpcInfo.VpcId) +} + +func initiatePeeringConnCommonTasks(t *testing.T) (*golangsdk.ServiceClient, *golangsdk.ServiceClient, + *golangsdk.ServiceClient, *golangsdk.ServiceClient, *peerings.Peering) { + + clientV2, err := clients.NewNetworkV2Client() + if err != nil { + t.Fatalf("Unable to create a network v2 client: %v", err) + } + + clientV1, err := clients.NewNetworkV1Client() + if err != nil { + t.Fatalf("Unable to create a network v1 client: %v", err) + } + + peerClientV2, err := clients.NewPeerNetworkV2Client() + if err != nil { + t.Fatalf("Unable to create a network v2 client for peer: %v", err) + } + + peerClientV1, err := clients.NewPeerNetworkV1Client() + if err != nil { + t.Fatalf("Unable to create a network v1 client for peer: %v", err) + } + + // Create a vpc peering connection + peeringConn, err := CreatePeeringResourcesNConn(t, clientV2, peerClientV2, clientV1, peerClientV1) + if err != nil { + t.Fatalf("Unable to create vpc peering connection: %v", err) + } + + return clientV2, peerClientV2, clientV1, peerClientV1, peeringConn +} + +func WaitForPeeringConnToCreate(client *golangsdk.ServiceClient, peeringConnID string, secs int) error { + return golangsdk.WaitFor(secs, func() (bool, error) { + conn, err := peerings.Get(client, peeringConnID).Extract() + if err != nil { + return false, err + } + + if conn.Status == "PENDING_ACCEPTANCE" { + return true, nil + } + + return false, nil + }) +} diff --git a/acceptance/openstack/networking/v2/peerings/peerings_test.go b/acceptance/openstack/networking/v2/peerings/peerings_test.go new file mode 100644 index 000000000..e9820979e --- /dev/null +++ b/acceptance/openstack/networking/v2/peerings/peerings_test.go @@ -0,0 +1,79 @@ +package v2 + +import ( + "github.com/huaweicloud/golangsdk/acceptance/clients" + "github.com/huaweicloud/golangsdk/acceptance/tools" + "github.com/huaweicloud/golangsdk/openstack/networking/v2/peerings" + "testing" +) + +func TestPeeringList(t *testing.T) { + client, err := clients.NewNetworkV2Client() + if err != nil { + t.Fatalf("Unable to create a vpc client: %v", err) + } + + listOpts := peerings.ListOpts{} + peering, err := peerings.List(client, listOpts) + if err != nil { + t.Fatalf("Unable to list peerings: %v", err) + } + for _, peering := range peering { + tools.PrintResource(t, peering) + } +} + +func TestAcceptPeering(t *testing.T) { + + clientV2, peerClientV2, clientV1, peerClientV1, peeringConn := initiatePeeringConnCommonTasks(t) + + // Delete a vpc peering connection + defer DeletePeeringConnNResources(t, clientV2, clientV1, peerClientV1, peeringConn) + + peeringConn1, err := peerings.Accept(peerClientV2, peeringConn.ID).ExtractResult() + if err != nil { + t.Fatalf("Unable to accept peering request: %v", err) + } + tools.PrintResource(t, peeringConn1) + +} + +func TestRejectPeering(t *testing.T) { + + clientV2, peerClientV2, clientV1, peerClientV1, peeringConn := initiatePeeringConnCommonTasks(t) + + // Delete a vpc peering connection + defer DeletePeeringConnNResources(t, clientV2, clientV1, peerClientV1, peeringConn) + + peerConn1, err := peerings.Reject(peerClientV2, peeringConn.ID).ExtractResult() + if err != nil { + t.Fatalf("Unable to Reject peering request: %v", err) + } + tools.PrintResource(t, peerConn1) + +} + +func TestPeeringCRUD(t *testing.T) { + + clientV2, peerClientV2, clientV1, peerClientV1, peeringConn := initiatePeeringConnCommonTasks(t) + + // Delete a vpc peering connection + defer DeletePeeringConnNResources(t, clientV2, clientV1, peerClientV1, peeringConn) + + tools.PrintResource(t, peeringConn) + updateOpts := peerings.UpdateOpts{ + Name: "test2", + } + + _, err := peerings.Update(clientV2, peeringConn.ID, updateOpts).Extract() + if err != nil { + t.Fatalf("Unable to update vpc peering connection: %v", err) + } + + peeringConnGet, err := peerings.Get(peerClientV2, peeringConn.ID).Extract() + if err != nil { + t.Fatalf("Unable to retrieve vpc peering connection: %v", err) + } + + tools.PrintResource(t, peeringConnGet) +} diff --git a/openstack/networking/v2/peerings/doc.go b/openstack/networking/v2/peerings/doc.go new file mode 100644 index 000000000..0b7d0efb4 --- /dev/null +++ b/openstack/networking/v2/peerings/doc.go @@ -0,0 +1,88 @@ + +/* +Package peerings enables management and retrieval of vpc peering connections from the Open Telekom Cloud VPC service. + +Example to List a Vpc Peering Connections + listOpts:=peerings.ListOpts{} + + peering,err :=peerings.List(client,sub).AllPages() + + peerings,err:=peerings.ExtractPeerings(peering) + + + if err != nil{ + fmt.Println(err) + } + +Example to Get a Vpc Peering Connection + + peeringID := "6bbacb0f-9f94-4fe8-a6b6-1818bdccb2a3" + + + peering,err :=peerings.Get(client,peeringID).Extract() + + + if err != nil{ + fmt.Println(err) + } + + + +Example to Accept a Vpc Peering Connection Request + // Note:- The TenantId should be of accepter + + peeringID := "6bbacb0f-9f94-4fe8-a6b6-1818bdccb2a3" + + peering,err:=peerings.Accept(client,peeringID).ExtractResult() + + if err != nil{ + fmt.Println(err) + } + + +Example to Reject a Vpc Peering Connection Request + // Note:- The TenantId should be of accepter + peeringID := "6bbacb0f-9f94-4fe8-a6b6-1818bdccb2a3" + + peering,err:=peerings.Reject(client,peeringID).ExtractResult() + + if err != nil{ + fmt.Println(err) + } + +Example to Create a Vpc Peering Connection + + RequestVpcInfo:=peerings.VpcInfo{VpcId:"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf"} + AcceptVpcInfo:=peerings.VpcInfo{"c6efbdb7-dca4-4178-b3ec-692f125c1e25","17fbda95add24720a4038ba4b1c705ed"} + + opt:=peerings.CreateOpts{"C2C_test",RequestVpcInfo,AcceptVpcInfo} + + peering,err:=peerings.Create(client,opt).Extract() + + if err != nil{ + fmt.Println(err) + } + + +Example to Update a VpcPeeringConnection + + peeringID := "6bbacb0f-9f94-4fe8-a6b6-1818bdccb2a3" + + updateOpts:=peerings.UpdateOpts{"C2C_tes1"} + + peering,err:=peerings.Update(client,peeringID,updateOpts).Extract() + + if err != nil{ + fmt.Println(err) + } + + +Example to Delete a VpcPeeringConnection + + peeringID := "6bbacb0f-9f94-4fe8-a6b6-1818bdccb2a3" + err := peerings.Delete(client,"6bbacb0f-9f94-4fe8-a6b6-1818bdccb2a3") + if err != nil { + panic(err) + } +*/ +package peerings diff --git a/openstack/networking/v2/peerings/requests.go b/openstack/networking/v2/peerings/requests.go new file mode 100644 index 000000000..675a709a0 --- /dev/null +++ b/openstack/networking/v2/peerings/requests.go @@ -0,0 +1,221 @@ +package peerings + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" + "reflect" +) + +// ListOpts allows the filtering of paginated collections through +// the API. Filtering is achieved by passing in struct field values that map to +// the floating IP attributes you want to see returned. +type ListOpts struct { + //ID is the unique identifier for the vpc_peering_connection. + ID string `q:"id"` + + //Name is the human readable name for the vpc_peering_connection. It does not have to be + // unique. + Name string `q:"name"` + + //Status indicates whether or not a vpc_peering_connection is currently operational. + Status string `q:"status"` + + // TenantId indicates vpc_peering_connection avalable in specific tenant. + TenantId string `q:"tenant_id"` + + // VpcId indicates vpc_peering_connection avalable in specific vpc. + VpcId string `q:"vpc_id"` + + // VpcId indicates vpc_peering_connection available in specific vpc. + Peer_VpcId string +} + +func FilterVpcIdParam(opts ListOpts) (filter ListOpts) { + + if opts.VpcId != "" { + filter.VpcId = opts.VpcId + } else { + filter.VpcId = opts.Peer_VpcId + } + + filter.Name = opts.Name + filter.ID = opts.ID + filter.Status = opts.Status + filter.TenantId = opts.TenantId + + return filter +} + +// List returns a Pager which allows you to iterate over a collection of +// vpc_peering_connection resources. It accepts a ListOpts struct, which allows you to +// filter the returned collection for greater efficiency. +func List(c *golangsdk.ServiceClient, opts ListOpts) ([]Peering, error) { + filter := FilterVpcIdParam(opts) + q, err := golangsdk.BuildQueryString(&filter) + if err != nil { + return nil, err + } + u := rootURL(c) + q.String() + pages, err := pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page { + return PeeringConnectionPage{pagination.LinkedPageBase{PageResult: r}} + }).AllPages() + + allPeeringConns, err := ExtractPeerings(pages) + if err != nil { + return nil, err + } + + return FilterVpcPeeringConns(allPeeringConns, opts) +} + +func FilterVpcPeeringConns(peerings []Peering, opts ListOpts) ([]Peering, error) { + var refinedPeerings []Peering + var matched bool + filterMap := map[string]interface{}{} + + if opts.VpcId != "" { + filterMap["RequestVpcInfo"] = opts.VpcId + } + + if opts.Peer_VpcId != "" { + filterMap["AcceptVpcInfo"] = opts.Peer_VpcId + } + + if len(filterMap) > 0 && len(peerings) > 0 { + for _, peering := range peerings { + matched = true + + for key, value := range filterMap { + if sVal := getStructNestedField(&peering, key); !(sVal == value) { + matched = false + } + } + + if matched { + refinedPeerings = append(refinedPeerings, peering) + } + + } + } else { + refinedPeerings = peerings + } + + return refinedPeerings, nil + + /*for _, peering := range peerings { + matched = true + Peer_VpcId:=getStructNestedField(&peering,"AcceptVpcInfo"); + VpcId:=getStructNestedField(&peering,"RequestVpcInfo") + + if opts.VpcId != "" || opts.Peer_VpcId != "" { + if opts.VpcId != "" && opts.Peer_VpcId != "" { + if !(Peer_VpcId ==opts.Peer_VpcId ) && !(VpcId ==opts.VpcId ) { + matched = false + } + } + if opts.Peer_VpcId != ""{ + if !(Peer_VpcId ==opts.Peer_VpcId ){ + matched = false + } + } + } + + if matched { + refinedPeerings = append(refinedPeerings, peering) + } + }*/ + +} + +func getStructNestedField(v *Peering, field string) string { + r := reflect.ValueOf(v) + f := reflect.Indirect(r).FieldByName(field).Interface() + r1 := reflect.ValueOf(f) + f1 := reflect.Indirect(r1).FieldByName("VpcId") + return string(f1.String()) +} + +func Get(c *golangsdk.ServiceClient, id string) (r GetResult) { + _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) + return +} + +// Accept is used by a tenant to accept a VPC peering connection request initiated by another tenant. +func Accept(c *golangsdk.ServiceClient, id string) (r AcceptResult) { + _, r.Err = c.Put(acceptURL(c, id), nil, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +// Reject is used by a tenant to reject a VPC peering connection request initiated by another tenant. +func Reject(c *golangsdk.ServiceClient, id string) (r RejectResult) { + _, r.Err = c.Put(rejectURL(c, id), nil, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +//CreateOptsBuilder is an interface by which can build the request body of vpc peering connection. +type CreateOptsBuilder interface { + ToPeeringCreateMap() (map[string]interface{}, error) +} + +//CreateOpts is a struct which is used to create vpc peering connection. +type CreateOpts struct { + Name string `json:"name"` + RequestVpcInfo VpcInfo `json:"request_vpc_info" required:"true"` + AcceptVpcInfo VpcInfo `json:"accept_vpc_info" required:"true"` +} + +//ToVpcPeeringCreateMap builds a create request body from CreateOpts. +func (opts CreateOpts) ToPeeringCreateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "peering") +} + +//Create is a method by which can access to create the vpc peering connection. +func Create(client *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToPeeringCreateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = client.Post(rootURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{201}, + }) + return +} + +//Delete is a method by which can be able to delete a vpc peering connection. +func Delete(client *golangsdk.ServiceClient, id string) (r DeleteResult) { + _, r.Err = client.Delete(resourceURL(client, id), nil) + return +} + +//UpdateOptsBuilder is an interface by which can be able to build the request body of vpc peering connection. +type UpdateOptsBuilder interface { + ToVpcPeeringUpdateMap() (map[string]interface{}, error) +} + +//UpdateOpts is a struct which represents the request body of update method. +type UpdateOpts struct { + Name string `json:"name,omitempty"` +} + +//ToVpcPeeringUpdateMap builds a update request body from UpdateOpts. +func (opts UpdateOpts) ToVpcPeeringUpdateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "peering") +} + +//Update is a method which can be able to update the name of vpc peering connection. +func Update(client *golangsdk.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToVpcPeeringUpdateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = client.Put(resourceURL(client, id), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} diff --git a/openstack/networking/v2/peerings/results.go b/openstack/networking/v2/peerings/results.go new file mode 100644 index 000000000..54e61f4a0 --- /dev/null +++ b/openstack/networking/v2/peerings/results.go @@ -0,0 +1,144 @@ +package peerings + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +type VpcInfo struct { + VpcId string `json:"vpc_id" required:"true"` + TenantId string `json:"tenant_id,omitempty"` + +} + +// Peering represents a Neutron VPC peering connection. +//Manage and perform other operations on VPC peering connections, +// including querying VPC peering connections as well as +// creating, querying, deleting, and updating a VPC peering connection. +type Peering struct { + // ID is the unique identifier for the vpc_peering_connection. + ID string `json:"id"` + + // Name is the human readable name for the vpc_peering_connection. It does not have to be + // unique. + Name string `json:"name"` + + // Status indicates whether or not a vpc_peering_connections is currently operational. + Status string `json:"status"` + + // RequestVpcInfo indicates information about the local VPC + RequestVpcInfo VpcInfo `json:"request_vpc_info"` + + // AcceptVpcInfo indicates information about the peer VPC + AcceptVpcInfo VpcInfo `json:"accept_vpc_info"` +} + +// PeeringConnectionPage is the page returned by a pager when traversing over a +// collection of vpc_peering_connections. +type PeeringConnectionPage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of vpc_peering_connections has reached +// the end of a page and the pager seeks to traverse over a new one. In order +// to do this, it needs to construct the next page's URL. +func (r PeeringConnectionPage) NextPageURL() (string, error) { + var s struct { + Links []golangsdk.Link `json:"peerings_links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return golangsdk.ExtractNextURL(s.Links) +} + +// IsEmpty checks whether a PeeringConnectionPage struct is empty. +func (r PeeringConnectionPage) IsEmpty() (bool, error) { + is, err := ExtractPeerings(r) + return len(is) == 0, err +} + +// ExtractPeerings accepts a Page struct, specifically a PeeringConnectionPage struct, +// and extracts the elements into a slice of Peering structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractPeerings(r pagination.Page) ([]Peering, error) { + var s struct { + Peerings []Peering `json:"peerings"` + } + err := (r.(PeeringConnectionPage)).ExtractInto(&s) + return s.Peerings, err +} + +type commonResult struct { + golangsdk.Result +} + +// Extract is a function that accepts a result and extracts a Peering. +func (r commonResult) Extract() (*Peering, error) { + var s struct { + Peering *Peering `json:"peering"` + } + err := r.ExtractInto(&s) + return s.Peering, err +} + +// ExtractResult is a function that accepts a result and extracts a Peering. +func (r commonResult) ExtractResult() (Peering, error) { + var s struct { + // ID is the unique identifier for the vpc. + ID string `json:"id"` + // Name is the human readable name for the vpc. It does not have to be + // unique. + Name string `json:"name"` + + // Status indicates whether or not a vpc is currently operational. + Status string `json:"status"` + + // Status indicates whether or not a vpc is currently operational. + RequestVpcInfo VpcInfo `json:"request_vpc_info"` + + //Provides informaion about shared snat + AcceptVpcInfo VpcInfo `json:"accept_vpc_info"` + } + err1 := r.ExtractInto(&s) + return s, err1 +} + +// GetResult represents the result of a get operation. Call its Extract +// method to interpret it as a Vpc Peering Connection. +type GetResult struct { + commonResult +} + +// AcceptResult represents the result of a get operation. Call its Extract +// method to interpret it as a Vpc Peering Connection. +type AcceptResult struct { + commonResult +} + +// RejectResult represents the result of a get operation. Call its Extract +// method to interpret it as a Vpc Peering Connection. +type RejectResult struct { + commonResult +} + +// CreateResult represents the result of a create operation. Call its Extract +// method to interpret it as a vpc peering connection. +type CreateResult struct { + commonResult +} + +// UpdateResult represents the result of an update operation. Call its Extract +// method to interpret it as a vpc peering connection. +type UpdateResult struct { + commonResult +} + +// DeleteResult represents the result of a delete operation. Call its ExtractErr +// method to determine if the request succeeded or failed. +type DeleteResult struct { + golangsdk.ErrResult +} + + diff --git a/openstack/networking/v2/peerings/testing/doc.go b/openstack/networking/v2/peerings/testing/doc.go new file mode 100644 index 000000000..281471cca --- /dev/null +++ b/openstack/networking/v2/peerings/testing/doc.go @@ -0,0 +1,2 @@ +// peerings unit tests +package testing diff --git a/openstack/networking/v2/peerings/testing/requests_test.go b/openstack/networking/v2/peerings/testing/requests_test.go new file mode 100644 index 000000000..c3b5b1b62 --- /dev/null +++ b/openstack/networking/v2/peerings/testing/requests_test.go @@ -0,0 +1,311 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + fake "github.com/huaweicloud/golangsdk/openstack/networking/v2/common" + "github.com/huaweicloud/golangsdk/openstack/networking/v2/peerings" + th "github.com/huaweicloud/golangsdk/testhelper" +) + +func TestListVpcPeerings(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v2.0/vpc/peerings", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` +{ + "peerings": [ + { + "status": "PENDING_ACCEPTANCE", + "accept_vpc_info": { + "vpc_id": "c6efbdb7-dca4-4178-b3ec-692f125c1e25", + "tenant_id": "17fbda95add24720a4038ba4b1c705ed" + }, + "request_vpc_info": { + "vpc_id": "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e" + }, + "name": "test_peering", + "id": "22a3e5b1-1150-408e-99f7-5e25a391cead" + }, + { + "status": "ACTIVE", + "accept_vpc_info": { + "vpc_id": "93e94d8e-31a6-4c22-bdf7-8b23c7b67329", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e" + }, + "request_vpc_info": { + "vpc_id": "b0d686e5-312c-4279-b69c-eedbc779ae69", + "tenant_id": "bf74229f30c0421fae270386a43315ee" + }, + "name": "peering-7750-sunway", + "id": "283aabd7-dab4-409d-96ff-6c878b9a0219" + }, + { + "status": "ACTIVE", + "accept_vpc_info": { + "vpc_id": "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e" + }, + "request_vpc_info": { + "vpc_id": "4117d38e-4c8f-4624-a505-bd96b97d024c", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e" + }, + "name": "test", + "id": "71d64714-bd4e-44c4-917a-d8d1239e5292" + } + ] + } + `) + }) + + //count := 0 + actual , err := peerings.List(fake.ServiceClient(), peerings.ListOpts{}) + + if err != nil { + t.Errorf("Failed to extract vpc_peering_connections: %v", err) + } + + expected := []peerings.Peering{ + { + ID: "22a3e5b1-1150-408e-99f7-5e25a391cead", + Name: "test_peering", + Status: "PENDING_ACCEPTANCE", + RequestVpcInfo: peerings.VpcInfo{VpcId:"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, + AcceptVpcInfo: peerings.VpcInfo{VpcId:"c6efbdb7-dca4-4178-b3ec-692f125c1e25",TenantId:"17fbda95add24720a4038ba4b1c705ed"}, + }, + { + ID: "283aabd7-dab4-409d-96ff-6c878b9a0219", + Name: "peering-7750-sunway", + Status: "ACTIVE", + RequestVpcInfo: peerings.VpcInfo{VpcId:"b0d686e5-312c-4279-b69c-eedbc779ae69",TenantId:"bf74229f30c0421fae270386a43315ee"}, + AcceptVpcInfo: peerings.VpcInfo{VpcId:"93e94d8e-31a6-4c22-bdf7-8b23c7b67329",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, + }, + { + ID: "71d64714-bd4e-44c4-917a-d8d1239e5292", + Name: "test", + Status: "ACTIVE", + RequestVpcInfo: peerings.VpcInfo{VpcId:"4117d38e-4c8f-4624-a505-bd96b97d024c",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, + AcceptVpcInfo: peerings.VpcInfo{VpcId:"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, + }, + } + + th.AssertDeepEquals(t, expected, actual) +} + +func TestCreateVpcPeeringConnection(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v2.0/vpc/peerings", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "peering": { + "name": "test", + + "request_vpc_info": { + "vpc_id": "4117d38e-4c8f-4624-a505-bd96b97d024c" + }, + "accept_vpc_info": { + "vpc_id": "c6efbdb7-dca4-4178-b3ec-692f125c1e25", + "tenant_id": "17fbda95add24720a4038ba4b1c705ed" + } + } +} `) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + + fmt.Fprintf(w, ` +{ + "peering": { + "status": "PENDING_ACCEPTANCE", + "accept_vpc_info": { + "vpc_id": "c6efbdb7-dca4-4178-b3ec-692f125c1e25", + "tenant_id": "17fbda95add24720a4038ba4b1c705ed" + }, + "request_vpc_info": { + "vpc_id": "4117d38e-4c8f-4624-a505-bd96b97d024c", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e" + }, + "name": "test", + "id": "4e6ca99d-8344-4eb2-b2c9-b77368db3704" + } +} `) + }) + + options := peerings.CreateOpts{ + Name:"test", + RequestVpcInfo: peerings.VpcInfo{VpcId:"4117d38e-4c8f-4624-a505-bd96b97d024c"}, + AcceptVpcInfo: peerings.VpcInfo{VpcId:"c6efbdb7-dca4-4178-b3ec-692f125c1e25",TenantId:"17fbda95add24720a4038ba4b1c705ed"}, + } + n, err := peerings.Create(fake.ServiceClient(), options).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, "test", n.Name) + th.AssertEquals(t, "4e6ca99d-8344-4eb2-b2c9-b77368db3704", n.ID) + + th.AssertEquals(t, peerings.VpcInfo{VpcId:"4117d38e-4c8f-4624-a505-bd96b97d024c",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) + th.AssertEquals(t, peerings.VpcInfo{VpcId:"c6efbdb7-dca4-4178-b3ec-692f125c1e25",TenantId:"17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) + th.AssertEquals(t, "PENDING_ACCEPTANCE", n.Status) +} + +func TestUpdateVpcPeeringConnection(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v2.0/vpc/peerings/4e6ca99d-8344-4eb2-b2c9-b77368db3704", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "peering": { + "name": "test2" + } +}`) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` +{ + "peering": { + "status": "PENDING_ACCEPTANCE", + "accept_vpc_info": { + "vpc_id": "c6efbdb7-dca4-4178-b3ec-692f125c1e25", + "tenant_id": "17fbda95add24720a4038ba4b1c705ed" + }, + "request_vpc_info": { + "vpc_id": "4117d38e-4c8f-4624-a505-bd96b97d024c", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e" + }, + "name": "test2", + "id": "4e6ca99d-8344-4eb2-b2c9-b77368db3704" + } +} + `) + }) + + options := peerings.UpdateOpts{Name:"test2"} + + n, err := peerings.Update(fake.ServiceClient(), "4e6ca99d-8344-4eb2-b2c9-b77368db3704",options).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, "test2", n.Name) + th.AssertEquals(t, "4e6ca99d-8344-4eb2-b2c9-b77368db3704", n.ID) + th.AssertEquals(t, peerings.VpcInfo{VpcId:"4117d38e-4c8f-4624-a505-bd96b97d024c",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) + th.AssertEquals(t, peerings.VpcInfo{VpcId:"c6efbdb7-dca4-4178-b3ec-692f125c1e25",TenantId:"17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) + th.AssertEquals(t, "PENDING_ACCEPTANCE", n.Status) +} + +func TestDeleteVpcPeeringConnection(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v2.0/vpc/peerings/4e6ca99d-8344-4eb2-b2c9-b77368db3704", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + w.WriteHeader(http.StatusNoContent) + }) + + res := peerings.Delete(fake.ServiceClient(), "4e6ca99d-8344-4eb2-b2c9-b77368db3704") + th.AssertNoErr(t, res.Err) +} + + +func TestAcceptVpcPeering(t *testing.T) { + + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v2.0/vpc/peerings/22a3e5b1-1150-408e-99f7-5e25a391cead/accept", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Accept", "application/json") + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` { + "status": "ACTIVE", + "name": "test_peering", + "tenant_id": "17fbda95add24720a4038ba4b1c705ed", + "request_vpc_info": { + "vpc_id": "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e" + }, + "accept_vpc_info": { + "vpc_id": "c6efbdb7-dca4-4178-b3ec-692f125c1e25", + "tenant_id": "17fbda95add24720a4038ba4b1c705ed" + }, + "id": "22a3e5b1-1150-408e-99f7-5e25a391cead" + } + `) + }) + + + n, err := peerings.Accept(fake.ServiceClient(), "22a3e5b1-1150-408e-99f7-5e25a391cead",).ExtractResult() + th.AssertNoErr(t, err) + th.AssertEquals(t, "22a3e5b1-1150-408e-99f7-5e25a391cead", n.ID) + th.AssertEquals(t, "test_peering", n.Name) + th.AssertEquals(t, "ACTIVE", n.Status) + th.AssertDeepEquals(t, peerings.VpcInfo{"c6efbdb7-dca4-4178-b3ec-692f125c1e25","17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) + th.AssertDeepEquals(t, peerings.VpcInfo{"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf","87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) + +} + +func TestRejectVpcPeering(t *testing.T) { + + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v2.0/vpc/peerings/22a3e5b1-1150-408e-99f7-5e25a391cead/reject", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Accept", "application/json") + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` { + "status": "ACTIVE", + "name": "test_peering", + "tenant_id": "17fbda95add24720a4038ba4b1c705ed", + "request_vpc_info": { + "vpc_id": "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e" + }, + "accept_vpc_info": { + "vpc_id": "c6efbdb7-dca4-4178-b3ec-692f125c1e25", + "tenant_id": "17fbda95add24720a4038ba4b1c705ed" + }, + "id": "22a3e5b1-1150-408e-99f7-5e25a391cead" + } + `) + }) + + + n, err := peerings.Reject(fake.ServiceClient(), "22a3e5b1-1150-408e-99f7-5e25a391cead",).ExtractResult() + th.AssertNoErr(t, err) + th.AssertEquals(t, "22a3e5b1-1150-408e-99f7-5e25a391cead", n.ID) + th.AssertEquals(t, "test_peering", n.Name) + th.AssertEquals(t, "ACTIVE", n.Status) + th.AssertDeepEquals(t, peerings.VpcInfo{"c6efbdb7-dca4-4178-b3ec-692f125c1e25","17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) + th.AssertDeepEquals(t, peerings.VpcInfo{"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf","87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) + +} + + diff --git a/openstack/networking/v2/peerings/urls.go b/openstack/networking/v2/peerings/urls.go new file mode 100644 index 000000000..a513450a4 --- /dev/null +++ b/openstack/networking/v2/peerings/urls.go @@ -0,0 +1,24 @@ +package peerings + +import "github.com/huaweicloud/golangsdk" + +const ( + resourcePath = "peerings" + rootpath="vpc" +) + +func rootURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL(rootpath,resourcePath) +} + +func resourceURL(c *golangsdk.ServiceClient, id string) string { + return c.ServiceURL(rootpath,resourcePath, id) +} + +func acceptURL(c *golangsdk.ServiceClient, id string) string { + return c.ServiceURL( rootpath,resourcePath, id ,"accept") +} + +func rejectURL(c *golangsdk.ServiceClient, id string) string { + return c.ServiceURL( rootpath,resourcePath, id ,"reject") +} \ No newline at end of file From 54107b9f2fb4254f594604e6dcc8d6e7a4f65538 Mon Sep 17 00:00:00 2001 From: savasw Date: Tue, 27 Mar 2018 17:55:52 +0530 Subject: [PATCH 03/10] added subnet module and unit acceptance tests --- .../openstack/networking/v1/subnets/subnet.go | 86 ++++++ .../networking/v1/subnets/subnet_test.go | 50 ++++ openstack/networking/v1/subnets/doc.go | 57 ++++ openstack/networking/v1/subnets/requests.go | 218 ++++++++++++++ openstack/networking/v1/subnets/results.go | 118 ++++++++ .../networking/v1/subnets/testing/doc.go | 2 + .../v1/subnets/testing/requests_test.go | 270 ++++++++++++++++++ openstack/networking/v1/subnets/urls.go | 20 ++ 8 files changed, 821 insertions(+) create mode 100644 acceptance/openstack/networking/v1/subnets/subnet.go create mode 100644 acceptance/openstack/networking/v1/subnets/subnet_test.go create mode 100644 openstack/networking/v1/subnets/doc.go create mode 100644 openstack/networking/v1/subnets/requests.go create mode 100644 openstack/networking/v1/subnets/results.go create mode 100644 openstack/networking/v1/subnets/testing/doc.go create mode 100644 openstack/networking/v1/subnets/testing/requests_test.go create mode 100644 openstack/networking/v1/subnets/urls.go diff --git a/acceptance/openstack/networking/v1/subnets/subnet.go b/acceptance/openstack/networking/v1/subnets/subnet.go new file mode 100644 index 000000000..970f2d88c --- /dev/null +++ b/acceptance/openstack/networking/v1/subnets/subnet.go @@ -0,0 +1,86 @@ +package v1 + +import ( + "testing" + + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/acceptance/tools" + "github.com/huaweicloud/golangsdk/openstack/networking/v1/subnets" + "github.com/huaweicloud/golangsdk/openstack/networking/v1/vpcs" +) + +func CreateSubnetNResources(t *testing.T, client *golangsdk.ServiceClient) (*subnets.Subnet, error) { + + vpcName := tools.RandomString("TESTACC-", 8) + + createOpts := vpcs.CreateOpts{ + Name: vpcName, + CIDR: "192.168.20.0/24", + } + + t.Logf("Attempting to create vpc: %s", vpcName) + + vpc, err := vpcs.Create(client, createOpts).Extract() + if err != nil { + return nil, err + } + t.Logf("Created vpc: %s", vpcName) + + subnetName := tools.RandomString("ACPTTEST-", 8) + + createSubnetOpts := subnets.CreateOpts{ + Name: subnetName, + CIDR: "192.168.20.0/24", + GatewayIP: "192.168.20.1", + EnableDHCP: true, + AvailabilityZone: "eu-de-02", + VPC_ID: vpc.ID, + } + + t.Logf("Attempting to create subnet: %s", subnetName) + + subnet, err := subnets.Create(client, createSubnetOpts).Extract() + if err != nil { + return subnet, err + } + t.Logf("Created subnet: %s", subnet) + + return subnet, nil +} + +func DeleteSubnetNResources(t *testing.T, client *golangsdk.ServiceClient, vpcID string, id string) { + t.Logf("Attempting to delete subnet: %s", id) + + err := subnets.Delete(client, vpcID, id).ExtractErr() + if err != nil { + t.Fatalf("Error deleting subnet: %v", err) + } + + t.Logf("Deleted subnet: %s", id) + + if err := WaitForSubnetToDelete(client, id, 60); err != nil { + t.Fatalf("Error deleting subnet: %v", err) + } + + t.Logf("Attempting to delete vpc: %s", vpcID) + + err = vpcs.Delete(client, vpcID).ExtractErr() + if err != nil { + t.Fatalf("Error deleting vpc: %v", err) + } + + t.Logf("Deleted vpc: %s", vpcID) +} + +func WaitForSubnetToDelete(client *golangsdk.ServiceClient, subnetID string, secs int) error { + return golangsdk.WaitFor(secs, func() (bool, error) { + _, err := subnets.Get(client, subnetID).Extract() + if err != nil { + if _, ok := err.(golangsdk.ErrDefault404); ok { + return true, nil + } + } + + return false, nil + }) +} diff --git a/acceptance/openstack/networking/v1/subnets/subnet_test.go b/acceptance/openstack/networking/v1/subnets/subnet_test.go new file mode 100644 index 000000000..4a32c47da --- /dev/null +++ b/acceptance/openstack/networking/v1/subnets/subnet_test.go @@ -0,0 +1,50 @@ +package v1 + +import ( + "github.com/huaweicloud/golangsdk/acceptance/clients" + "github.com/huaweicloud/golangsdk/acceptance/tools" + "github.com/huaweicloud/golangsdk/openstack/networking/v1/subnets" + "testing" +) + +func TestSubnetList(t *testing.T) { + client, err := clients.NewNetworkV1Client() + if err != nil { + t.Fatalf("Unable to create a subnet : %v", err) + } + allPages, err := subnets.List(client, subnets.ListOpts{}) + tools.PrintResource(t, allPages) + +} + +func TestSubnetsCRUD(t *testing.T) { + client, err := clients.NewNetworkV1Client() + if err != nil { + t.Fatalf("Unable to create a subnet : %v", err) + } + + // Create a subnet + subnet, err := CreateSubnetNResources(t, client) + if err != nil { + t.Fatalf("Unable to create subnet: %v", err) + } + + // Delete a subnet + defer DeleteSubnetNResources(t, client, subnet.VPC_ID, subnet.ID) + tools.PrintResource(t, subnet) + + // Update a subnet + newName := tools.RandomString("ACPTTEST-", 8) + updateOpts := &subnets.UpdateOpts{ + Name: newName, + } + _, err = subnets.Update(client, subnet.VPC_ID, subnet.ID, updateOpts).Extract() + + // Query a subnet + newSubnet, err := subnets.Get(client, subnet.ID).Extract() + if err != nil { + t.Fatalf("Unable to retrieve subnet: %v", err) + } + + tools.PrintResource(t, newSubnet) +} diff --git a/openstack/networking/v1/subnets/doc.go b/openstack/networking/v1/subnets/doc.go new file mode 100644 index 000000000..a4164b30e --- /dev/null +++ b/openstack/networking/v1/subnets/doc.go @@ -0,0 +1,57 @@ +/* +Package Subnets enables management and retrieval of Subnets from the Open Telekom Cloud VPC service. + +Example to List Vpcs + + listOpts := subnets.ListOpts{} + allSubnets, err := subnets.List(subnetClient, listOpts) + if err != nil { + panic(err) + } + + for _, subnet := range allSubnets { + fmt.Printf("%+v\n", subnet) + } + +Example to Create a Vpc + + createOpts := subnets.CreateOpts{ + Name: "test_subnets", + CIDR: "192.168.0.0/16" + GatewayIP: "192.168.0.1" + PRIMARY_DNS: "8.8.8.8" + SECONDARY_DNS: "8.8.4.4" + AvailabilityZone:"eu-de-02" + VPC_ID:"3b9740a0-b44d-48f0-84ee-42eb166e54f7" + + } + vpc, err := subnets.Create(subnetClient, createOpts).Extract() + + if err != nil { + panic(err) + } + +Example to Update a Vpc + + subnetID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + + updateOpts := subnets.UpdateOpts{ + Name: "testsubnet", + } + + subnet, err := subnets.Update(subnetClient, subnetID, updateOpts).Extract() + if err != nil { + panic(err) + } + +Example to Delete a Vpc + + subnetID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + + err := subnets.Delete(subnetClient, subnetID).ExtractErr() + + if err != nil { + panic(err) + } +*/ +package subnets diff --git a/openstack/networking/v1/subnets/requests.go b/openstack/networking/v1/subnets/requests.go new file mode 100644 index 000000000..4df6b6311 --- /dev/null +++ b/openstack/networking/v1/subnets/requests.go @@ -0,0 +1,218 @@ +package subnets + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" + + "reflect" +) + +// ListOpts allows the filtering and sorting of paginated collections through +// the API. Filtering is achieved by passing in struct field values that map to +// the floating IP attributes you want to see returned. SortKey allows you to +// sort by a particular network attribute. SortDir sets the direction, and is +// either `asc' or `desc'. Marker and Limit are used for pagination. + +type ListOpts struct { + // ID is the unique identifier for the subnet. + ID string `json:"id"` + + // Name is the human readable name for the subnet. It does not have to be + // unique. + Name string `json:"name"` + + //Specifies the network segment on which the subnet resides. + CIDR string `json:"cidr"` + + //Specifies the IP address list of DNS servers on the subnet. + DnsList []string `json:"dnsList"` + + // Status indicates whether or not a subnet is currently operational. + Status string `json:"status"` + + //Specifies the gateway of the subnet. + GatewayIP string `json:"gateway_ip"` + + //Specifies whether the DHCP function is enabled for the subnet. + EnableDHCP bool `json:"dhcp_enable"` + + //Specifies the IP address of DNS server 1 on the subnet. + PRIMARY_DNS string `json:"primary_dns"` + + //Specifies the IP address of DNS server 2 on the subnet. + SECONDARY_DNS string `json:"secondary_dns"` + + //Identifies the availability zone (AZ) to which the subnet belongs. + AvailabilityZone string `json:"availability_zone"` + + //Specifies the ID of the VPC to which the subnet belongs. + VPC_ID string `json:"vpc_id"` +} + +// List returns collection of +// subnets. It accepts a ListOpts struct, which allows you to filter and sort +// the returned collection for greater efficiency. +// +// Default policy settings return only those subnets that are owned by the +// tenant who submits the request, unless an admin user submits the request. + +func List(c *golangsdk.ServiceClient, opts ListOpts) ([]Subnet, error) { + u := rootURL(c) + pages, err := pagination.NewPager(c, u, func(r pagination.PageResult) pagination.Page { + return SubnetPage{pagination.LinkedPageBase{PageResult: r}} + }).AllPages() + + allSubnets, err := ExtractSubnets(pages) + if err != nil { + return nil, err + } + + return FilterSubnets(allSubnets, opts) +} + +func FilterSubnets(subnets []Subnet, opts ListOpts) ([]Subnet, error) { + + var refinedSubnets []Subnet + var matched bool + m := map[string]interface{}{} + + if opts.ID != "" { + m["ID"] = opts.ID + } + if opts.Name != "" { + m["Name"] = opts.Name + } + if opts.CIDR != "" { + m["CIDR"] = opts.CIDR + } + if opts.Status != "" { + m["Status"] = opts.Status + } + if opts.GatewayIP != "" { + m["GatewayIP"] = opts.GatewayIP + } + if opts.PRIMARY_DNS != "" { + m["PRIMARY_DNS"] = opts.PRIMARY_DNS + } + if opts.SECONDARY_DNS != "" { + m["SECONDARY_DNS"] = opts.SECONDARY_DNS + } + if opts.AvailabilityZone != "" { + m["AvailabilityZone"] = opts.AvailabilityZone + } + if opts.VPC_ID != "" { + m["VPC_ID"] = opts.VPC_ID + } + + if len(m) > 0 && len(subnets) > 0 { + for _, subnet := range subnets { + matched = true + + for key, value := range m { + if sVal := getStructField(&subnet, key); !(sVal == value) { + matched = false + } + } + + if matched { + refinedSubnets = append(refinedSubnets, subnet) + } + } + + } else { + refinedSubnets = subnets + } + + return refinedSubnets, nil +} + +func getStructField(v *Subnet, field string) string { + r := reflect.ValueOf(v) + f := reflect.Indirect(r).FieldByName(field) + return string(f.String()) +} + +// CreateOptsBuilder allows extensions to add additional parameters to the +// Create request. +type CreateOptsBuilder interface { + ToSubnetCreateMap() (map[string]interface{}, error) +} + +// CreateOpts contains all the values needed to create a new subnets. There are +// no required values. +type CreateOpts struct { + Name string `json:"name" required:"true"` + CIDR string `json:"cidr" required:"true"` + GatewayIP string `json:"gateway_ip" required:"true"` + EnableDHCP bool `json:"dhcp_enable,omitempty"` + PRIMARY_DNS string `json:"primary_dns,omitempty"` + SECONDARY_DNS string `json:"secondary_dns,omitempty"` + AvailabilityZone string `json:"availability_zone"` + VPC_ID string `json:"vpc_id" required:"true"` +} + +// ToSubnetCreateMap builds a create request body from CreateOpts. +func (opts CreateOpts) ToSubnetCreateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "subnet") +} + +// Create accepts a CreateOpts struct and uses the values to create a new +// logical subnets. When it is created, the subnets does not have an internal +// interface - it is not associated to any subnet. +// +func Create(c *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToSubnetCreateMap() + if err != nil { + r.Err = err + return + } + reqOpt := &golangsdk.RequestOpts{OkCodes: []int{200}} + _, r.Err = c.Post(rootURL(c), b, &r.Body, reqOpt) + return +} + +// Get retrieves a particular subnets based on its unique ID. +func Get(c *golangsdk.ServiceClient, id string) (r GetResult) { + _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) + return +} + +// UpdateOptsBuilder allows extensions to add additional parameters to the +// Update request. +type UpdateOptsBuilder interface { + //ToSubnetUpdateMap() (map[string]interface{}, error) + ToSubnetUpdateMap() (map[string]interface{}, error) +} + +// UpdateOpts contains the values used when updating a subnets. +type UpdateOpts struct { + Name string `json:"name,omitempty"` + EnableDHCP bool `json:"dhcp_enable,omitempty"` + PRIMARY_DNS string `json:"primary_dns,omitempty"` + SECONDARY_DNS string `json:"secondary_dns,omitempty"` +} + +// ToSubnetUpdateMap builds an update body based on UpdateOpts. +func (opts UpdateOpts) ToSubnetUpdateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "subnet") +} + +// Update allows subnets to be updated. You can update the name, administrative +// state, and the external gateway. +func Update(c *golangsdk.ServiceClient, vpcid string, id string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToSubnetUpdateMap() + if err != nil { + r.Err = err + return + } + _, r.Err = c.Put(updateURL(c, vpcid, id), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{200}, + }) + return +} + +// Delete will permanently delete a particular subnets based on its unique ID. +func Delete(c *golangsdk.ServiceClient, vpcid string, id string) (r DeleteResult) { + _, r.Err = c.Delete(updateURL(c, vpcid, id), nil) + return +} diff --git a/openstack/networking/v1/subnets/results.go b/openstack/networking/v1/subnets/results.go new file mode 100644 index 000000000..68f7ba797 --- /dev/null +++ b/openstack/networking/v1/subnets/results.go @@ -0,0 +1,118 @@ +package subnets + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +type Subnet struct { + // ID is the unique identifier for the subnet. + ID string `json:"id"` + + // Name is the human readable name for the subnet. It does not have to be + // unique. + Name string `json:"name"` + + //Specifies the network segment on which the subnet resides. + CIDR string `json:"cidr"` + + //Specifies the IP address list of DNS servers on the subnet. + DnsList []string `json:"dnsList"` + + // Status indicates whether or not a subnet is currently operational. + Status string `json:"status"` + + //Specifies the gateway of the subnet. + GatewayIP string `json:"gateway_ip"` + + //Specifies whether the DHCP function is enabled for the subnet. + EnableDHCP bool `json:"dhcp_enable"` + + //Specifies the IP address of DNS server 1 on the subnet. + PRIMARY_DNS string `json:"primary_dns"` + + //Specifies the IP address of DNS server 2 on the subnet. + SECONDARY_DNS string `json:"secondary_dns"` + + //Identifies the availability zone (AZ) to which the subnet belongs. + AvailabilityZone string `json:"availability_zone"` + + //Specifies the ID of the VPC to which the subnet belongs. + VPC_ID string `json:"vpc_id"` + +} + +// SubnetPage is the page returned by a pager when traversing over a +// collection of subnets. +type SubnetPage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of subnets has reached +// the end of a page and the pager seeks to traverse over a new one. In order +// to do this, it needs to construct the next page's URL. +func (r SubnetPage) NextPageURL() (string, error) { + var s struct { + Links []golangsdk.Link `json:"subnets_links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return golangsdk.ExtractNextURL(s.Links) +} + +// IsEmpty checks whether a SubnetPage struct is empty. +func (r SubnetPage) IsEmpty() (bool, error) { + is, err := ExtractSubnets(r) + return len(is) == 0, err +} + +// ExtractSubnets accepts a Page struct, specifically a SubnetPage struct, +// and extracts the elements into a slice of Subnet structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractSubnets(r pagination.Page) ([]Subnet, error) { + var s struct { + Subnets []Subnet `json:"subnets"` + } + err := (r.(SubnetPage)).ExtractInto(&s) + return s.Subnets, err +} + +type commonResult struct { + golangsdk.Result +} + +// Extract is a function that accepts a result and extracts a Subnet. +func (r commonResult) Extract() (*Subnet, error) { + var s struct { + Subnet *Subnet `json:"subnet"` + } + err := r.ExtractInto(&s) + return s.Subnet, err +} + +// CreateResult represents the result of a create operation. Call its Extract +// method to interpret it as a Subnet. +type CreateResult struct { + commonResult +} + +// GetResult represents the result of a get operation. Call its Extract +// method to interpret it as a Subnet. +type GetResult struct { + commonResult +} + +// UpdateResult represents the result of an update operation. Call its Extract +// method to interpret it as a Subnet. +type UpdateResult struct { + commonResult +} + +// DeleteResult represents the result of a delete operation. Call its ExtractErr +// method to determine if the request succeeded or failed. +type DeleteResult struct { + golangsdk.ErrResult +} + diff --git a/openstack/networking/v1/subnets/testing/doc.go b/openstack/networking/v1/subnets/testing/doc.go new file mode 100644 index 000000000..77f41573c --- /dev/null +++ b/openstack/networking/v1/subnets/testing/doc.go @@ -0,0 +1,2 @@ +// vpcs unit tests +package testing diff --git a/openstack/networking/v1/subnets/testing/requests_test.go b/openstack/networking/v1/subnets/testing/requests_test.go new file mode 100644 index 000000000..cc2e528db --- /dev/null +++ b/openstack/networking/v1/subnets/testing/requests_test.go @@ -0,0 +1,270 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + fake "github.com/huaweicloud/golangsdk/openstack/networking/v1/common" + "github.com/huaweicloud/golangsdk/openstack/networking/v1/subnets" + th "github.com/huaweicloud/golangsdk/testhelper" +) + + +func TestListSubnet(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v1/85636478b0bd8e67e89469c7749d4127/subnets", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` +{ + "subnets": [ + { + "id": "134ca339-24dc-44f5-ae6a-cf0404216ed2", + "name": "openlab-subnet", + "cidr": "192.168.200.0/24", + "status": "ACTIVE", + "vpc_id": "58c24204-170e-4ff0-9b42-c53cdea9239a", + "gateway_ip": "192.168.200.1", + "dhcp_enable": true + }, + { + "id": "134ca339-24dc-44f5-ae6a-cf0404216ed2", + "name": "openlab-subnet", + "cidr": "192.168.200.0/24", + "status": "ACTIVE", + "vpc_id": "58c24204-170e-4ff0-9b42-c53cdea9239a", + "gateway_ip": "192.168.200.1", + "dhcp_enable": true + } + ] +} + + `) + }) + + actual, err := subnets.List(fake.ServiceClient(), subnets.ListOpts{}) + if err != nil { + t.Errorf("Failed to extract subnets: %v", err) + } + + expected := []subnets.Subnet{ + { + Status: "ACTIVE", + CIDR: "192.168.200.0/24", + EnableDHCP: true, + Name: "openlab-subnet", + //DnsList: []string{}, + ID: "134ca339-24dc-44f5-ae6a-cf0404216ed2", + GatewayIP: "192.168.200.1", + VPC_ID: "58c24204-170e-4ff0-9b42-c53cdea9239a", + }, + { + Status: "ACTIVE", + CIDR: "192.168.200.0/24", + EnableDHCP: true, + Name: "openlab-subnet", + //DnsList: []string{}, + ID: "134ca339-24dc-44f5-ae6a-cf0404216ed2", + GatewayIP: "192.168.200.1", + VPC_ID: "58c24204-170e-4ff0-9b42-c53cdea9239a", + }, + /*{ + Status: "ACTIVE", + DnsList: []string{"100.125.4.25", "8.8.8.8"}, + VPC_ID: "e8fab5a4-61d3-4e84-85fd-0049676f926a", + GatewayIP: "192.168.106.1", + PRIMARY_DNS: "100.125.4.25", + SECONDARY_DNS: "8.8.8.8", + CIDR: "192.168.106.0/24", + EnableDHCP: true, + Name: "subnet-a0c9", + ID: "470ef214-acbe-4134-9fbf-1b20f4b8f28d", + },*/ +} + th.AssertDeepEquals(t, expected, actual) +} + + + + + +func TestGetSubnet(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v1/85636478b0bd8e67e89469c7749d4127/subnets/aab2f0ef-b08b-4f34-9e1a-9f1d8da1afcb", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.Header().Add("Content-Type", "application/json") + + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` +{ + "subnet": { + "id": "aab2f0ef-b08b-4f34-9e1a-9f1d8da1afcb", + "name": "subnet-mgmt", + "cidr": "10.0.0.0/24", + "dnsList": [ + "100.125.4.25", + "8.8.8.8" + ], + "status": "ACTIVE", + "vpc_id": "d4f2c817-d5df-4a66-994a-6571312b470e", + "gateway_ip": "10.0.0.1", + "dhcp_enable": true, + "primary_dns": "100.125.4.25", + "secondary_dns": "8.8.8.8" + } +} + `) + }) + + n, err := subnets.Get(fake.ServiceClient(), "aab2f0ef-b08b-4f34-9e1a-9f1d8da1afcb").Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, "aab2f0ef-b08b-4f34-9e1a-9f1d8da1afcb", n.ID) + th.AssertEquals(t, "subnet-mgmt", n.Name) + th.AssertEquals(t, "10.0.0.0/24", n.CIDR) + th.AssertEquals(t, "ACTIVE", n.Status) + th.AssertEquals(t, "d4f2c817-d5df-4a66-994a-6571312b470e", n.VPC_ID) + th.AssertEquals(t, "10.0.0.1", n.GatewayIP) + th.AssertEquals(t, "100.125.4.25", n.PRIMARY_DNS) + th.AssertEquals(t, "8.8.8.8", n.SECONDARY_DNS) + th.AssertEquals(t, true, n.EnableDHCP) + +} + +func TestCreateSubnet(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v1/85636478b0bd8e67e89469c7749d4127/subnets", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "subnet": + { + "name": "test_subnets", + "cidr": "192.168.0.0/16", + "gateway_ip": "192.168.0.1", + "primary_dns": "8.8.8.8", + "secondary_dns": "8.8.4.4", + "availability_zone":"eu-de-02", + "vpc_id":"3b9740a0-b44d-48f0-84ee-42eb166e54f7" + } +} + `) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` +{ + "subnet": { + "id": "6b0cf733-f496-4159-9df1-d74c3584a9f7", + "name": "test_subnets", + "cidr": "192.168.0.0/16", + "dnsList": [ + "8.8.8.8", + "8.8.4.4" + ], + "status": "UNKNOWN", + "vpc_id": "3b9740a0-b44d-48f0-84ee-42eb166e54f7", + "gateway_ip": "192.168.0.1", + "dhcp_enable": true, + "primary_dns": "8.8.8.8", + "secondary_dns": "8.8.4.4", + "availability_zone": "eu-de-02" + } +} `) + }) + + options := subnets.CreateOpts{ + Name: "test_subnets", + CIDR: "192.168.0.0/16", + GatewayIP: "192.168.0.1", + PRIMARY_DNS: "8.8.8.8", + SECONDARY_DNS: "8.8.4.4", + AvailabilityZone: "eu-de-02", + VPC_ID: "3b9740a0-b44d-48f0-84ee-42eb166e54f7", + } + n, err := subnets.Create(fake.ServiceClient(), options).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, "test_subnets", n.Name) + th.AssertEquals(t, "192.168.0.1", n.GatewayIP) + th.AssertEquals(t, "192.168.0.0/16", n.CIDR) + th.AssertEquals(t, true, n.EnableDHCP) + th.AssertEquals(t, "8.8.8.8", n.PRIMARY_DNS) + th.AssertEquals(t, "8.8.4.4", n.SECONDARY_DNS) + th.AssertEquals(t, "eu-de-02", n.AvailabilityZone) + th.AssertEquals(t, "6b0cf733-f496-4159-9df1-d74c3584a9f7", n.ID) + th.AssertEquals(t, "UNKNOWN", n.Status) + th.AssertEquals(t, "3b9740a0-b44d-48f0-84ee-42eb166e54f7", n.VPC_ID) + +} + +func TestUpdateSubnet(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v1/85636478b0bd8e67e89469c7749d4127/vpcs/8f794f06-2275-4d82-9f5a-6d68fbe21a75/subnets/83e3bddc-b9ed-4614-a0dc-8a997095a86c", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ +"subnet": + { + "name": "testsubnet" + } +} +`) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` +{ + "subnet": { + "id": "83e3bddc-b9ed-4614-a0dc-8a997095a86c", + "name": "testsubnet", + "status": "ACTIVE" + } +} + `) + }) + + options := subnets.UpdateOpts{Name: "testsubnet"} + + n, err := subnets.Update(fake.ServiceClient(), "8f794f06-2275-4d82-9f5a-6d68fbe21a75","83e3bddc-b9ed-4614-a0dc-8a997095a86c", options).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, "testsubnet", n.Name) + th.AssertEquals(t, "83e3bddc-b9ed-4614-a0dc-8a997095a86c", n.ID) + th.AssertEquals(t, "ACTIVE", n.Status) +} + +func TestDeleteSubnet(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v1/85636478b0bd8e67e89469c7749d4127/vpcs/8f794f06-2275-4d82-9f5a-6d68fbe21a75/subnets/83e3bddc-b9ed-4614-a0dc-8a997095a86c", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + w.WriteHeader(http.StatusNoContent) + }) + + res := subnets.Delete(fake.ServiceClient(), "8f794f06-2275-4d82-9f5a-6d68fbe21a75","83e3bddc-b9ed-4614-a0dc-8a997095a86c") + th.AssertNoErr(t, res.Err) +} \ No newline at end of file diff --git a/openstack/networking/v1/subnets/urls.go b/openstack/networking/v1/subnets/urls.go new file mode 100644 index 000000000..14582c4b0 --- /dev/null +++ b/openstack/networking/v1/subnets/urls.go @@ -0,0 +1,20 @@ +package subnets + +import "github.com/huaweicloud/golangsdk" + +const ( + resourcePath = "subnets" + rootpath = "vpcs" +) + +func rootURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL(c.ProjectID,resourcePath) +} + +func resourceURL(c *golangsdk.ServiceClient, id string) string { + return c.ServiceURL(c.ProjectID,resourcePath, id) +} + +func updateURL(c *golangsdk.ServiceClient, vpcid, id string) string { + return c.ServiceURL(c.ProjectID,rootpath, vpcid, resourcePath, id) +} \ No newline at end of file From d07b10256181344c396c39bee2af307f4441b008 Mon Sep 17 00:00:00 2001 From: savasw Date: Wed, 28 Mar 2018 11:48:04 +0530 Subject: [PATCH 04/10] updated package name --- acceptance/openstack/networking/v1/subnets/subnet.go | 2 +- acceptance/openstack/networking/v1/subnets/subnet_test.go | 2 +- .../networking/v2/{peerings => peering}/peerings.go | 4 ++-- .../networking/v2/{peerings => peering}/peerings_test.go | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) rename acceptance/openstack/networking/v2/{peerings => peering}/peerings.go (98%) rename acceptance/openstack/networking/v2/{peerings => peering}/peerings_test.go (94%) diff --git a/acceptance/openstack/networking/v1/subnets/subnet.go b/acceptance/openstack/networking/v1/subnets/subnet.go index 970f2d88c..d8ddd8d70 100644 --- a/acceptance/openstack/networking/v1/subnets/subnet.go +++ b/acceptance/openstack/networking/v1/subnets/subnet.go @@ -1,4 +1,4 @@ -package v1 +package subnets import ( "testing" diff --git a/acceptance/openstack/networking/v1/subnets/subnet_test.go b/acceptance/openstack/networking/v1/subnets/subnet_test.go index 4a32c47da..c9ae560d6 100644 --- a/acceptance/openstack/networking/v1/subnets/subnet_test.go +++ b/acceptance/openstack/networking/v1/subnets/subnet_test.go @@ -1,4 +1,4 @@ -package v1 +package subnets import ( "github.com/huaweicloud/golangsdk/acceptance/clients" diff --git a/acceptance/openstack/networking/v2/peerings/peerings.go b/acceptance/openstack/networking/v2/peering/peerings.go similarity index 98% rename from acceptance/openstack/networking/v2/peerings/peerings.go rename to acceptance/openstack/networking/v2/peering/peerings.go index efd615919..8dfde14c6 100644 --- a/acceptance/openstack/networking/v2/peerings/peerings.go +++ b/acceptance/openstack/networking/v2/peering/peerings.go @@ -1,4 +1,4 @@ -package v2 +package peering import ( "github.com/huaweicloud/golangsdk" @@ -84,7 +84,7 @@ func DeletePeeringConnNResources(t *testing.T, clientV2 *golangsdk.ServiceClient t.Logf("Deleted vpcs: %s and %s", peeringConn.RequestVpcInfo.VpcId, peeringConn.AcceptVpcInfo.VpcId) } -func initiatePeeringConnCommonTasks(t *testing.T) (*golangsdk.ServiceClient, *golangsdk.ServiceClient, +func InitiatePeeringConnCommonTasks(t *testing.T) (*golangsdk.ServiceClient, *golangsdk.ServiceClient, *golangsdk.ServiceClient, *golangsdk.ServiceClient, *peerings.Peering) { clientV2, err := clients.NewNetworkV2Client() diff --git a/acceptance/openstack/networking/v2/peerings/peerings_test.go b/acceptance/openstack/networking/v2/peering/peerings_test.go similarity index 94% rename from acceptance/openstack/networking/v2/peerings/peerings_test.go rename to acceptance/openstack/networking/v2/peering/peerings_test.go index e9820979e..6bce3a041 100644 --- a/acceptance/openstack/networking/v2/peerings/peerings_test.go +++ b/acceptance/openstack/networking/v2/peering/peerings_test.go @@ -1,4 +1,4 @@ -package v2 +package peering import ( "github.com/huaweicloud/golangsdk/acceptance/clients" @@ -25,7 +25,7 @@ func TestPeeringList(t *testing.T) { func TestAcceptPeering(t *testing.T) { - clientV2, peerClientV2, clientV1, peerClientV1, peeringConn := initiatePeeringConnCommonTasks(t) + clientV2, peerClientV2, clientV1, peerClientV1, peeringConn := InitiatePeeringConnCommonTasks(t) // Delete a vpc peering connection defer DeletePeeringConnNResources(t, clientV2, clientV1, peerClientV1, peeringConn) @@ -40,7 +40,7 @@ func TestAcceptPeering(t *testing.T) { func TestRejectPeering(t *testing.T) { - clientV2, peerClientV2, clientV1, peerClientV1, peeringConn := initiatePeeringConnCommonTasks(t) + clientV2, peerClientV2, clientV1, peerClientV1, peeringConn := InitiatePeeringConnCommonTasks(t) // Delete a vpc peering connection defer DeletePeeringConnNResources(t, clientV2, clientV1, peerClientV1, peeringConn) @@ -55,7 +55,7 @@ func TestRejectPeering(t *testing.T) { func TestPeeringCRUD(t *testing.T) { - clientV2, peerClientV2, clientV1, peerClientV1, peeringConn := initiatePeeringConnCommonTasks(t) + clientV2, peerClientV2, clientV1, peerClientV1, peeringConn := InitiatePeeringConnCommonTasks(t) // Delete a vpc peering connection defer DeletePeeringConnNResources(t, clientV2, clientV1, peerClientV1, peeringConn) From 8856e748de2f9a9b63e78b0038bbfbd1d8241968 Mon Sep 17 00:00:00 2001 From: savasw Date: Wed, 28 Mar 2018 11:48:27 +0530 Subject: [PATCH 05/10] added route module and unit acceptance tests --- .../openstack/networking/v2/routes/route.go | 39 ++++ .../networking/v2/routes/route_test.go | 61 ++++++ openstack/networking/v2/routes/doc.go | 28 +++ openstack/networking/v2/routes/requests.go | 108 ++++++++++ openstack/networking/v2/routes/results.go | 94 +++++++++ openstack/networking/v2/routes/testing/doc.go | 1 + .../v2/routes/testing/requests_test.go | 194 ++++++++++++++++++ openstack/networking/v2/routes/urls.go | 18 ++ 8 files changed, 543 insertions(+) create mode 100644 acceptance/openstack/networking/v2/routes/route.go create mode 100644 acceptance/openstack/networking/v2/routes/route_test.go create mode 100644 openstack/networking/v2/routes/doc.go create mode 100644 openstack/networking/v2/routes/requests.go create mode 100644 openstack/networking/v2/routes/results.go create mode 100644 openstack/networking/v2/routes/testing/doc.go create mode 100644 openstack/networking/v2/routes/testing/requests_test.go create mode 100644 openstack/networking/v2/routes/urls.go diff --git a/acceptance/openstack/networking/v2/routes/route.go b/acceptance/openstack/networking/v2/routes/route.go new file mode 100644 index 000000000..888457656 --- /dev/null +++ b/acceptance/openstack/networking/v2/routes/route.go @@ -0,0 +1,39 @@ +package routes + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/openstack/networking/v2/peerings" + "github.com/huaweicloud/golangsdk/openstack/networking/v2/routes" + "testing" +) + +func CreateRoute(t *testing.T, clientV2 *golangsdk.ServiceClient, peeringConn *peerings.Peering) (*routes.Route, error) { + + createRouteOpts := routes.CreateOpts{ + NextHop: peeringConn.ID, + Destination: "192.168.0.0/16", + VPC_ID: peeringConn.RequestVpcInfo.VpcId, + Type: "peering", + } + + t.Logf("Attempting to create route") + + route, err := routes.Create(clientV2, createRouteOpts).Extract() + if err != nil { + return route, err + } + t.Logf("Created route: %s", route) + + return route, nil +} + +func DeleteRoute(t *testing.T, clientV2 *golangsdk.ServiceClient, routeID string) { + t.Logf("Attempting to delete route: %s", routeID) + + err := routes.Delete(clientV2, routeID).ExtractErr() + if err != nil { + t.Fatalf("Error deleting route: %v", err) + } + + t.Logf("Deleted route: %s", routeID) +} diff --git a/acceptance/openstack/networking/v2/routes/route_test.go b/acceptance/openstack/networking/v2/routes/route_test.go new file mode 100644 index 000000000..64b7619e5 --- /dev/null +++ b/acceptance/openstack/networking/v2/routes/route_test.go @@ -0,0 +1,61 @@ +package routes + +import ( + "github.com/huaweicloud/golangsdk/acceptance/clients" + "github.com/huaweicloud/golangsdk/acceptance/openstack/networking/v2/peering" + "github.com/huaweicloud/golangsdk/acceptance/tools" + "github.com/huaweicloud/golangsdk/openstack/networking/v2/peerings" + "github.com/huaweicloud/golangsdk/openstack/networking/v2/routes" + "testing" +) + +func TestRouteList(t *testing.T) { + client, err := clients.NewNetworkV2Client() + if err != nil { + t.Fatalf("Unable to create a route client: %v", err) + } + + listOpts := routes.ListOpts{} + pages, err := routes.List(client, listOpts).AllPages() + if err != nil { + t.Fatalf("Unable to list routers: %v", err) + } + + allRoutes, err := routes.ExtractRoutes(pages) + if err != nil { + t.Errorf("Failed to extract routes: %v", err) + } + + for _, router := range allRoutes { + tools.PrintResource(t, router) + } +} + +func TestRoutesCRUD(t *testing.T) { + + clientV2, peerClientV2, clientV1, peerClientV1, peeringConn := peering.InitiatePeeringConnCommonTasks(t) + + _, err := peerings.Accept(peerClientV2, peeringConn.ID).ExtractResult() + if err != nil { + t.Fatalf("Unable to accept peering request: %v", err) + } + + // Create a Route + route, err := CreateRoute(t, clientV2, peeringConn) + + if err != nil { + t.Fatalf("Unable to create route: %v", err) + } + + defer peering.DeletePeeringConnNResources(t, clientV2, clientV1, peerClientV1, peeringConn) + defer DeleteRoute(t, clientV2, route.RouteID) + + tools.PrintResource(t, route) + + newRoute, err := routes.Get(clientV2, route.RouteID).Extract() + if err != nil { + t.Fatalf("Unable to retrieve route: %v", err) + } + + tools.PrintResource(t, newRoute) +} diff --git a/openstack/networking/v2/routes/doc.go b/openstack/networking/v2/routes/doc.go new file mode 100644 index 000000000..a4dad0f55 --- /dev/null +++ b/openstack/networking/v2/routes/doc.go @@ -0,0 +1,28 @@ +/* +Package routes enables management and retrieval of Routes from the Open Telekom Cloud +Route service. + +Example to List Routes + + listroute:=routes.ListOpts{VPC_ID:"93e94d8e-31a6-4c22-bdf7-8b23c7b67329"} + out,err:=routes.List(client,listroute) + fmt.Println(out[0].RouteID) + + +Example to Create a Route + + route:=routes.CreateOpts{ + Type:"peering", + NextHop:"d2dea4ba-e988-4e9c-8162-652e74b2560c", + Destination:"192.168.0.0/16", + VPC_ID:"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf"} + outroute,err:=routes.Create(client,route).Extract() + fmt.Println(outroute) + + +Example to Delete a Route + + out:=routes.Delete(client,"39a07dcb-f30e-41c1-97ac-182c8f0d43c1") + fmt.Println(out) +*/ +package routes diff --git a/openstack/networking/v2/routes/requests.go b/openstack/networking/v2/routes/requests.go new file mode 100644 index 000000000..27216e665 --- /dev/null +++ b/openstack/networking/v2/routes/requests.go @@ -0,0 +1,108 @@ +package routes + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +// ListOpts allows the filtering and sorting of paginated collections through +// the API. Filtering is achieved by passing in struct field values that map to +// the attributes you want to see returned. +type ListOpts struct { + // Specifies the route type. + Type string `q:"type"` + + // Specifies the next hop. If the route type is peering, enter the VPC peering connection ID. + //NextHop string `q:"nexthop"` + + //Specifies the destination IP address or CIDR block. + Destination string `q:"destination"` + + // Specifies the VPC for which a route is to be added. + VPC_ID string `q:"vpc_id"` + + //Specifies the tenant ID. Only the administrator can specify the tenant ID of other tenants. + Tenant_Id string `q:"tenant_id"` + + //Specifies the route ID. + RouteID string `q:"id"` +} +type ListOptsBuilder interface { + ToRouteListQuery() (string, error) +} + +// ToRouteListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToRouteListQuery() (string, error) { + q, err := golangsdk.BuildQueryString(opts) + if err != nil { + return "", err + } + return q.String(), nil +} + +// List returns a Pager which allows you to iterate over a collection of +// vpc routes resources. It accepts a ListOpts struct, which allows you to +// filter the returned collection for greater efficiency. +func List(c *golangsdk.ServiceClient, opts ListOptsBuilder) pagination.Pager { + url := rootURL(c) + + if opts != nil { + query, err := opts.ToRouteListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + + return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { + return RoutePage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// CreateOptsBuilder allows extensions to add additional parameters to the +// Create request. +type CreateOptsBuilder interface { + ToRouteCreateMap() (map[string]interface{}, error) +} + +// CreateOpts contains all the values needed to create a new routes. There are +// no required values. +type CreateOpts struct { + Type string `json:"type,omitempty" required:"true"` + NextHop string `json:"nexthop,omitempty" required:"true"` + Destination string `json:"destination,omitempty" required:"true"` + Tenant_Id string `json:"tenant_id,omitempty"` + VPC_ID string `json:"vpc_id,omitempty" required:"true"` +} + +// ToRouteCreateMap builds a create request body from CreateOpts. +func (opts CreateOpts) ToRouteCreateMap() (map[string]interface{}, error) { + return golangsdk.BuildRequestBody(opts, "route") +} + +// Create accepts a CreateOpts struct and uses the values to create a new +// logical routes. When it is created, the routes does not have an internal +// interface - it is not associated to any routes. +// +func Create(c *golangsdk.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToRouteCreateMap() + if err != nil { + r.Err = err + return + } + reqOpt := &golangsdk.RequestOpts{OkCodes: []int{201}} + _, r.Err = c.Post(rootURL(c), b, &r.Body, reqOpt) + return +} + +// Get retrieves a particular route based on its unique ID. +func Get(c *golangsdk.ServiceClient, id string) (r GetResult) { + _, r.Err = c.Get(resourceURL(c, id), &r.Body, nil) + return +} + +// Delete will permanently delete a particular route based on its unique ID. +func Delete(c *golangsdk.ServiceClient, id string) (r DeleteResult) { + _, r.Err = c.Delete(deleteURL(c, id), nil) + return +} diff --git a/openstack/networking/v2/routes/results.go b/openstack/networking/v2/routes/results.go new file mode 100644 index 000000000..ef97c904e --- /dev/null +++ b/openstack/networking/v2/routes/results.go @@ -0,0 +1,94 @@ +package routes + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/pagination" +) + +type Route struct { + // Specifies the route type. + Type string `json:"type"` + + // Specifies the next hop. If the route type is peering, enter the VPC peering connection ID. + NextHop string `json:"nexthop"` + + //Specifies the destination IP address or CIDR block. + Destination string `json:"destination"` + + // Specifies the VPC for which a route is to be added. + VPC_ID string `json:"vpc_id"` + + //Specifies the tenant ID. Only the administrator can specify the tenant ID of other tenants. + Tenant_Id string `json:"tenant_id"` + + //Specifies the route ID. + RouteID string `json:"id"` +} + +// RoutePage is the page returned by a pager when traversing over a +// collection of routes. +type RoutePage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of routes has reached +// the end of a page and the pager seeks to traverse over a new one. In order +// to do this, it needs to construct the next page's URL. +func (r RoutePage) NextPageURL() (string, error) { + var s struct { + Links []golangsdk.Link `json:"routes_links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return golangsdk.ExtractNextURL(s.Links) +} + +// IsEmpty checks whether a RoutePage struct is empty. +func (r RoutePage) IsEmpty() (bool, error) { + is, err := ExtractRoutes(r) + return len(is) == 0, err +} + +// ExtractRoutes accepts a Page struct, specifically a RoutePage struct, +// and extracts the elements into a slice of Roue structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractRoutes(r pagination.Page) ([]Route, error) { + var s struct { + Routes []Route `json:"routes"` + } + err := (r.(RoutePage)).ExtractInto(&s) + return s.Routes, err +} + +type commonResult struct { + golangsdk.Result +} + +// Extract is a function that accepts a result and extracts a Route. +func (r commonResult) Extract() (*Route, error) { + var s struct { + Route *Route `json:"route"` + } + err := r.ExtractInto(&s) + return s.Route, err +} + +// CreateResult represents the result of a create operation. Call its Extract +// method to interpret it as a Route. +type CreateResult struct { + commonResult +} + +// GetResult represents the result of a get operation. Call its Extract +// method to interpret it as a Route. +type GetResult struct { + commonResult +} + +// DeleteResult represents the result of a delete operation. Call its ExtractErr +// method to determine if the request succeeded or failed. +type DeleteResult struct { + golangsdk.ErrResult +} diff --git a/openstack/networking/v2/routes/testing/doc.go b/openstack/networking/v2/routes/testing/doc.go new file mode 100644 index 000000000..7603f836a --- /dev/null +++ b/openstack/networking/v2/routes/testing/doc.go @@ -0,0 +1 @@ +package testing diff --git a/openstack/networking/v2/routes/testing/requests_test.go b/openstack/networking/v2/routes/testing/requests_test.go new file mode 100644 index 000000000..61f5c6ffe --- /dev/null +++ b/openstack/networking/v2/routes/testing/requests_test.go @@ -0,0 +1,194 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + fake "github.com/huaweicloud/golangsdk/openstack/networking/v2/common" + "github.com/huaweicloud/golangsdk/openstack/networking/v2/routes" + th "github.com/huaweicloud/golangsdk/testhelper" +) + +func TestListRoutes(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v2.0/vpc/routes", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` +{ + "routes": [ + { + "destination": "172.31.8.192/26", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e", + "nexthop": "283aabd7-dab4-409d-96ff-6c878b9a0219", + "vpc_id": "93e94d8e-31a6-4c22-bdf7-8b23c7b67329", + "type": "peering", + "id": "4ae95cd4-292d-4a27-b3de-1be835eb32e1" + }, + { + "destination": "172.31.8.128/26", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e", + "nexthop": "283aabd7-dab4-409d-96ff-6c878b9a0219", + "vpc_id": "93e94d8e-31a6-4c22-bdf7-8b23c7b67329", + "type": "peering", + "id": "804d5d09-cee2-418d-8d1b-be29b8e8e9e8" + }, + { + "destination": "172.31.8.112/28", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e", + "nexthop": "283aabd7-dab4-409d-96ff-6c878b9a0219", + "vpc_id": "93e94d8e-31a6-4c22-bdf7-8b23c7b67329", + "type": "peering", + "id": "9f54e4ac-e052-4198-bb73-51b22ad41035" + } + ] +} + `) + }) + + pages, err := routes.List(fake.ServiceClient(), routes.ListOpts{}).AllPages() + if err != nil { + t.Errorf("Failed to get routes: %v", err) + } + + actual, err := routes.ExtractRoutes(pages) + if err != nil { + t.Errorf("Failed to extract routes: %v", err) + } + + expected := []routes.Route{ + { + Type: "peering", + NextHop: "283aabd7-dab4-409d-96ff-6c878b9a0219", + Destination: "172.31.8.192/26", + VPC_ID: "93e94d8e-31a6-4c22-bdf7-8b23c7b67329", + Tenant_Id: "87a56a48977e42068f70ad3280c50f0e", + RouteID: "4ae95cd4-292d-4a27-b3de-1be835eb32e1", + }, + { + Type: "peering", + NextHop: "283aabd7-dab4-409d-96ff-6c878b9a0219", + Destination: "172.31.8.128/26", + VPC_ID: "93e94d8e-31a6-4c22-bdf7-8b23c7b67329", + Tenant_Id: "87a56a48977e42068f70ad3280c50f0e", + RouteID: "804d5d09-cee2-418d-8d1b-be29b8e8e9e8", + }, + { + Type: "peering", + NextHop: "283aabd7-dab4-409d-96ff-6c878b9a0219", + Destination: "172.31.8.112/28", + VPC_ID: "93e94d8e-31a6-4c22-bdf7-8b23c7b67329", + Tenant_Id: "87a56a48977e42068f70ad3280c50f0e", + RouteID: "9f54e4ac-e052-4198-bb73-51b22ad41035", + }, + } + + th.AssertDeepEquals(t, expected, actual) +} + +func TestGetRoutes(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v2.0/vpc/routes/39a07dcb-f30e-41c1-97ac-182c8f0d43c1", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprintf(w, ` +{ + "route": { + "destination": "192.168.0.0/16", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e", + "nexthop": "d2dea4ba-e988-4e9c-8162-652e74b2560c", + "vpc_id": "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", + "type": "peering", + "id": "39a07dcb-f30e-41c1-97ac-182c8f0d43c1" + } +} + `) + }) + + n, err := routes.Get(fake.ServiceClient(), "39a07dcb-f30e-41c1-97ac-182c8f0d43c1").Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, "39a07dcb-f30e-41c1-97ac-182c8f0d43c1", n.RouteID) + th.AssertEquals(t, "192.168.0.0/16", n.Destination) + th.AssertEquals(t, "87a56a48977e42068f70ad3280c50f0e", n.Tenant_Id) + th.AssertEquals(t, "d2dea4ba-e988-4e9c-8162-652e74b2560c", n.NextHop) + th.AssertEquals(t, "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", n.VPC_ID) + th.AssertEquals(t, "peering", n.Type) +} + +func TestCreateRoute(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v2.0/vpc/routes", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "route": { + "type": "peering", + "nexthop": "d2dea4ba-e988-4e9c-8162-652e74b2560c", + "destination": "192.168.0.0/16", + "vpc_id": "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf" + } +} + `) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + + fmt.Fprintf(w, ` +{ + "route": { + "destination": "192.168.0.0/16", + "tenant_id": "87a56a48977e42068f70ad3280c50f0e", + "nexthop": "d2dea4ba-e988-4e9c-8162-652e74b2560c", + "vpc_id": "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", + "type": "peering", + "id": "39a07dcb-f30e-41c1-97ac-182c8f0d43c1" + } +} `) + }) + + options := routes.CreateOpts{ + Type: "peering", + NextHop: "d2dea4ba-e988-4e9c-8162-652e74b2560c", + Destination: "192.168.0.0/16", + VPC_ID: "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", + } + n, err := routes.Create(fake.ServiceClient(), options).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, "peering", n.Type) + th.AssertEquals(t, "d2dea4ba-e988-4e9c-8162-652e74b2560c", n.NextHop) + th.AssertEquals(t, "192.168.0.0/16", n.Destination) + th.AssertEquals(t, "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", n.VPC_ID) + th.AssertEquals(t, "39a07dcb-f30e-41c1-97ac-182c8f0d43c1", n.RouteID) +} + +func TestDeleteRoute(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v2.0/vpc/routes/39a07dcb-f30e-41c1-97ac-182c8f0d43c1", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + w.WriteHeader(http.StatusNoContent) + }) + + res := routes.Delete(fake.ServiceClient(), "39a07dcb-f30e-41c1-97ac-182c8f0d43c1") + th.AssertNoErr(t, res.Err) +} diff --git a/openstack/networking/v2/routes/urls.go b/openstack/networking/v2/routes/urls.go new file mode 100644 index 000000000..f43ae0596 --- /dev/null +++ b/openstack/networking/v2/routes/urls.go @@ -0,0 +1,18 @@ +package routes + +import "github.com/huaweicloud/golangsdk" + +const resourcePath = "routes" +const rootPath = "vpc" + +func rootURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL(rootPath, resourcePath) +} + +func resourceURL(c *golangsdk.ServiceClient, id string) string { + return c.ServiceURL(rootPath, resourcePath, id) +} + +func deleteURL(c *golangsdk.ServiceClient, id string) string { + return c.ServiceURL(rootPath, resourcePath, id) +} From 466e5020f2443a71b7ba9747fce8a9e6bdf5e121 Mon Sep 17 00:00:00 2001 From: savasw Date: Wed, 28 Mar 2018 12:31:05 +0530 Subject: [PATCH 06/10] fix go vet issue-composite literal uses unkeyed fields --- acceptance/openstack/networking/v1/subnets/subnet.go | 2 +- acceptance/openstack/networking/v2/peering/peerings.go | 2 +- openstack/networking/v2/peerings/testing/requests_test.go | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/acceptance/openstack/networking/v1/subnets/subnet.go b/acceptance/openstack/networking/v1/subnets/subnet.go index d8ddd8d70..754dee3e7 100644 --- a/acceptance/openstack/networking/v1/subnets/subnet.go +++ b/acceptance/openstack/networking/v1/subnets/subnet.go @@ -43,7 +43,7 @@ func CreateSubnetNResources(t *testing.T, client *golangsdk.ServiceClient) (*sub if err != nil { return subnet, err } - t.Logf("Created subnet: %s", subnet) + t.Logf("Created subnet: %v", subnet) return subnet, nil } diff --git a/acceptance/openstack/networking/v2/peering/peerings.go b/acceptance/openstack/networking/v2/peering/peerings.go index 8dfde14c6..4abfdcc49 100644 --- a/acceptance/openstack/networking/v2/peering/peerings.go +++ b/acceptance/openstack/networking/v2/peering/peerings.go @@ -39,7 +39,7 @@ func CreatePeeringResourcesNConn(t *testing.T, clientV2 *golangsdk.ServiceClient peerCreateOpts := peerings.CreateOpts{ Name: peeringConnName, RequestVpcInfo: peerings.VpcInfo{VpcId: vpc.ID}, - AcceptVpcInfo: peerings.VpcInfo{peerVpc.ID, peerClientV2.ProjectID}, + AcceptVpcInfo: peerings.VpcInfo{VpcId: peerVpc.ID, TenantId: peerClientV2.ProjectID}, } t.Logf("Attempting to create vpc peering connection: %s", peeringConnName) diff --git a/openstack/networking/v2/peerings/testing/requests_test.go b/openstack/networking/v2/peerings/testing/requests_test.go index c3b5b1b62..58584e65d 100644 --- a/openstack/networking/v2/peerings/testing/requests_test.go +++ b/openstack/networking/v2/peerings/testing/requests_test.go @@ -262,8 +262,8 @@ func TestAcceptVpcPeering(t *testing.T) { th.AssertEquals(t, "22a3e5b1-1150-408e-99f7-5e25a391cead", n.ID) th.AssertEquals(t, "test_peering", n.Name) th.AssertEquals(t, "ACTIVE", n.Status) - th.AssertDeepEquals(t, peerings.VpcInfo{"c6efbdb7-dca4-4178-b3ec-692f125c1e25","17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) - th.AssertDeepEquals(t, peerings.VpcInfo{"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf","87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) + th.AssertDeepEquals(t, peerings.VpcInfo{VpcId:"c6efbdb7-dca4-4178-b3ec-692f125c1e25",TenantId:"17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) + th.AssertDeepEquals(t, peerings.VpcInfo{VpcId:"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) } @@ -303,8 +303,8 @@ func TestRejectVpcPeering(t *testing.T) { th.AssertEquals(t, "22a3e5b1-1150-408e-99f7-5e25a391cead", n.ID) th.AssertEquals(t, "test_peering", n.Name) th.AssertEquals(t, "ACTIVE", n.Status) - th.AssertDeepEquals(t, peerings.VpcInfo{"c6efbdb7-dca4-4178-b3ec-692f125c1e25","17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) - th.AssertDeepEquals(t, peerings.VpcInfo{"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf","87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) + th.AssertDeepEquals(t, peerings.VpcInfo{VpcId:"c6efbdb7-dca4-4178-b3ec-692f125c1e25",TenantId:"17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) + th.AssertDeepEquals(t, peerings.VpcInfo{VpcId:"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) } From 138ec337bd514d8e4cc8d7c299f1d085cdc7cbee Mon Sep 17 00:00:00 2001 From: savasw Date: Wed, 28 Mar 2018 13:53:28 +0530 Subject: [PATCH 07/10] formatted using go fmt --- openstack/networking/v1/subnets/results.go | 4 +- .../v1/subnets/testing/requests_test.go | 49 ++++++-------- openstack/networking/v1/subnets/urls.go | 10 +-- openstack/networking/v2/peerings/doc.go | 1 - openstack/networking/v2/peerings/results.go | 19 +++--- .../v2/peerings/testing/requests_test.go | 67 +++++++++---------- openstack/networking/v2/peerings/urls.go | 12 ++-- 7 files changed, 73 insertions(+), 89 deletions(-) diff --git a/openstack/networking/v1/subnets/results.go b/openstack/networking/v1/subnets/results.go index 68f7ba797..bf0097955 100644 --- a/openstack/networking/v1/subnets/results.go +++ b/openstack/networking/v1/subnets/results.go @@ -17,7 +17,7 @@ type Subnet struct { CIDR string `json:"cidr"` //Specifies the IP address list of DNS servers on the subnet. - DnsList []string `json:"dnsList"` + DnsList []string `json:"dnsList"` // Status indicates whether or not a subnet is currently operational. Status string `json:"status"` @@ -39,7 +39,6 @@ type Subnet struct { //Specifies the ID of the VPC to which the subnet belongs. VPC_ID string `json:"vpc_id"` - } // SubnetPage is the page returned by a pager when traversing over a @@ -115,4 +114,3 @@ type UpdateResult struct { type DeleteResult struct { golangsdk.ErrResult } - diff --git a/openstack/networking/v1/subnets/testing/requests_test.go b/openstack/networking/v1/subnets/testing/requests_test.go index cc2e528db..776bf2bdc 100644 --- a/openstack/networking/v1/subnets/testing/requests_test.go +++ b/openstack/networking/v1/subnets/testing/requests_test.go @@ -10,7 +10,6 @@ import ( th "github.com/huaweicloud/golangsdk/testhelper" ) - func TestListSubnet(t *testing.T) { th.SetupHTTP() defer th.TeardownHTTP() @@ -76,25 +75,21 @@ func TestListSubnet(t *testing.T) { VPC_ID: "58c24204-170e-4ff0-9b42-c53cdea9239a", }, /*{ - Status: "ACTIVE", - DnsList: []string{"100.125.4.25", "8.8.8.8"}, - VPC_ID: "e8fab5a4-61d3-4e84-85fd-0049676f926a", - GatewayIP: "192.168.106.1", - PRIMARY_DNS: "100.125.4.25", - SECONDARY_DNS: "8.8.8.8", - CIDR: "192.168.106.0/24", - EnableDHCP: true, - Name: "subnet-a0c9", - ID: "470ef214-acbe-4134-9fbf-1b20f4b8f28d", - },*/ -} - th.AssertDeepEquals(t, expected, actual) + Status: "ACTIVE", + DnsList: []string{"100.125.4.25", "8.8.8.8"}, + VPC_ID: "e8fab5a4-61d3-4e84-85fd-0049676f926a", + GatewayIP: "192.168.106.1", + PRIMARY_DNS: "100.125.4.25", + SECONDARY_DNS: "8.8.8.8", + CIDR: "192.168.106.0/24", + EnableDHCP: true, + Name: "subnet-a0c9", + ID: "470ef214-acbe-4134-9fbf-1b20f4b8f28d", + },*/ + } + th.AssertDeepEquals(t, expected, actual) } - - - - func TestGetSubnet(t *testing.T) { th.SetupHTTP() defer th.TeardownHTTP() @@ -191,13 +186,13 @@ func TestCreateSubnet(t *testing.T) { }) options := subnets.CreateOpts{ - Name: "test_subnets", - CIDR: "192.168.0.0/16", - GatewayIP: "192.168.0.1", - PRIMARY_DNS: "8.8.8.8", - SECONDARY_DNS: "8.8.4.4", + Name: "test_subnets", + CIDR: "192.168.0.0/16", + GatewayIP: "192.168.0.1", + PRIMARY_DNS: "8.8.8.8", + SECONDARY_DNS: "8.8.4.4", AvailabilityZone: "eu-de-02", - VPC_ID: "3b9740a0-b44d-48f0-84ee-42eb166e54f7", + VPC_ID: "3b9740a0-b44d-48f0-84ee-42eb166e54f7", } n, err := subnets.Create(fake.ServiceClient(), options).Extract() th.AssertNoErr(t, err) @@ -248,7 +243,7 @@ func TestUpdateSubnet(t *testing.T) { options := subnets.UpdateOpts{Name: "testsubnet"} - n, err := subnets.Update(fake.ServiceClient(), "8f794f06-2275-4d82-9f5a-6d68fbe21a75","83e3bddc-b9ed-4614-a0dc-8a997095a86c", options).Extract() + n, err := subnets.Update(fake.ServiceClient(), "8f794f06-2275-4d82-9f5a-6d68fbe21a75", "83e3bddc-b9ed-4614-a0dc-8a997095a86c", options).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, "testsubnet", n.Name) th.AssertEquals(t, "83e3bddc-b9ed-4614-a0dc-8a997095a86c", n.ID) @@ -265,6 +260,6 @@ func TestDeleteSubnet(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) - res := subnets.Delete(fake.ServiceClient(), "8f794f06-2275-4d82-9f5a-6d68fbe21a75","83e3bddc-b9ed-4614-a0dc-8a997095a86c") + res := subnets.Delete(fake.ServiceClient(), "8f794f06-2275-4d82-9f5a-6d68fbe21a75", "83e3bddc-b9ed-4614-a0dc-8a997095a86c") th.AssertNoErr(t, res.Err) -} \ No newline at end of file +} diff --git a/openstack/networking/v1/subnets/urls.go b/openstack/networking/v1/subnets/urls.go index 14582c4b0..2ebb20d11 100644 --- a/openstack/networking/v1/subnets/urls.go +++ b/openstack/networking/v1/subnets/urls.go @@ -4,17 +4,17 @@ import "github.com/huaweicloud/golangsdk" const ( resourcePath = "subnets" - rootpath = "vpcs" + rootpath = "vpcs" ) func rootURL(c *golangsdk.ServiceClient) string { - return c.ServiceURL(c.ProjectID,resourcePath) + return c.ServiceURL(c.ProjectID, resourcePath) } func resourceURL(c *golangsdk.ServiceClient, id string) string { - return c.ServiceURL(c.ProjectID,resourcePath, id) + return c.ServiceURL(c.ProjectID, resourcePath, id) } func updateURL(c *golangsdk.ServiceClient, vpcid, id string) string { - return c.ServiceURL(c.ProjectID,rootpath, vpcid, resourcePath, id) -} \ No newline at end of file + return c.ServiceURL(c.ProjectID, rootpath, vpcid, resourcePath, id) +} diff --git a/openstack/networking/v2/peerings/doc.go b/openstack/networking/v2/peerings/doc.go index 0b7d0efb4..ea159efce 100644 --- a/openstack/networking/v2/peerings/doc.go +++ b/openstack/networking/v2/peerings/doc.go @@ -1,4 +1,3 @@ - /* Package peerings enables management and retrieval of vpc peering connections from the Open Telekom Cloud VPC service. diff --git a/openstack/networking/v2/peerings/results.go b/openstack/networking/v2/peerings/results.go index 54e61f4a0..1f2cf8394 100644 --- a/openstack/networking/v2/peerings/results.go +++ b/openstack/networking/v2/peerings/results.go @@ -5,10 +5,9 @@ import ( "github.com/huaweicloud/golangsdk/pagination" ) -type VpcInfo struct { +type VpcInfo struct { VpcId string `json:"vpc_id" required:"true"` - TenantId string `json:"tenant_id,omitempty"` - + TenantId string `json:"tenant_id,omitempty"` } // Peering represents a Neutron VPC peering connection. @@ -17,11 +16,11 @@ type VpcInfo struct { // creating, querying, deleting, and updating a VPC peering connection. type Peering struct { // ID is the unique identifier for the vpc_peering_connection. - ID string `json:"id"` + ID string `json:"id"` // Name is the human readable name for the vpc_peering_connection. It does not have to be // unique. - Name string `json:"name"` + Name string `json:"name"` // Status indicates whether or not a vpc_peering_connections is currently operational. Status string `json:"status"` @@ -30,7 +29,7 @@ type Peering struct { RequestVpcInfo VpcInfo `json:"request_vpc_info"` // AcceptVpcInfo indicates information about the peer VPC - AcceptVpcInfo VpcInfo `json:"accept_vpc_info"` + AcceptVpcInfo VpcInfo `json:"accept_vpc_info"` } // PeeringConnectionPage is the page returned by a pager when traversing over a @@ -87,10 +86,10 @@ func (r commonResult) Extract() (*Peering, error) { func (r commonResult) ExtractResult() (Peering, error) { var s struct { // ID is the unique identifier for the vpc. - ID string `json:"id"` + ID string `json:"id"` // Name is the human readable name for the vpc. It does not have to be // unique. - Name string `json:"name"` + Name string `json:"name"` // Status indicates whether or not a vpc is currently operational. Status string `json:"status"` @@ -99,7 +98,7 @@ func (r commonResult) ExtractResult() (Peering, error) { RequestVpcInfo VpcInfo `json:"request_vpc_info"` //Provides informaion about shared snat - AcceptVpcInfo VpcInfo `json:"accept_vpc_info"` + AcceptVpcInfo VpcInfo `json:"accept_vpc_info"` } err1 := r.ExtractInto(&s) return s, err1 @@ -140,5 +139,3 @@ type UpdateResult struct { type DeleteResult struct { golangsdk.ErrResult } - - diff --git a/openstack/networking/v2/peerings/testing/requests_test.go b/openstack/networking/v2/peerings/testing/requests_test.go index 58584e65d..5a080d4c7 100644 --- a/openstack/networking/v2/peerings/testing/requests_test.go +++ b/openstack/networking/v2/peerings/testing/requests_test.go @@ -69,7 +69,7 @@ func TestListVpcPeerings(t *testing.T) { }) //count := 0 - actual , err := peerings.List(fake.ServiceClient(), peerings.ListOpts{}) + actual, err := peerings.List(fake.ServiceClient(), peerings.ListOpts{}) if err != nil { t.Errorf("Failed to extract vpc_peering_connections: %v", err) @@ -77,25 +77,25 @@ func TestListVpcPeerings(t *testing.T) { expected := []peerings.Peering{ { - ID: "22a3e5b1-1150-408e-99f7-5e25a391cead", - Name: "test_peering", - Status: "PENDING_ACCEPTANCE", - RequestVpcInfo: peerings.VpcInfo{VpcId:"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, - AcceptVpcInfo: peerings.VpcInfo{VpcId:"c6efbdb7-dca4-4178-b3ec-692f125c1e25",TenantId:"17fbda95add24720a4038ba4b1c705ed"}, + ID: "22a3e5b1-1150-408e-99f7-5e25a391cead", + Name: "test_peering", + Status: "PENDING_ACCEPTANCE", + RequestVpcInfo: peerings.VpcInfo{VpcId: "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", TenantId: "87a56a48977e42068f70ad3280c50f0e"}, + AcceptVpcInfo: peerings.VpcInfo{VpcId: "c6efbdb7-dca4-4178-b3ec-692f125c1e25", TenantId: "17fbda95add24720a4038ba4b1c705ed"}, }, { - ID: "283aabd7-dab4-409d-96ff-6c878b9a0219", - Name: "peering-7750-sunway", - Status: "ACTIVE", - RequestVpcInfo: peerings.VpcInfo{VpcId:"b0d686e5-312c-4279-b69c-eedbc779ae69",TenantId:"bf74229f30c0421fae270386a43315ee"}, - AcceptVpcInfo: peerings.VpcInfo{VpcId:"93e94d8e-31a6-4c22-bdf7-8b23c7b67329",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, + ID: "283aabd7-dab4-409d-96ff-6c878b9a0219", + Name: "peering-7750-sunway", + Status: "ACTIVE", + RequestVpcInfo: peerings.VpcInfo{VpcId: "b0d686e5-312c-4279-b69c-eedbc779ae69", TenantId: "bf74229f30c0421fae270386a43315ee"}, + AcceptVpcInfo: peerings.VpcInfo{VpcId: "93e94d8e-31a6-4c22-bdf7-8b23c7b67329", TenantId: "87a56a48977e42068f70ad3280c50f0e"}, }, { - ID: "71d64714-bd4e-44c4-917a-d8d1239e5292", - Name: "test", - Status: "ACTIVE", - RequestVpcInfo: peerings.VpcInfo{VpcId:"4117d38e-4c8f-4624-a505-bd96b97d024c",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, - AcceptVpcInfo: peerings.VpcInfo{VpcId:"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, + ID: "71d64714-bd4e-44c4-917a-d8d1239e5292", + Name: "test", + Status: "ACTIVE", + RequestVpcInfo: peerings.VpcInfo{VpcId: "4117d38e-4c8f-4624-a505-bd96b97d024c", TenantId: "87a56a48977e42068f70ad3280c50f0e"}, + AcceptVpcInfo: peerings.VpcInfo{VpcId: "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", TenantId: "87a56a48977e42068f70ad3280c50f0e"}, }, } @@ -148,17 +148,17 @@ func TestCreateVpcPeeringConnection(t *testing.T) { }) options := peerings.CreateOpts{ - Name:"test", - RequestVpcInfo: peerings.VpcInfo{VpcId:"4117d38e-4c8f-4624-a505-bd96b97d024c"}, - AcceptVpcInfo: peerings.VpcInfo{VpcId:"c6efbdb7-dca4-4178-b3ec-692f125c1e25",TenantId:"17fbda95add24720a4038ba4b1c705ed"}, + Name: "test", + RequestVpcInfo: peerings.VpcInfo{VpcId: "4117d38e-4c8f-4624-a505-bd96b97d024c"}, + AcceptVpcInfo: peerings.VpcInfo{VpcId: "c6efbdb7-dca4-4178-b3ec-692f125c1e25", TenantId: "17fbda95add24720a4038ba4b1c705ed"}, } n, err := peerings.Create(fake.ServiceClient(), options).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, "test", n.Name) th.AssertEquals(t, "4e6ca99d-8344-4eb2-b2c9-b77368db3704", n.ID) - th.AssertEquals(t, peerings.VpcInfo{VpcId:"4117d38e-4c8f-4624-a505-bd96b97d024c",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) - th.AssertEquals(t, peerings.VpcInfo{VpcId:"c6efbdb7-dca4-4178-b3ec-692f125c1e25",TenantId:"17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) + th.AssertEquals(t, peerings.VpcInfo{VpcId: "4117d38e-4c8f-4624-a505-bd96b97d024c", TenantId: "87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) + th.AssertEquals(t, peerings.VpcInfo{VpcId: "c6efbdb7-dca4-4178-b3ec-692f125c1e25", TenantId: "17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) th.AssertEquals(t, "PENDING_ACCEPTANCE", n.Status) } @@ -200,14 +200,14 @@ func TestUpdateVpcPeeringConnection(t *testing.T) { `) }) - options := peerings.UpdateOpts{Name:"test2"} + options := peerings.UpdateOpts{Name: "test2"} - n, err := peerings.Update(fake.ServiceClient(), "4e6ca99d-8344-4eb2-b2c9-b77368db3704",options).Extract() + n, err := peerings.Update(fake.ServiceClient(), "4e6ca99d-8344-4eb2-b2c9-b77368db3704", options).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, "test2", n.Name) th.AssertEquals(t, "4e6ca99d-8344-4eb2-b2c9-b77368db3704", n.ID) - th.AssertEquals(t, peerings.VpcInfo{VpcId:"4117d38e-4c8f-4624-a505-bd96b97d024c",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) - th.AssertEquals(t, peerings.VpcInfo{VpcId:"c6efbdb7-dca4-4178-b3ec-692f125c1e25",TenantId:"17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) + th.AssertEquals(t, peerings.VpcInfo{VpcId: "4117d38e-4c8f-4624-a505-bd96b97d024c", TenantId: "87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) + th.AssertEquals(t, peerings.VpcInfo{VpcId: "c6efbdb7-dca4-4178-b3ec-692f125c1e25", TenantId: "17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) th.AssertEquals(t, "PENDING_ACCEPTANCE", n.Status) } @@ -225,7 +225,6 @@ func TestDeleteVpcPeeringConnection(t *testing.T) { th.AssertNoErr(t, res.Err) } - func TestAcceptVpcPeering(t *testing.T) { th.SetupHTTP() @@ -256,14 +255,13 @@ func TestAcceptVpcPeering(t *testing.T) { `) }) - - n, err := peerings.Accept(fake.ServiceClient(), "22a3e5b1-1150-408e-99f7-5e25a391cead",).ExtractResult() + n, err := peerings.Accept(fake.ServiceClient(), "22a3e5b1-1150-408e-99f7-5e25a391cead").ExtractResult() th.AssertNoErr(t, err) th.AssertEquals(t, "22a3e5b1-1150-408e-99f7-5e25a391cead", n.ID) th.AssertEquals(t, "test_peering", n.Name) th.AssertEquals(t, "ACTIVE", n.Status) - th.AssertDeepEquals(t, peerings.VpcInfo{VpcId:"c6efbdb7-dca4-4178-b3ec-692f125c1e25",TenantId:"17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) - th.AssertDeepEquals(t, peerings.VpcInfo{VpcId:"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) + th.AssertDeepEquals(t, peerings.VpcInfo{VpcId: "c6efbdb7-dca4-4178-b3ec-692f125c1e25", TenantId: "17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) + th.AssertDeepEquals(t, peerings.VpcInfo{VpcId: "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", TenantId: "87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) } @@ -297,15 +295,12 @@ func TestRejectVpcPeering(t *testing.T) { `) }) - - n, err := peerings.Reject(fake.ServiceClient(), "22a3e5b1-1150-408e-99f7-5e25a391cead",).ExtractResult() + n, err := peerings.Reject(fake.ServiceClient(), "22a3e5b1-1150-408e-99f7-5e25a391cead").ExtractResult() th.AssertNoErr(t, err) th.AssertEquals(t, "22a3e5b1-1150-408e-99f7-5e25a391cead", n.ID) th.AssertEquals(t, "test_peering", n.Name) th.AssertEquals(t, "ACTIVE", n.Status) - th.AssertDeepEquals(t, peerings.VpcInfo{VpcId:"c6efbdb7-dca4-4178-b3ec-692f125c1e25",TenantId:"17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) - th.AssertDeepEquals(t, peerings.VpcInfo{VpcId:"3127e30b-5f8e-42d1-a3cc-fdadf412c5bf",TenantId:"87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) + th.AssertDeepEquals(t, peerings.VpcInfo{VpcId: "c6efbdb7-dca4-4178-b3ec-692f125c1e25", TenantId: "17fbda95add24720a4038ba4b1c705ed"}, n.AcceptVpcInfo) + th.AssertDeepEquals(t, peerings.VpcInfo{VpcId: "3127e30b-5f8e-42d1-a3cc-fdadf412c5bf", TenantId: "87a56a48977e42068f70ad3280c50f0e"}, n.RequestVpcInfo) } - - diff --git a/openstack/networking/v2/peerings/urls.go b/openstack/networking/v2/peerings/urls.go index a513450a4..06ad30910 100644 --- a/openstack/networking/v2/peerings/urls.go +++ b/openstack/networking/v2/peerings/urls.go @@ -4,21 +4,21 @@ import "github.com/huaweicloud/golangsdk" const ( resourcePath = "peerings" - rootpath="vpc" + rootpath = "vpc" ) func rootURL(c *golangsdk.ServiceClient) string { - return c.ServiceURL(rootpath,resourcePath) + return c.ServiceURL(rootpath, resourcePath) } func resourceURL(c *golangsdk.ServiceClient, id string) string { - return c.ServiceURL(rootpath,resourcePath, id) + return c.ServiceURL(rootpath, resourcePath, id) } func acceptURL(c *golangsdk.ServiceClient, id string) string { - return c.ServiceURL( rootpath,resourcePath, id ,"accept") + return c.ServiceURL(rootpath, resourcePath, id, "accept") } func rejectURL(c *golangsdk.ServiceClient, id string) string { - return c.ServiceURL( rootpath,resourcePath, id ,"reject") -} \ No newline at end of file + return c.ServiceURL(rootpath, resourcePath, id, "reject") +} From 86e7aacece78f4e884c43e57a3a01f45fe05ca6c Mon Sep 17 00:00:00 2001 From: savasw Date: Wed, 28 Mar 2018 15:04:23 +0530 Subject: [PATCH 08/10] fixed import ordering issue --- acceptance/openstack/networking/v1/subnets/subnet_test.go | 3 ++- acceptance/openstack/networking/v1/vpcs_test.go | 3 ++- acceptance/openstack/networking/v2/peering/peerings.go | 3 ++- acceptance/openstack/networking/v2/peering/peerings_test.go | 3 ++- acceptance/openstack/networking/v2/routes/route.go | 3 ++- acceptance/openstack/networking/v2/routes/route_test.go | 3 ++- openstack/networking/v1/subnets/requests.go | 4 ++-- openstack/networking/v1/vpcs/requests.go | 3 ++- openstack/networking/v2/peerings/requests.go | 3 ++- 9 files changed, 18 insertions(+), 10 deletions(-) diff --git a/acceptance/openstack/networking/v1/subnets/subnet_test.go b/acceptance/openstack/networking/v1/subnets/subnet_test.go index c9ae560d6..792e707ab 100644 --- a/acceptance/openstack/networking/v1/subnets/subnet_test.go +++ b/acceptance/openstack/networking/v1/subnets/subnet_test.go @@ -1,10 +1,11 @@ package subnets import ( + "testing" + "github.com/huaweicloud/golangsdk/acceptance/clients" "github.com/huaweicloud/golangsdk/acceptance/tools" "github.com/huaweicloud/golangsdk/openstack/networking/v1/subnets" - "testing" ) func TestSubnetList(t *testing.T) { diff --git a/acceptance/openstack/networking/v1/vpcs_test.go b/acceptance/openstack/networking/v1/vpcs_test.go index f6a9e5d48..4114f9911 100644 --- a/acceptance/openstack/networking/v1/vpcs_test.go +++ b/acceptance/openstack/networking/v1/vpcs_test.go @@ -1,10 +1,11 @@ package v1 import ( + "testing" + "github.com/huaweicloud/golangsdk/acceptance/clients" "github.com/huaweicloud/golangsdk/acceptance/tools" "github.com/huaweicloud/golangsdk/openstack/networking/v1/vpcs" - "testing" ) func TestVpcList(t *testing.T) { diff --git a/acceptance/openstack/networking/v2/peering/peerings.go b/acceptance/openstack/networking/v2/peering/peerings.go index 4abfdcc49..adb08f754 100644 --- a/acceptance/openstack/networking/v2/peering/peerings.go +++ b/acceptance/openstack/networking/v2/peering/peerings.go @@ -1,12 +1,13 @@ package peering import ( + "testing" + "github.com/huaweicloud/golangsdk" "github.com/huaweicloud/golangsdk/acceptance/clients" "github.com/huaweicloud/golangsdk/acceptance/tools" "github.com/huaweicloud/golangsdk/openstack/networking/v1/vpcs" "github.com/huaweicloud/golangsdk/openstack/networking/v2/peerings" - "testing" ) func CreatePeeringResourcesNConn(t *testing.T, clientV2 *golangsdk.ServiceClient, peerClientV2 *golangsdk.ServiceClient, diff --git a/acceptance/openstack/networking/v2/peering/peerings_test.go b/acceptance/openstack/networking/v2/peering/peerings_test.go index 6bce3a041..ffa0a3ac4 100644 --- a/acceptance/openstack/networking/v2/peering/peerings_test.go +++ b/acceptance/openstack/networking/v2/peering/peerings_test.go @@ -1,10 +1,11 @@ package peering import ( + "testing" + "github.com/huaweicloud/golangsdk/acceptance/clients" "github.com/huaweicloud/golangsdk/acceptance/tools" "github.com/huaweicloud/golangsdk/openstack/networking/v2/peerings" - "testing" ) func TestPeeringList(t *testing.T) { diff --git a/acceptance/openstack/networking/v2/routes/route.go b/acceptance/openstack/networking/v2/routes/route.go index 888457656..1d40e0118 100644 --- a/acceptance/openstack/networking/v2/routes/route.go +++ b/acceptance/openstack/networking/v2/routes/route.go @@ -1,10 +1,11 @@ package routes import ( + "testing" + "github.com/huaweicloud/golangsdk" "github.com/huaweicloud/golangsdk/openstack/networking/v2/peerings" "github.com/huaweicloud/golangsdk/openstack/networking/v2/routes" - "testing" ) func CreateRoute(t *testing.T, clientV2 *golangsdk.ServiceClient, peeringConn *peerings.Peering) (*routes.Route, error) { diff --git a/acceptance/openstack/networking/v2/routes/route_test.go b/acceptance/openstack/networking/v2/routes/route_test.go index 64b7619e5..83ba88d35 100644 --- a/acceptance/openstack/networking/v2/routes/route_test.go +++ b/acceptance/openstack/networking/v2/routes/route_test.go @@ -1,12 +1,13 @@ package routes import ( + "testing" + "github.com/huaweicloud/golangsdk/acceptance/clients" "github.com/huaweicloud/golangsdk/acceptance/openstack/networking/v2/peering" "github.com/huaweicloud/golangsdk/acceptance/tools" "github.com/huaweicloud/golangsdk/openstack/networking/v2/peerings" "github.com/huaweicloud/golangsdk/openstack/networking/v2/routes" - "testing" ) func TestRouteList(t *testing.T) { diff --git a/openstack/networking/v1/subnets/requests.go b/openstack/networking/v1/subnets/requests.go index 4df6b6311..893cf65f2 100644 --- a/openstack/networking/v1/subnets/requests.go +++ b/openstack/networking/v1/subnets/requests.go @@ -1,10 +1,10 @@ package subnets import ( + "reflect" + "github.com/huaweicloud/golangsdk" "github.com/huaweicloud/golangsdk/pagination" - - "reflect" ) // ListOpts allows the filtering and sorting of paginated collections through diff --git a/openstack/networking/v1/vpcs/requests.go b/openstack/networking/v1/vpcs/requests.go index a9539b9ce..7cfb3ab4a 100644 --- a/openstack/networking/v1/vpcs/requests.go +++ b/openstack/networking/v1/vpcs/requests.go @@ -1,9 +1,10 @@ package vpcs import ( + "reflect" + "github.com/huaweicloud/golangsdk" "github.com/huaweicloud/golangsdk/pagination" - "reflect" ) // ListOpts allows the filtering and sorting of paginated collections through diff --git a/openstack/networking/v2/peerings/requests.go b/openstack/networking/v2/peerings/requests.go index 675a709a0..9cc8b720b 100644 --- a/openstack/networking/v2/peerings/requests.go +++ b/openstack/networking/v2/peerings/requests.go @@ -1,9 +1,10 @@ package peerings import ( + "reflect" + "github.com/huaweicloud/golangsdk" "github.com/huaweicloud/golangsdk/pagination" - "reflect" ) // ListOpts allows the filtering of paginated collections through From 4a4972492bbc45b16a97808ea1c176065921f6a0 Mon Sep 17 00:00:00 2001 From: savasw Date: Thu, 29 Mar 2018 11:00:05 +0530 Subject: [PATCH 09/10] update comments --- openstack/networking/v1/subnets/doc.go | 2 +- openstack/networking/v1/vpcs/doc.go | 2 +- openstack/networking/v2/peerings/doc.go | 2 +- openstack/networking/v2/routes/doc.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openstack/networking/v1/subnets/doc.go b/openstack/networking/v1/subnets/doc.go index a4164b30e..c418b7be2 100644 --- a/openstack/networking/v1/subnets/doc.go +++ b/openstack/networking/v1/subnets/doc.go @@ -1,5 +1,5 @@ /* -Package Subnets enables management and retrieval of Subnets from the Open Telekom Cloud VPC service. +Package Subnets enables management and retrieval of Subnets Example to List Vpcs diff --git a/openstack/networking/v1/vpcs/doc.go b/openstack/networking/v1/vpcs/doc.go index 87dc6dded..6aa6597c2 100644 --- a/openstack/networking/v1/vpcs/doc.go +++ b/openstack/networking/v1/vpcs/doc.go @@ -1,5 +1,5 @@ /* -Package vpcs enables management and retrieval of Vpcs from the Open Telekom Cloud +Package vpcs enables management and retrieval of Vpcs VPC service. Example to List Vpcs diff --git a/openstack/networking/v2/peerings/doc.go b/openstack/networking/v2/peerings/doc.go index ea159efce..c51cb1588 100644 --- a/openstack/networking/v2/peerings/doc.go +++ b/openstack/networking/v2/peerings/doc.go @@ -1,5 +1,5 @@ /* -Package peerings enables management and retrieval of vpc peering connections from the Open Telekom Cloud VPC service. +Package peerings enables management and retrieval of vpc peering connections Example to List a Vpc Peering Connections listOpts:=peerings.ListOpts{} diff --git a/openstack/networking/v2/routes/doc.go b/openstack/networking/v2/routes/doc.go index a4dad0f55..8b3ae0bbc 100644 --- a/openstack/networking/v2/routes/doc.go +++ b/openstack/networking/v2/routes/doc.go @@ -1,5 +1,5 @@ /* -Package routes enables management and retrieval of Routes from the Open Telekom Cloud +Package routes enables management and retrieval of Routes Route service. Example to List Routes From c0376cde75c954c9f4e91608e23b61315a41acd8 Mon Sep 17 00:00:00 2001 From: savasw Date: Thu, 29 Mar 2018 11:01:37 +0530 Subject: [PATCH 10/10] remove redundant code --- openstack/networking/v2/peerings/requests.go | 23 -------------------- openstack/networking/v2/routes/requests.go | 2 +- openstack/networking/v2/routes/urls.go | 4 ---- 3 files changed, 1 insertion(+), 28 deletions(-) diff --git a/openstack/networking/v2/peerings/requests.go b/openstack/networking/v2/peerings/requests.go index 9cc8b720b..4a26c4726 100644 --- a/openstack/networking/v2/peerings/requests.go +++ b/openstack/networking/v2/peerings/requests.go @@ -103,29 +103,6 @@ func FilterVpcPeeringConns(peerings []Peering, opts ListOpts) ([]Peering, error) return refinedPeerings, nil - /*for _, peering := range peerings { - matched = true - Peer_VpcId:=getStructNestedField(&peering,"AcceptVpcInfo"); - VpcId:=getStructNestedField(&peering,"RequestVpcInfo") - - if opts.VpcId != "" || opts.Peer_VpcId != "" { - if opts.VpcId != "" && opts.Peer_VpcId != "" { - if !(Peer_VpcId ==opts.Peer_VpcId ) && !(VpcId ==opts.VpcId ) { - matched = false - } - } - if opts.Peer_VpcId != ""{ - if !(Peer_VpcId ==opts.Peer_VpcId ){ - matched = false - } - } - } - - if matched { - refinedPeerings = append(refinedPeerings, peering) - } - }*/ - } func getStructNestedField(v *Peering, field string) string { diff --git a/openstack/networking/v2/routes/requests.go b/openstack/networking/v2/routes/requests.go index 27216e665..6d0de1e16 100644 --- a/openstack/networking/v2/routes/requests.go +++ b/openstack/networking/v2/routes/requests.go @@ -103,6 +103,6 @@ func Get(c *golangsdk.ServiceClient, id string) (r GetResult) { // Delete will permanently delete a particular route based on its unique ID. func Delete(c *golangsdk.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(deleteURL(c, id), nil) + _, r.Err = c.Delete(resourceURL(c, id), nil) return } diff --git a/openstack/networking/v2/routes/urls.go b/openstack/networking/v2/routes/urls.go index f43ae0596..c3cfe2b9f 100644 --- a/openstack/networking/v2/routes/urls.go +++ b/openstack/networking/v2/routes/urls.go @@ -12,7 +12,3 @@ func rootURL(c *golangsdk.ServiceClient) string { func resourceURL(c *golangsdk.ServiceClient, id string) string { return c.ServiceURL(rootPath, resourcePath, id) } - -func deleteURL(c *golangsdk.ServiceClient, id string) string { - return c.ServiceURL(rootPath, resourcePath, id) -}