Skip to content

Commit 3c8c43f

Browse files
committed
Moved aggregate functions to openstack module
1 parent a3c5486 commit 3c8c43f

File tree

4 files changed

+117
-89
lines changed

4 files changed

+117
-89
lines changed

internal/controller/aggregates_controller.go

Lines changed: 3 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import (
3232
logger "sigs.k8s.io/controller-runtime/pkg/log"
3333

3434
"github.com/gophercloud/gophercloud/v2"
35-
"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/aggregates"
3635

3736
kvmv1 "github.com/cobaltcore-dev/openstack-hypervisor-operator/api/v1"
3837
"github.com/cobaltcore-dev/openstack-hypervisor-operator/internal/openstack"
@@ -70,7 +69,7 @@ func (ac *AggregatesController) Reconcile(ctx context.Context, req ctrl.Request)
7069
return ctrl.Result{}, nil
7170
}
7271

73-
aggs, err := aggregatesByName(ctx, ac.computeClient)
72+
aggs, err := openstack.GetAggregatesByName(ctx, ac.computeClient)
7473
if err != nil {
7574
err = fmt.Errorf("failed listing aggregates: %w", err)
7675
if err2 := ac.setErrorCondition(ctx, hv, err.Error()); err2 != nil {
@@ -91,7 +90,7 @@ func (ac *AggregatesController) Reconcile(ctx context.Context, req ctrl.Request)
9190
if len(toAdd) > 0 {
9291
log.Info("Adding", "aggregates", toAdd)
9392
for item := range slices.Values(toAdd) {
94-
if err = addToAggregate(ctx, ac.computeClient, aggs, hv.Name, item, ""); err != nil {
93+
if err = openstack.AddToAggregate(ctx, ac.computeClient, aggs, hv.Name, item, ""); err != nil {
9594
errs = append(errs, err)
9695
}
9796
}
@@ -100,7 +99,7 @@ func (ac *AggregatesController) Reconcile(ctx context.Context, req ctrl.Request)
10099
if len(toRemove) > 0 {
101100
log.Info("Removing", "aggregates", toRemove)
102101
for item := range slices.Values(toRemove) {
103-
if err = removeFromAggregate(ctx, ac.computeClient, aggs, hv.Name, item); err != nil {
102+
if err = openstack.RemoveFromAggregate(ctx, ac.computeClient, aggs, hv.Name, item); err != nil {
104103
errs = append(errs, err)
105104
}
106105
}
@@ -162,81 +161,3 @@ func (ac *AggregatesController) SetupWithManager(mgr ctrl.Manager) error {
162161
For(&kvmv1.Hypervisor{}, builder.WithPredicates(utils.LifecycleEnabledPredicate)).
163162
Complete(ac)
164163
}
165-
166-
func aggregatesByName(ctx context.Context, serviceClient *gophercloud.ServiceClient) (map[string]*aggregates.Aggregate, error) {
167-
pages, err := aggregates.List(serviceClient).AllPages(ctx)
168-
if err != nil {
169-
return nil, fmt.Errorf("cannot list aggregates due to %w", err)
170-
}
171-
172-
aggs, err := aggregates.ExtractAggregates(pages)
173-
if err != nil {
174-
return nil, fmt.Errorf("cannot list aggregates due to %w", err)
175-
}
176-
177-
aggregateMap := make(map[string]*aggregates.Aggregate, len(aggs))
178-
for _, aggregate := range aggs {
179-
aggregateMap[aggregate.Name] = &aggregate
180-
}
181-
return aggregateMap, nil
182-
}
183-
184-
func addToAggregate(ctx context.Context, serviceClient *gophercloud.ServiceClient, aggs map[string]*aggregates.Aggregate, host, name, zone string) (err error) {
185-
aggregate, found := aggs[name]
186-
log := logger.FromContext(ctx)
187-
if !found {
188-
aggregate, err = aggregates.Create(ctx, serviceClient,
189-
aggregates.CreateOpts{
190-
Name: name,
191-
AvailabilityZone: zone,
192-
}).Extract()
193-
if err != nil {
194-
return fmt.Errorf("failed to create aggregate %v due to %w", name, err)
195-
}
196-
aggs[name] = aggregate
197-
}
198-
199-
if slices.Contains(aggregate.Hosts, host) {
200-
log.Info("Found host in aggregate", "host", host, "name", name)
201-
return nil
202-
}
203-
204-
result, err := aggregates.AddHost(ctx, serviceClient, aggregate.ID, aggregates.AddHostOpts{Host: host}).Extract()
205-
if err != nil {
206-
return fmt.Errorf("failed to add host %v to aggregate %v due to %w", host, name, err)
207-
}
208-
log.Info("Added host to aggregate", "host", host, "name", name)
209-
aggs[name] = result
210-
211-
return nil
212-
}
213-
214-
func removeFromAggregate(ctx context.Context, serviceClient *gophercloud.ServiceClient, aggs map[string]*aggregates.Aggregate, host, name string) error {
215-
aggregate, found := aggs[name]
216-
log := logger.FromContext(ctx)
217-
if !found {
218-
log.Info("cannot find aggregate", "name", name)
219-
return nil
220-
}
221-
222-
found = false
223-
for _, aggHost := range aggregate.Hosts {
224-
if aggHost == host {
225-
found = true
226-
}
227-
}
228-
229-
if !found {
230-
log.Info("cannot find host in aggregate", "host", host, "name", name)
231-
return nil
232-
}
233-
234-
result, err := aggregates.RemoveHost(ctx, serviceClient, aggregate.ID, aggregates.RemoveHostOpts{Host: host}).Extract()
235-
if err != nil {
236-
return fmt.Errorf("failed to add host %v to aggregate %v due to %w", host, name, err)
237-
}
238-
aggs[name] = result
239-
log.Info("removed host from aggregate", "host", host, "name", name)
240-
241-
return nil
242-
}

internal/controller/decomission_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ func (r *NodeDecommissionReconciler) Reconcile(ctx context.Context, req ctrl.Req
128128

129129
// Before removing the service, first take the node out of the aggregates,
130130
// so when the node comes back, it doesn't up with the old associations
131-
aggs, err := aggregatesByName(ctx, r.computeClient)
131+
aggs, err := openstack.GetAggregatesByName(ctx, r.computeClient)
132132
if err != nil {
133133
return r.setDecommissioningCondition(ctx, hv, fmt.Sprintf("cannot list aggregates due to %v", err))
134134
}

internal/controller/onboarding_controller.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,16 +197,16 @@ func (r *OnboardingController) initialOnboarding(ctx context.Context, hv *kvmv1.
197197
return fmt.Errorf("cannot find availability-zone label %v on node", corev1.LabelTopologyZone)
198198
}
199199

200-
aggs, err := aggregatesByName(ctx, r.computeClient)
200+
aggs, err := openstack.GetAggregatesByName(ctx, r.computeClient)
201201
if err != nil {
202202
return fmt.Errorf("cannot list aggregates %w", err)
203203
}
204204

205-
if err = addToAggregate(ctx, r.computeClient, aggs, host, zone, zone); err != nil {
205+
if err = openstack.AddToAggregate(ctx, r.computeClient, aggs, host, zone, zone); err != nil {
206206
return fmt.Errorf("failed to agg to availability-zone aggregate %w", err)
207207
}
208208

209-
err = addToAggregate(ctx, r.computeClient, aggs, host, testAggregateName, "")
209+
err = openstack.AddToAggregate(ctx, r.computeClient, aggs, host, testAggregateName, "")
210210
if err != nil {
211211
return fmt.Errorf("failed to agg to test aggregate %w", err)
212212
}
@@ -217,7 +217,7 @@ func (r *OnboardingController) initialOnboarding(ctx context.Context, hv *kvmv1.
217217
continue
218218
}
219219
if slices.Contains(aggregate.Hosts, host) {
220-
if err := removeFromAggregate(ctx, r.computeClient, aggs, host, aggregateName); err != nil {
220+
if err := openstack.RemoveFromAggregate(ctx, r.computeClient, aggs, host, aggregateName); err != nil {
221221
errs = append(errs, err)
222222
}
223223
}
@@ -345,12 +345,12 @@ func (r *OnboardingController) completeOnboarding(ctx context.Context, host stri
345345
return ctrl.Result{}, err
346346
}
347347

348-
aggs, err := aggregatesByName(ctx, r.computeClient)
348+
aggs, err := openstack.GetAggregatesByName(ctx, r.computeClient)
349349
if err != nil {
350350
return ctrl.Result{}, fmt.Errorf("failed to get aggregates %w", err)
351351
}
352352

353-
err = removeFromAggregate(ctx, r.computeClient, aggs, host, testAggregateName)
353+
err = openstack.RemoveFromAggregate(ctx, r.computeClient, aggs, host, testAggregateName)
354354
if err != nil {
355355
return ctrl.Result{}, fmt.Errorf("failed to remove from test aggregate %w", err)
356356
}

internal/openstack/aggregates.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
SPDX-FileCopyrightText: Copyright 2024 SAP SE or an SAP affiliate company and cobaltcore-dev contributors
3+
SPDX-License-Identifier: Apache-2.0
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
*/
14+
15+
package openstack
16+
17+
import (
18+
"context"
19+
"fmt"
20+
"slices"
21+
22+
logger "sigs.k8s.io/controller-runtime/pkg/log"
23+
24+
"github.com/gophercloud/gophercloud/v2"
25+
"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/aggregates"
26+
)
27+
28+
// GetAggregatesByName retrieves all aggregates from nova and returns them as a map keyed by name.
29+
func GetAggregatesByName(ctx context.Context, serviceClient *gophercloud.ServiceClient) (map[string]*aggregates.Aggregate, error) {
30+
pages, err := aggregates.List(serviceClient).AllPages(ctx)
31+
if err != nil {
32+
return nil, fmt.Errorf("cannot list aggregates due to %w", err)
33+
}
34+
35+
aggs, err := aggregates.ExtractAggregates(pages)
36+
if err != nil {
37+
return nil, fmt.Errorf("cannot list aggregates due to %w", err)
38+
}
39+
40+
aggregateMap := make(map[string]*aggregates.Aggregate, len(aggs))
41+
for _, aggregate := range aggs {
42+
aggregateMap[aggregate.Name] = &aggregate
43+
}
44+
return aggregateMap, nil
45+
}
46+
47+
// AddToAggregate adds the given host to the named aggregate, creating the aggregate if it does not yet exist.
48+
func AddToAggregate(ctx context.Context, serviceClient *gophercloud.ServiceClient, aggs map[string]*aggregates.Aggregate, host, name, zone string) (err error) {
49+
aggregate, found := aggs[name]
50+
log := logger.FromContext(ctx)
51+
if !found {
52+
aggregate, err = aggregates.Create(ctx, serviceClient,
53+
aggregates.CreateOpts{
54+
Name: name,
55+
AvailabilityZone: zone,
56+
}).Extract()
57+
if err != nil {
58+
return fmt.Errorf("failed to create aggregate %v due to %w", name, err)
59+
}
60+
aggs[name] = aggregate
61+
}
62+
63+
if slices.Contains(aggregate.Hosts, host) {
64+
log.Info("Found host in aggregate", "host", host, "name", name)
65+
return nil
66+
}
67+
68+
result, err := aggregates.AddHost(ctx, serviceClient, aggregate.ID, aggregates.AddHostOpts{Host: host}).Extract()
69+
if err != nil {
70+
return fmt.Errorf("failed to add host %v to aggregate %v due to %w", host, name, err)
71+
}
72+
log.Info("Added host to aggregate", "host", host, "name", name)
73+
aggs[name] = result
74+
75+
return nil
76+
}
77+
78+
// RemoveFromAggregate removes the given host from the named aggregate.
79+
func RemoveFromAggregate(ctx context.Context, serviceClient *gophercloud.ServiceClient, aggs map[string]*aggregates.Aggregate, host, name string) error {
80+
aggregate, found := aggs[name]
81+
log := logger.FromContext(ctx)
82+
if !found {
83+
log.Info("cannot find aggregate", "name", name)
84+
return nil
85+
}
86+
87+
found = false
88+
for _, aggHost := range aggregate.Hosts {
89+
if aggHost == host {
90+
found = true
91+
}
92+
}
93+
94+
if !found {
95+
log.Info("cannot find host in aggregate", "host", host, "name", name)
96+
return nil
97+
}
98+
99+
result, err := aggregates.RemoveHost(ctx, serviceClient, aggregate.ID, aggregates.RemoveHostOpts{Host: host}).Extract()
100+
if err != nil {
101+
return fmt.Errorf("failed to add host %v to aggregate %v due to %w", host, name, err)
102+
}
103+
aggs[name] = result
104+
log.Info("removed host from aggregate", "host", host, "name", name)
105+
106+
return nil
107+
}

0 commit comments

Comments
 (0)