Skip to content

Commit 0509681

Browse files
committed
Manual fixups to auto-generated code
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
1 parent 3b560fa commit 0509681

File tree

29 files changed

+126
-187
lines changed

29 files changed

+126
-187
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ kubectl delete -f $ORC_RELEASE
6969
|:---------------------------:|:-------:|:-------:|:--------:|
7070
| flavor | |||
7171
| floating ip | |||
72+
| host aggregate | |||
7273
| image ||||
7374
| network | |||
7475
| port | |||

api/v1alpha1/hostaggregate_types.go

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,18 @@ package v1alpha1
1818

1919
// HostAggregateResourceSpec contains the desired state of the resource.
2020
type HostAggregateResourceSpec struct {
21+
// TODO(stephenfin): Enforce that the name should not contain a colon.
2122
// name will be the name of the created resource. If not specified, the
2223
// name of the ORC object will be used.
2324
// +optional
24-
Name *OpenStackName `json:"name,omitempty"`
25+
Name *OpenStackName `json:"name"`
2526

26-
// description is a human-readable description for the resource.
27+
// availabilityZone is the availability zone of the host aggregate.
2728
// +kubebuilder:validation:MinLength:=1
2829
// +kubebuilder:validation:MaxLength:=255
30+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="availabilityZone is immutable"
2931
// +optional
30-
Description *string `json:"description,omitempty"`
31-
32-
// TODO(scaffolding): Add more types.
33-
// To see what is supported, you can take inspiration from the CreateOpts stucture from
34-
// github.com/gophercloud/gophercloud/v2/openstack/compute/v2/aggregates
35-
//
36-
// Until you have implemented mutability for the field, you must add a CEL validation
37-
// preventing the field being modified:
38-
// `// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="<fieldname> is immutable"`
32+
AvailabilityZone *string `json:"availabilityZone,omitempty"`
3933
}
4034

4135
// HostAggregateFilter defines an existing resource by its properties
@@ -44,31 +38,38 @@ type HostAggregateFilter struct {
4438
// name of the existing resource
4539
// +optional
4640
Name *OpenStackName `json:"name,omitempty"`
47-
48-
// description of the existing resource
49-
// +kubebuilder:validation:MinLength:=1
50-
// +kubebuilder:validation:MaxLength:=255
51-
// +optional
52-
Description *string `json:"description,omitempty"`
53-
54-
// TODO(scaffolding): Add more types.
55-
// To see what is supported, you can take inspiration from the ListOpts stucture from
56-
// github.com/gophercloud/gophercloud/v2/openstack/compute/v2/aggregates
5741
}
5842

5943
// HostAggregateResourceStatus represents the observed state of the resource.
6044
type HostAggregateResourceStatus struct {
45+
// The availability zone of the host aggregate.
46+
AvailabilityZone string `json:"availabilityZone"`
47+
48+
// A list of host ids in this aggregate.
49+
//Hosts []string `json:"hosts"`
50+
51+
// The ID of the host aggregate.
52+
ID int `json:"id"`
53+
54+
// Metadata key and value pairs associate with the aggregate.
55+
// Metadata map[string]string `json:"metadata"`
56+
6157
// name is a Human-readable name for the resource. Might not be unique.
6258
// +kubebuilder:validation:MaxLength=1024
63-
// +optional
64-
Name string `json:"name,omitempty"`
59+
Name string `json:"name"`
6560

66-
// description is a human-readable description for the resource.
67-
// +kubebuilder:validation:MaxLength=1024
68-
// +optional
69-
Description string `json:"description,omitempty"`
61+
// The date and time when the resource was created.
62+
// CreatedAt time.Time `json:"-"`
63+
64+
// The date and time when the resource was updated,
65+
// if the resource has not been updated, this field will show as null.
66+
// UpdatedAt time.Time `json:"-"`
67+
68+
// The date and time when the resource was deleted,
69+
// if the resource has not been deleted yet, this field will be null.
70+
// DeletedAt time.Time `json:"-"`
7071

71-
// TODO(scaffolding): Add more types.
72-
// To see what is supported, you can take inspiration from the HostAggregate stucture from
73-
// github.com/gophercloud/gophercloud/v2/openstack/compute/v2/aggregates
72+
// A boolean indicates whether this aggregate is deleted or not,
73+
// if it has not been deleted, false will appear.
74+
// Deleted bool `json:"deleted"`
7475
}

