Add the ability to create, delete, list, and get networks, ports and subnets

Partially implements network-v2

Updated to use Session

Change-Id: I9c57cbe524712313892868c0fb38eb6f6062d362
This commit is contained in:
Chris Robinson
2014-10-28 16:55:33 -07:00
committed by Dean Troyer
parent 4141ca3ed3
commit c42cbe79a0
8 changed files with 896 additions and 0 deletions

252
examples/40-network-v2.go Normal file
View File

@@ -0,0 +1,252 @@
// Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package main
import (
"fmt"
"net/http"
"reflect"
"time"
"git.openstack.org/openstack/golang-client.git/network/v2"
"git.openstack.org/openstack/golang-client.git/openstack"
)
func main() {
config := getConfig()
// Authenticate with a username, password, tenant id.
creds := openstack.AuthOpts{
AuthUrl: config.Host,
Project: config.ProjectName,
Username: config.Username,
Password: config.Password,
}
auth, err := openstack.DoAuthRequest(creds)
if err != nil {
panicString := fmt.Sprint("There was an error authenticating:", err)
panic(panicString)
}
if !auth.GetExpiration().After(time.Now()) {
panic("There was an error. The auth token has an invalid expiration.")
}
// Find the endpoint for the network service.
url, err := auth.GetEndpoint("network", "")
if url == "" || err != nil {
panic("v2 network service url not found during authentication")
}
// Make a new client with these creds
sess, err := openstack.NewSession(nil, auth, nil)
if err != nil {
panicString := fmt.Sprint("Error crating new Session:", err)
panic(panicString)
}
networkService := network.Service{
Session: *sess,
Client: *http.DefaultClient,
URL: url + "/v2.0", // We're forcing Network v2.0 for now
}
networkName := "OtherNetwork"
activeNetwork := CreateNewNetworkVerifyExistsAndActive(networkService, networkName)
// Create list, get and delete a subnet
activeSubnet := CreateSubnetAndVerify(networkService, activeNetwork)
activePort := CreatePortAndVerify(networkService, activeSubnet, activeNetwork)
DeletePortAndVerify(networkService, activePort)
DeleteSubnetAndVerify(networkService, activeSubnet)
DeleteNetworkAndVerify(networkService, activeNetwork)
}
func CreatePortAndVerify(networkService network.Service, subnet network.SubnetResponse, activeNetwork network.Response) network.PortResponse {
var portToCreate = network.CreatePortParameters{AdminStateUp: false, Name: "testPort", NetworkID: activeNetwork.ID}
portCreated, err := networkService.CreatePort(portToCreate)
if err != nil {
panicString := fmt.Sprint("Error in creating port:", err)
panic(panicString)
}
foundPorts, err := networkService.Ports()
if err != nil {
panicString := fmt.Sprint("Error in getting list of subnets:", err)
panic(panicString)
}
foundCreatedPort := false
for _, portFound := range foundPorts {
if reflect.DeepEqual(portCreated, portFound) {
foundCreatedPort = true
}
}
if !foundCreatedPort {
panic("Cannot find the newly created port.")
}
return portCreated
}
func DeletePortAndVerify(networkService network.Service, port network.PortResponse) {
err := networkService.DeletePort(port.ID)
if err != nil {
panicString := fmt.Sprint("Error in deleting port:", err)
panic(panicString)
}
ports, err := networkService.Ports()
if err != nil {
panicString := fmt.Sprint("There was an error getting a list of ports to verify the port was deleted:", err)
panic(panicString)
}
portDeleted := true
for _, portFound := range ports {
if reflect.DeepEqual(portFound, port) {
portDeleted = false
}
}
if !portDeleted {
panic("port was not deleted.")
}
}
func CreateSubnetAndVerify(networkService network.Service, activeNetwork network.Response) network.SubnetResponse {
var allocationPools = []network.AllocationPool{network.AllocationPool{Start: "10.1.2.5", End: "10.1.2.15"}}
subnetToCreate := network.CreateSubnetParameters{NetworkID: activeNetwork.ID, IPVersion: network.IPV4,
CIDR: "10.1.2.1/25", AllocationPools: allocationPools}
subnetCreated, err := networkService.CreateSubnet(subnetToCreate)
if err != nil {
panicString := fmt.Sprint("Error in creating subnet:", err)
panic(panicString)
}
foundSubnets, err := networkService.Subnets()
if err != nil {
panicString := fmt.Sprint("Error in getting list of subnets:", err)
panic(panicString)
}
foundCreatedSubnet := false
for _, subnetFound := range foundSubnets {
if reflect.DeepEqual(subnetCreated, subnetFound) {
foundCreatedSubnet = true
}
}
if !foundCreatedSubnet {
panic("Cannot find the newly created subnet.")
}
return subnetCreated
}
func DeleteSubnetAndVerify(networkService network.Service, subnet network.SubnetResponse) {
err := networkService.DeleteSubnet(subnet.ID)
if err != nil {
panicString := fmt.Sprint("Error in deleting subnet:", err)
panic(panicString)
}
subnets, err := networkService.Subnets()
if err != nil {
panicString := fmt.Sprint("There was an error getting a list of networks to verify the network was deleted:", err)
panic(panicString)
}
subnetDeleted := true
for _, subnetFound := range subnets {
if reflect.DeepEqual(subnetFound, subnet) {
subnetDeleted = false
}
}
if !subnetDeleted {
panic("subnet was not deleted.")
}
}
func DeleteNetworkAndVerify(networkService network.Service, activeNetwork network.Response) {
err := networkService.DeleteNetwork(activeNetwork.ID)
if err != nil {
panicString := fmt.Sprint("Error in deleting 'OtherNetwork'", err)
panic(panicString)
}
networks, err := networkService.Networks()
if err != nil {
panicString := fmt.Sprint("There was an error getting a list of networks to verify the network was deleted:", err)
panic(panicString)
}
networkDeleted := true
for _, networkFound := range networks {
if reflect.DeepEqual(activeNetwork, networkFound) {
networkDeleted = false
}
}
if !networkDeleted {
panic("network was not deleted.")
}
}
func CreateNewNetworkVerifyExistsAndActive(networkService network.Service, networkName string) network.Response {
createdNetwork, err := networkService.CreateNetwork(true, networkName, false)
if err != nil {
panicString := fmt.Sprint("There was an error creating a network:", err)
panic(panicString)
}
networks, err := networkService.Networks()
if err != nil {
panicString := fmt.Sprint("There was an error getting a list of networks:", err)
panic(panicString)
}
foundCreatedNetwork := false
for _, networkFound := range networks {
if reflect.DeepEqual(createdNetwork, networkFound) {
foundCreatedNetwork = true
}
}
if !foundCreatedNetwork {
panic("Cannot find network called 'OtherNetwork' when getting a list of networks.")
}
// Might be nice to have some sugar api that can do this easily for a developer...
// Keep iterating until active or until more than 5 tries has been exceeded.
//numTries := 0
//activeNetwork := createdNetwork
//for activeNetwork.Status != "ACTIVE" && numTries < 5 {
// activeNetwork, _ = networkService.Network(createdNetwork.ID)
// numTries++
// fmt.Println("Sleeping 50ms on try:" + string(numTries) + " with status currently " + activeNetwork.Status)
// sleepDuration, _ := time.ParseDuration("50ms")
// time.Sleep(sleepDuration)
//}
//if activeNetwork.Status != "ACTIVE" {
// panic("The network is not in the active state and cannot be deleted")
//}
return createdNetwork
}

