Skip to content

Commit f05feab

Browse files
ozerovandreijtopjian
authored andcommitted
Add Neutron subnetpool creation support (#702)
* Add Neutron subnetpool creation support Add support to create a Neutron subnetpool through a POST request on /v2.0/subnetpools. The same command with OpenStack CLI is done with: openstack subnet pool create or neutron subnetpool-create * Add acceptance test for the subnetpool creation Add the TestCreateSubnetPool acceptance test and a generic CreateSubnetPool function inside the acceptance tests for sharing with other components. * Rename TestCreateSubnetPool to TestSubnetPoolsCRUD * Fix Subnetpools CreateOpts comments Fix DefaultPrefixLen comment and remove empty line at the beginning of a struct.
1 parent 2f0d338 commit f05feab

8 files changed

Lines changed: 231 additions & 0 deletions

File tree

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package v2
2+
3+
import (
4+
"testing"
5+
6+
"github.com/gophercloud/gophercloud"
7+
"github.com/gophercloud/gophercloud/acceptance/tools"
8+
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/subnetpools"
9+
)
10+
11+
// CreateSubnetPool will create a subnetpool. An error will be returned if the
12+
// subnetpool could not be created.
13+
func CreateSubnetPool(t *testing.T, client *gophercloud.ServiceClient) (*subnetpools.SubnetPool, error) {
14+
subnetPoolName := tools.RandomString("TESTACC-", 8)
15+
subnetPoolPrefixes := []string{
16+
"10.0.0.0/8",
17+
}
18+
createOpts := subnetpools.CreateOpts{
19+
Name: subnetPoolName,
20+
Prefixes: subnetPoolPrefixes,
21+
}
22+
23+
t.Logf("Attempting to create a subnetpool: %s", subnetPoolName)
24+
25+
subnetPool, err := subnetpools.Create(client, createOpts).Extract()
26+
if err != nil {
27+
return nil, err
28+
}
29+
30+
t.Logf("Successfully created the subnetpool.")
31+
return subnetPool, nil
32+
}

acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@ import (
1010
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/subnetpools"
1111
)
1212

13+
func TestSubnetPoolsCRUD(t *testing.T) {
14+
client, err := clients.NewNetworkV2Client()
15+
if err != nil {
16+
t.Fatalf("Unable to create a network client: %v", err)
17+
}
18+
19+
// Create a subnetpool
20+
subnetPool, err := CreateSubnetPool(t, client)
21+
if err != nil {
22+
t.Fatalf("Unable to create a subnetpool: %v", err)
23+
}
24+
25+
tools.PrintResource(t, subnetPool)
26+
}
27+
1328
func TestSubnetPoolsList(t *testing.T) {
1429
client, err := clients.NewNetworkV2Client()
1530
if err != nil {

openstack/networking/v2/extensions/subnetpools/doc.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,22 @@ Example to Get a Subnetpool
2828
if err != nil {
2929
panic(err)
3030
}
31+
32+
Example to Create a new Subnetpool.
33+
34+
subnetPoolName := "private_pool"
35+
subnetPoolPrefixes := []string{
36+
"10.0.0.0/8",
37+
"172.16.0.0/12",
38+
"192.168.0.0/16",
39+
}
40+
subnetPoolOpts := subnetpools.CreateOpts{
41+
Name: subnetPoolName,
42+
Prefixes: subnetPoolPrefixes,
43+
}
44+
subnetPool, err := subnetpools.Create(networkClient, subnetPoolOpts).Extract()
45+
if err != nil {
46+
panic(err)
47+
}
3148
*/
3249
package subnetpools

openstack/networking/v2/extensions/subnetpools/requests.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,76 @@ func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
7272
_, r.Err = c.Get(getURL(c, id), &r.Body, nil)
7373
return
7474
}
75+
76+
// CreateOptsBuilder allows to add additional parameters to the
77+
// Create request.
78+
type CreateOptsBuilder interface {
79+
ToSubnetPoolCreateMap() (map[string]interface{}, error)
80+
}
81+
82+
// CreateOpts specifies parameters of a new subnetpool.
83+
type CreateOpts struct {
84+
// Name is the human-readable name of the subnetpool.
85+
Name string `json:"name"`
86+
87+
// DefaultQuota is the per-project quota on the prefix space
88+
// that can be allocated from the subnetpool for project subnets.
89+
DefaultQuota int `json:"default_quota,omitempty"`
90+
91+
// TenantID is the id of the Identity project.
92+
TenantID string `json:"tenant_id,omitempty"`
93+
94+
// ProjectID is the id of the Identity project.
95+
ProjectID string `json:"project_id,omitempty"`
96+
97+
// Prefixes is the list of subnet prefixes to assign to the subnetpool.
98+
// Neutron API merges adjacent prefixes and treats them as a single prefix.
99+
// Each subnet prefix must be unique among all subnet prefixes in all subnetpools
100+
// that are associated with the address scope.
101+
Prefixes []string `json:"prefixes"`
102+
103+
// DefaultPrefixLen is the size of the prefix to allocate when the cidr
104+
// or prefixlen attributes are omitted when you create the subnet.
105+
// Defaults to the MinPrefixLen.
106+
DefaultPrefixLen int `json:"default_prefixlen,omitempty"`
107+
108+
// MinPrefixLen is the smallest prefix that can be allocated from a subnetpool.
109+
// For IPv4 subnetpools, default is 8.
110+
// For IPv6 subnetpools, default is 64.
111+
MinPrefixLen int `json:"min_prefixlen,omitempty"`
112+
113+
// MaxPrefixLen is the maximum prefix size that can be allocated from the subnetpool.
114+
// For IPv4 subnetpools, default is 32.
115+
// For IPv6 subnetpools, default is 128.
116+
MaxPrefixLen int `json:"max_prefixlen,omitempty"`
117+
118+
// AddressScopeID is the Neutron address scope to assign to the subnetpool.
119+
AddressScopeID string `json:"address_scope_id,omitempty"`
120+
121+
// Shared indicates whether this network is shared across all projects.
122+
Shared bool `json:"shared,omitempty"`
123+
124+
// Description is the human-readable description for the resource.
125+
Description string `json:"description,omitempty"`
126+
127+
// IsDefault indicates if the subnetpool is default pool or not.
128+
IsDefault bool `json:"is_default,omitempty"`
129+
}
130+
131+
// ToSubnetPoolCreateMap constructs a request body from CreateOpts.
132+
func (opts CreateOpts) ToSubnetPoolCreateMap() (map[string]interface{}, error) {
133+
return gophercloud.BuildRequestBody(opts, "subnetpool")
134+
}
135+
136+
// Create requests the creation of a new subnetpool on the server.
137+
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
138+
b, err := opts.ToSubnetPoolCreateMap()
139+
if err != nil {
140+
r.Err = err
141+
return
142+
}
143+
_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
144+
OkCodes: []int{201},
145+
})
146+
return
147+
}

