@@ -19,8 +19,10 @@ package openstack
1919
2020import (
2121 "context"
22+ "fmt"
2223
2324 "github.com/gophercloud/gophercloud/v2"
25+ "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceproviders"
2426)
2527
2628// UpdateTraitsResult is the response of a Put traits operations. Call its Extract method
@@ -67,3 +69,93 @@ func UpdateTraits(ctx context.Context, client *gophercloud.ServiceClient, resour
6769 _ , r .Header , r .Err = gophercloud .ParseResponse (resp , err )
6870 return
6971}
72+
73+ func getAllocationsURL (client * gophercloud.ServiceClient , consumerID string ) string {
74+ return client .ServiceURL ("allocations" , consumerID )
75+ }
76+
77+ // ListAllocationsResult is the response of a Get allocations operations. Call its Extract method
78+ // to interpret it as a Allocations.
79+ type ListAllocationsResult struct {
80+ gophercloud.Result
81+ }
82+
83+ type ConsumerAllocations struct {
84+ Allocations map [string ]resourceproviders.Allocation `json:"allocations"`
85+ ConsumerGeneration int `json:"consumer_generation"`
86+ ProjectID string `json:"project_id"`
87+ UserID string `json:"user_id"`
88+ ConsumerType string `json:"consumer_type"`
89+ }
90+
91+ // Extract interprets a ListAllocationsResult as a Allocations.
92+ func (r ListAllocationsResult ) Extract () (* ConsumerAllocations , error ) {
93+ var s ConsumerAllocations
94+ err := r .ExtractInto (& s )
95+ return & s , err
96+ }
97+
98+ // List Allocations for a certain consumer
99+ func ListAllocations (ctx context.Context , client * gophercloud.ServiceClient , consumerID string ) (r ListAllocationsResult ) {
100+ resp , err := client .Get (ctx , getAllocationsURL (client , consumerID ), nil , & gophercloud.RequestOpts {
101+ OkCodes : []int {200 },
102+ })
103+ if err != nil {
104+ r .Err = err
105+ return
106+ }
107+
108+ _ , r .Header , r .Err = gophercloud .ParseResponse (resp , err )
109+ return
110+ }
111+
112+ // Delete all Allocations for a certain consumer
113+ func DeleteConsumerAllocations (ctx context.Context , client * gophercloud.ServiceClient , consumerID string ) (r ListAllocationsResult ) {
114+ resp , err := client .Delete (ctx , getAllocationsURL (client , consumerID ), & gophercloud.RequestOpts {
115+ OkCodes : []int {204 , 404 },
116+ })
117+ if err != nil {
118+ r .Err = err
119+ return
120+ }
121+
122+ _ , r .Header , r .Err = gophercloud .ParseResponse (resp , err )
123+ return
124+ }
125+
126+ // Remove all empty Allocations for a certain provider, and if it is empty, delete it
127+ func CleanupResourceProvider (ctx context.Context , client * gophercloud.ServiceClient , provider * resourceproviders.ResourceProvider ) error {
128+ if provider == nil {
129+ return nil
130+ }
131+ result := resourceproviders .GetAllocations (ctx , client , provider .UUID )
132+ providerAllocations , err := result .Extract ()
133+ if err != nil {
134+ return err
135+ }
136+ if providerAllocations == nil {
137+ return nil
138+ }
139+ allocations := len (providerAllocations .Allocations )
140+ for consumerID := range providerAllocations .Allocations {
141+ result := ListAllocations (ctx , client , consumerID )
142+ consumerAllocations , err := result .Extract ()
143+ if err != nil {
144+ return err
145+ }
146+ if len (consumerAllocations .Allocations ) == 0 {
147+ DeleteConsumerAllocations (ctx , client , consumerID )
148+ allocations -= 1
149+ continue
150+ }
151+ return fmt .Errorf ("cannot clean up provider, still has some allocation" )
152+ }
153+
154+ if allocations == 0 {
155+ result := resourceproviders .Delete (ctx , client , provider .UUID )
156+ if result .Err != nil {
157+ return result .Err
158+ }
159+ }
160+ return nil
161+ }
0 commit comments