94
network/v2/network.go Normal file
View File

@@ -0,0 +1,94 @@
// Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
// Package network is used to create, delete, and query, networks, ports and subnets
package network
import (
"net/http"
"git.openstack.org/openstack/golang-client.git/openstack"
)
// Service holds state that is use to make requests and get responses for networks,
// ports and subnets
type Service struct {
Client http.Client
Session openstack.Session
URL string
}
// Response returns a set of values of the a network response.
type Response struct {
ID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
Subnets []string `json:"subnets"`
TenantID string `json:"tenant_id"`
RouterExternal bool `json:"router:external"`
AdminStateUp bool `json:"admin_state_up"`
Shared bool `json:"shared"`
PortSecurityEnabled bool `json:"port_security_enabled"`
}
// Networks will issue a get query that returns a list of networks
func (networkService Service) Networks() ([]Response, error) {
reqURL := networkService.URL + "/networks"
nwContainer := networksResp{}
_, err := networkService.Session.GetJSON(reqURL, nil, nil, &nwContainer)
return nwContainer.Networks, err
}
// Network will issue a get request for a specific network.
func (networkService Service) Network(id string) (Response, error) {
reqURL := networkService.URL + "/networks/" + id
nwContainer := networkResp{}
_, err := networkService.Session.GetJSON(reqURL, nil, nil, &nwContainer)
return nwContainer.Network, err
}
// CreateNetwork will send a POST request to create a new network with the specified parameters.
func (networkService Service) CreateNetwork(adminStateUp bool, name string, shared bool) (Response, error) {
createParameters := createNetworkValuesContainer{createNetworkValues{Name: name, AdminStateUp: adminStateUp, Shared: shared, TenantID: ""}}
reqURL := networkService.URL + "/networks"
nwContainer := networkResp{}
_, err := networkService.Session.PostJSON(reqURL, nil, nil, &createParameters, &nwContainer)
return nwContainer.Network, err
}
// DeleteNetwork will delete the specified network.
func (networkService Service) DeleteNetwork(name string) (err error) {
reqURL := networkService.URL + "/networks/" + name
_, err = networkService.Session.Delete(reqURL, nil, nil)
return err
}
type createNetworkValues struct {
Name string `json:"name"`
AdminStateUp bool `json:"admin_state_up"`
Shared bool `json:"shared"`
TenantID string `json:"tenant_id"`
}
type createNetworkValuesContainer struct {
Network createNetworkValues `json:"network"`
}
type networksResp struct {
Networks []Response `json:"networks"`
}
type networkResp struct {
Network Response `json:"network"`
}

