Skip to content

Commit b1cbc1e

Browse files
committed
Baremetal API V1: Allocations
1 parent 2e9e550 commit b1cbc1e

File tree

9 files changed

+630
-0
lines changed

9 files changed

+630
-0
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// +build acceptance baremetal allocations
2+
3+
package noauth
4+
5+
import (
6+
"testing"
7+
8+
"github.com/gophercloud/gophercloud/acceptance/clients"
9+
v1 "github.com/gophercloud/gophercloud/acceptance/openstack/baremetal/v1"
10+
"github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations"
11+
"github.com/gophercloud/gophercloud/pagination"
12+
th "github.com/gophercloud/gophercloud/testhelper"
13+
)
14+
15+
func TestAllocationsCreateDestroy(t *testing.T) {
16+
clients.RequireLong(t)
17+
18+
client, err := clients.NewBareMetalV1NoAuthClient()
19+
th.AssertNoErr(t, err)
20+
21+
client.Microversion = "1.52"
22+
23+
allocation, err := v1.CreateAllocation(t, client)
24+
th.AssertNoErr(t, err)
25+
defer v1.DeleteAllocation(t, client, allocation)
26+
27+
found := false
28+
err = allocations.List(client, allocations.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
29+
allocationList, err := allocations.ExtractAllocations(page)
30+
if err != nil {
31+
return false, err
32+
}
33+
34+
for _, a := range allocationList {
35+
if a.UUID == allocation.UUID {
36+
found = true
37+
return true, nil
38+
}
39+
}
40+
41+
return false, nil
42+
})
43+
th.AssertNoErr(t, err)
44+
th.AssertEquals(t, found, true)
45+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// +build acceptance baremetal allocations
2+
3+
package v1
4+
5+
import (
6+
"testing"
7+
8+
"github.com/gophercloud/gophercloud/acceptance/clients"
9+
"github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations"
10+
"github.com/gophercloud/gophercloud/pagination"
11+
th "github.com/gophercloud/gophercloud/testhelper"
12+
)
13+
14+
func TestAllocationsCreateDestroy(t *testing.T) {
15+
clients.RequireLong(t)
16+
17+
client, err := clients.NewBareMetalV1Client()
18+
th.AssertNoErr(t, err)
19+
20+
client.Microversion = "1.52"
21+
22+
allocation, err := CreateAllocation(t, client)
23+
th.AssertNoErr(t, err)
24+
defer DeleteAllocation(t, client, allocation)
25+
26+
found := false
27+
err = allocations.List(client, allocations.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
28+
allocationList, err := allocations.ExtractAllocations(page)
29+
if err != nil {
30+
return false, err
31+
}
32+
33+
for _, a := range allocationList {
34+
if a.UUID == allocation.UUID {
35+
found = true
36+
return true, nil
37+
}
38+
}
39+
40+
return false, nil
41+
})
42+
th.AssertNoErr(t, err)
43+
th.AssertEquals(t, found, true)
44+
}

acceptance/openstack/baremetal/v1/baremetal.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/gophercloud/gophercloud"
77
"github.com/gophercloud/gophercloud/acceptance/tools"
8+
"github.com/gophercloud/gophercloud/openstack/baremetal/v1/allocations"
89
"github.com/gophercloud/gophercloud/openstack/baremetal/v1/nodes"
910
"github.com/gophercloud/gophercloud/openstack/baremetal/v1/ports"
1011
)
@@ -41,6 +42,29 @@ func DeleteNode(t *testing.T, client *gophercloud.ServiceClient, node *nodes.Nod
4142
t.Logf("Deleted server: %s", node.UUID)
4243
}
4344