cmd/manager/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/flavor"
3131
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/floatingip"
3232
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces"
33+
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/hostaggregate"
3334
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/image"
3435
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/network"
3536
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/port"
@@ -112,6 +113,7 @@ func main() {
112113
server.New(scopeFactory),
113114
servergroup.New(scopeFactory),
114115
project.New(scopeFactory),
116+
hostaggregate.New(scopeFactory),
115117
}
116118

117119
restConfig := ctrl.GetConfigOrDie()

cmd/resource-generator/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ var resources []templateFields = []templateFields{
8585
IsNotNamed: true, // FloatingIP is not named in OpenStack
8686
ExistingOSClient: true,
8787
},
88+
{
89+
Name: "HostAggregate",
90+
},
8891
{
8992
Name: "Image",
9093
SpecExtraValidations: []specExtraValidation{

config/samples/openstack_v1alpha1_hostaggregate.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@ metadata:
55
name: hostaggregate-sample
66
spec:
77
cloudCredentialsRef:
8-
# TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created
9-
cloudName: openstack
8+
cloudName: openstack-admin
109
secretName: openstack-clouds
1110
managementPolicy: managed
1211
resource:
13-
description: Sample HostAggregate
14-
# TODO(scaffolding): Add all fields the resource supports
12+
availabilityZone: sample-az1

internal/controllers/hostaggregate/actuator.go

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ package hostaggregate
1919
import (
2020
"context"
2121
"iter"
22+
"strconv"
2223

2324
"github.com/gophercloud/gophercloud/v2/openstack/compute/v2/aggregates"
2425
corev1 "k8s.io/api/core/v1"
25-
"k8s.io/utils/ptr"
2626
ctrl "sigs.k8s.io/controller-runtime"
2727
"sigs.k8s.io/controller-runtime/pkg/client"
2828

@@ -36,7 +36,7 @@ import (
3636

3737
// OpenStack resource types
3838
type (
39-
osResourceT = aggregates.HostAggregate
39+
osResourceT = aggregates.Aggregate
4040

4141
createResourceActuator = interfaces.CreateResourceActuator[orcObjectPT, orcObjectT, filterT, osResourceT]
4242
deleteResourceActuator = interfaces.DeleteResourceActuator[orcObjectPT, orcObjectT, osResourceT]
@@ -52,12 +52,14 @@ type hostaggregateActuator struct {
5252
var _ createResourceActuator = hostaggregateActuator{}
5353
var _ deleteResourceActuator = hostaggregateActuator{}
5454

55+
// TODO(stephenfin): I suspect we need to change the interface since Nova expects integer IDs
5556
func (hostaggregateActuator) GetResourceID(osResource *osResourceT) string {
56-
return osResource.ID
57+
return strconv.Itoa(osResource.ID)
5758
}
5859

5960
func (actuator hostaggregateActuator) GetOSResourceByID(ctx context.Context, id string) (*osResourceT, progress.ReconcileStatus) {
60-
resource, err := actuator.osClient.GetHostAggregate(ctx, id)
61+
iid, err := strconv.Atoi(id)
62+
resource, err := actuator.osClient.GetHostAggregate(ctx, iid)
6163
if err != nil {
6264
return nil, progress.WrapError(err)
6365
}
@@ -70,30 +72,36 @@ func (actuator hostaggregateActuator) ListOSResourcesForAdoption(ctx context.Con
7072
return nil, false
7173
}
7274

73-
// TODO(scaffolding) If you need to filter resources on fields that the List() function
74-
// of gophercloud does not support, it's possible to perform client-side filtering.
75-
// Check osclients.ResourceFilter
75+
var filters []osclients.ResourceFilter[osResourceT]
7676

77-
listOpts := aggregates.ListOpts{
78-
Name: getResourceName(orcObject),
79-
Description: ptr.Deref(resourceSpec.Description, ""),
80-
}
77+
// NOTE: The API doesn't allow filtering by name or description, we'll have to do it client-side.
78+
filters = append(filters,
79+
func(f *aggregates.Aggregate) bool {
80+
name := getResourceName(orcObject)
81+
// Compare non-pointer values
82+
return f.Name == name
83+
},
84+
)
8185

82-
return actuator.osClient.ListHostAggregates(ctx, listOpts), true
86+
return actuator.listOSResources(ctx, filters), true
8387
}
8488

8589
func (actuator hostaggregateActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) {
86-
// TODO(scaffolding) If you need to filter resources on fields that the List() function
87-
// of gophercloud does not support, it's possible to perform client-side filtering.
88-
// Check osclients.ResourceFilter
90+
var filters []osclients.ResourceFilter[osResourceT]
8991

90-
listOpts := aggregates.ListOpts{
91-
Name: string(ptr.Deref(filter.Name, "")),
92-
Description: string(ptr.Deref(filter.Description, "")),
93-
// TODO(scaffolding): Add more import filters
92+
// NOTE: The API doesn't allow filtering by name or description, we'll have to do it client-side.
93+
if filter.Name != nil {
94+
filters = append(filters, func(f *aggregates.Aggregate) bool {
95+
return f.Name == string(*filter.Name)
96+
})
9497
}
9598

96-
return actuator.osClient.ListHostAggregates(ctx, listOpts), nil
99+
return actuator.listOSResources(ctx, filters), nil
100+
}
101+
102+
func (actuator hostaggregateActuator) listOSResources(ctx context.Context, filters []osclients.ResourceFilter[osResourceT]) iter.Seq2[*aggregates.Aggregate, error] {
103+
volumetypes := actuator.osClient.ListHostAggregates(ctx)
104+
return osclients.Filter(volumetypes, filters...)
97105
}
98106

99107
func (actuator hostaggregateActuator) CreateResource(ctx context.Context, obj orcObjectPT) (*osResourceT, progress.ReconcileStatus) {
@@ -106,8 +114,6 @@ func (actuator hostaggregateActuator) CreateResource(ctx context.Context, obj or
106114
}
107115
createOpts := aggregates.CreateOpts{
108116
Name: getResourceName(obj),
109-
Description: ptr.Deref(resource.Description, ""),
110-
// TODO(scaffolding): Add more fields
111117
}
112118

113119
osResource, err := actuator.osClient.CreateHostAggregate(ctx, createOpts)
@@ -138,7 +144,6 @@ func (actuator hostaggregateActuator) updateResource(ctx context.Context, obj or
138144
updateOpts := aggregates.UpdateOpts{}
139145

140146
handleNameUpdate(&updateOpts, obj, osResource)
141-
handleDescriptionUpdate(&updateOpts, resource, osResource)
142147

143148
// TODO(scaffolding): add handler for all fields supporting mutability
144149

@@ -167,7 +172,7 @@ func (actuator hostaggregateActuator) updateResource(ctx context.Context, obj or
167172
}
168173

169174
func needsUpdate(updateOpts aggregates.UpdateOpts) (bool, error) {
170-
updateOptsMap, err := updateOpts.ToHostAggregateUpdateMap()
175+
updateOptsMap, err := updateOpts.ToAggregatesUpdateMap()
171176
if err != nil {
172177
return false, err
173178
}
@@ -183,14 +188,7 @@ func needsUpdate(updateOpts aggregates.UpdateOpts) (bool, error) {
183188
func handleNameUpdate(updateOpts *aggregates.UpdateOpts, obj orcObjectPT, osResource *osResourceT) {
184189
name := getResourceName(obj)
185190
if osResource.Name != name {
186-
updateOpts.Name = &name
187-
}
188-
}
189-
190-
func handleDescriptionUpdate(updateOpts *aggregates.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) {
191-
description := ptr.Deref(resource.Description, "")
192-
if osResource.Description != description {
193-
updateOpts.Description = &description
191+
updateOpts.Name = name
194192
}
195193
}
196194

internal/controllers/hostaggregate/actuator_test.go

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func TestNeedsUpdate(t *testing.T) {
3737
},
3838
{
3939
name: "Updated opts",
40-
updateOpts: aggregates.UpdateOpts{Name: ptr.To("updated")},
40+
updateOpts: aggregates.UpdateOpts{Name: "updated"},
4141
expectChange: true,
4242
},
4343
}
@@ -86,34 +86,3 @@ func TestHandleNameUpdate(t *testing.T) {
8686

8787
}
8888
}
89-
90-
func TestHandleDescriptionUpdate(t *testing.T) {
91-
ptrToDescription := ptr.To[string]
92-
testCases := []struct {
93-
name string
94-
newValue *string
95-
existingValue string
96-
expectChange bool
97-
}{
98-
{name: "Identical", newValue: ptrToDescription("desc"), existingValue: "desc", expectChange: false},
99-
{name: "Different", newValue: ptrToDescription("new-desc"), existingValue: "desc", expectChange: true},
100-
{name: "No value provided, existing is set", newValue: nil, existingValue: "desc", expectChange: true},
101-
{name: "No value provided, existing is empty", newValue: nil, existingValue: "", expectChange: false},
102-
}
103-
104-
for _, tt := range testCases {
105-
t.Run(tt.name, func(t *testing.T) {
106-
resource := &orcv1alpha1.HostAggregateResourceSpec{Description: tt.newValue}
107-
osResource := &osResourceT{Description: tt.existingValue}
108-
109-
updateOpts := aggregates.UpdateOpts{}
110-
handleDescriptionUpdate(&updateOpts, resource, osResource)
111-
112-
got, _ := needsUpdate(updateOpts)
113-
if got != tt.expectChange {
114-
t.Errorf("Expected change: %v, got: %v", tt.expectChange, got)
115-
}
116-
})
117-
118-
}
119-
}

internal/controllers/hostaggregate/status.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,5 @@ func (hostaggregateStatusWriter) ApplyResourceStatus(log logr.Logger, osResource
5252
resourceStatus := orcapplyconfigv1alpha1.HostAggregateResourceStatus().
5353
WithName(osResource.Name)
5454

55-
// TODO(scaffolding): add all of the fields supported in the HostAggregateResourceStatus struct
56-
// If a zero-value isn't expected in the response, place it behind a conditional
57-
58-
if osResource.Description != "" {
59-
resourceStatus.WithDescription(osResource.Description)
60-
}
61-
6255
statusApply.WithResource(resourceStatus)
6356
}

internal/controllers/hostaggregate/tests/hostaggregate-create-full/00-assert.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ metadata:
66
status:
77
resource:
88
name: hostaggregate-create-full-override
9-
description: HostAggregate from "create full" test
10-
# TODO(scaffolding): Add all fields the resource supports
119
conditions:
1210
- type: Available
1311
status: "True"
@@ -25,4 +23,3 @@ resourceRefs:
2523
ref: hostaggregate
2624
assertAll:
2725
- celExpr: "hostaggregate.status.id != ''"
28-
# TODO(scaffolding): Add more checks

internal/controllers/hostaggregate/tests/hostaggregate-create-full/00-create-resource.yaml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@ metadata:
55
name: hostaggregate-create-full
66
spec:
77
cloudCredentialsRef:
8-
# TODO(scaffolding): Use openstack-admin if the resouce needs admin credentials to be created
9-
cloudName: openstack
8+
cloudName: openstack-admin
109
secretName: openstack-clouds
1110
managementPolicy: managed
1211
resource:
1312
name: hostaggregate-create-full-override
14-
description: HostAggregate from "create full" test
15-
# TODO(scaffolding): Add all fields the resource supports

0 commit comments

Comments
 (0)