107
network/v2/network_test.go Normal file
View File

@@ -0,0 +1,107 @@
// Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package network_test
import (
"encoding/json"
"errors"
"git.openstack.org/openstack/golang-client.git/network/v2"
"git.openstack.org/openstack/golang-client.git/testutil"
"net/http"
"testing"
)
var tokn = "eaaafd18-0fed-4b3a-81b4-663c99ec1cbb"
var subnets = []string{"10.3.5.2", "12.34.1.4"}
var sampleNetworkResponse = network.Response{
ID: "16470140hb",
Name: "networkName",
Status: "active",
Subnets: subnets,
TenantID: "tenantID",
RouterExternal: true,
AdminStateUp: false,
Shared: true,
PortSecurityEnabled: false}
func TestGetNetworks(t *testing.T) {
mockResponseObject := networksContainer{Networks: []network.Response{sampleNetworkResponse}}
apiServer := testUtil.CreateGetJSONTestRequestServerWithMockObject(t, tokn, mockResponseObject, "/networks")
defer apiServer.Close()
networkService := CreateNetworkService(apiServer.URL)
networks, err := networkService.Networks()
if err != nil {
t.Error(err)
}
if len(networks) != 1 {
t.Error(errors.New("Error: Expected 2 networks to be listed"))
}
testUtil.Equals(t, sampleNetworkResponse, networks[0])
}
func TestGetNetwork(t *testing.T) {
mockResponseObject := networkContainer{Network: sampleNetworkResponse}
apiServer := testUtil.CreateGetJSONTestRequestServerWithMockObject(t, tokn, mockResponseObject, "/networks/5270u2tg0")
defer apiServer.Close()
networkService := CreateNetworkService(apiServer.URL)
network, err := networkService.Network("5270u2tg0")
if err != nil {
t.Error(err)
}
testUtil.Equals(t, sampleNetworkResponse, network)
}
func TestDeleteNetwork(t *testing.T) {
name := "networkName"
apiServer := testUtil.CreateDeleteTestRequestServer(t, tokn, "/networks/"+name)
defer apiServer.Close()
networkService := CreateNetworkService(apiServer.URL)
err := networkService.DeleteNetwork(name)
if err != nil {
t.Error(err)
}
}
func TestCreateNetwork(t *testing.T) {
mockResponse, _ := json.Marshal(networkContainer{sampleNetworkResponse})
apiServer := testUtil.CreatePostJSONTestRequestServer(t, tokn, string(mockResponse), "/networks",
`{"network":{"name":"networkName","admin_state_up":false,"shared":true,"tenant_id":"tenantId"}}`)
defer apiServer.Close()
networkService := CreateNetworkService(apiServer.URL)
actualNetwork, err := networkService.CreateNetwork(false, "networkName", true)
if err != nil {
t.Error(err)
}
testUtil.Equals(t, sampleNetworkResponse, actualNetwork)
}
func CreateNetworkService(url string) network.Service {
return network.Service{TokenID: tokn, TenantID: "tenantId", Client: *http.DefaultClient, URL: url}
}
type networksContainer struct {
Networks []network.Response `json:"networks"`
}
type networkContainer struct {
Network network.Response `json:"network"`
}