45+
// CreateAllocation creates an allocation
46+
func CreateAllocation(t *testing.T, client *gophercloud.ServiceClient) (*allocations.Allocation, error) {
47+
name := tools.RandomString("ACPTTEST", 16)
48+
t.Logf("Attempting to create bare metal allocation: %s", name)
49+
50+
allocation, err := allocations.Create(client, allocations.CreateOpts{
51+
Name: name,
52+
ResourceClass: "baremetal",
53+
}).Extract()
54+
55+
return allocation, err
56+
}
57+
58+
// DeleteAllocation deletes a bare metal allocation via its UUID.
59+
func DeleteAllocation(t *testing.T, client *gophercloud.ServiceClient, allocation *allocations.Allocation) {
60+
err := allocations.Delete(client, allocation.UUID).ExtractErr()
61+
if err != nil {
62+
t.Fatalf("Unable to delete allocation %s: %s", allocation.UUID, err)
63+
}
64+
65+
t.Logf("Deleted allocation: %s", allocation.UUID)
66+
}
67+
4468
// CreateFakeNode creates a node with fake-hardware to use for port tests.
4569
func CreateFakeNode(t *testing.T, client *gophercloud.ServiceClient) (*nodes.Node, error) {
4670
name := tools.RandomString("ACPTTEST", 16)

acceptance/openstack/baremetal/v1/nodes_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// +build acceptance baremetal nodes
2+
13
package v1
24

35
import (
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package allocations
2+
3+
import (
4+
"github.com/gophercloud/gophercloud"
5+
"github.com/gophercloud/gophercloud/pagination"
6+
)
7+
8+
// CreateOptsBuilder allows extensions to add additional parameters to the
9+
// Create request.
10+
type CreateOptsBuilder interface {
11+
ToAllocationCreateMap() (map[string]interface{}, error)
12+
}
13+
14+
// CreateOpts specifies allocation creation parameters
15+
type CreateOpts struct {
16+
// The requested resource class for the allocation.
17+
ResourceClass string `json:"resource_class" required:"true"`
18+
19+
// The list of nodes (names or UUIDs) that should be considered for this allocation. If not provided, all available nodes will be considered.
20+
CandidateNodes []string `json:"candidate_nodes,omitempty"`
21+
22+
// The unique name of the Allocation.
23+
Name string `json:"name,omitempty"`
24+
25+
// The list of requested traits for the allocation.
26+
Traits []string `json:"traits,omitempty"`
27+
28+
// The UUID for the resource.
29+
UUID string `json:"uuid,omitempty"`
30+
31+
// A set of one or more arbitrary metadata key and value pairs.
32+
Extra map[string]string `json:"extra,omitempty"`
33+
}
34+
35+
// ToAllocationCreateMap assembles a request body based on the contents of a CreateOpts.
36+
func (opts CreateOpts) ToAllocationCreateMap() (map[string]interface{}, error) {
37+
body, err := gophercloud.BuildRequestBody(opts, "")
38+
if err != nil {
39+
return nil, err
40+
}
41+
42+
return body, nil
43+
}
44+
45+
// Create requests a node to be created
46+
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
47+
reqBody, err := opts.ToAllocationCreateMap()
48+
if err != nil {
49+
r.Err = err
50+
return
51+
}
52+
53+
_, r.Err = client.Post(createURL(client), reqBody, &r.Body, nil)
54+
return
55+
}
56+
57+
type AllocationState string
58+
59+
var (
60+
Allocating AllocationState = "allocating"
61+
Active = "active"
62+
Error = "error"
63+
)
64+
65+
// ListOptsBuilder allows extensions to add additional parameters to the List request.
66+
type ListOptsBuilder interface {
67+
ToAllocationListQuery() (string, error)
68+
}
69+
70+
// ListOpts allows the filtering and sorting of paginated collections through the API.
71+
type ListOpts struct {
72+
// Filter the list of allocations by the node UUID or name.
73+
Node string `q:"node"`
74+
75+
// Filter the list of returned nodes, and only return the ones with the specified resource class.
76+
ResourceClass string `q:"resource_class"`
77+
78+
// Filter the list of allocations by the allocation state, one of active, allocating or error.
79+
State AllocationState `q:"state"`
80+
81+
// One or more fields to be returned in the response.
82+
Fields []string `q:"fields"`
83+
84+
// Requests a page size of items.
85+
Limit int `q:"limit"`
86+
87+
// The ID of the last-seen item
88+
Marker string `q:"marker"`
89+
90+
// Sorts the response by the requested sort direction.
91+
// Valid value is asc (ascending) or desc (descending). Default is asc.
92+
SortDir string `q:"sort_dir"`
93+
94+
// Sorts the response by the this attribute value. Default is id.
95+
SortKey string `q:"sort_key"`
96+
}
97+
98+
// ToAllocationListQuery formats a ListOpts into a query string.
99+
func (opts ListOpts) ToAllocationListQuery() (string, error) {
100+
q, err := gophercloud.BuildQueryString(opts)
101+
return q.String(), err
102+
}
103+
104+
// List makes a request against the API to list allocations accessible to you.
105+
func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
106+
url := listURL(client)
107+
if opts != nil {
108+
query, err := opts.ToAllocationListQuery()
109+
if err != nil {
110+
return pagination.Pager{Err: err}
111+
}
112+
url += query
113+
}
114+
return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page {
115+
return AllocationPage{pagination.LinkedPageBase{PageResult: r}}
116+
})
117+
}
118+
119+
// Get requests the details of an allocation by ID.
120+
func Get(client *gophercloud.ServiceClient, id string) (r GetResult) {
121+
_, r.Err = client.Get(getURL(client, id), &r.Body, &gophercloud.RequestOpts{
122+
OkCodes: []int{200},
123+
})
124+
return
125+
}
126+
127+
// Delete requests the deletion of an allocation
128+
func Delete(client *gophercloud.ServiceClient, id string) (r DeleteResult) {
129+
_, r.Err = client.Delete(deleteURL(client, id), nil)
130+
return
131+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package allocations
2+
3+
import (
4+
"time"
5+
6+
"github.com/gophercloud/gophercloud"
7+
"github.com/gophercloud/gophercloud/pagination"
8+
)
9+
10+
type Allocation struct {
11+
// The UUID for the resource.
12+
UUID string `json:"uuid"`
13+
14+
// A list of UUIDs of the nodes that are candidates for this allocation.
15+
CandidateNodes []string `json:"candidate_nodes"`
16+
17+
// The error message for the allocation if it is in the error state, null otherwise.
18+
LastError string `json:"last_error"`
19+
20+
// The unique name of the allocation.
21+
Name string `json:"name"`
22+
23+
// The UUID of the node assigned to the allocation. Will be null if a node is not yet assigned.
24+
NodeUUID string `json:"node_uuid"`
25+
26+
// The current state of the allocation. One of: allocation, active, error
27+
State string `json:"state"`
28+
29+
// The resource class requested for the allocation.
30+
ResourceClass string `json:"resource_class"`
31+
32+
// The list of the traits requested for the allocation.
33+
Traits []string `json:"traits"`
34+
35+
// A set of one or more arbitrary metadata key and value pairs.
36+
Extra map[string]string `json:"extra"`
37+
38+
// The UTC date and time when the resource was created, ISO 8601 format.
39+
CreatedAt time.Time `json:"created_at"`
40+
41+
// The UTC date and time when the resource was updated, ISO 8601 format. May be “null”.
42+
UpdatedAt time.Time `json:"updated_at"`
43+
44+
// A list of relative links. Includes the self and bookmark links.
45+
Links []interface{} `json:"links"`
46+
}
47+
48+
type allocationResult struct {
49+
gophercloud.Result
50+
}
51+
52+
func (r allocationResult) Extract() (*Allocation, error) {
53+
var s Allocation
54+
err := r.ExtractInto(&s)
55+
return &s, err
56+
}
57+
58+
func (r allocationResult) ExtractInto(v interface{}) error {
59+
return r.Result.ExtractIntoStructPtr(v, "")
60+
}
61+
62+
func ExtractAllocationsInto(r pagination.Page, v interface{}) error {
63+
return r.(AllocationPage).Result.ExtractIntoSlicePtr(v, "allocations")
64+
}
65+
66+
// AllocationPage abstracts the raw results of making a List() request against
67+
// the API.
68+
type AllocationPage struct {
69+
pagination.LinkedPageBase
70+
}
71+
72+
// IsEmpty returns true if a page contains no Allocation results.
73+
func (r AllocationPage) IsEmpty() (bool, error) {
74+
s, err := ExtractAllocations(r)
75+
return len(s) == 0, err
76+
}
77+
78+
// NextPageURL uses the response's embedded link reference to navigate to the
79+
// next page of results.
80+
func (r AllocationPage) NextPageURL() (string, error) {
81+
var s struct {
82+
Links []gophercloud.Link `json:"allocations_links"`
83+
}
84+
err := r.ExtractInto(&s)
85+
if err != nil {
86+
return "", err
87+
}
88+
return gophercloud.ExtractNextURL(s.Links)
89+
}
90+
91+
// ExtractAllocations interprets the results of a single page from a List() call,
92+
// producing a slice of Allocation entities.
93+
func ExtractAllocations(r pagination.Page) ([]Allocation, error) {
94+
var s []Allocation
95+
err := ExtractAllocationsInto(r, &s)
96+
return s, err
97+
}
98+
99+
// GetResult is the response from a Get operation. Call its Extract
100+
// method to interpret it as a Allocation.
101+
type GetResult struct {
102+
allocationResult
103+
}
104+
105+
// CreateResult is the response from a Create operation.
106+
type CreateResult struct {
107+
allocationResult
108+
}
109+
110+
// DeleteResult is the response from a Delete operation. Call its ExtractErr
111+
// method to determine if the call succeeded or failed.
112+
type DeleteResult struct {
113+
gophercloud.ErrResult
114+
}

0 commit comments

Comments
 (0)