openstack/networking/v2/extensions/subnetpools/results.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ type GetResult struct {
2828
commonResult
2929
}
3030

31+
// CreateResult represents the result of a create operation. Call its Extract
32+
// method to interpret it as a SubnetPool.
33+
type CreateResult struct {
34+
commonResult
35+
}
36+
3137
// SubnetPool represents a Neutron subnetpool.
3238
// A subnetpool is a pool of addresses from which subnets can be allocated.
3339
type SubnetPool struct {

openstack/networking/v2/extensions/subnetpools/testing/fixtures.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,46 @@ const SubnetPoolGetResult = `
169169
}
170170
}
171171
`
172+
173+
const SubnetPoolCreateRequest = `
174+
{
175+
"subnetpool": {
176+
"name": "my_ipv4_pool",
177+
"prefixes": [
178+
"10.10.0.0/16",
179+
"10.11.11.0/24"
180+
],
181+
"address_scope_id": "3d4e2e2a-552b-42ad-a16d-820bbf3edaf3",
182+
"min_prefixlen": 25,
183+
"max_prefixlen": 30,
184+
"description": "ipv4 prefixes"
185+
}
186+
}
187+
`
188+
189+
const SubnetPoolCreateResult = `
190+
{
191+
"subnetpool": {
192+
"address_scope_id": "3d4e2e2a-552b-42ad-a16d-820bbf3edaf3",
193+
"created_at": "2018-01-01T00:00:15Z",
194+
"default_prefixlen": "25",
195+
"default_quota": null,
196+
"description": "ipv4 prefixes",
197+
"id": "55b5999c-c2fe-42cd-bce0-961a551b80f5",
198+
"ip_version": 4,
199+
"is_default": false,
200+
"max_prefixlen": "30",
201+
"min_prefixlen": "25",
202+
"name": "my_ipv4_pool",
203+
"prefixes": [
204+
"10.10.0.0/16",
205+
"10.11.11.0/24"
206+
],
207+
"project_id": "1e2b9857295a4a3e841809ef492812c5",
208+
"revision_number": 1,
209+
"shared": false,
210+
"tenant_id": "1e2b9857295a4a3e841809ef492812c5",
211+
"updated_at": "2018-01-01T00:00:15Z"
212+
}
213+
}
214+
`

openstack/networking/v2/extensions/subnetpools/testing/requests_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,44 @@ func TestGet(t *testing.T) {
8888
th.AssertEquals(t, s.IsDefault, true)
8989
th.AssertEquals(t, s.RevisionNumber, 2)
9090
}
91+
func TestCreate(t *testing.T) {
92+
th.SetupHTTP()
93+
defer th.TeardownHTTP()
94+
95+
th.Mux.HandleFunc("/v2.0/subnetpools", func(w http.ResponseWriter, r *http.Request) {
96+
th.TestMethod(t, r, "POST")
97+
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
98+
th.TestHeader(t, r, "Content-Type", "application/json")
99+
th.TestHeader(t, r, "Accept", "application/json")
100+
th.TestJSONRequest(t, r, SubnetPoolCreateRequest)
101+
102+
w.Header().Add("Content-Type", "application/json")
103+
w.WriteHeader(http.StatusCreated)
104+
105+
fmt.Fprintf(w, SubnetPoolCreateResult)
106+
})
107+
108+
opts := subnetpools.CreateOpts{
109+
Name: "my_ipv4_pool",
110+
Prefixes: []string{
111+
"10.10.0.0/16",
112+
"10.11.11.0/24",
113+
},
114+
MinPrefixLen: 25,
115+
MaxPrefixLen: 30,
116+
AddressScopeID: "3d4e2e2a-552b-42ad-a16d-820bbf3edaf3",
117+
Description: "ipv4 prefixes",
118+
}
119+
s, err := subnetpools.Create(fake.ServiceClient(), opts).Extract()
120+
th.AssertNoErr(t, err)
121+
122+
th.AssertEquals(t, s.Name, "my_ipv4_pool")
123+
th.AssertDeepEquals(t, s.Prefixes, []string{
124+
"10.10.0.0/16",
125+
"10.11.11.0/24",
126+
})
127+
th.AssertEquals(t, s.MinPrefixLen, 25)
128+
th.AssertEquals(t, s.MaxPrefixLen, 30)
129+
th.AssertEquals(t, s.AddressScopeID, "3d4e2e2a-552b-42ad-a16d-820bbf3edaf3")
130+
th.AssertEquals(t, s.Description, "ipv4 prefixes")
131+
}

openstack/networking/v2/extensions/subnetpools/urls.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,7 @@ func listURL(c *gophercloud.ServiceClient) string {
1919
func getURL(c *gophercloud.ServiceClient, id string) string {
2020
return resourceURL(c, id)
2121
}
22+
23+
func createURL(c *gophercloud.ServiceClient) string {
24+
return rootURL(c)
25+
}

0 commit comments

Comments
 (0)