109
network/v2/port.go Normal file
View File

@@ -0,0 +1,109 @@
// Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package network
import (
// "git.openstack.org/openstack/golang-client.git/openstack"
)
// PortResponse returns a set of values of the a port response.
type PortResponse struct {
ID string `json:"id"`
Name string `json:"name"`
Status string `json:"status"`
AdminStateUp bool `json:"admin_state_up"`
PortSecurityEnabled bool `json:"port_security_enabled"`
DeviceID string `json:"device_id"`
DeviceOwner string `json:"device_owner"`
NetworkID string `json:"network_id"`
TenantID string `json:"tenant_id"`
MacAddress string `json:"mac_address"`
FixedIPs []FixedIP `json:"fixed_ips"`
SecurityGroups []string `json:"security_groups"`
}
// CreatePortParameters holds a set of values that specify how
// to create a new port.
type CreatePortParameters struct {
AdminStateUp bool `json:"admin_state_up,omitempty"`
Name string `json:"name,omitempty"`
NetworkID string `json:"network_id"`
DeviceID string `json:"device_id,omitempty"`
MacAddress string `json:"mac_address,omitempty"`
FixedIPs []FixedIP `json:"fixed_ips,omitempty"`
SecurityGroups []string `json:"security_groups,omitempty"`
}
// PortResponses is a type for a slice of PortResponses.
type PortResponses []PortResponse
func (a PortResponses) Len() int { return len(a) }
func (a PortResponses) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a PortResponses) Less(i, j int) bool { return a[i].Name < a[j].Name }
// FixedIP is holds data that specifies a fixed IP.
type FixedIP struct {
SubnetID string `json:"subnet_id"`
IPAddress string `json:"ip_address,omitempty"`
}
// Ports issues a GET request that returns the found port responses
func (networkService Service) Ports() ([]PortResponse, error) {
reqURL := networkService.URL + "/ports"
var portResponse = portsResp{}
_, err := networkService.Session.GetJSON(reqURL, nil, nil, &portResponse)
if err != nil {
return nil, err
}
return portResponse.Ports, nil
}
// Port issues a GET request that returns a specific port response.
func (networkService Service) Port(id string) (PortResponse, error) {
reqURL := networkService.URL + "/ports/" + id
portResponse := portResp{}
_, err := networkService.Session.GetJSON(reqURL, nil, nil, &portResponse)
return portResponse.Port, err
}
// DeletePort issues a DELETE to the specified port url to delete it.
func (networkService Service) DeletePort(id string) error {
reqURL := networkService.URL + "/ports/" + id
_, err := networkService.Session.Delete(reqURL, nil, nil)
return err
}
// CreatePort issues a POST to create the specified port and return a PortResponse.
func (networkService Service) CreatePort(parameters CreatePortParameters) (PortResponse, error) {
reqURL := networkService.URL + "/ports"
parametersContainer := createPortContainer{Port: parameters}
portResponse := portResp{}
_, err := networkService.Session.PostJSON(reqURL, nil, nil, &parametersContainer, &portResponse)
return portResponse.Port, err
}
type portsResp struct {
Ports []PortResponse `json:"ports"`
}
type portResp struct {
Port PortResponse `json:"port"`
}
type createPortContainer struct {
Port CreatePortParameters `json:"port"`
}

104
network/v2/port_test.go Normal file
View File

@@ -0,0 +1,104 @@
// Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package network_test
import (
"encoding/json"
"errors"
"git.openstack.org/openstack/golang-client.git/network/v2"
"git.openstack.org/openstack/golang-client.git/testutil"
"testing"
)
var fixedIps = []network.FixedIP{network.FixedIP{SubnetID: "125071206726"}, network.FixedIP{SubnetID: "15615526", IPAddress: "132.145.15.11"}}
var samplePortResponse = network.PortResponse{
ID: "2490640zbg",
Name: "Port14",
Status: "active",
AdminStateUp: true,
PortSecurityEnabled: true,
DeviceID: "deviceid",
DeviceOwner: "deviceowner",
NetworkID: "networkid",
TenantID: "tenantid",
MacAddress: "macAddress",
FixedIPs: fixedIps,
SecurityGroups: []string{"sec1", "sec2"}}
func TestGetPorts(t *testing.T) {
mockResponseObject := portsContainer{Ports: []network.PortResponse{samplePortResponse}}
apiServer := testUtil.CreateGetJSONTestRequestServerWithMockObject(t, tokn, mockResponseObject, "/ports")
defer apiServer.Close()
networkService := CreateNetworkService(apiServer.URL)
ports, err := networkService.Ports()
if err != nil {
t.Error(err)
}
if len(ports) != 1 {
t.Error(errors.New("Error: Expected 2 networks to be listed"))
}
testUtil.Equals(t, samplePortResponse, ports[0])
}
func TestGetPort(t *testing.T) {
mockResponseObject := portContainer{Port: samplePortResponse}
apiServer := testUtil.CreateGetJSONTestRequestServerWithMockObject(t, tokn, mockResponseObject, "/ports/23507256")
defer apiServer.Close()
networkService := CreateNetworkService(apiServer.URL)
port, err := networkService.Port("23507256")
if err != nil {
t.Error(err)
}
testUtil.Equals(t, samplePortResponse, port)
}
func TestDeletePort(t *testing.T) {
portName := "portName"
apiServer := testUtil.CreateDeleteTestRequestServer(t, tokn, "/ports/"+portName)
defer apiServer.Close()
networkService := CreateNetworkService(apiServer.URL)
err := networkService.DeletePort(portName)
if err != nil {
t.Error(err)
}
}
func TestCreatePort(t *testing.T) {
mockResponse, _ := json.Marshal(portContainer{Port: samplePortResponse})
apiServer := testUtil.CreatePostJSONTestRequestServer(t, tokn, string(mockResponse), "/ports",
`{"port":{"admin_state_up":true,"name":"name","network_id":"networkid","fixed_ips":[{"subnet_id":"125071206726"},{"subnet_id":"15615526","ip_address":"132.145.15.11"}]}}`)
defer apiServer.Close()
networkService := CreateNetworkService(apiServer.URL)
createPortParameters := network.CreatePortParameters{AdminStateUp: true, Name: "name", NetworkID: "networkid", FixedIPs: fixedIps}
actualPort, err := networkService.CreatePort(createPortParameters)
if err != nil {
t.Error(err)
}
testUtil.Equals(t, samplePortResponse, actualPort)
}
type portsContainer struct {
Ports []network.PortResponse `json:"ports"`
}
type portContainer struct {
Port network.PortResponse `json:"port"`
}

106
network/v2/subnet.go Normal file
View File

@@ -0,0 +1,106 @@
// Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package network
import (
// "git.openstack.org/openstack/golang-client.git/openstack"
)
// SubnetResponse returns a set of values of the a Subnet response
type SubnetResponse struct {
ID string `json:"id"`
Name string `json:"name"`
NetworkID string `json:"network_id"`
TenantID string `json:"tenant_id"`
EnableDHCP bool `json:"enable_dhcp"`
DNSNameserver []string `json:"dns_nameservers"`
AllocationPools []AllocationPool `json:"allocation_pools"`
HostRoutes []string `json:"host_routes"`
IPVersion IPVersion `json:"ip_version"`
GatewayIP string `json:"gateway_ip"`
CIDR string `json:"cidr"`
}
// CreateSubnetParameters is a set of values to create a new subnet.
type CreateSubnetParameters struct {
NetworkID string `json:"network_id"`
IPVersion IPVersion `json:"ip_version"`
CIDR string `json:"cidr"`
AllocationPools []AllocationPool `json:"allocation_pools"`
}
// AllocationPool is a set of values for an allocation pool of ip addresses.
type AllocationPool struct {
Start string `json:"start"`
End string `json:"end"`
}
// IPVersion type indicates whether an ip address is IPV4 or IPV6.
type IPVersion int
const (
// IPV4 indicates its an ip address version 4.
IPV4 IPVersion = 4
// IPV6 indicates its an ip address version 6
IPV6 IPVersion = 6
)
// Subnets issues a GET request to return all subnets.
func (networkService Service) Subnets() ([]SubnetResponse, error) {
reqURL := networkService.URL + "/subnets"
var subnetResponse = subnetsResp{}
_, err := networkService.Session.GetJSON(reqURL, nil, nil, &subnetResponse)
return subnetResponse.Subnets, err
}
// Subnet issues a GET request to a specific url of a subnet and returns a subnet response.
func (networkService Service) Subnet(id string) (SubnetResponse, error) {
reqURL := networkService.URL + "/subnets/" + id
subnetResponse := subnetResp{}
_, err := networkService.Session.GetJSON(reqURL, nil, nil, &subnetResponse)
return subnetResponse.Subnet, err
}
// DeleteSubnet issues a DELETE request to remove the subnet.
func (networkService Service) DeleteSubnet(id string) error {
reqURL := networkService.URL + "/subnets/" + id
_, err := networkService.Session.Delete(reqURL, nil, nil)
return err
}
// CreateSubnet issues a GET request to add a Subnet with the specified parameters
// and returns the Subnet created.
func (networkService Service) CreateSubnet(parameters CreateSubnetParameters) (SubnetResponse, error) {
reqURL := networkService.URL + "/subnets"
parametersContainer := createSubnetContainer{Subnet: parameters}
subnetResponse := subnetResp{}
_, err := networkService.Session.PostJSON(reqURL, nil, nil, &parametersContainer, &subnetResponse)
return subnetResponse.Subnet, err
}
type subnetResp struct {
Subnet SubnetResponse `json:"subnet"`
}
type subnetsResp struct {
Subnets []SubnetResponse `json:"subnets"`
}
type createSubnetContainer struct {
Subnet CreateSubnetParameters `json:"subnet"`
}

107
network/v2/subnet_test.go Normal file
View File

@@ -0,0 +1,107 @@
// Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package network_test
import (
"encoding/json"
"errors"
"git.openstack.org/openstack/golang-client.git/network/v2"
"git.openstack.org/openstack/golang-client.git/testutil"
"testing"
)
var allocationPool1 = network.AllocationPool{Start: "13.14.14.15", End: "13.14.14.15"}
var allocationPools = []network.AllocationPool{allocationPool1}
var sampleSubNetResponse = network.SubnetResponse{
ID: "subnet",
Name: "name",
NetworkID: "networkid",
TenantID: "tenantid",
EnableDHCP: true,
DNSNameserver: []string{"13.14.14.15"},
AllocationPools: allocationPools,
HostRoutes: []string{"35.15.15.15"},
IPVersion: network.IPV4,
GatewayIP: "35.15.15.1",
CIDR: "35.15.15.3"}
func TestGetSubnets(t *testing.T) {
mockResponseObject := subnetsResp{Subnets: []network.SubnetResponse{sampleSubNetResponse}}
apiServer := testUtil.CreateGetJSONTestRequestServerWithMockObject(t, tokn, mockResponseObject, "/subnets")
defer apiServer.Close()
networkService := CreateNetworkService(apiServer.URL)
subnets, err := networkService.Subnets()
if err != nil {
t.Error(err)
}
if len(subnets) != 1 {
t.Error(errors.New("Error: Expected 1 subnet to be listed"))
}
testUtil.Equals(t, sampleSubNetResponse, subnets[0])
}
func TestGetSubnet(t *testing.T) {
mockResponseObject := subnetResp{Subnet: sampleSubNetResponse}
apiServer := testUtil.CreateGetJSONTestRequestServerWithMockObject(t, tokn, mockResponseObject, "/subnets/5270u2tg0")
defer apiServer.Close()
networkService := CreateNetworkService(apiServer.URL)
subnet, err := networkService.Subnet("5270u2tg0")
if err != nil {
t.Error(err)
}
testUtil.Equals(t, sampleSubNetResponse, subnet)
}
func TestDeleteSubnet(t *testing.T) {
name := "subnetName"
apiServer := testUtil.CreateDeleteTestRequestServer(t, tokn, "/subnets/"+name)
defer apiServer.Close()
networkService := CreateNetworkService(apiServer.URL)
err := networkService.DeleteSubnet(name)
if err != nil {
t.Error(err)
}
}
func TestCreateSubnet(t *testing.T) {
mockResponse, err := json.Marshal(subnetResp{Subnet: sampleSubNetResponse})
apiServer := testUtil.CreatePostJSONTestRequestServer(t, tokn, string(mockResponse), "/subnets",
`{"subnet":{"network_id":"subnetid","ip_version":4,"cidr":"12.14.76.87","allocation_pools":[{"start":"13.14.14.15","end":"13.14.14.15"}]}}`)
defer apiServer.Close()
networkService := CreateNetworkService(apiServer.URL)
createSubnetParameters := network.CreateSubnetParameters{NetworkID: "subnetid", AllocationPools: allocationPools, CIDR: "12.14.76.87", IPVersion: 4}
actualPort, err := networkService.CreateSubnet(createSubnetParameters)
if err != nil {
t.Error(err)
}
testUtil.Equals(t, sampleSubNetResponse, actualPort)
}
type subnetsResp struct {
Subnets []network.SubnetResponse `json:"subnets"`
}
type subnetResp struct {
Subnet network.SubnetResponse `json:"subnet"`
}

View File

@@ -16,6 +16,7 @@
package testUtil package testUtil
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
@@ -101,6 +102,22 @@ func CreateGetJSONTestRequestServer(t *testing.T, expectedAuthTokenValue string,
})) }))
} }
// CreateGetJSONTestRequestServerWithMockObject a http.Server that can be used to test PostJson requests. Specify the token,
// response object which will be marshaled to a json payload and the expected ending url.
func CreateGetJSONTestRequestServerWithMockObject(t *testing.T, token string, mockResponseObject interface{}, urlEndsWith string) *httptest.Server {
mockResponse, err := json.Marshal(mockResponseObject)
if err != nil {
t.Error("Test failed to marshal mockResponseObject:", err)
}
anon := func(req *http.Request) {
reqURL := req.URL.String()
if !strings.HasSuffix(reqURL, urlEndsWith) {
t.Error(errors.New("Incorrect url created, expected:" + urlEndsWith + " at the end, actual url:" + reqURL))
}
}
return CreateGetJSONTestRequestServer(t, token, string(mockResponse), anon)
}
// CreatePostJSONTestRequestServer creates a http.Server that can be used to test PostJson requests. Specify the token, // CreatePostJSONTestRequestServer creates a http.Server that can be used to test PostJson requests. Specify the token,
// response json payload and the url and request body that is expected. // response json payload and the url and request body that is expected.
func CreatePostJSONTestRequestServer(t *testing.T, expectedAuthTokenValue string, outputResponseJSONPayload string, expectedRequestURLEndsWith string, expectedRequestBody string) *httptest.Server { func CreatePostJSONTestRequestServer(t *testing.T, expectedAuthTokenValue string, outputResponseJSONPayload string, expectedRequestURLEndsWith string, expectedRequestBody string) *httptest.Server {