From 95335a99e05ca09743af92461f5322ebb69a1b63 Mon Sep 17 00:00:00 2001 From: Gondermann Date: Mon, 13 Jul 2026 11:43:07 +0200 Subject: [PATCH 01/10] Scaffolding for the RegisteredLimit controller $ go run ./cmd/scaffold-controller -interactive=false \ -kind=RegisteredLimit \ -gophercloud-client=NewIdentityV3 \ -gophercloud-module=github.com/gophercloud/gophercloud/v2/openstack/identity/v3/registeredlimits \ -gophercloud-type=RegisteredLimit \ -openstack-json-object=registered_limits \ -required-create-dependency=Service On-behalf-of: SAP nils.gondermann@sap.com --- api/v1alpha1/registeredlimit_types.go | 84 ++++++ api/v1alpha1/zz_generated.deepcopy.go | 65 +++++ cmd/models-schema/zz_generated.openapi.go | 99 +++++++ config/rbac/role.yaml | 2 + .../openstack_v1alpha1_registeredlimit.yaml | 14 + .../controllers/registeredlimit/actuator.go | 252 ++++++++++++++++++ .../registeredlimit/actuator_test.go | 119 +++++++++ .../controllers/registeredlimit/controller.go | 99 +++++++ .../controllers/registeredlimit/status.go | 64 +++++ .../00-assert.yaml | 33 +++ .../00-create-resource.yaml | 29 ++ .../00-secret.yaml | 6 + .../registeredlimit-create-full/README.md | 11 + .../00-assert.yaml | 32 +++ .../00-create-resource.yaml | 28 ++ .../00-secret.yaml | 6 + .../01-assert.yaml | 11 + .../01-delete-secret.yaml | 7 + .../registeredlimit-create-minimal/README.md | 15 ++ .../registeredlimit-dependency/00-assert.yaml | 30 +++ .../00-create-resources-missing-deps.yaml | 42 +++ .../registeredlimit-dependency/00-secret.yaml | 6 + .../registeredlimit-dependency/01-assert.yaml | 30 +++ .../01-create-dependencies.yaml | 19 ++ .../registeredlimit-dependency/02-assert.yaml | 17 ++ .../02-delete-dependencies.yaml | 9 + .../registeredlimit-dependency/03-assert.yaml | 9 + .../03-delete-resources.yaml | 10 + .../registeredlimit-dependency/README.md | 21 ++ .../00-assert.yaml | 30 +++ .../00-create-resources.yaml | 43 +++ .../00-secret.yaml | 6 + .../01-assert.yaml | 15 ++ .../01-import-resource.yaml | 13 + .../registeredlimit-import-error/README.md | 13 + .../registeredlimit-import/00-assert.yaml | 15 ++ .../00-import-resource.yaml | 15 ++ .../registeredlimit-import/00-secret.yaml | 6 + .../registeredlimit-import/01-assert.yaml | 34 +++ .../01-create-trap-resource.yaml | 31 +++ .../registeredlimit-import/02-assert.yaml | 33 +++ .../02-create-resource.yaml | 28 ++ .../tests/registeredlimit-import/README.md | 18 ++ .../registeredlimit-update/00-assert.yaml | 26 ++ .../00-minimal-resource.yaml | 28 ++ .../registeredlimit-update/00-secret.yaml | 6 + .../registeredlimit-update/01-assert.yaml | 17 ++ .../01-updated-resource.yaml | 10 + .../registeredlimit-update/02-assert.yaml | 26 ++ .../02-reverted-resource.yaml | 7 + .../tests/registeredlimit-update/README.md | 17 ++ internal/osclients/registeredlimit.go | 104 ++++++++ test/apivalidations/registeredlimit_test.go | 128 +++++++++ website/docs/crd-reference.md | 9 + 54 files changed, 1847 insertions(+) create mode 100644 api/v1alpha1/registeredlimit_types.go create mode 100644 config/samples/openstack_v1alpha1_registeredlimit.yaml create mode 100644 internal/controllers/registeredlimit/actuator.go create mode 100644 internal/controllers/registeredlimit/actuator_test.go create mode 100644 internal/controllers/registeredlimit/controller.go create mode 100644 internal/controllers/registeredlimit/status.go create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-create-resource.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-secret.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-create-full/README.md create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-create-resource.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-secret.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/01-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/01-delete-secret.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/README.md create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-create-resources-missing-deps.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-secret.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-dependency/01-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-dependency/01-create-dependencies.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-dependency/02-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-dependency/02-delete-dependencies.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-dependency/03-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-dependency/03-delete-resources.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-dependency/README.md create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-create-resources.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-secret.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import-error/01-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import-error/01-import-resource.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import-error/README.md create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import/00-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import/00-import-resource.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import/00-secret.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import/01-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import/01-create-trap-resource.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import/02-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import/02-create-resource.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-import/README.md create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-update/00-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-update/00-minimal-resource.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-update/00-secret.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-update/01-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-update/01-updated-resource.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-update/02-assert.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-update/02-reverted-resource.yaml create mode 100644 internal/controllers/registeredlimit/tests/registeredlimit-update/README.md create mode 100644 internal/osclients/registeredlimit.go create mode 100644 test/apivalidations/registeredlimit_test.go diff --git a/api/v1alpha1/registeredlimit_types.go b/api/v1alpha1/registeredlimit_types.go new file mode 100644 index 000000000..0514c787e --- /dev/null +++ b/api/v1alpha1/registeredlimit_types.go @@ -0,0 +1,84 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +// RegisteredLimitResourceSpec contains the desired state of the resource. +type RegisteredLimitResourceSpec struct { + // name will be the name of the created resource. If not specified, the + // name of the ORC object will be used. + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // description is a human-readable description for the resource. + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +optional + Description *string `json:"description,omitempty"` + + // serviceRef is a reference to the ORC Service which this resource is associated with. + // +required + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="serviceRef is immutable" + ServiceRef KubernetesNameRef `json:"serviceRef,omitempty"` + + // TODO(scaffolding): Add more types. + // To see what is supported, you can take inspiration from the CreateOpts structure from + // github.com/gophercloud/gophercloud/v2/openstack/identity/v3/registeredlimits + // + // Until you have implemented mutability for the field, you must add a CEL validation + // preventing the field being modified: + // `// +kubebuilder:validation:XValidation:rule="self == oldSelf",message=" is immutable"` +} + +// RegisteredLimitFilter defines an existing resource by its properties +// +kubebuilder:validation:MinProperties:=1 +type RegisteredLimitFilter struct { + // name of the existing resource + // +optional + Name *OpenStackName `json:"name,omitempty"` + + // description of the existing resource + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +optional + Description *string `json:"description,omitempty"` + + // TODO(scaffolding): Add more types. + // To see what is supported, you can take inspiration from the ListOpts structure from + // github.com/gophercloud/gophercloud/v2/openstack/identity/v3/registeredlimits +} + +// RegisteredLimitResourceStatus represents the observed state of the resource. +type RegisteredLimitResourceStatus struct { + // name is a Human-readable name for the resource. Might not be unique. + // +kubebuilder:validation:MaxLength=1024 + // +optional + Name string `json:"name,omitempty"` + + // description is a human-readable description for the resource. + // +kubebuilder:validation:MaxLength=1024 + // +optional + Description string `json:"description,omitempty"` + + // serviceID is the ID of the Service to which the resource is associated. + // +kubebuilder:validation:MaxLength=1024 + // +optional + ServiceID string `json:"serviceID,omitempty"` + + // TODO(scaffolding): Add more types. + // To see what is supported, you can take inspiration from the RegisteredLimit structure from + // github.com/gophercloud/gophercloud/v2/openstack/identity/v3/registeredlimits +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 4e7d7e3c1..383ae4bab 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -3908,6 +3908,71 @@ func (in *ProviderPropertiesStatus) DeepCopy() *ProviderPropertiesStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RegisteredLimitFilter) DeepCopyInto(out *RegisteredLimitFilter) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) + **out = **in + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegisteredLimitFilter. +func (in *RegisteredLimitFilter) DeepCopy() *RegisteredLimitFilter { + if in == nil { + return nil + } + out := new(RegisteredLimitFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RegisteredLimitResourceSpec) DeepCopyInto(out *RegisteredLimitResourceSpec) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(OpenStackName) + **out = **in + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegisteredLimitResourceSpec. +func (in *RegisteredLimitResourceSpec) DeepCopy() *RegisteredLimitResourceSpec { + if in == nil { + return nil + } + out := new(RegisteredLimitResourceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RegisteredLimitResourceStatus) DeepCopyInto(out *RegisteredLimitResourceStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegisteredLimitResourceStatus. +func (in *RegisteredLimitResourceStatus) DeepCopy() *RegisteredLimitResourceStatus { + if in == nil { + return nil + } + out := new(RegisteredLimitResourceStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Role) DeepCopyInto(out *Role) { *out = *in diff --git a/cmd/models-schema/zz_generated.openapi.go b/cmd/models-schema/zz_generated.openapi.go index 29d2fa1b1..f696eb9f5 100644 --- a/cmd/models-schema/zz_generated.openapi.go +++ b/cmd/models-schema/zz_generated.openapi.go @@ -160,6 +160,9 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectSpec(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectStatus(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProviderPropertiesStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ProviderPropertiesStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitFilter": schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitResourceSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitResourceStatus(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Role": schema_openstack_resource_controller_v2_api_v1alpha1_Role(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignment": schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignment(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentFilter": schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentFilter(ref), @@ -7415,6 +7418,102 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ProviderPropertiesStat } } +func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RegisteredLimitFilter defines an existing resource by its properties", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description of the existing resource", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RegisteredLimitResourceSpec contains the desired state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "serviceRef": { + SchemaProps: spec.SchemaProps{ + Description: "serviceRef is a reference to the ORC Service which this resource is associated with.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"serviceRef"}, + }, + }, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RegisteredLimitResourceStatus represents the observed state of the resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is a Human-readable name for the resource. Might not be unique.", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human-readable description for the resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "serviceID": { + SchemaProps: spec.SchemaProps{ + Description: "serviceID is the ID of the Service to which the resource is associated.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + func schema_openstack_resource_controller_v2_api_v1alpha1_Role(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index a04a488e2..1ad5c7875 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -29,6 +29,7 @@ rules: - networks - ports - projects + - registeredlimits - roleassignments - roles - routerinterfaces @@ -66,6 +67,7 @@ rules: - networks/status - ports/status - projects/status + - registeredlimits/status - roleassignments/status - roles/status - routerinterfaces/status diff --git a/config/samples/openstack_v1alpha1_registeredlimit.yaml b/config/samples/openstack_v1alpha1_registeredlimit.yaml new file mode 100644 index 000000000..37e036127 --- /dev/null +++ b/config/samples/openstack_v1alpha1_registeredlimit.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-sample +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: Sample RegisteredLimit + # TODO(scaffolding): Add all fields the resource supports diff --git a/internal/controllers/registeredlimit/actuator.go b/internal/controllers/registeredlimit/actuator.go new file mode 100644 index 000000000..d2a55c42c --- /dev/null +++ b/internal/controllers/registeredlimit/actuator.go @@ -0,0 +1,252 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package registeredlimit + +import ( + "context" + "iter" + + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/registeredlimits" + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + "github.com/k-orc/openstack-resource-controller/v2/internal/logging" + "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" +) + +// OpenStack resource types +type ( + osResourceT = registeredlimits.RegisteredLimit + + createResourceActuator = interfaces.CreateResourceActuator[orcObjectPT, orcObjectT, filterT, osResourceT] + deleteResourceActuator = interfaces.DeleteResourceActuator[orcObjectPT, orcObjectT, osResourceT] + resourceReconciler = interfaces.ResourceReconciler[orcObjectPT, osResourceT] + helperFactory = interfaces.ResourceHelperFactory[orcObjectPT, orcObjectT, resourceSpecT, filterT, osResourceT] +) + +type registeredlimitActuator struct { + osClient osclients.RegisteredLimitClient + k8sClient client.Client +} + +var _ createResourceActuator = registeredlimitActuator{} +var _ deleteResourceActuator = registeredlimitActuator{} + +func (registeredlimitActuator) GetResourceID(osResource *osResourceT) string { + return osResource.ID +} + +func (actuator registeredlimitActuator) GetOSResourceByID(ctx context.Context, id string) (*osResourceT, progress.ReconcileStatus) { + resource, err := actuator.osClient.GetRegisteredLimit(ctx, id) + if err != nil { + return nil, progress.WrapError(err) + } + return resource, nil +} + +func (actuator registeredlimitActuator) ListOSResourcesForAdoption(ctx context.Context, orcObject orcObjectPT) (iter.Seq2[*osResourceT, error], bool) { + resourceSpec := orcObject.Spec.Resource + if resourceSpec == nil { + return nil, false + } + + // TODO(scaffolding) If you need to filter resources on fields that the List() function + // of gophercloud does not support, it's possible to perform client-side filtering. + // Check osclients.ResourceFilter + + listOpts := registeredlimits.ListOpts{ + Name: getResourceName(orcObject), + Description: ptr.Deref(resourceSpec.Description, ""), + } + + return actuator.osClient.ListRegisteredLimits(ctx, listOpts), true +} + +func (actuator registeredlimitActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { + // TODO(scaffolding) If you need to filter resources on fields that the List() function + // of gophercloud does not support, it's possible to perform client-side filtering. + // Check osclients.ResourceFilter + + listOpts := registeredlimits.ListOpts{ + Name: string(ptr.Deref(filter.Name, "")), + Description: string(ptr.Deref(filter.Description, "")), + // TODO(scaffolding): Add more import filters + } + + return actuator.osClient.ListRegisteredLimits(ctx, listOpts), nil +} + +func (actuator registeredlimitActuator) CreateResource(ctx context.Context, obj orcObjectPT) (*osResourceT, progress.ReconcileStatus) { + resource := obj.Spec.Resource + + if resource == nil { + // Should have been caught by API validation + return nil, progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Creation requested, but spec.resource is not set")) + } + var reconcileStatus progress.ReconcileStatus + + var serviceID string + service, serviceDepRS := serviceDependency.GetDependency( + ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(serviceDepRS) + if service != nil { + serviceID = ptr.Deref(service.Status.ID, "") + } + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + createOpts := registeredlimits.CreateOpts{ + Name: getResourceName(obj), + Description: ptr.Deref(resource.Description, ""), + ServiceID: serviceID, + // TODO(scaffolding): Add more fields + } + + osResource, err := actuator.osClient.CreateRegisteredLimit(ctx, createOpts) + if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) + } + return nil, progress.WrapError(err) + } + + return osResource, nil +} + +func (actuator registeredlimitActuator) DeleteResource(ctx context.Context, _ orcObjectPT, resource *osResourceT) progress.ReconcileStatus { + return progress.WrapError(actuator.osClient.DeleteRegisteredLimit(ctx, resource.ID)) +} + +func (actuator registeredlimitActuator) updateResource(ctx context.Context, obj orcObjectPT, osResource *osResourceT) progress.ReconcileStatus { + log := ctrl.LoggerFrom(ctx) + resource := obj.Spec.Resource + if resource == nil { + // Should have been caught by API validation + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "Update requested, but spec.resource is not set")) + } + + updateOpts := registeredlimits.UpdateOpts{} + + handleNameUpdate(&updateOpts, obj, osResource) + handleDescriptionUpdate(&updateOpts, resource, osResource) + + // TODO(scaffolding): add handler for all fields supporting mutability + + needsUpdate, err := needsUpdate(updateOpts) + if err != nil { + return progress.WrapError( + orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err)) + } + if !needsUpdate { + log.V(logging.Debug).Info("No changes") + return nil + } + + _, err = actuator.osClient.UpdateRegisteredLimit(ctx, osResource.ID, updateOpts) + + if err != nil { + if !orcerrors.IsRetryable(err) { + err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration updating resource: "+err.Error(), err) + } + return progress.WrapError(err) + } + + return progress.NeedsRefresh() +} + +func needsUpdate(updateOpts registeredlimits.UpdateOpts) (bool, error) { + updateOptsMap, err := updateOpts.ToRegisteredLimitUpdateMap() + if err != nil { + return false, err + } + + updateMap, ok := updateOptsMap["registered_limits"].(map[string]any) + if !ok { + updateMap = make(map[string]any) + } + + return len(updateMap) > 0, nil +} + +func handleNameUpdate(updateOpts *registeredlimits.UpdateOpts, obj orcObjectPT, osResource *osResourceT) { + name := getResourceName(obj) + if osResource.Name != name { + updateOpts.Name = &name + } +} + +func handleDescriptionUpdate(updateOpts *registeredlimits.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { + description := ptr.Deref(resource.Description, "") + if osResource.Description != description { + updateOpts.Description = &description + } +} + +func (actuator registeredlimitActuator) GetResourceReconcilers(ctx context.Context, orcObject orcObjectPT, osResource *osResourceT, controller interfaces.ResourceController) ([]resourceReconciler, progress.ReconcileStatus) { + return []resourceReconciler{ + actuator.updateResource, + }, nil +} + +type registeredlimitHelperFactory struct{} + +var _ helperFactory = registeredlimitHelperFactory{} + +func newActuator(ctx context.Context, orcObject *orcv1alpha1.RegisteredLimit, controller interfaces.ResourceController) (registeredlimitActuator, progress.ReconcileStatus) { + log := ctrl.LoggerFrom(ctx) + + // Ensure credential secrets exist and have our finalizer + _, reconcileStatus := credentialsDependency.GetDependencies(ctx, controller.GetK8sClient(), orcObject, func(*corev1.Secret) bool { return true }) + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return registeredlimitActuator{}, reconcileStatus + } + + clientScope, err := controller.GetScopeFactory().NewClientScopeFromObject(ctx, controller.GetK8sClient(), log, orcObject) + if err != nil { + return registeredlimitActuator{}, progress.WrapError(err) + } + osClient, err := clientScope.NewRegisteredLimitClient() + if err != nil { + return registeredlimitActuator{}, progress.WrapError(err) + } + + return registeredlimitActuator{ + osClient: osClient, + k8sClient: controller.GetK8sClient(), + }, nil +} + +func (registeredlimitHelperFactory) NewAPIObjectAdapter(obj orcObjectPT) adapterI { + return registeredlimitAdapter{obj} +} + +func (registeredlimitHelperFactory) NewCreateActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (createResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} + +func (registeredlimitHelperFactory) NewDeleteActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (deleteResourceActuator, progress.ReconcileStatus) { + return newActuator(ctx, orcObject, controller) +} diff --git a/internal/controllers/registeredlimit/actuator_test.go b/internal/controllers/registeredlimit/actuator_test.go new file mode 100644 index 000000000..ca8678a48 --- /dev/null +++ b/internal/controllers/registeredlimit/actuator_test.go @@ -0,0 +1,119 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package registeredlimit + +import ( + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/registeredlimits" + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "k8s.io/utils/ptr" +) + +func TestNeedsUpdate(t *testing.T) { + testCases := []struct { + name string + updateOpts registeredlimits.UpdateOpts + expectChange bool + }{ + { + name: "Empty base opts", + updateOpts: registeredlimits.UpdateOpts{}, + expectChange: false, + }, + { + name: "Updated opts", + updateOpts: registeredlimits.UpdateOpts{Name: ptr.To("updated")}, + expectChange: true, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + got, _ := needsUpdate(tt.updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + } +} + +func TestHandleNameUpdate(t *testing.T) { + ptrToName := ptr.To[orcv1alpha1.OpenStackName] + testCases := []struct { + name string + newValue *orcv1alpha1.OpenStackName + existingValue string + expectChange bool + }{ + {name: "Identical", newValue: ptrToName("name"), existingValue: "name", expectChange: false}, + {name: "Different", newValue: ptrToName("new-name"), existingValue: "name", expectChange: true}, + {name: "No value provided, existing is identical to object name", newValue: nil, existingValue: "object-name", expectChange: false}, + {name: "No value provided, existing is different from object name", newValue: nil, existingValue: "different-from-object-name", expectChange: true}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.RegisteredLimit{} + resource.Name = "object-name" + resource.Spec = orcv1alpha1.RegisteredLimitSpec{ + Resource: &orcv1alpha1.RegisteredLimitResourceSpec{Name: tt.newValue}, + } + osResource := &osResourceT{Name: tt.existingValue} + + updateOpts := registeredlimits.UpdateOpts{} + handleNameUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + + } +} + +func TestHandleDescriptionUpdate(t *testing.T) { + ptrToDescription := ptr.To[string] + testCases := []struct { + name string + newValue *string + existingValue string + expectChange bool + }{ + {name: "Identical", newValue: ptrToDescription("desc"), existingValue: "desc", expectChange: false}, + {name: "Different", newValue: ptrToDescription("new-desc"), existingValue: "desc", expectChange: true}, + {name: "No value provided, existing is set", newValue: nil, existingValue: "desc", expectChange: true}, + {name: "No value provided, existing is empty", newValue: nil, existingValue: "", expectChange: false}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.RegisteredLimitResourceSpec{Description: tt.newValue} + osResource := &osResourceT{Description: tt.existingValue} + + updateOpts := registeredlimits.UpdateOpts{} + handleDescriptionUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + + } +} diff --git a/internal/controllers/registeredlimit/controller.go b/internal/controllers/registeredlimit/controller.go new file mode 100644 index 000000000..fc1f0591d --- /dev/null +++ b/internal/controllers/registeredlimit/controller.go @@ -0,0 +1,99 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package registeredlimit + +import ( + "context" + "errors" + "time" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/controller" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/reconciler" + "github.com/k-orc/openstack-resource-controller/v2/internal/scope" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/credentials" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + "github.com/k-orc/openstack-resource-controller/v2/pkg/predicates" +) + +const controllerName = "registeredlimit" + +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=registeredlimits,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=registeredlimits/status,verbs=get;update;patch + +type registeredlimitReconcilerConstructor struct { + scopeFactory scope.Factory + defaultResyncPeriod time.Duration +} + +func New(scopeFactory scope.Factory) interfaces.Controller { + return ®isteredlimitReconcilerConstructor{scopeFactory: scopeFactory} +} + +func (registeredlimitReconcilerConstructor) GetName() string { + return controllerName +} + +func (c *registeredlimitReconcilerConstructor) SetDefaultResyncPeriod(d time.Duration) { + c.defaultResyncPeriod = d +} + +var serviceDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.RegisteredLimitList, *orcv1alpha1.Service]( + "spec.resource.serviceRef", + func(registeredlimit *orcv1alpha1.RegisteredLimit) []string { + resource := registeredlimit.Spec.Resource + if resource == nil { + return nil + } + return []string{string(resource.ServiceRef)} + }, + finalizer, externalObjectFieldOwner, +) + +// SetupWithManager sets up the controller with the Manager. +func (c *registeredlimitReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error { + log := ctrl.LoggerFrom(ctx) + k8sClient := mgr.GetClient() + + serviceWatchEventHandler, err := serviceDependency.WatchEventHandler(log, k8sClient) + if err != nil { + return err + } + + builder := ctrl.NewControllerManagedBy(mgr). + WithOptions(options). + Watches(&orcv1alpha1.Service{}, serviceWatchEventHandler, + builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Service{})), + ). + For(&orcv1alpha1.RegisteredLimit{}) + + if err := errors.Join( + serviceDependency.AddToManager(ctx, mgr), + credentialsDependency.AddToManager(ctx, mgr), + credentials.AddCredentialsWatch(log, mgr.GetClient(), builder, credentialsDependency), + ); err != nil { + return err + } + + r := reconciler.NewController(controllerName, mgr.GetClient(), c.scopeFactory, registeredlimitHelperFactory{}, registeredlimitStatusWriter{}, c.defaultResyncPeriod) + return builder.Complete(&r) +} diff --git a/internal/controllers/registeredlimit/status.go b/internal/controllers/registeredlimit/status.go new file mode 100644 index 000000000..f25c193fd --- /dev/null +++ b/internal/controllers/registeredlimit/status.go @@ -0,0 +1,64 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package registeredlimit + +import ( + "github.com/go-logr/logr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" + orcapplyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +type registeredlimitStatusWriter struct{} + +type objectApplyT = orcapplyconfigv1alpha1.RegisteredLimitApplyConfiguration +type statusApplyT = orcapplyconfigv1alpha1.RegisteredLimitStatusApplyConfiguration + +var _ interfaces.ResourceStatusWriter[*orcv1alpha1.RegisteredLimit, *osResourceT, *objectApplyT, *statusApplyT] = registeredlimitStatusWriter{} + +func (registeredlimitStatusWriter) GetApplyConfig(name, namespace string) *objectApplyT { + return orcapplyconfigv1alpha1.RegisteredLimit(name, namespace) +} + +func (registeredlimitStatusWriter) ResourceAvailableStatus(orcObject *orcv1alpha1.RegisteredLimit, osResource *osResourceT) (metav1.ConditionStatus, progress.ReconcileStatus) { + if osResource == nil { + if orcObject.Status.ID == nil { + return metav1.ConditionFalse, nil + } else { + return metav1.ConditionUnknown, nil + } + } + return metav1.ConditionTrue, nil +} + +func (registeredlimitStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResourceT, statusApply *statusApplyT) { + resourceStatus := orcapplyconfigv1alpha1.RegisteredLimitResourceStatus(). + WithServiceID(osResource.ServiceID). + WithName(osResource.Name) + + // TODO(scaffolding): add all of the fields supported in the RegisteredLimitResourceStatus struct + // If a zero-value isn't expected in the response, place it behind a conditional + + if osResource.Description != "" { + resourceStatus.WithDescription(osResource.Description) + } + + statusApply.WithResource(resourceStatus) +} diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-assert.yaml new file mode 100644 index 000000000..1a3428e1a --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-assert.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-create-full +status: + resource: + name: registeredlimit-create-full-override + description: RegisteredLimit from "create full" test + # TODO(scaffolding): Add all fields the resource supports + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RegisteredLimit + name: registeredlimit-create-full + ref: registeredlimit + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Service + name: registeredlimit-create-full + ref: service +assertAll: + - celExpr: "registeredlimit.status.id != ''" + - celExpr: "registeredlimit.status.resource.serviceID == service.status.id" + # TODO(scaffolding): Add more checks diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-create-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-create-resource.yaml new file mode 100644 index 000000000..9ee0e80a6 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-create-resource.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: registeredlimit-create-full +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + # TODO(scaffolding): Add the necessary fields to create the resource + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-create-full +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + name: registeredlimit-create-full-override + description: RegisteredLimit from "create full" test + serviceRef: registeredlimit-create-full + # TODO(scaffolding): Add all fields the resource supports diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-secret.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-full/README.md b/internal/controllers/registeredlimit/tests/registeredlimit-create-full/README.md new file mode 100644 index 000000000..289aec7af --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-full/README.md @@ -0,0 +1,11 @@ +# Create a RegisteredLimit with all the options + +## Step 00 + +Create a RegisteredLimit using all available fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name from the spec when it is specified. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-full diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-assert.yaml new file mode 100644 index 000000000..41c81b5bc --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-assert.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-create-minimal +status: + resource: + name: registeredlimit-create-minimal + # TODO(scaffolding): Add all fields the resource supports + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RegisteredLimit + name: registeredlimit-create-minimal + ref: registeredlimit + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Service + name: registeredlimit-create-minimal + ref: service +assertAll: + - celExpr: "registeredlimit.status.id != ''" + - celExpr: "registeredlimit.status.resource.serviceID == service.status.id" + # TODO(scaffolding): Add more checks diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-create-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-create-resource.yaml new file mode 100644 index 000000000..e4eea36c6 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-create-resource.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: registeredlimit-create-minimal +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + # TODO(scaffolding): Add the necessary fields to create the resource + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-create-minimal +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + # TODO(scaffolding): Only add the mandatory fields. It's possible the resource + # doesn't have mandatory fields, in that case, leave it empty. + resource: + serviceRef: registeredlimit-create-minimal diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-secret.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/01-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/01-assert.yaml new file mode 100644 index 000000000..fe4656696 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/01-assert.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: v1 + kind: Secret + name: openstack-clouds + ref: secret +assertAll: + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/registeredlimit' in secret.metadata.finalizers" diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/01-delete-secret.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/01-delete-secret.yaml new file mode 100644 index 000000000..1620791b9 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/01-delete-secret.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete secret openstack-clouds --wait=false + namespaced: true diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/README.md b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/README.md new file mode 100644 index 000000000..c82541797 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/README.md @@ -0,0 +1,15 @@ +# Create a RegisteredLimit with the minimum options + +## Step 00 + +Create a minimal RegisteredLimit, that sets only the required fields, and verify that the observed state corresponds to the spec. + +Also validate that the OpenStack resource uses the name of the ORC object when no name is explicitly specified. + +## Step 01 + +Try deleting the secret and ensure that it is not deleted thanks to the finalizer. + +## Reference + +https://k-orc.cloud/development/writing-tests/#create-minimal diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-assert.yaml new file mode 100644 index 000000000..bad56a8dd --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-dependency-no-secret +status: + conditions: + - type: Available + message: Waiting for Secret/registeredlimit-dependency to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Secret/registeredlimit-dependency to be created + status: "True" + reason: Progressing +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-dependency-no-service +status: + conditions: + - type: Available + message: Waiting for Service/registeredlimit-dependency-pending to be created + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for Service/registeredlimit-dependency-pending to be created + status: "True" + reason: Progressing diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-create-resources-missing-deps.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-create-resources-missing-deps.yaml new file mode 100644 index 000000000..afef6b42a --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-create-resources-missing-deps.yaml @@ -0,0 +1,42 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: registeredlimit-dependency +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + # TODO(scaffolding): Add the necessary fields to create the resource + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-dependency-no-service +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + serviceRef: registeredlimit-dependency-pending + # TODO(scaffolding): Add the necessary fields to create the resource + +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-dependency-no-secret +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: registeredlimit-dependency + managementPolicy: managed + # TODO(scaffolding): Add the necessary fields to create the resource + resource: + serviceRef: registeredlimit-dependency diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-secret.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/01-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/01-assert.yaml new file mode 100644 index 000000000..9cd0b1305 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/01-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-dependency-no-secret +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-dependency-no-service +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/01-create-dependencies.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/01-create-dependencies.yaml new file mode 100644 index 000000000..6c177cb7b --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/01-create-dependencies.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic registeredlimit-dependency --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: registeredlimit-dependency-pending +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + # TODO(scaffolding): Add the necessary fields to create the resource + resource: {} diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/02-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/02-assert.yaml new file mode 100644 index 000000000..9d33deab9 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/02-assert.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: Service + name: registeredlimit-dependency + ref: service + - apiVersion: v1 + kind: Secret + name: registeredlimit-dependency + ref: secret +assertAll: + - celExpr: "service.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/registeredlimit' in service.metadata.finalizers" + - celExpr: "secret.metadata.deletionTimestamp != 0" + - celExpr: "'openstack.k-orc.cloud/registeredlimit' in secret.metadata.finalizers" diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/02-delete-dependencies.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/02-delete-dependencies.yaml new file mode 100644 index 000000000..34fc235e6 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/02-delete-dependencies.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + # We expect the deletion to hang due to the finalizer, so use --wait=false + - command: kubectl delete service.openstack.k-orc.cloud registeredlimit-dependency --wait=false + namespaced: true + - command: kubectl delete secret registeredlimit-dependency --wait=false + namespaced: true diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/03-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/03-assert.yaml new file mode 100644 index 000000000..8961cd03b --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/03-assert.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +commands: +# Dependencies that were prevented deletion before should now be gone +- script: "! kubectl get service.openstack.k-orc.cloud registeredlimit-dependency --namespace $NAMESPACE" + skipLogOutput: true +- script: "! kubectl get secret registeredlimit-dependency --namespace $NAMESPACE" + skipLogOutput: true diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/03-delete-resources.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/03-delete-resources.yaml new file mode 100644 index 000000000..be9c2681d --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/03-delete-resources.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RegisteredLimit + name: registeredlimit-dependency-no-secret +- apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RegisteredLimit + name: registeredlimit-dependency-no-service diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/README.md b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/README.md new file mode 100644 index 000000000..d228fad7e --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/README.md @@ -0,0 +1,21 @@ +# Creation and deletion dependencies + +## Step 00 + +Create RegisteredLimits referencing non-existing resources. Each RegisteredLimit is dependent on other non-existing resource. Verify that the RegisteredLimits are waiting for the needed resources to be created externally. + +## Step 01 + +Create the missing dependencies and verify all the RegisteredLimits are available. + +## Step 02 + +Delete all the dependencies and check that ORC prevents deletion since there is still a resource that depends on them. + +## Step 03 + +Delete the RegisteredLimits and validate that all resources are gone. + +## Reference + +https://k-orc.cloud/development/writing-tests/#dependency diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-assert.yaml new file mode 100644 index 000000000..1b21b4078 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-assert.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import-error-external-1 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import-error-external-2 +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-create-resources.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-create-resources.yaml new file mode 100644 index 000000000..4df73e9db --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-create-resources.yaml @@ -0,0 +1,43 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: registeredlimit-import-error +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + # TODO(scaffolding): Add the necessary fields to create the resource + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import-error-external-1 +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: RegisteredLimit from "import error" test + serviceRef: registeredlimit-import-error + # TODO(scaffolding): add any required field +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import-error-external-2 +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: RegisteredLimit from "import error" test + serviceRef: registeredlimit-import-error + # TODO(scaffolding): add any required field diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-secret.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import-error/01-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/01-assert.yaml new file mode 100644 index 000000000..b14eabd6b --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/01-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import-error +status: + conditions: + - type: Available + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration + - type: Progressing + message: found more than one matching OpenStack resource during import + status: "False" + reason: InvalidConfiguration diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import-error/01-import-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/01-import-resource.yaml new file mode 100644 index 000000000..af79d8e58 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/01-import-resource.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import-error +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + description: RegisteredLimit from "import error" test diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import-error/README.md b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/README.md new file mode 100644 index 000000000..aad6bc42a --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/README.md @@ -0,0 +1,13 @@ +# Import RegisteredLimit with more than one matching resources + +## Step 00 + +Create two RegisteredLimits with identical specs. + +## Step 01 + +Ensure that an imported RegisteredLimit with a filter matching the resources returns an error. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import-error diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/00-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/00-assert.yaml new file mode 100644 index 000000000..9be45921a --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/00-assert.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/00-import-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/00-import-resource.yaml new file mode 100644 index 000000000..6b56bbd1a --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/00-import-resource.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import +spec: + cloudCredentialsRef: + cloudName: openstack + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + name: registeredlimit-import-external + description: RegisteredLimit registeredlimit-import-external from "registeredlimit-import" test + # TODO(scaffolding): Add all fields supported by the filter diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/00-secret.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/01-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/01-assert.yaml new file mode 100644 index 000000000..0d4faa09a --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/01-assert.yaml @@ -0,0 +1,34 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import-external-not-this-one +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + name: registeredlimit-import-external-not-this-one + description: RegisteredLimit registeredlimit-import-external from "registeredlimit-import" test + # TODO(scaffolding): Add fields necessary to match filter +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import +status: + conditions: + - type: Available + message: Waiting for OpenStack resource to be created externally + status: "False" + reason: Progressing + - type: Progressing + message: Waiting for OpenStack resource to be created externally + status: "True" + reason: Progressing diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/01-create-trap-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/01-create-trap-resource.yaml new file mode 100644 index 000000000..a9a1e630a --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/01-create-trap-resource.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: registeredlimit-import-external-not-this-one +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + # TODO(scaffolding): Add the necessary fields to create the resource + resource: {} +--- +# This `registeredlimit-import-external-not-this-one` resource serves two purposes: +# - ensure that we can successfully create another resource which name is a substring of it (i.e. it's not being adopted) +# - ensure that importing a resource which name is a substring of it will not pick this one. +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import-external-not-this-one +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: RegisteredLimit registeredlimit-import-external from "registeredlimit-import" test + serviceRef: registeredlimit-import-external-not-this-one + # TODO(scaffolding): Add fields necessary to match filter diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/02-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/02-assert.yaml new file mode 100644 index 000000000..516eb9a9d --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/02-assert.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RegisteredLimit + name: registeredlimit-import-external + ref: registeredlimit1 + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RegisteredLimit + name: registeredlimit-import-external-not-this-one + ref: registeredlimit2 +assertAll: + - celExpr: "registeredlimit1.status.id != registeredlimit2.status.id" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import +status: + conditions: + - type: Available + message: OpenStack resource is available + status: "True" + reason: Success + - type: Progressing + message: OpenStack resource is up to date + status: "False" + reason: Success + resource: + name: registeredlimit-import-external + description: RegisteredLimit registeredlimit-import-external from "registeredlimit-import" test + # TODO(scaffolding): Add all fields the resource supports diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/02-create-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/02-create-resource.yaml new file mode 100644 index 000000000..cec0a745d --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/02-create-resource.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: registeredlimit-import +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + # TODO(scaffolding): Add the necessary fields to create the resource + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-import-external +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + resource: + description: RegisteredLimit registeredlimit-import-external from "registeredlimit-import" test + serviceRef: registeredlimit-import + # TODO(scaffolding): Add fields necessary to match filter diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/README.md b/internal/controllers/registeredlimit/tests/registeredlimit-import/README.md new file mode 100644 index 000000000..f9e1193d2 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/README.md @@ -0,0 +1,18 @@ +# Import RegisteredLimit + +## Step 00 + +Import a registeredlimit that matches all fields in the filter, and verify it is waiting for the external resource to be created. + +## Step 01 + +Create a registeredlimit whose name is a superstring of the one specified in the import filter, otherwise matching the filter, and verify that it's not being imported. + +## Step 02 + +Create a registeredlimit matching the filter and verify that the observed status on the imported registeredlimit corresponds to the spec of the created registeredlimit. +Also, confirm that it does not adopt any registeredlimit whose name is a superstring of its own. + +## Reference + +https://k-orc.cloud/development/writing-tests/#import diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/00-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-update/00-assert.yaml new file mode 100644 index 000000000..29f6774a3 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/00-assert.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RegisteredLimit + name: registeredlimit-update + ref: registeredlimit +assertAll: + - celExpr: "!has(registeredlimit.status.resource.description)" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-update +status: + resource: + name: registeredlimit-update + # TODO(scaffolding): Add matches for more fields + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/00-minimal-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-update/00-minimal-resource.yaml new file mode 100644 index 000000000..25fdd17b4 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/00-minimal-resource.yaml @@ -0,0 +1,28 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: registeredlimit-update +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + # TODO(scaffolding): Add the necessary fields to create the resource + resource: {} +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-update +spec: + cloudCredentialsRef: + # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created or updated + cloudName: openstack + secretName: openstack-clouds + managementPolicy: managed + # TODO(scaffolding): Only add the mandatory fields. It's possible the resource + # doesn't have mandatory fields, in that case, leave it empty. + resource: + serviceRef: registeredlimit-update diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/00-secret.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-update/00-secret.yaml new file mode 100644 index 000000000..045711ee7 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/00-secret.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl create secret generic openstack-clouds --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT} + namespaced: true diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/01-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-update/01-assert.yaml new file mode 100644 index 000000000..c3346cc9a --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/01-assert.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-update +status: + resource: + name: registeredlimit-update-updated + description: registeredlimit-update-updated + # TODO(scaffolding): match all fields that were modified + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/01-updated-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-update/01-updated-resource.yaml new file mode 100644 index 000000000..aa31f5657 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/01-updated-resource.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-update +spec: + resource: + name: registeredlimit-update-updated + description: registeredlimit-update-updated + # TODO(scaffolding): update all mutable fields diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/02-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-update/02-assert.yaml new file mode 100644 index 000000000..36ce759e6 --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/02-assert.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestAssert +resourceRefs: + - apiVersion: openstack.k-orc.cloud/v1alpha1 + kind: RegisteredLimit + name: registeredlimit-update + ref: registeredlimit +assertAll: + - celExpr: "!has(registeredlimit.status.resource.description)" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: RegisteredLimit +metadata: + name: registeredlimit-update +status: + resource: + name: registeredlimit-update + # TODO(scaffolding): validate that updated fields were all reverted to their original value + conditions: + - type: Available + status: "True" + reason: Success + - type: Progressing + status: "False" + reason: Success diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/02-reverted-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-update/02-reverted-resource.yaml new file mode 100644 index 000000000..2c6c253ff --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/02-reverted-resource.yaml @@ -0,0 +1,7 @@ +# NOTE: kuttl only does patch updates, which means we can't delete a field. +# We have to use a kubectl apply command instead. +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl replace -f 00-minimal-resource.yaml + namespaced: true diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/README.md b/internal/controllers/registeredlimit/tests/registeredlimit-update/README.md new file mode 100644 index 000000000..cc8f1be9c --- /dev/null +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/README.md @@ -0,0 +1,17 @@ +# Update RegisteredLimit + +## Step 00 + +Create a RegisteredLimit using only mandatory fields. + +## Step 01 + +Update all mutable fields. + +## Step 02 + +Revert the resource to its original value and verify that the resulting object matches its state when first created. + +## Reference + +https://k-orc.cloud/development/writing-tests/#update diff --git a/internal/osclients/registeredlimit.go b/internal/osclients/registeredlimit.go new file mode 100644 index 000000000..d2e851061 --- /dev/null +++ b/internal/osclients/registeredlimit.go @@ -0,0 +1,104 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package osclients + +import ( + "context" + "fmt" + "iter" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack" + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/registeredlimits" + "github.com/gophercloud/utils/v2/openstack/clientconfig" +) + +type RegisteredLimitClient interface { + ListRegisteredLimits(ctx context.Context, listOpts registeredlimits.ListOptsBuilder) iter.Seq2[*registeredlimits.RegisteredLimit, error] + CreateRegisteredLimit(ctx context.Context, opts registeredlimits.CreateOptsBuilder) (*registeredlimits.RegisteredLimit, error) + DeleteRegisteredLimit(ctx context.Context, resourceID string) error + GetRegisteredLimit(ctx context.Context, resourceID string) (*registeredlimits.RegisteredLimit, error) + UpdateRegisteredLimit(ctx context.Context, id string, opts registeredlimits.UpdateOptsBuilder) (*registeredlimits.RegisteredLimit, error) +} + +type registeredlimitClient struct{ client *gophercloud.ServiceClient } + +// NewRegisteredLimitClient returns a new OpenStack client. +func NewRegisteredLimitClient(providerClient *gophercloud.ProviderClient, providerClientOpts *clientconfig.ClientOpts) (RegisteredLimitClient, error) { + client, err := openstack.NewIdentityV3(providerClient, gophercloud.EndpointOpts{ + Region: providerClientOpts.RegionName, + Availability: clientconfig.GetEndpointType(providerClientOpts.EndpointType), + }) + + if err != nil { + return nil, fmt.Errorf("failed to create registeredlimit service client: %v", err) + } + + return ®isteredlimitClient{client}, nil +} + +func (c registeredlimitClient) ListRegisteredLimits(ctx context.Context, listOpts registeredlimits.ListOptsBuilder) iter.Seq2[*registeredlimits.RegisteredLimit, error] { + pager := registeredlimits.List(c.client, listOpts) + return func(yield func(*registeredlimits.RegisteredLimit, error) bool) { + _ = pager.EachPage(ctx, yieldPage(registeredlimits.ExtractRegisteredLimits, yield)) + } +} + +func (c registeredlimitClient) CreateRegisteredLimit(ctx context.Context, opts registeredlimits.CreateOptsBuilder) (*registeredlimits.RegisteredLimit, error) { + return registeredlimits.Create(ctx, c.client, opts).Extract() +} + +func (c registeredlimitClient) DeleteRegisteredLimit(ctx context.Context, resourceID string) error { + return registeredlimits.Delete(ctx, c.client, resourceID).ExtractErr() +} + +func (c registeredlimitClient) GetRegisteredLimit(ctx context.Context, resourceID string) (*registeredlimits.RegisteredLimit, error) { + return registeredlimits.Get(ctx, c.client, resourceID).Extract() +} + +func (c registeredlimitClient) UpdateRegisteredLimit(ctx context.Context, id string, opts registeredlimits.UpdateOptsBuilder) (*registeredlimits.RegisteredLimit, error) { + return registeredlimits.Update(ctx, c.client, id, opts).Extract() +} + +type registeredlimitErrorClient struct{ error } + +// NewRegisteredLimitErrorClient returns a RegisteredLimitClient in which every method returns the given error. +func NewRegisteredLimitErrorClient(e error) RegisteredLimitClient { + return registeredlimitErrorClient{e} +} + +func (e registeredlimitErrorClient) ListRegisteredLimits(_ context.Context, _ registeredlimits.ListOptsBuilder) iter.Seq2[*registeredlimits.RegisteredLimit, error] { + return func(yield func(*registeredlimits.RegisteredLimit, error) bool) { + yield(nil, e.error) + } +} + +func (e registeredlimitErrorClient) CreateRegisteredLimit(_ context.Context, _ registeredlimits.CreateOptsBuilder) (*registeredlimits.RegisteredLimit, error) { + return nil, e.error +} + +func (e registeredlimitErrorClient) DeleteRegisteredLimit(_ context.Context, _ string) error { + return e.error +} + +func (e registeredlimitErrorClient) GetRegisteredLimit(_ context.Context, _ string) (*registeredlimits.RegisteredLimit, error) { + return nil, e.error +} + +func (e registeredlimitErrorClient) UpdateRegisteredLimit(_ context.Context, _ string, _ registeredlimits.UpdateOptsBuilder) (*registeredlimits.RegisteredLimit, error) { + return nil, e.error +} diff --git a/test/apivalidations/registeredlimit_test.go b/test/apivalidations/registeredlimit_test.go new file mode 100644 index 000000000..c5773ffa1 --- /dev/null +++ b/test/apivalidations/registeredlimit_test.go @@ -0,0 +1,128 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package apivalidations + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" +) + +const ( + registeredlimitName = "registeredlimit" + registeredlimitID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae120" +) + +func registeredlimitStub(namespace *corev1.Namespace) *orcv1alpha1.RegisteredLimit { + obj := &orcv1alpha1.RegisteredLimit{} + obj.Name = registeredlimitName + obj.Namespace = namespace.Name + return obj +} + +func testRegisteredLimitResource() *applyconfigv1alpha1.RegisteredLimitResourceSpecApplyConfiguration { + return applyconfigv1alpha1.RegisteredLimitResourceSpec(). + WithServiceRef("service") +} + +func baseRegisteredLimitPatch(obj client.Object) *applyconfigv1alpha1.RegisteredLimitApplyConfiguration { + return applyconfigv1alpha1.RegisteredLimit(obj.GetName(), obj.GetNamespace()). + WithSpec(applyconfigv1alpha1.RegisteredLimitSpec(). + WithCloudCredentialsRef(testCredentials())) +} + +func testRegisteredLimitImport() *applyconfigv1alpha1.RegisteredLimitImportApplyConfiguration { + return applyconfigv1alpha1.RegisteredLimitImport().WithID(registeredlimitID) +} + +var _ = Describe("ORC RegisteredLimit API validations", func() { + var namespace *corev1.Namespace + BeforeEach(func() { + namespace = createNamespace() + }) + + runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.RegisteredLimitApplyConfiguration]{ + createObject: func(ns *corev1.Namespace) client.Object { return registeredlimitStub(ns) }, + basePatch: func(obj client.Object) *applyconfigv1alpha1.RegisteredLimitApplyConfiguration { + return baseRegisteredLimitPatch(obj) + }, + applyResource: func(p *applyconfigv1alpha1.RegisteredLimitApplyConfiguration) { + p.Spec.WithResource(testRegisteredLimitResource()) + }, + applyImport: func(p *applyconfigv1alpha1.RegisteredLimitApplyConfiguration) { + p.Spec.WithImport(testRegisteredLimitImport()) + }, + applyEmptyImport: func(p *applyconfigv1alpha1.RegisteredLimitApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.RegisteredLimitImport()) + }, + applyEmptyFilter: func(p *applyconfigv1alpha1.RegisteredLimitApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.RegisteredLimitImport().WithFilter(applyconfigv1alpha1.RegisteredLimitFilter())) + }, + applyValidFilter: func(p *applyconfigv1alpha1.RegisteredLimitApplyConfiguration) { + p.Spec.WithImport(applyconfigv1alpha1.RegisteredLimitImport().WithFilter(applyconfigv1alpha1.RegisteredLimitFilter().WithName("foo"))) + }, + applyManaged: func(p *applyconfigv1alpha1.RegisteredLimitApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) + }, + applyUnmanaged: func(p *applyconfigv1alpha1.RegisteredLimitApplyConfiguration) { + p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged) + }, + applyManagedOptions: func(p *applyconfigv1alpha1.RegisteredLimitApplyConfiguration) { + p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach)) + }, + getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy { + return obj.(*orcv1alpha1.RegisteredLimit).Spec.ManagementPolicy + }, + getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete { + return obj.(*orcv1alpha1.RegisteredLimit).Spec.ManagedOptions.OnDelete + }, + }) + + It("should reject a registeredlimit without required fields", func(ctx context.Context) { + obj := registeredlimitStub(namespace) + patch := baseRegisteredLimitPatch(obj) + patch.Spec.WithResource(applyconfigv1alpha1.RegisteredLimitResourceSpec()) + Expect(applyObj(ctx, obj, patch)).NotTo(Succeed()) + }) + + It("should have immutable serviceRef", func(ctx context.Context) { + obj := registeredlimitStub(namespace) + patch := baseRegisteredLimitPatch(obj) + patch.Spec.WithResource(testRegisteredLimitResource(). + WithServiceRef("service-a")) + Expect(applyObj(ctx, obj, patch)).To(Succeed()) + + patch.Spec.WithResource(testRegisteredLimitResource(). + WithServiceRef("service-b")) + Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("serviceRef is immutable"))) + }) + + // TODO(scaffolding): Add more resource-specific validation tests. + // Some common things to test: + // - Immutability of fields with `self == oldSelf` validation + // - Enum validation (valid and invalid values) + // - Numeric range validation (min/max bounds) + // - Tag uniqueness (if the resource has tags with listType=set) + // - Format validation (CIDR, UUID, etc.) + // - Cross-field validation rules +}) diff --git a/website/docs/crd-reference.md b/website/docs/crd-reference.md index 3cfdb8ac9..c16937584 100644 --- a/website/docs/crd-reference.md +++ b/website/docs/crd-reference.md @@ -2216,6 +2216,7 @@ _Appears in:_ - [PortResourceSpec](#portresourcespec) - [ProjectFilter](#projectfilter) - [ProjectResourceSpec](#projectresourcespec) +- [RegisteredLimitResourceSpec](#registeredlimitresourcespec) - [RoleAssignmentFilter](#roleassignmentfilter) - [RoleAssignmentResourceSpec](#roleassignmentresourcespec) - [RoleFilter](#rolefilter) @@ -2644,6 +2645,8 @@ _Appears in:_ - [NetworkResourceSpec](#networkresourcespec) - [PortFilter](#portfilter) - [PortResourceSpec](#portresourcespec) +- [RegisteredLimitFilter](#registeredlimitfilter) +- [RegisteredLimitResourceSpec](#registeredlimitresourcespec) - [RouterFilter](#routerfilter) - [RouterResourceSpec](#routerresourcespec) - [SecurityGroupFilter](#securitygroupfilter) @@ -3124,6 +3127,12 @@ _Appears in:_ | `segmentationID` _integer_ | segmentationID is the ID of the isolated segment on the
physical network. The network_type attribute defines the
segmentation model. For example, if the network_type value is vlan,
this ID is a vlan identifier. If the network_type value is gre, this
ID is a gre key. | | Optional: \{\}
| + + + + + + #### Role From 0f876a3dadf1f4daeb9cded8a7f84030829cac98 Mon Sep 17 00:00:00 2001 From: Gondermann Date: Mon, 13 Jul 2026 11:46:36 +0200 Subject: [PATCH 02/10] Scaffolding for the RegisteredLimit controller Register with the resource generator On-behalf-of: SAP nils.gondermann@sap.com --- PROJECT | 8 + api/v1alpha1/zz_generated.deepcopy.go | 156 +++++++++ .../zz_generated.registeredlimit-resource.go | 194 +++++++++++ cmd/models-schema/zz_generated.openapi.go | 247 ++++++++++++++ cmd/resource-generator/main.go | 4 + ...penstack.k-orc.cloud_registeredlimits.yaml | 321 ++++++++++++++++++ config/crd/kustomization.yaml | 1 + config/samples/kustomization.yaml | 1 + .../registeredlimit/zz_generated.adapter.go | 88 +++++ .../zz_generated.controller.go | 45 +++ internal/osclients/mock/doc.go | 3 + internal/osclients/mock/registeredlimit.go | 131 +++++++ kuttl-test.yaml | 1 + .../api/v1alpha1/registeredlimit.go | 281 +++++++++++++++ .../api/v1alpha1/registeredlimitfilter.go | 52 +++ .../api/v1alpha1/registeredlimitimport.go | 48 +++ .../v1alpha1/registeredlimitresourcespec.go | 61 ++++ .../v1alpha1/registeredlimitresourcestatus.go | 57 ++++ .../api/v1alpha1/registeredlimitspec.go | 89 +++++ .../api/v1alpha1/registeredlimitstatus.go | 76 +++++ .../applyconfiguration/internal/internal.go | 105 ++++++ pkg/clients/applyconfiguration/utils.go | 14 + .../typed/api/v1alpha1/api_client.go | 5 + .../api/v1alpha1/fake/fake_api_client.go | 4 + .../api/v1alpha1/fake/fake_registeredlimit.go | 53 +++ .../typed/api/v1alpha1/generated_expansion.go | 2 + .../typed/api/v1alpha1/registeredlimit.go | 74 ++++ .../api/v1alpha1/interface.go | 7 + .../api/v1alpha1/registeredlimit.go | 102 ++++++ .../informers/externalversions/generic.go | 2 + .../api/v1alpha1/expansion_generated.go | 8 + .../listers/api/v1alpha1/registeredlimit.go | 70 ++++ website/docs/crd-reference.md | 131 +++++++ 33 files changed, 2441 insertions(+) create mode 100644 api/v1alpha1/zz_generated.registeredlimit-resource.go create mode 100644 config/crd/bases/openstack.k-orc.cloud_registeredlimits.yaml create mode 100644 internal/controllers/registeredlimit/zz_generated.adapter.go create mode 100644 internal/controllers/registeredlimit/zz_generated.controller.go create mode 100644 internal/osclients/mock/registeredlimit.go create mode 100644 pkg/clients/applyconfiguration/api/v1alpha1/registeredlimit.go create mode 100644 pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitfilter.go create mode 100644 pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitimport.go create mode 100644 pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcespec.go create mode 100644 pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcestatus.go create mode 100644 pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitspec.go create mode 100644 pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitstatus.go create mode 100644 pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_registeredlimit.go create mode 100644 pkg/clients/clientset/clientset/typed/api/v1alpha1/registeredlimit.go create mode 100644 pkg/clients/informers/externalversions/api/v1alpha1/registeredlimit.go create mode 100644 pkg/clients/listers/api/v1alpha1/registeredlimit.go diff --git a/PROJECT b/PROJECT index 357849779..64b74d157 100644 --- a/PROJECT +++ b/PROJECT @@ -104,6 +104,14 @@ resources: kind: Project path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + domain: k-orc.cloud + group: openstack + kind: RegisteredLimit + path: github.com/k-orc/openstack-resource-controller/api/v1alpha1 + version: v1alpha1 - api: crdVersion: v1 namespaced: true diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 383ae4bab..4326af491 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -3908,6 +3908,33 @@ func (in *ProviderPropertiesStatus) DeepCopy() *ProviderPropertiesStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RegisteredLimit) DeepCopyInto(out *RegisteredLimit) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegisteredLimit. +func (in *RegisteredLimit) DeepCopy() *RegisteredLimit { + if in == nil { + return nil + } + out := new(RegisteredLimit) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RegisteredLimit) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RegisteredLimitFilter) DeepCopyInto(out *RegisteredLimitFilter) { *out = *in @@ -3933,6 +3960,63 @@ func (in *RegisteredLimitFilter) DeepCopy() *RegisteredLimitFilter { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RegisteredLimitImport) DeepCopyInto(out *RegisteredLimitImport) { + *out = *in + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(RegisteredLimitFilter) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegisteredLimitImport. +func (in *RegisteredLimitImport) DeepCopy() *RegisteredLimitImport { + if in == nil { + return nil + } + out := new(RegisteredLimitImport) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RegisteredLimitList) DeepCopyInto(out *RegisteredLimitList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]RegisteredLimit, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegisteredLimitList. +func (in *RegisteredLimitList) DeepCopy() *RegisteredLimitList { + if in == nil { + return nil + } + out := new(RegisteredLimitList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RegisteredLimitList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RegisteredLimitResourceSpec) DeepCopyInto(out *RegisteredLimitResourceSpec) { *out = *in @@ -3973,6 +4057,78 @@ func (in *RegisteredLimitResourceStatus) DeepCopy() *RegisteredLimitResourceStat return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RegisteredLimitSpec) DeepCopyInto(out *RegisteredLimitSpec) { + *out = *in + if in.Import != nil { + in, out := &in.Import, &out.Import + *out = new(RegisteredLimitImport) + (*in).DeepCopyInto(*out) + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(RegisteredLimitResourceSpec) + (*in).DeepCopyInto(*out) + } + if in.ManagedOptions != nil { + in, out := &in.ManagedOptions, &out.ManagedOptions + *out = new(ManagedOptions) + **out = **in + } + if in.ResyncPeriod != nil { + in, out := &in.ResyncPeriod, &out.ResyncPeriod + *out = new(v1.Duration) + **out = **in + } + out.CloudCredentialsRef = in.CloudCredentialsRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegisteredLimitSpec. +func (in *RegisteredLimitSpec) DeepCopy() *RegisteredLimitSpec { + if in == nil { + return nil + } + out := new(RegisteredLimitSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RegisteredLimitStatus) DeepCopyInto(out *RegisteredLimitStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ID != nil { + in, out := &in.ID, &out.ID + *out = new(string) + **out = **in + } + if in.Resource != nil { + in, out := &in.Resource, &out.Resource + *out = new(RegisteredLimitResourceStatus) + **out = **in + } + if in.LastSyncTime != nil { + in, out := &in.LastSyncTime, &out.LastSyncTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegisteredLimitStatus. +func (in *RegisteredLimitStatus) DeepCopy() *RegisteredLimitStatus { + if in == nil { + return nil + } + out := new(RegisteredLimitStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Role) DeepCopyInto(out *Role) { *out = *in diff --git a/api/v1alpha1/zz_generated.registeredlimit-resource.go b/api/v1alpha1/zz_generated.registeredlimit-resource.go new file mode 100644 index 000000000..ecbe76231 --- /dev/null +++ b/api/v1alpha1/zz_generated.registeredlimit-resource.go @@ -0,0 +1,194 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// RegisteredLimitImport specifies an existing resource which will be imported instead of +// creating a new one +// +kubebuilder:validation:MinProperties:=1 +// +kubebuilder:validation:MaxProperties:=1 +type RegisteredLimitImport struct { + // id contains the unique identifier of an existing OpenStack resource. Note + // that when specifying an import by ID, the resource MUST already exist. + // The ORC object will enter an error state if the resource does not exist. + // +kubebuilder:validation:Format:=uuid + // +kubebuilder:validation:MaxLength:=36 + // +optional + ID *string `json:"id,omitempty"` //nolint:kubeapilinter + + // filter contains a resource query which is expected to return a single + // result. The controller will continue to retry if filter returns no + // results. If filter returns multiple results the controller will set an + // error state and will not continue to retry. + // +optional + Filter *RegisteredLimitFilter `json:"filter,omitempty"` +} + +// RegisteredLimitSpec defines the desired state of an ORC object. +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? has(self.resource) : true",message="resource must be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'managed' ? !has(self.__import__) : true",message="import may not be specified when policy is managed" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? !has(self.resource) : true",message="resource may not be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="self.managementPolicy == 'unmanaged' ? has(self.__import__) : true",message="import must be specified when policy is unmanaged" +// +kubebuilder:validation:XValidation:rule="has(self.managedOptions) ? self.managementPolicy == 'managed' : true",message="managedOptions may only be provided when policy is managed" +type RegisteredLimitSpec struct { + // import refers to an existing OpenStack resource which will be imported instead of + // creating a new one. + // +optional + Import *RegisteredLimitImport `json:"import,omitempty"` + + // resource specifies the desired state of the resource. + // + // resource may not be specified if the management policy is `unmanaged`. + // + // resource must be specified if the management policy is `managed`. + // +optional + Resource *RegisteredLimitResourceSpec `json:"resource,omitempty"` + + // managementPolicy defines how ORC will treat the object. Valid values are + // `managed`: ORC will create, update, and delete the resource; `unmanaged`: + // ORC will import an existing resource, and will not apply updates to it or + // delete it. + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="managementPolicy is immutable" + // +kubebuilder:default:=managed + // +optional + ManagementPolicy ManagementPolicy `json:"managementPolicy,omitempty"` + + // managedOptions specifies options which may be applied to managed objects. + // +optional + ManagedOptions *ManagedOptions `json:"managedOptions,omitempty"` + + // resyncPeriod defines how frequently the controller will re-reconcile + // this resource even when no changes have been detected. This overrides + // the global default resync period. The value must be a valid Go duration + // string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + // this resource. Very low values may cause excessive OpenStack API load. + // +optional + ResyncPeriod *metav1.Duration `json:"resyncPeriod,omitempty"` //nolint:kubeapilinter // metav1.Duration is appropriate for user-facing duration config + + // cloudCredentialsRef points to a secret containing OpenStack credentials + // +required + CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"` +} + +// RegisteredLimitStatus defines the observed state of an ORC resource. +type RegisteredLimitStatus struct { + // conditions represents the observed status of the object. + // Known .status.conditions.type are: "Available", "Progressing" + // + // Available represents the availability of the OpenStack resource. If it is + // true then the resource is ready for use. + // + // Progressing indicates whether the controller is still attempting to + // reconcile the current state of the OpenStack resource to the desired + // state. Progressing will be False either because the desired state has + // been achieved, or because some terminal error prevents it from ever being + // achieved and the controller is no longer attempting to reconcile. If + // Progressing is True, an observer waiting on the resource should continue + // to wait. + // + // +kubebuilder:validation:MaxItems:=32 + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` + + // id is the unique identifier of the OpenStack resource. + // +kubebuilder:validation:MaxLength:=1024 + // +optional + ID *string `json:"id,omitempty"` + + // resource contains the observed state of the OpenStack resource. + // +optional + Resource *RegisteredLimitResourceStatus `json:"resource,omitempty"` + + // lastSyncTime is the timestamp of the last successful reconciliation + // that fetched state from OpenStack. It is updated each time the + // controller successfully reads the resource state from the OpenStack + // API. + // +optional + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +var _ ObjectWithConditions = &RegisteredLimit{} + +func (i *RegisteredLimit) GetConditions() []metav1.Condition { + return i.Status.Conditions +} + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:resource:categories=openstack +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="ID",type="string",JSONPath=".status.id",description="Resource ID" +// +kubebuilder:printcolumn:name="Available",type="string",JSONPath=".status.conditions[?(@.type=='Available')].status",description="Availability status of resource" +// +kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Progressing')].message",description="Message describing current progress status" + +// RegisteredLimit is the Schema for an ORC resource. +type RegisteredLimit struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the object metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // spec specifies the desired state of the resource. + // +required + Spec RegisteredLimitSpec `json:"spec,omitzero"` + + // status defines the observed state of the resource. + // +optional + Status RegisteredLimitStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// RegisteredLimitList contains a list of RegisteredLimit. +type RegisteredLimitList struct { + metav1.TypeMeta `json:",inline"` + + // metadata contains the list metadata + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + // items contains a list of RegisteredLimit. + // +required + Items []RegisteredLimit `json:"items"` +} + +func (l *RegisteredLimitList) GetItems() []RegisteredLimit { + return l.Items +} + +func init() { + SchemeBuilder.Register(&RegisteredLimit{}, &RegisteredLimitList{}) +} + +func (i *RegisteredLimit) GetCloudCredentialsRef() (*string, *CloudCredentialsReference) { + if i == nil { + return nil, nil + } + + return &i.Namespace, &i.Spec.CloudCredentialsRef +} + +var _ CloudCredentialsRefProvider = &RegisteredLimit{} diff --git a/cmd/models-schema/zz_generated.openapi.go b/cmd/models-schema/zz_generated.openapi.go index f696eb9f5..46aee6d2f 100644 --- a/cmd/models-schema/zz_generated.openapi.go +++ b/cmd/models-schema/zz_generated.openapi.go @@ -160,9 +160,14 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectSpec": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectSpec(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProjectStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ProjectStatus(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ProviderPropertiesStatus": schema_openstack_resource_controller_v2_api_v1alpha1_ProviderPropertiesStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimit": schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimit(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitFilter": schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitFilter(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitImport": schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitImport(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitList": schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitList(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitResourceSpec(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitResourceStatus(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitSpec": schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitSpec(ref), + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitStatus": schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitStatus(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.Role": schema_openstack_resource_controller_v2_api_v1alpha1_Role(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignment": schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignment(ref), "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RoleAssignmentFilter": schema_openstack_resource_controller_v2_api_v1alpha1_RoleAssignmentFilter(ref), @@ -7418,6 +7423,57 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_ProviderPropertiesStat } } +func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimit(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RegisteredLimit is the Schema for an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the object metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "spec specifies the desired state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status defines the observed state of the resource.", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -7445,6 +7501,85 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitFilter( } } +func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitImport(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RegisteredLimitImport specifies an existing resource which will be imported instead of creating a new one", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id contains the unique identifier of an existing OpenStack resource. Note that when specifying an import by ID, the resource MUST already exist. The ORC object will enter an error state if the resource does not exist.", + Type: []string{"string"}, + Format: "", + }, + }, + "filter": { + SchemaProps: spec.SchemaProps{ + Description: "filter contains a resource query which is expected to return a single result. The controller will continue to retry if filter returns no results. If filter returns multiple results the controller will set an error state and will not continue to retry.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitFilter"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitFilter"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RegisteredLimitList contains a list of RegisteredLimit.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "metadata contains the list metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "items contains a list of RegisteredLimit.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimit"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimit", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -7514,6 +7649,118 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitResourc } } +func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RegisteredLimitSpec defines the desired state of an ORC object.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "import": { + SchemaProps: spec.SchemaProps{ + Description: "import refers to an existing OpenStack resource which will be imported instead of creating a new one.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitImport"), + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource specifies the desired state of the resource.\n\nresource may not be specified if the management policy is `unmanaged`.\n\nresource must be specified if the management policy is `managed`.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitResourceSpec"), + }, + }, + "managementPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "managementPolicy defines how ORC will treat the object. Valid values are `managed`: ORC will create, update, and delete the resource; `unmanaged`: ORC will import an existing resource, and will not apply updates to it or delete it.", + Type: []string{"string"}, + Format: "", + }, + }, + "managedOptions": { + SchemaProps: spec.SchemaProps{ + Description: "managedOptions specifies options which may be applied to managed objects.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions"), + }, + }, + "resyncPeriod": { + SchemaProps: spec.SchemaProps{ + Description: "resyncPeriod defines how frequently the controller will re-reconcile this resource even when no changes have been detected. This overrides the global default resync period. The value must be a valid Go duration string, e.g. \"10m\", \"1h\". Set to \"0s\" to disable periodic resync for this resource. Very low values may cause excessive OpenStack API load.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "cloudCredentialsRef": { + SchemaProps: spec.SchemaProps{ + Description: "cloudCredentialsRef points to a secret containing OpenStack credentials", + Default: map[string]interface{}{}, + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference"), + }, + }, + }, + Required: []string{"cloudCredentialsRef"}, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.CloudCredentialsReference", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.ManagedOptions", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitResourceSpec", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration"}, + } +} + +func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RegisteredLimitStatus defines the observed state of an ORC resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "type", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions represents the observed status of the object. Known .status.conditions.type are: \"Available\", \"Progressing\"\n\nAvailable represents the availability of the OpenStack resource. If it is true then the resource is ready for use.\n\nProgressing indicates whether the controller is still attempting to reconcile the current state of the OpenStack resource to the desired state. Progressing will be False either because the desired state has been achieved, or because some terminal error prevents it from ever being achieved and the controller is no longer attempting to reconcile. If Progressing is True, an observer waiting on the resource should continue to wait.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + "id": { + SchemaProps: spec.SchemaProps{ + Description: "id is the unique identifier of the OpenStack resource.", + Type: []string{"string"}, + Format: "", + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Description: "resource contains the observed state of the OpenStack resource.", + Ref: ref("github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitResourceStatus"), + }, + }, + "lastSyncTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastSyncTime is the timestamp of the last successful reconciliation that fetched state from OpenStack. It is updated each time the controller successfully reads the resource state from the OpenStack API.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.RegisteredLimitResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + func schema_openstack_resource_controller_v2_api_v1alpha1_Role(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/cmd/resource-generator/main.go b/cmd/resource-generator/main.go index c5d6bc042..163b66e23 100644 --- a/cmd/resource-generator/main.go +++ b/cmd/resource-generator/main.go @@ -189,6 +189,10 @@ var resources []templateFields = []templateFields{ { Name: "ApplicationCredential", }, + { + Name: "RegisteredLimit", + IsNotNamed: true, + }, } // These resources won't be generated diff --git a/config/crd/bases/openstack.k-orc.cloud_registeredlimits.yaml b/config/crd/bases/openstack.k-orc.cloud_registeredlimits.yaml new file mode 100644 index 000000000..00e1d5048 --- /dev/null +++ b/config/crd/bases/openstack.k-orc.cloud_registeredlimits.yaml @@ -0,0 +1,321 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.20.1 + name: registeredlimits.openstack.k-orc.cloud +spec: + group: openstack.k-orc.cloud + names: + categories: + - openstack + kind: RegisteredLimit + listKind: RegisteredLimitList + plural: registeredlimits + singular: registeredlimit + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Resource ID + jsonPath: .status.id + name: ID + type: string + - description: Availability status of resource + jsonPath: .status.conditions[?(@.type=='Available')].status + name: Available + type: string + - description: Message describing current progress status + jsonPath: .status.conditions[?(@.type=='Progressing')].message + name: Message + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: RegisteredLimit is the Schema for an ORC resource. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: spec specifies the desired state of the resource. + properties: + cloudCredentialsRef: + description: cloudCredentialsRef points to a secret containing OpenStack + credentials + properties: + cloudName: + description: cloudName specifies the name of the entry in the + clouds.yaml file to use. + maxLength: 256 + minLength: 1 + type: string + secretName: + description: |- + secretName is the name of a secret in the same namespace as the resource being provisioned. + The secret must contain a key named `clouds.yaml` which contains an OpenStack clouds.yaml file. + The secret may optionally contain a key named `cacert` containing a PEM-encoded CA certificate. + maxLength: 253 + minLength: 1 + type: string + required: + - cloudName + - secretName + type: object + import: + description: |- + import refers to an existing OpenStack resource which will be imported instead of + creating a new one. + maxProperties: 1 + minProperties: 1 + properties: + filter: + description: |- + filter contains a resource query which is expected to return a single + result. The controller will continue to retry if filter returns no + results. If filter returns multiple results the controller will set an + error state and will not continue to retry. + minProperties: 1 + properties: + description: + description: description of the existing resource + maxLength: 255 + minLength: 1 + type: string + name: + description: name of the existing resource + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + type: object + id: + description: |- + id contains the unique identifier of an existing OpenStack resource. Note + that when specifying an import by ID, the resource MUST already exist. + The ORC object will enter an error state if the resource does not exist. + format: uuid + maxLength: 36 + type: string + type: object + managedOptions: + description: managedOptions specifies options which may be applied + to managed objects. + properties: + onDelete: + default: delete + description: |- + onDelete specifies the behaviour of the controller when the ORC + object is deleted. Options are `delete` - delete the OpenStack resource; + `detach` - do not delete the OpenStack resource. If not specified, the + default is `delete`. + enum: + - delete + - detach + type: string + type: object + managementPolicy: + default: managed + description: |- + managementPolicy defines how ORC will treat the object. Valid values are + `managed`: ORC will create, update, and delete the resource; `unmanaged`: + ORC will import an existing resource, and will not apply updates to it or + delete it. + enum: + - managed + - unmanaged + type: string + x-kubernetes-validations: + - message: managementPolicy is immutable + rule: self == oldSelf + resource: + description: |- + resource specifies the desired state of the resource. + + resource may not be specified if the management policy is `unmanaged`. + + resource must be specified if the management policy is `managed`. + properties: + description: + description: description is a human-readable description for the + resource. + maxLength: 255 + minLength: 1 + type: string + name: + description: |- + name will be the name of the created resource. If not specified, the + name of the ORC object will be used. + maxLength: 255 + minLength: 1 + pattern: ^[^,]+$ + type: string + serviceRef: + description: serviceRef is a reference to the ORC Service which + this resource is associated with. + maxLength: 253 + minLength: 1 + type: string + x-kubernetes-validations: + - message: serviceRef is immutable + rule: self == oldSelf + required: + - serviceRef + type: object + resyncPeriod: + description: |- + resyncPeriod defines how frequently the controller will re-reconcile + this resource even when no changes have been detected. This overrides + the global default resync period. The value must be a valid Go duration + string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for + this resource. Very low values may cause excessive OpenStack API load. + type: string + required: + - cloudCredentialsRef + type: object + x-kubernetes-validations: + - message: resource must be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? has(self.resource) : true' + - message: import may not be specified when policy is managed + rule: 'self.managementPolicy == ''managed'' ? !has(self.__import__) + : true' + - message: resource may not be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? !has(self.resource) + : true' + - message: import must be specified when policy is unmanaged + rule: 'self.managementPolicy == ''unmanaged'' ? has(self.__import__) + : true' + - message: managedOptions may only be provided when policy is managed + rule: 'has(self.managedOptions) ? self.managementPolicy == ''managed'' + : true' + status: + description: status defines the observed state of the resource. + properties: + conditions: + description: |- + conditions represents the observed status of the object. + Known .status.conditions.type are: "Available", "Progressing" + + Available represents the availability of the OpenStack resource. If it is + true then the resource is ready for use. + + Progressing indicates whether the controller is still attempting to + reconcile the current state of the OpenStack resource to the desired + state. Progressing will be False either because the desired state has + been achieved, or because some terminal error prevents it from ever being + achieved and the controller is no longer attempting to reconcile. If + Progressing is True, an observer waiting on the resource should continue + to wait. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 32 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + id: + description: id is the unique identifier of the OpenStack resource. + maxLength: 1024 + type: string + lastSyncTime: + description: |- + lastSyncTime is the timestamp of the last successful reconciliation + that fetched state from OpenStack. It is updated each time the + controller successfully reads the resource state from the OpenStack + API. + format: date-time + type: string + resource: + description: resource contains the observed state of the OpenStack + resource. + properties: + description: + description: description is a human-readable description for the + resource. + maxLength: 1024 + type: string + name: + description: name is a Human-readable name for the resource. Might + not be unique. + maxLength: 1024 + type: string + serviceID: + description: serviceID is the ID of the Service to which the resource + is associated. + maxLength: 1024 + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 9c133d11c..944b1c3b5 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -15,6 +15,7 @@ resources: - bases/openstack.k-orc.cloud_networks.yaml - bases/openstack.k-orc.cloud_ports.yaml - bases/openstack.k-orc.cloud_projects.yaml +- bases/openstack.k-orc.cloud_registeredlimits.yaml - bases/openstack.k-orc.cloud_roles.yaml - bases/openstack.k-orc.cloud_roleassignments.yaml - bases/openstack.k-orc.cloud_routers.yaml diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index ceb05e15e..bdfa6ae6b 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -13,6 +13,7 @@ resources: - openstack_v1alpha1_network.yaml - openstack_v1alpha1_port.yaml - openstack_v1alpha1_project.yaml +- openstack_v1alpha1_registeredlimit.yaml - openstack_v1alpha1_role.yaml - openstack_v1alpha1_roleassignment.yaml - openstack_v1alpha1_router.yaml diff --git a/internal/controllers/registeredlimit/zz_generated.adapter.go b/internal/controllers/registeredlimit/zz_generated.adapter.go new file mode 100644 index 000000000..2038cc49b --- /dev/null +++ b/internal/controllers/registeredlimit/zz_generated.adapter.go @@ -0,0 +1,88 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package registeredlimit + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + orcv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/interfaces" +) + +// Fundamental types +type ( + orcObjectT = orcv1alpha1.RegisteredLimit + orcObjectListT = orcv1alpha1.RegisteredLimitList + resourceSpecT = orcv1alpha1.RegisteredLimitResourceSpec + filterT = orcv1alpha1.RegisteredLimitFilter +) + +// Derived types +type ( + orcObjectPT = *orcObjectT + adapterI = interfaces.APIObjectAdapter[orcObjectPT, resourceSpecT, filterT] + adapterT = registeredlimitAdapter +) + +type registeredlimitAdapter struct { + *orcv1alpha1.RegisteredLimit +} + +var _ adapterI = &adapterT{} + +func (f adapterT) GetObject() orcObjectPT { + return f.RegisteredLimit +} + +func (f adapterT) GetManagementPolicy() orcv1alpha1.ManagementPolicy { + return f.Spec.ManagementPolicy +} + +func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions { + return f.Spec.ManagedOptions +} + +func (f adapterT) GetResyncPeriod() *metav1.Duration { + return f.Spec.ResyncPeriod +} + +func (f adapterT) GetLastSyncTime() *metav1.Time { + return f.Status.LastSyncTime +} + +func (f adapterT) GetStatusID() *string { + return f.Status.ID +} + +func (f adapterT) GetResourceSpec() *resourceSpecT { + return f.Spec.Resource +} + +func (f adapterT) GetImportID() *string { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.ID +} + +func (f adapterT) GetImportFilter() *filterT { + if f.Spec.Import == nil { + return nil + } + return f.Spec.Import.Filter +} diff --git a/internal/controllers/registeredlimit/zz_generated.controller.go b/internal/controllers/registeredlimit/zz_generated.controller.go new file mode 100644 index 000000000..da7df7528 --- /dev/null +++ b/internal/controllers/registeredlimit/zz_generated.controller.go @@ -0,0 +1,45 @@ +// Code generated by resource-generator. DO NOT EDIT. +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package registeredlimit + +import ( + corev1 "k8s.io/api/core/v1" + + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" + orcstrings "github.com/k-orc/openstack-resource-controller/v2/internal/util/strings" +) + +var ( + // NOTE: controllerName must be defined in any controller using this template + + // finalizer is the string this controller adds to an object's Finalizers + finalizer = orcstrings.GetFinalizerName(controllerName) + + // externalObjectFieldOwner is the field owner we use when using + // server-side-apply on objects we don't control + externalObjectFieldOwner = orcstrings.GetSSAFieldOwner(controllerName) + + credentialsDependency = dependency.NewDeletionGuardDependency[*orcObjectListT, *corev1.Secret]( + "spec.cloudCredentialsRef.secretName", + func(obj orcObjectPT) []string { + return []string{obj.Spec.CloudCredentialsRef.SecretName} + }, + finalizer, externalObjectFieldOwner, + dependency.OverrideDependencyName("credentials"), + ) +) diff --git a/internal/osclients/mock/doc.go b/internal/osclients/mock/doc.go index 466a548e6..d4908f3dd 100644 --- a/internal/osclients/mock/doc.go +++ b/internal/osclients/mock/doc.go @@ -53,6 +53,9 @@ import ( //go:generate mockgen -package mock -destination=keypair.go -source=../keypair.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock KeyPairClient //go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt keypair.go > _keypair.go && mv _keypair.go keypair.go" +//go:generate mockgen -package mock -destination=registeredlimit.go -source=../registeredlimit.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock RegisteredLimitClient +//go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt registeredlimit.go > _registeredlimit.go && mv _registeredlimit.go registeredlimit.go" + //go:generate mockgen -package mock -destination=role.go -source=../role.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock RoleClient //go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt role.go > _role.go && mv _role.go role.go" diff --git a/internal/osclients/mock/registeredlimit.go b/internal/osclients/mock/registeredlimit.go new file mode 100644 index 000000000..dfd5eedce --- /dev/null +++ b/internal/osclients/mock/registeredlimit.go @@ -0,0 +1,131 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by MockGen. DO NOT EDIT. +// Source: ../registeredlimit.go +// +// Generated by this command: +// +// mockgen -package mock -destination=registeredlimit.go -source=../registeredlimit.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock RegisteredLimitClient +// + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + iter "iter" + reflect "reflect" + + registeredlimits "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/registeredlimits" + gomock "go.uber.org/mock/gomock" +) + +// MockRegisteredLimitClient is a mock of RegisteredLimitClient interface. +type MockRegisteredLimitClient struct { + ctrl *gomock.Controller + recorder *MockRegisteredLimitClientMockRecorder + isgomock struct{} +} + +// MockRegisteredLimitClientMockRecorder is the mock recorder for MockRegisteredLimitClient. +type MockRegisteredLimitClientMockRecorder struct { + mock *MockRegisteredLimitClient +} + +// NewMockRegisteredLimitClient creates a new mock instance. +func NewMockRegisteredLimitClient(ctrl *gomock.Controller) *MockRegisteredLimitClient { + mock := &MockRegisteredLimitClient{ctrl: ctrl} + mock.recorder = &MockRegisteredLimitClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRegisteredLimitClient) EXPECT() *MockRegisteredLimitClientMockRecorder { + return m.recorder +} + +// CreateRegisteredLimit mocks base method. +func (m *MockRegisteredLimitClient) CreateRegisteredLimit(ctx context.Context, opts registeredlimits.CreateOptsBuilder) (*registeredlimits.RegisteredLimit, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateRegisteredLimit", ctx, opts) + ret0, _ := ret[0].(*registeredlimits.RegisteredLimit) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateRegisteredLimit indicates an expected call of CreateRegisteredLimit. +func (mr *MockRegisteredLimitClientMockRecorder) CreateRegisteredLimit(ctx, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRegisteredLimit", reflect.TypeOf((*MockRegisteredLimitClient)(nil).CreateRegisteredLimit), ctx, opts) +} + +// DeleteRegisteredLimit mocks base method. +func (m *MockRegisteredLimitClient) DeleteRegisteredLimit(ctx context.Context, resourceID string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteRegisteredLimit", ctx, resourceID) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteRegisteredLimit indicates an expected call of DeleteRegisteredLimit. +func (mr *MockRegisteredLimitClientMockRecorder) DeleteRegisteredLimit(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRegisteredLimit", reflect.TypeOf((*MockRegisteredLimitClient)(nil).DeleteRegisteredLimit), ctx, resourceID) +} + +// GetRegisteredLimit mocks base method. +func (m *MockRegisteredLimitClient) GetRegisteredLimit(ctx context.Context, resourceID string) (*registeredlimits.RegisteredLimit, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetRegisteredLimit", ctx, resourceID) + ret0, _ := ret[0].(*registeredlimits.RegisteredLimit) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetRegisteredLimit indicates an expected call of GetRegisteredLimit. +func (mr *MockRegisteredLimitClientMockRecorder) GetRegisteredLimit(ctx, resourceID any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRegisteredLimit", reflect.TypeOf((*MockRegisteredLimitClient)(nil).GetRegisteredLimit), ctx, resourceID) +} + +// ListRegisteredLimits mocks base method. +func (m *MockRegisteredLimitClient) ListRegisteredLimits(ctx context.Context, listOpts registeredlimits.ListOptsBuilder) iter.Seq2[*registeredlimits.RegisteredLimit, error] { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListRegisteredLimits", ctx, listOpts) + ret0, _ := ret[0].(iter.Seq2[*registeredlimits.RegisteredLimit, error]) + return ret0 +} + +// ListRegisteredLimits indicates an expected call of ListRegisteredLimits. +func (mr *MockRegisteredLimitClientMockRecorder) ListRegisteredLimits(ctx, listOpts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRegisteredLimits", reflect.TypeOf((*MockRegisteredLimitClient)(nil).ListRegisteredLimits), ctx, listOpts) +} + +// UpdateRegisteredLimit mocks base method. +func (m *MockRegisteredLimitClient) UpdateRegisteredLimit(ctx context.Context, id string, opts registeredlimits.UpdateOptsBuilder) (*registeredlimits.RegisteredLimit, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateRegisteredLimit", ctx, id, opts) + ret0, _ := ret[0].(*registeredlimits.RegisteredLimit) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateRegisteredLimit indicates an expected call of UpdateRegisteredLimit. +func (mr *MockRegisteredLimitClientMockRecorder) UpdateRegisteredLimit(ctx, id, opts any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateRegisteredLimit", reflect.TypeOf((*MockRegisteredLimitClient)(nil).UpdateRegisteredLimit), ctx, id, opts) +} diff --git a/kuttl-test.yaml b/kuttl-test.yaml index 90fc98dde..e675eb5bd 100644 --- a/kuttl-test.yaml +++ b/kuttl-test.yaml @@ -14,6 +14,7 @@ testDirs: - ./internal/controllers/network/tests/ - ./internal/controllers/port/tests/ - ./internal/controllers/project/tests/ +- ./internal/controllers/registeredlimit/tests/ - ./internal/controllers/role/tests/ - ./internal/controllers/roleassignment/tests/ - ./internal/controllers/router/tests/ diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimit.go b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimit.go new file mode 100644 index 000000000..dd10f671d --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimit.go @@ -0,0 +1,281 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + internal "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/internal" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + managedfields "k8s.io/apimachinery/pkg/util/managedfields" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// RegisteredLimitApplyConfiguration represents a declarative configuration of the RegisteredLimit type for use +// with apply. +type RegisteredLimitApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Spec *RegisteredLimitSpecApplyConfiguration `json:"spec,omitempty"` + Status *RegisteredLimitStatusApplyConfiguration `json:"status,omitempty"` +} + +// RegisteredLimit constructs a declarative configuration of the RegisteredLimit type for use with +// apply. +func RegisteredLimit(name, namespace string) *RegisteredLimitApplyConfiguration { + b := &RegisteredLimitApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("RegisteredLimit") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b +} + +// ExtractRegisteredLimit extracts the applied configuration owned by fieldManager from +// registeredLimit. If no managedFields are found in registeredLimit for fieldManager, a +// RegisteredLimitApplyConfiguration is returned with only the Name, Namespace (if applicable), +// APIVersion and Kind populated. It is possible that no managed fields were found for because other +// field managers have taken ownership of all the fields previously owned by fieldManager, or because +// the fieldManager never owned fields any fields. +// registeredLimit must be a unmodified RegisteredLimit API object that was retrieved from the Kubernetes API. +// ExtractRegisteredLimit provides a way to perform a extract/modify-in-place/apply workflow. +// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously +// applied if another fieldManager has updated or force applied any of the previously applied fields. +// Experimental! +func ExtractRegisteredLimit(registeredLimit *apiv1alpha1.RegisteredLimit, fieldManager string) (*RegisteredLimitApplyConfiguration, error) { + return extractRegisteredLimit(registeredLimit, fieldManager, "") +} + +// ExtractRegisteredLimitStatus is the same as ExtractRegisteredLimit except +// that it extracts the status subresource applied configuration. +// Experimental! +func ExtractRegisteredLimitStatus(registeredLimit *apiv1alpha1.RegisteredLimit, fieldManager string) (*RegisteredLimitApplyConfiguration, error) { + return extractRegisteredLimit(registeredLimit, fieldManager, "status") +} + +func extractRegisteredLimit(registeredLimit *apiv1alpha1.RegisteredLimit, fieldManager string, subresource string) (*RegisteredLimitApplyConfiguration, error) { + b := &RegisteredLimitApplyConfiguration{} + err := managedfields.ExtractInto(registeredLimit, internal.Parser().Type("com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimit"), fieldManager, b, subresource) + if err != nil { + return nil, err + } + b.WithName(registeredLimit.Name) + b.WithNamespace(registeredLimit.Namespace) + + b.WithKind("RegisteredLimit") + b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1") + return b, nil +} +func (b RegisteredLimitApplyConfiguration) IsApplyConfiguration() {} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithKind(value string) *RegisteredLimitApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithAPIVersion(value string) *RegisteredLimitApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithName(value string) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithGenerateName(value string) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithNamespace(value string) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithUID(value types.UID) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithResourceVersion(value string) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithGeneration(value int64) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithCreationTimestamp(value metav1.Time) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *RegisteredLimitApplyConfiguration) WithLabels(entries map[string]string) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *RegisteredLimitApplyConfiguration) WithAnnotations(entries map[string]string) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *RegisteredLimitApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *RegisteredLimitApplyConfiguration) WithFinalizers(values ...string) *RegisteredLimitApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *RegisteredLimitApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSpec sets the Spec field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Spec field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithSpec(value *RegisteredLimitSpecApplyConfiguration) *RegisteredLimitApplyConfiguration { + b.Spec = value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *RegisteredLimitApplyConfiguration) WithStatus(value *RegisteredLimitStatusApplyConfiguration) *RegisteredLimitApplyConfiguration { + b.Status = value + return b +} + +// GetKind retrieves the value of the Kind field in the declarative configuration. +func (b *RegisteredLimitApplyConfiguration) GetKind() *string { + return b.TypeMetaApplyConfiguration.Kind +} + +// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration. +func (b *RegisteredLimitApplyConfiguration) GetAPIVersion() *string { + return b.TypeMetaApplyConfiguration.APIVersion +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *RegisteredLimitApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} + +// GetNamespace retrieves the value of the Namespace field in the declarative configuration. +func (b *RegisteredLimitApplyConfiguration) GetNamespace() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Namespace +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitfilter.go new file mode 100644 index 000000000..1d77a6ad0 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitfilter.go @@ -0,0 +1,52 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// RegisteredLimitFilterApplyConfiguration represents a declarative configuration of the RegisteredLimitFilter type for use +// with apply. +type RegisteredLimitFilterApplyConfiguration struct { + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + Description *string `json:"description,omitempty"` +} + +// RegisteredLimitFilterApplyConfiguration constructs a declarative configuration of the RegisteredLimitFilter type for use with +// apply. +func RegisteredLimitFilter() *RegisteredLimitFilterApplyConfiguration { + return &RegisteredLimitFilterApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *RegisteredLimitFilterApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *RegisteredLimitFilterApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *RegisteredLimitFilterApplyConfiguration) WithDescription(value string) *RegisteredLimitFilterApplyConfiguration { + b.Description = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitimport.go new file mode 100644 index 000000000..e8ba245e2 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitimport.go @@ -0,0 +1,48 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// RegisteredLimitImportApplyConfiguration represents a declarative configuration of the RegisteredLimitImport type for use +// with apply. +type RegisteredLimitImportApplyConfiguration struct { + ID *string `json:"id,omitempty"` + Filter *RegisteredLimitFilterApplyConfiguration `json:"filter,omitempty"` +} + +// RegisteredLimitImportApplyConfiguration constructs a declarative configuration of the RegisteredLimitImport type for use with +// apply. +func RegisteredLimitImport() *RegisteredLimitImportApplyConfiguration { + return &RegisteredLimitImportApplyConfiguration{} +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *RegisteredLimitImportApplyConfiguration) WithID(value string) *RegisteredLimitImportApplyConfiguration { + b.ID = &value + return b +} + +// WithFilter sets the Filter field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Filter field is set to the value of the last call. +func (b *RegisteredLimitImportApplyConfiguration) WithFilter(value *RegisteredLimitFilterApplyConfiguration) *RegisteredLimitImportApplyConfiguration { + b.Filter = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcespec.go new file mode 100644 index 000000000..f1208e30f --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcespec.go @@ -0,0 +1,61 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" +) + +// RegisteredLimitResourceSpecApplyConfiguration represents a declarative configuration of the RegisteredLimitResourceSpec type for use +// with apply. +type RegisteredLimitResourceSpecApplyConfiguration struct { + Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + ServiceRef *apiv1alpha1.KubernetesNameRef `json:"serviceRef,omitempty"` +} + +// RegisteredLimitResourceSpecApplyConfiguration constructs a declarative configuration of the RegisteredLimitResourceSpec type for use with +// apply. +func RegisteredLimitResourceSpec() *RegisteredLimitResourceSpecApplyConfiguration { + return &RegisteredLimitResourceSpecApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *RegisteredLimitResourceSpecApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *RegisteredLimitResourceSpecApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *RegisteredLimitResourceSpecApplyConfiguration) WithDescription(value string) *RegisteredLimitResourceSpecApplyConfiguration { + b.Description = &value + return b +} + +// WithServiceRef sets the ServiceRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ServiceRef field is set to the value of the last call. +func (b *RegisteredLimitResourceSpecApplyConfiguration) WithServiceRef(value apiv1alpha1.KubernetesNameRef) *RegisteredLimitResourceSpecApplyConfiguration { + b.ServiceRef = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcestatus.go new file mode 100644 index 000000000..a2e3077a2 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcestatus.go @@ -0,0 +1,57 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// RegisteredLimitResourceStatusApplyConfiguration represents a declarative configuration of the RegisteredLimitResourceStatus type for use +// with apply. +type RegisteredLimitResourceStatusApplyConfiguration struct { + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + ServiceID *string `json:"serviceID,omitempty"` +} + +// RegisteredLimitResourceStatusApplyConfiguration constructs a declarative configuration of the RegisteredLimitResourceStatus type for use with +// apply. +func RegisteredLimitResourceStatus() *RegisteredLimitResourceStatusApplyConfiguration { + return &RegisteredLimitResourceStatusApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *RegisteredLimitResourceStatusApplyConfiguration) WithName(value string) *RegisteredLimitResourceStatusApplyConfiguration { + b.Name = &value + return b +} + +// WithDescription sets the Description field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Description field is set to the value of the last call. +func (b *RegisteredLimitResourceStatusApplyConfiguration) WithDescription(value string) *RegisteredLimitResourceStatusApplyConfiguration { + b.Description = &value + return b +} + +// WithServiceID sets the ServiceID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ServiceID field is set to the value of the last call. +func (b *RegisteredLimitResourceStatusApplyConfiguration) WithServiceID(value string) *RegisteredLimitResourceStatusApplyConfiguration { + b.ServiceID = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitspec.go new file mode 100644 index 000000000..7bdf58935 --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitspec.go @@ -0,0 +1,89 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// RegisteredLimitSpecApplyConfiguration represents a declarative configuration of the RegisteredLimitSpec type for use +// with apply. +type RegisteredLimitSpecApplyConfiguration struct { + Import *RegisteredLimitImportApplyConfiguration `json:"import,omitempty"` + Resource *RegisteredLimitResourceSpecApplyConfiguration `json:"resource,omitempty"` + ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"` + ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"` + ResyncPeriod *v1.Duration `json:"resyncPeriod,omitempty"` + CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"` +} + +// RegisteredLimitSpecApplyConfiguration constructs a declarative configuration of the RegisteredLimitSpec type for use with +// apply. +func RegisteredLimitSpec() *RegisteredLimitSpecApplyConfiguration { + return &RegisteredLimitSpecApplyConfiguration{} +} + +// WithImport sets the Import field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Import field is set to the value of the last call. +func (b *RegisteredLimitSpecApplyConfiguration) WithImport(value *RegisteredLimitImportApplyConfiguration) *RegisteredLimitSpecApplyConfiguration { + b.Import = value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *RegisteredLimitSpecApplyConfiguration) WithResource(value *RegisteredLimitResourceSpecApplyConfiguration) *RegisteredLimitSpecApplyConfiguration { + b.Resource = value + return b +} + +// WithManagementPolicy sets the ManagementPolicy field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagementPolicy field is set to the value of the last call. +func (b *RegisteredLimitSpecApplyConfiguration) WithManagementPolicy(value apiv1alpha1.ManagementPolicy) *RegisteredLimitSpecApplyConfiguration { + b.ManagementPolicy = &value + return b +} + +// WithManagedOptions sets the ManagedOptions field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ManagedOptions field is set to the value of the last call. +func (b *RegisteredLimitSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsApplyConfiguration) *RegisteredLimitSpecApplyConfiguration { + b.ManagedOptions = value + return b +} + +// WithResyncPeriod sets the ResyncPeriod field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResyncPeriod field is set to the value of the last call. +func (b *RegisteredLimitSpecApplyConfiguration) WithResyncPeriod(value v1.Duration) *RegisteredLimitSpecApplyConfiguration { + b.ResyncPeriod = &value + return b +} + +// WithCloudCredentialsRef sets the CloudCredentialsRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CloudCredentialsRef field is set to the value of the last call. +func (b *RegisteredLimitSpecApplyConfiguration) WithCloudCredentialsRef(value *CloudCredentialsReferenceApplyConfiguration) *RegisteredLimitSpecApplyConfiguration { + b.CloudCredentialsRef = value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitstatus.go new file mode 100644 index 000000000..d2c87a1ff --- /dev/null +++ b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitstatus.go @@ -0,0 +1,76 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// RegisteredLimitStatusApplyConfiguration represents a declarative configuration of the RegisteredLimitStatus type for use +// with apply. +type RegisteredLimitStatusApplyConfiguration struct { + Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"` + ID *string `json:"id,omitempty"` + Resource *RegisteredLimitResourceStatusApplyConfiguration `json:"resource,omitempty"` + LastSyncTime *metav1.Time `json:"lastSyncTime,omitempty"` +} + +// RegisteredLimitStatusApplyConfiguration constructs a declarative configuration of the RegisteredLimitStatus type for use with +// apply. +func RegisteredLimitStatus() *RegisteredLimitStatusApplyConfiguration { + return &RegisteredLimitStatusApplyConfiguration{} +} + +// WithConditions adds the given value to the Conditions field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Conditions field. +func (b *RegisteredLimitStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *RegisteredLimitStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithConditions") + } + b.Conditions = append(b.Conditions, *values[i]) + } + return b +} + +// WithID sets the ID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ID field is set to the value of the last call. +func (b *RegisteredLimitStatusApplyConfiguration) WithID(value string) *RegisteredLimitStatusApplyConfiguration { + b.ID = &value + return b +} + +// WithResource sets the Resource field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Resource field is set to the value of the last call. +func (b *RegisteredLimitStatusApplyConfiguration) WithResource(value *RegisteredLimitResourceStatusApplyConfiguration) *RegisteredLimitStatusApplyConfiguration { + b.Resource = value + return b +} + +// WithLastSyncTime sets the LastSyncTime field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LastSyncTime field is set to the value of the last call. +func (b *RegisteredLimitStatusApplyConfiguration) WithLastSyncTime(value metav1.Time) *RegisteredLimitStatusApplyConfiguration { + b.LastSyncTime = &value + return b +} diff --git a/pkg/clients/applyconfiguration/internal/internal.go b/pkg/clients/applyconfiguration/internal/internal.go index 9fc18f739..9ffa9f549 100644 --- a/pkg/clients/applyconfiguration/internal/internal.go +++ b/pkg/clients/applyconfiguration/internal/internal.go @@ -2181,6 +2181,111 @@ var schemaYAML = typed.YAMLObject(`types: - name: segmentationID type: scalar: numeric +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimit + map: + fields: + - name: apiVersion + type: + scalar: string + - name: kind + type: + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} + - name: spec + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitSpec + default: {} + - name: status + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitStatus + default: {} +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitFilter + map: + fields: + - name: description + type: + scalar: string + - name: name + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitImport + map: + fields: + - name: filter + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitFilter + - name: id + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitResourceSpec + map: + fields: + - name: description + type: + scalar: string + - name: name + type: + scalar: string + - name: serviceRef + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitResourceStatus + map: + fields: + - name: description + type: + scalar: string + - name: name + type: + scalar: string + - name: serviceID + type: + scalar: string +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitSpec + map: + fields: + - name: cloudCredentialsRef + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.CloudCredentialsReference + default: {} + - name: import + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitImport + - name: managedOptions + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.ManagedOptions + - name: managementPolicy + type: + scalar: string + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitResourceSpec + - name: resyncPeriod + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Duration +- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitStatus + map: + fields: + - name: conditions + type: + list: + elementType: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition + elementRelationship: associative + keys: + - type + - name: id + type: + scalar: string + - name: lastSyncTime + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time + - name: resource + type: + namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitResourceStatus - name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.Role map: fields: diff --git a/pkg/clients/applyconfiguration/utils.go b/pkg/clients/applyconfiguration/utils.go index 22e66aea0..fee13d23f 100644 --- a/pkg/clients/applyconfiguration/utils.go +++ b/pkg/clients/applyconfiguration/utils.go @@ -268,6 +268,20 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apiv1alpha1.ProjectStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ProviderPropertiesStatus"): return &apiv1alpha1.ProviderPropertiesStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RegisteredLimit"): + return &apiv1alpha1.RegisteredLimitApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RegisteredLimitFilter"): + return &apiv1alpha1.RegisteredLimitFilterApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RegisteredLimitImport"): + return &apiv1alpha1.RegisteredLimitImportApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RegisteredLimitResourceSpec"): + return &apiv1alpha1.RegisteredLimitResourceSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RegisteredLimitResourceStatus"): + return &apiv1alpha1.RegisteredLimitResourceStatusApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RegisteredLimitSpec"): + return &apiv1alpha1.RegisteredLimitSpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("RegisteredLimitStatus"): + return &apiv1alpha1.RegisteredLimitStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("Role"): return &apiv1alpha1.RoleApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("RoleAssignment"): diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/api_client.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/api_client.go index e39fc5dc9..7ca2cc007 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/api_client.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/api_client.go @@ -40,6 +40,7 @@ type OpenstackV1alpha1Interface interface { NetworksGetter PortsGetter ProjectsGetter + RegisteredLimitsGetter RolesGetter RoleAssignmentsGetter RoutersGetter @@ -109,6 +110,10 @@ func (c *OpenstackV1alpha1Client) Projects(namespace string) ProjectInterface { return newProjects(c, namespace) } +func (c *OpenstackV1alpha1Client) RegisteredLimits(namespace string) RegisteredLimitInterface { + return newRegisteredLimits(c, namespace) +} + func (c *OpenstackV1alpha1Client) Roles(namespace string) RoleInterface { return newRoles(c, namespace) } diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_api_client.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_api_client.go index 5015aed35..dad9146f0 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_api_client.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_api_client.go @@ -76,6 +76,10 @@ func (c *FakeOpenstackV1alpha1) Projects(namespace string) v1alpha1.ProjectInter return newFakeProjects(c, namespace) } +func (c *FakeOpenstackV1alpha1) RegisteredLimits(namespace string) v1alpha1.RegisteredLimitInterface { + return newFakeRegisteredLimits(c, namespace) +} + func (c *FakeOpenstackV1alpha1) Roles(namespace string) v1alpha1.RoleInterface { return newFakeRoles(c, namespace) } diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_registeredlimit.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_registeredlimit.go new file mode 100644 index 000000000..d20464c93 --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_registeredlimit.go @@ -0,0 +1,53 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + typedapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/typed/api/v1alpha1" + gentype "k8s.io/client-go/gentype" +) + +// fakeRegisteredLimits implements RegisteredLimitInterface +type fakeRegisteredLimits struct { + *gentype.FakeClientWithListAndApply[*v1alpha1.RegisteredLimit, *v1alpha1.RegisteredLimitList, *apiv1alpha1.RegisteredLimitApplyConfiguration] + Fake *FakeOpenstackV1alpha1 +} + +func newFakeRegisteredLimits(fake *FakeOpenstackV1alpha1, namespace string) typedapiv1alpha1.RegisteredLimitInterface { + return &fakeRegisteredLimits{ + gentype.NewFakeClientWithListAndApply[*v1alpha1.RegisteredLimit, *v1alpha1.RegisteredLimitList, *apiv1alpha1.RegisteredLimitApplyConfiguration]( + fake.Fake, + namespace, + v1alpha1.SchemeGroupVersion.WithResource("registeredlimits"), + v1alpha1.SchemeGroupVersion.WithKind("RegisteredLimit"), + func() *v1alpha1.RegisteredLimit { return &v1alpha1.RegisteredLimit{} }, + func() *v1alpha1.RegisteredLimitList { return &v1alpha1.RegisteredLimitList{} }, + func(dst, src *v1alpha1.RegisteredLimitList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha1.RegisteredLimitList) []*v1alpha1.RegisteredLimit { + return gentype.ToPointerSlice(list.Items) + }, + func(list *v1alpha1.RegisteredLimitList, items []*v1alpha1.RegisteredLimit) { + list.Items = gentype.FromPointerSlice(items) + }, + ), + fake, + } +} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/generated_expansion.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/generated_expansion.go index 7c5d67d45..25d6f1156 100644 --- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/generated_expansion.go +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/generated_expansion.go @@ -42,6 +42,8 @@ type PortExpansion interface{} type ProjectExpansion interface{} +type RegisteredLimitExpansion interface{} + type RoleExpansion interface{} type RoleAssignmentExpansion interface{} diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/registeredlimit.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/registeredlimit.go new file mode 100644 index 000000000..9ace84641 --- /dev/null +++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/registeredlimit.go @@ -0,0 +1,74 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + applyconfigurationapiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/applyconfiguration/api/v1alpha1" + scheme "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// RegisteredLimitsGetter has a method to return a RegisteredLimitInterface. +// A group's client should implement this interface. +type RegisteredLimitsGetter interface { + RegisteredLimits(namespace string) RegisteredLimitInterface +} + +// RegisteredLimitInterface has methods to work with RegisteredLimit resources. +type RegisteredLimitInterface interface { + Create(ctx context.Context, registeredLimit *apiv1alpha1.RegisteredLimit, opts v1.CreateOptions) (*apiv1alpha1.RegisteredLimit, error) + Update(ctx context.Context, registeredLimit *apiv1alpha1.RegisteredLimit, opts v1.UpdateOptions) (*apiv1alpha1.RegisteredLimit, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, registeredLimit *apiv1alpha1.RegisteredLimit, opts v1.UpdateOptions) (*apiv1alpha1.RegisteredLimit, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*apiv1alpha1.RegisteredLimit, error) + List(ctx context.Context, opts v1.ListOptions) (*apiv1alpha1.RegisteredLimitList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *apiv1alpha1.RegisteredLimit, err error) + Apply(ctx context.Context, registeredLimit *applyconfigurationapiv1alpha1.RegisteredLimitApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.RegisteredLimit, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, registeredLimit *applyconfigurationapiv1alpha1.RegisteredLimitApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.RegisteredLimit, err error) + RegisteredLimitExpansion +} + +// registeredLimits implements RegisteredLimitInterface +type registeredLimits struct { + *gentype.ClientWithListAndApply[*apiv1alpha1.RegisteredLimit, *apiv1alpha1.RegisteredLimitList, *applyconfigurationapiv1alpha1.RegisteredLimitApplyConfiguration] +} + +// newRegisteredLimits returns a RegisteredLimits +func newRegisteredLimits(c *OpenstackV1alpha1Client, namespace string) *registeredLimits { + return ®isteredLimits{ + gentype.NewClientWithListAndApply[*apiv1alpha1.RegisteredLimit, *apiv1alpha1.RegisteredLimitList, *applyconfigurationapiv1alpha1.RegisteredLimitApplyConfiguration]( + "registeredlimits", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *apiv1alpha1.RegisteredLimit { return &apiv1alpha1.RegisteredLimit{} }, + func() *apiv1alpha1.RegisteredLimitList { return &apiv1alpha1.RegisteredLimitList{} }, + ), + } +} diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/interface.go b/pkg/clients/informers/externalversions/api/v1alpha1/interface.go index 69d2bdeaf..9f4b58ac4 100644 --- a/pkg/clients/informers/externalversions/api/v1alpha1/interface.go +++ b/pkg/clients/informers/externalversions/api/v1alpha1/interface.go @@ -48,6 +48,8 @@ type Interface interface { Ports() PortInformer // Projects returns a ProjectInformer. Projects() ProjectInformer + // RegisteredLimits returns a RegisteredLimitInformer. + RegisteredLimits() RegisteredLimitInformer // Roles returns a RoleInformer. Roles() RoleInformer // RoleAssignments returns a RoleAssignmentInformer. @@ -149,6 +151,11 @@ func (v *version) Projects() ProjectInformer { return &projectInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// RegisteredLimits returns a RegisteredLimitInformer. +func (v *version) RegisteredLimits() RegisteredLimitInformer { + return ®isteredLimitInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // Roles returns a RoleInformer. func (v *version) Roles() RoleInformer { return &roleInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/registeredlimit.go b/pkg/clients/informers/externalversions/api/v1alpha1/registeredlimit.go new file mode 100644 index 000000000..b4ea6a2c5 --- /dev/null +++ b/pkg/clients/informers/externalversions/api/v1alpha1/registeredlimit.go @@ -0,0 +1,102 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + context "context" + time "time" + + v2apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + clientset "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/clientset/clientset" + internalinterfaces "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/informers/externalversions/internalinterfaces" + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/pkg/clients/listers/api/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// RegisteredLimitInformer provides access to a shared informer and lister for +// RegisteredLimits. +type RegisteredLimitInformer interface { + Informer() cache.SharedIndexInformer + Lister() apiv1alpha1.RegisteredLimitLister +} + +type registeredLimitInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewRegisteredLimitInformer constructs a new informer for RegisteredLimit type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewRegisteredLimitInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredRegisteredLimitInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredRegisteredLimitInformer constructs a new informer for RegisteredLimit type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredRegisteredLimitInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().RegisteredLimits(namespace).List(context.Background(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().RegisteredLimits(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().RegisteredLimits(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.OpenstackV1alpha1().RegisteredLimits(namespace).Watch(ctx, options) + }, + }, + &v2apiv1alpha1.RegisteredLimit{}, + resyncPeriod, + indexers, + ) +} + +func (f *registeredLimitInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredRegisteredLimitInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *registeredLimitInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&v2apiv1alpha1.RegisteredLimit{}, f.defaultInformer) +} + +func (f *registeredLimitInformer) Lister() apiv1alpha1.RegisteredLimitLister { + return apiv1alpha1.NewRegisteredLimitLister(f.Informer().GetIndexer()) +} diff --git a/pkg/clients/informers/externalversions/generic.go b/pkg/clients/informers/externalversions/generic.go index f58420886..6434b02d3 100644 --- a/pkg/clients/informers/externalversions/generic.go +++ b/pkg/clients/informers/externalversions/generic.go @@ -77,6 +77,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Ports().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("projects"): return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Projects().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("registeredlimits"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().RegisteredLimits().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("roles"): return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Roles().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("roleassignments"): diff --git a/pkg/clients/listers/api/v1alpha1/expansion_generated.go b/pkg/clients/listers/api/v1alpha1/expansion_generated.go index 76fec1603..d17848450 100644 --- a/pkg/clients/listers/api/v1alpha1/expansion_generated.go +++ b/pkg/clients/listers/api/v1alpha1/expansion_generated.go @@ -114,6 +114,14 @@ type ProjectListerExpansion interface{} // ProjectNamespaceLister. type ProjectNamespaceListerExpansion interface{} +// RegisteredLimitListerExpansion allows custom methods to be added to +// RegisteredLimitLister. +type RegisteredLimitListerExpansion interface{} + +// RegisteredLimitNamespaceListerExpansion allows custom methods to be added to +// RegisteredLimitNamespaceLister. +type RegisteredLimitNamespaceListerExpansion interface{} + // RoleListerExpansion allows custom methods to be added to // RoleLister. type RoleListerExpansion interface{} diff --git a/pkg/clients/listers/api/v1alpha1/registeredlimit.go b/pkg/clients/listers/api/v1alpha1/registeredlimit.go new file mode 100644 index 000000000..345948c7c --- /dev/null +++ b/pkg/clients/listers/api/v1alpha1/registeredlimit.go @@ -0,0 +1,70 @@ +/* +Copyright The ORC Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + apiv1alpha1 "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1" + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" +) + +// RegisteredLimitLister helps list RegisteredLimits. +// All objects returned here must be treated as read-only. +type RegisteredLimitLister interface { + // List lists all RegisteredLimits in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.RegisteredLimit, err error) + // RegisteredLimits returns an object that can list and get RegisteredLimits. + RegisteredLimits(namespace string) RegisteredLimitNamespaceLister + RegisteredLimitListerExpansion +} + +// registeredLimitLister implements the RegisteredLimitLister interface. +type registeredLimitLister struct { + listers.ResourceIndexer[*apiv1alpha1.RegisteredLimit] +} + +// NewRegisteredLimitLister returns a new RegisteredLimitLister. +func NewRegisteredLimitLister(indexer cache.Indexer) RegisteredLimitLister { + return ®isteredLimitLister{listers.New[*apiv1alpha1.RegisteredLimit](indexer, apiv1alpha1.Resource("registeredlimit"))} +} + +// RegisteredLimits returns an object that can list and get RegisteredLimits. +func (s *registeredLimitLister) RegisteredLimits(namespace string) RegisteredLimitNamespaceLister { + return registeredLimitNamespaceLister{listers.NewNamespaced[*apiv1alpha1.RegisteredLimit](s.ResourceIndexer, namespace)} +} + +// RegisteredLimitNamespaceLister helps list and get RegisteredLimits. +// All objects returned here must be treated as read-only. +type RegisteredLimitNamespaceLister interface { + // List lists all RegisteredLimits in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1alpha1.RegisteredLimit, err error) + // Get retrieves the RegisteredLimit from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*apiv1alpha1.RegisteredLimit, error) + RegisteredLimitNamespaceListerExpansion +} + +// registeredLimitNamespaceLister implements the RegisteredLimitNamespaceLister +// interface. +type registeredLimitNamespaceLister struct { + listers.ResourceIndexer[*apiv1alpha1.RegisteredLimit] +} diff --git a/website/docs/crd-reference.md b/website/docs/crd-reference.md index c16937584..8b9486ded 100644 --- a/website/docs/crd-reference.md +++ b/website/docs/crd-reference.md @@ -22,6 +22,7 @@ Package v1alpha1 contains API Schema definitions for the openstack v1alpha1 API - [Network](#network) - [Port](#port) - [Project](#project) +- [RegisteredLimit](#registeredlimit) - [Role](#role) - [RoleAssignment](#roleassignment) - [Router](#router) @@ -519,6 +520,7 @@ _Appears in:_ - [NetworkSpec](#networkspec) - [PortSpec](#portspec) - [ProjectSpec](#projectspec) +- [RegisteredLimitSpec](#registeredlimitspec) - [RoleAssignmentSpec](#roleassignmentspec) - [RoleSpec](#rolespec) - [RouterSpec](#routerspec) @@ -2295,6 +2297,7 @@ _Appears in:_ - [NetworkSpec](#networkspec) - [PortSpec](#portspec) - [ProjectSpec](#projectspec) +- [RegisteredLimitSpec](#registeredlimitspec) - [RoleAssignmentSpec](#roleassignmentspec) - [RoleSpec](#rolespec) - [RouterSpec](#routerspec) @@ -2336,6 +2339,7 @@ _Appears in:_ - [NetworkSpec](#networkspec) - [PortSpec](#portspec) - [ProjectSpec](#projectspec) +- [RegisteredLimitSpec](#registeredlimitspec) - [RoleAssignmentSpec](#roleassignmentspec) - [RoleSpec](#rolespec) - [RouterSpec](#routerspec) @@ -3127,12 +3131,139 @@ _Appears in:_ | `segmentationID` _integer_ | segmentationID is the ID of the isolated segment on the
physical network. The network_type attribute defines the
segmentation model. For example, if the network_type value is vlan,
this ID is a vlan identifier. If the network_type value is gre, this
ID is a gre key. | | Optional: \{\}
| +#### RegisteredLimit +RegisteredLimit is the Schema for an ORC resource. + + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | | +| `kind` _string_ | `RegisteredLimit` | | | +| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | Optional: \{\}
| +| `spec` _[RegisteredLimitSpec](#registeredlimitspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
| +| `status` _[RegisteredLimitStatus](#registeredlimitstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
| + + +#### RegisteredLimitFilter + + + +RegisteredLimitFilter defines an existing resource by its properties + +_Validation:_ +- MinProperties: 1 + +_Appears in:_ +- [RegisteredLimitImport](#registeredlimitimport) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _string_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| + + +#### RegisteredLimitImport + + + +RegisteredLimitImport specifies an existing resource which will be imported instead of +creating a new one + +_Validation:_ +- MaxProperties: 1 +- MinProperties: 1 + +_Appears in:_ +- [RegisteredLimitSpec](#registeredlimitspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `id` _string_ | id contains the unique identifier of an existing OpenStack resource. Note
that when specifying an import by ID, the resource MUST already exist.
The ORC object will enter an error state if the resource does not exist. | | Format: uuid
MaxLength: 36
Optional: \{\}
| +| `filter` _[RegisteredLimitFilter](#registeredlimitfilter)_ | filter contains a resource query which is expected to return a single
result. The controller will continue to retry if filter returns no
results. If filter returns multiple results the controller will set an
error state and will not continue to retry. | | MinProperties: 1
Optional: \{\}
| + + +#### RegisteredLimitResourceSpec + + + +RegisteredLimitResourceSpec contains the desired state of the resource. + + + +_Appears in:_ +- [RegisteredLimitSpec](#registeredlimitspec) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `serviceRef` _[KubernetesNameRef](#kubernetesnameref)_ | serviceRef is a reference to the ORC Service which this resource is associated with. | | MaxLength: 253
MinLength: 1
Required: \{\}
| + + +#### RegisteredLimitResourceStatus + + + +RegisteredLimitResourceStatus represents the observed state of the resource. + + + +_Appears in:_ +- [RegisteredLimitStatus](#registeredlimitstatus) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| +| `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| +| `serviceID` _string_ | serviceID is the ID of the Service to which the resource is associated. | | MaxLength: 1024
Optional: \{\}
| + + +#### RegisteredLimitSpec + + + +RegisteredLimitSpec defines the desired state of an ORC object. + + + +_Appears in:_ +- [RegisteredLimit](#registeredlimit) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `import` _[RegisteredLimitImport](#registeredlimitimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
| +| `resource` _[RegisteredLimitResourceSpec](#registeredlimitresourcespec)_ | resource specifies the desired state of the resource.
resource may not be specified if the management policy is `unmanaged`.
resource must be specified if the management policy is `managed`. | | Optional: \{\}
| +| `managementPolicy` _[ManagementPolicy](#managementpolicy)_ | managementPolicy defines how ORC will treat the object. Valid values are
`managed`: ORC will create, update, and delete the resource; `unmanaged`:
ORC will import an existing resource, and will not apply updates to it or
delete it. | managed | Enum: [managed unmanaged]
Optional: \{\}
| +| `managedOptions` _[ManagedOptions](#managedoptions)_ | managedOptions specifies options which may be applied to managed objects. | | Optional: \{\}
| +| `resyncPeriod` _[Duration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#duration-v1-meta)_ | resyncPeriod defines how frequently the controller will re-reconcile
this resource even when no changes have been detected. This overrides
the global default resync period. The value must be a valid Go duration
string, e.g. "10m", "1h". Set to "0s" to disable periodic resync for
this resource. Very low values may cause excessive OpenStack API load. | | Optional: \{\}
| +| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
| + + +#### RegisteredLimitStatus + + + +RegisteredLimitStatus defines the observed state of an ORC resource. + + + +_Appears in:_ +- [RegisteredLimit](#registeredlimit) + +| Field | Description | Default | Validation | +| --- | --- | --- | --- | +| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#condition-v1-meta) array_ | conditions represents the observed status of the object.
Known .status.conditions.type are: "Available", "Progressing"
Available represents the availability of the OpenStack resource. If it is
true then the resource is ready for use.
Progressing indicates whether the controller is still attempting to
reconcile the current state of the OpenStack resource to the desired
state. Progressing will be False either because the desired state has
been achieved, or because some terminal error prevents it from ever being
achieved and the controller is no longer attempting to reconcile. If
Progressing is True, an observer waiting on the resource should continue
to wait. | | MaxItems: 32
Optional: \{\}
| +| `id` _string_ | id is the unique identifier of the OpenStack resource. | | MaxLength: 1024
Optional: \{\}
| +| `resource` _[RegisteredLimitResourceStatus](#registeredlimitresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
| +| `lastSyncTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | lastSyncTime is the timestamp of the last successful reconciliation
that fetched state from OpenStack. It is updated each time the
controller successfully reads the resource state from the OpenStack
API. | | Optional: \{\}
| + + #### Role From 2b23ba7259da01bff28909ad08737bd11880f3f4 Mon Sep 17 00:00:00 2001 From: Gondermann Date: Wed, 6 May 2026 14:26:45 +0200 Subject: [PATCH 03/10] Scaffolding for the RegisteredLimit controller Add the OpenStack client to scope On-behalf-of: SAP nils.gondermann@sap.com --- internal/scope/mock.go | 7 +++++++ internal/scope/provider.go | 4 ++++ internal/scope/scope.go | 1 + 3 files changed, 12 insertions(+) diff --git a/internal/scope/mock.go b/internal/scope/mock.go index e57e4da58..00e7e53fb 100644 --- a/internal/scope/mock.go +++ b/internal/scope/mock.go @@ -44,6 +44,7 @@ type MockScopeFactory struct { ImageClient *mock.MockImageClient KeyPairClient *mock.MockKeyPairClient NetworkClient *mock.MockNetworkClient + RegisteredLimitClient *mock.MockRegisteredLimitClient RoleClient *mock.MockRoleClient RoleAssignmentClient *mock.MockRoleAssignmentClient ServiceClient *mock.MockServiceClient @@ -66,6 +67,7 @@ func NewMockScopeFactory(mockCtrl *gomock.Controller) *MockScopeFactory { imageClient := mock.NewMockImageClient(mockCtrl) keypairClient := mock.NewMockKeyPairClient(mockCtrl) networkClient := mock.NewMockNetworkClient(mockCtrl) + registeredLimitClient := mock.NewMockRegisteredLimitClient(mockCtrl) roleClient := mock.NewMockRoleClient(mockCtrl) roleassignmentClient := mock.NewMockRoleAssignmentClient(mockCtrl) serviceClient := mock.NewMockServiceClient(mockCtrl) @@ -85,6 +87,7 @@ func NewMockScopeFactory(mockCtrl *gomock.Controller) *MockScopeFactory { ImageClient: imageClient, KeyPairClient: keypairClient, NetworkClient: networkClient, + RegisteredLimitClient: registeredLimitClient, RoleClient: roleClient, RoleAssignmentClient: roleassignmentClient, ServiceClient: serviceClient, @@ -158,6 +161,10 @@ func (f *MockScopeFactory) NewGroupClient() (osclients.GroupClient, error) { return f.GroupClient, nil } +func (f *MockScopeFactory) NewRegisteredLimitClient() (osclients.RegisteredLimitClient, error) { + return f.RegisteredLimitClient, nil +} + func (f *MockScopeFactory) NewRoleClient() (osclients.RoleClient, error) { return f.RoleClient, nil } diff --git a/internal/scope/provider.go b/internal/scope/provider.go index f1207bd6c..d82a3987e 100644 --- a/internal/scope/provider.go +++ b/internal/scope/provider.go @@ -197,6 +197,10 @@ func (s *providerScope) NewGroupClient() (clients.GroupClient, error) { return clients.NewGroupClient(s.providerClient, s.providerClientOpts) } +func (s *providerScope) NewRegisteredLimitClient() (clients.RegisteredLimitClient, error) { + return clients.NewRegisteredLimitClient(s.providerClient, s.providerClientOpts) +} + func (s *providerScope) NewRoleClient() (clients.RoleClient, error) { return clients.NewRoleClient(s.providerClient, s.providerClientOpts) } diff --git a/internal/scope/scope.go b/internal/scope/scope.go index 4f093fe9a..08a84594f 100644 --- a/internal/scope/scope.go +++ b/internal/scope/scope.go @@ -58,6 +58,7 @@ type Scope interface { NewImageClient() (osclients.ImageClient, error) NewKeyPairClient() (osclients.KeyPairClient, error) NewNetworkClient() (osclients.NetworkClient, error) + NewRegisteredLimitClient() (osclients.RegisteredLimitClient, error) NewRoleClient() (osclients.RoleClient, error) NewRoleAssignmentClient() (osclients.RoleAssignmentClient, error) NewServiceClient() (osclients.ServiceClient, error) From 4d13d7b2fcba99e23f206dd262e428d35eec1122 Mon Sep 17 00:00:00 2001 From: Gondermann Date: Wed, 6 May 2026 14:30:49 +0200 Subject: [PATCH 04/10] Scaffolding for the RegisteredLimit controller Register the controller On-behalf-of: SAP nils.gondermann@sap.com --- cmd/manager/main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/manager/main.go b/cmd/manager/main.go index 6f759c2e5..3772c0188 100644 --- a/cmd/manager/main.go +++ b/cmd/manager/main.go @@ -40,6 +40,7 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/network" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/port" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/project" + "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/registeredlimit" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/role" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/roleassignment" "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/router" @@ -141,6 +142,7 @@ func main() { sharenetwork.New(scopeFactory), keypair.New(scopeFactory), group.New(scopeFactory), + registeredlimit.New(scopeFactory), role.New(scopeFactory), roleassignment.New(scopeFactory), } From b954d46e6676c353d831bc44ed8c24e27b335d71 Mon Sep 17 00:00:00 2001 From: Gondermann Date: Wed, 6 May 2026 15:26:49 +0200 Subject: [PATCH 05/10] RegisteredLimit Adapt to BatchCreate API On-behalf-of: SAP nils.gondermann@sap.com --- .../controllers/registeredlimit/actuator.go | 23 ++++-------- .../registeredlimit/actuator_test.go | 37 +------------------ .../controllers/registeredlimit/status.go | 3 +- internal/osclients/mock/registeredlimit.go | 2 +- internal/osclients/registeredlimit.go | 14 +++++-- test/apivalidations/registeredlimit_test.go | 2 +- 6 files changed, 21 insertions(+), 60 deletions(-) diff --git a/internal/controllers/registeredlimit/actuator.go b/internal/controllers/registeredlimit/actuator.go index d2a55c42c..e1f09c959 100644 --- a/internal/controllers/registeredlimit/actuator.go +++ b/internal/controllers/registeredlimit/actuator.go @@ -75,8 +75,7 @@ func (actuator registeredlimitActuator) ListOSResourcesForAdoption(ctx context.C // Check osclients.ResourceFilter listOpts := registeredlimits.ListOpts{ - Name: getResourceName(orcObject), - Description: ptr.Deref(resourceSpec.Description, ""), + // TODO(scaffolding): Add import filters } return actuator.osClient.ListRegisteredLimits(ctx, listOpts), true @@ -88,9 +87,7 @@ func (actuator registeredlimitActuator) ListOSResourcesForImport(ctx context.Con // Check osclients.ResourceFilter listOpts := registeredlimits.ListOpts{ - Name: string(ptr.Deref(filter.Name, "")), - Description: string(ptr.Deref(filter.Description, "")), - // TODO(scaffolding): Add more import filters + // TODO(scaffolding): Add import filters } return actuator.osClient.ListRegisteredLimits(ctx, listOpts), nil @@ -118,13 +115,15 @@ func (actuator registeredlimitActuator) CreateResource(ctx context.Context, obj return nil, reconcileStatus } createOpts := registeredlimits.CreateOpts{ - Name: getResourceName(obj), Description: ptr.Deref(resource.Description, ""), - ServiceID: serviceID, + ServiceID: serviceID, // TODO(scaffolding): Add more fields } + batchCreateOpts := registeredlimits.BatchCreateOpts{ + createOpts, + } - osResource, err := actuator.osClient.CreateRegisteredLimit(ctx, createOpts) + osResource, err := actuator.osClient.CreateRegisteredLimit(ctx, batchCreateOpts) if err != nil { if !orcerrors.IsRetryable(err) { err = orcerrors.Terminal(orcv1alpha1.ConditionReasonInvalidConfiguration, "invalid configuration creating resource: "+err.Error(), err) @@ -150,7 +149,6 @@ func (actuator registeredlimitActuator) updateResource(ctx context.Context, obj updateOpts := registeredlimits.UpdateOpts{} - handleNameUpdate(&updateOpts, obj, osResource) handleDescriptionUpdate(&updateOpts, resource, osResource) // TODO(scaffolding): add handler for all fields supporting mutability @@ -191,13 +189,6 @@ func needsUpdate(updateOpts registeredlimits.UpdateOpts) (bool, error) { return len(updateMap) > 0, nil } -func handleNameUpdate(updateOpts *registeredlimits.UpdateOpts, obj orcObjectPT, osResource *osResourceT) { - name := getResourceName(obj) - if osResource.Name != name { - updateOpts.Name = &name - } -} - func handleDescriptionUpdate(updateOpts *registeredlimits.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { description := ptr.Deref(resource.Description, "") if osResource.Description != description { diff --git a/internal/controllers/registeredlimit/actuator_test.go b/internal/controllers/registeredlimit/actuator_test.go index ca8678a48..a8410e1ce 100644 --- a/internal/controllers/registeredlimit/actuator_test.go +++ b/internal/controllers/registeredlimit/actuator_test.go @@ -37,7 +37,7 @@ func TestNeedsUpdate(t *testing.T) { }, { name: "Updated opts", - updateOpts: registeredlimits.UpdateOpts{Name: ptr.To("updated")}, + updateOpts: registeredlimits.UpdateOpts{Description: ptr.To("updated")}, expectChange: true, }, } @@ -52,41 +52,6 @@ func TestNeedsUpdate(t *testing.T) { } } -func TestHandleNameUpdate(t *testing.T) { - ptrToName := ptr.To[orcv1alpha1.OpenStackName] - testCases := []struct { - name string - newValue *orcv1alpha1.OpenStackName - existingValue string - expectChange bool - }{ - {name: "Identical", newValue: ptrToName("name"), existingValue: "name", expectChange: false}, - {name: "Different", newValue: ptrToName("new-name"), existingValue: "name", expectChange: true}, - {name: "No value provided, existing is identical to object name", newValue: nil, existingValue: "object-name", expectChange: false}, - {name: "No value provided, existing is different from object name", newValue: nil, existingValue: "different-from-object-name", expectChange: true}, - } - - for _, tt := range testCases { - t.Run(tt.name, func(t *testing.T) { - resource := &orcv1alpha1.RegisteredLimit{} - resource.Name = "object-name" - resource.Spec = orcv1alpha1.RegisteredLimitSpec{ - Resource: &orcv1alpha1.RegisteredLimitResourceSpec{Name: tt.newValue}, - } - osResource := &osResourceT{Name: tt.existingValue} - - updateOpts := registeredlimits.UpdateOpts{} - handleNameUpdate(&updateOpts, resource, osResource) - - got, _ := needsUpdate(updateOpts) - if got != tt.expectChange { - t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) - } - }) - - } -} - func TestHandleDescriptionUpdate(t *testing.T) { ptrToDescription := ptr.To[string] testCases := []struct { diff --git a/internal/controllers/registeredlimit/status.go b/internal/controllers/registeredlimit/status.go index f25c193fd..bf8118b23 100644 --- a/internal/controllers/registeredlimit/status.go +++ b/internal/controllers/registeredlimit/status.go @@ -50,8 +50,7 @@ func (registeredlimitStatusWriter) ResourceAvailableStatus(orcObject *orcv1alpha func (registeredlimitStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResourceT, statusApply *statusApplyT) { resourceStatus := orcapplyconfigv1alpha1.RegisteredLimitResourceStatus(). - WithServiceID(osResource.ServiceID). - WithName(osResource.Name) + WithServiceID(osResource.ServiceID) // TODO(scaffolding): add all of the fields supported in the RegisteredLimitResourceStatus struct // If a zero-value isn't expected in the response, place it behind a conditional diff --git a/internal/osclients/mock/registeredlimit.go b/internal/osclients/mock/registeredlimit.go index dfd5eedce..404d91868 100644 --- a/internal/osclients/mock/registeredlimit.go +++ b/internal/osclients/mock/registeredlimit.go @@ -58,7 +58,7 @@ func (m *MockRegisteredLimitClient) EXPECT() *MockRegisteredLimitClientMockRecor } // CreateRegisteredLimit mocks base method. -func (m *MockRegisteredLimitClient) CreateRegisteredLimit(ctx context.Context, opts registeredlimits.CreateOptsBuilder) (*registeredlimits.RegisteredLimit, error) { +func (m *MockRegisteredLimitClient) CreateRegisteredLimit(ctx context.Context, opts registeredlimits.BatchCreateOptsBuilder) (*registeredlimits.RegisteredLimit, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreateRegisteredLimit", ctx, opts) ret0, _ := ret[0].(*registeredlimits.RegisteredLimit) diff --git a/internal/osclients/registeredlimit.go b/internal/osclients/registeredlimit.go index d2e851061..e90578e62 100644 --- a/internal/osclients/registeredlimit.go +++ b/internal/osclients/registeredlimit.go @@ -29,7 +29,7 @@ import ( type RegisteredLimitClient interface { ListRegisteredLimits(ctx context.Context, listOpts registeredlimits.ListOptsBuilder) iter.Seq2[*registeredlimits.RegisteredLimit, error] - CreateRegisteredLimit(ctx context.Context, opts registeredlimits.CreateOptsBuilder) (*registeredlimits.RegisteredLimit, error) + CreateRegisteredLimit(ctx context.Context, opts registeredlimits.BatchCreateOptsBuilder) (*registeredlimits.RegisteredLimit, error) DeleteRegisteredLimit(ctx context.Context, resourceID string) error GetRegisteredLimit(ctx context.Context, resourceID string) (*registeredlimits.RegisteredLimit, error) UpdateRegisteredLimit(ctx context.Context, id string, opts registeredlimits.UpdateOptsBuilder) (*registeredlimits.RegisteredLimit, error) @@ -58,8 +58,14 @@ func (c registeredlimitClient) ListRegisteredLimits(ctx context.Context, listOpt } } -func (c registeredlimitClient) CreateRegisteredLimit(ctx context.Context, opts registeredlimits.CreateOptsBuilder) (*registeredlimits.RegisteredLimit, error) { - return registeredlimits.Create(ctx, c.client, opts).Extract() +func (c registeredlimitClient) CreateRegisteredLimit(ctx context.Context, opts registeredlimits.BatchCreateOptsBuilder) (*registeredlimits.RegisteredLimit, error) { + batch, err := registeredlimits.BatchCreate(ctx, c.client, opts).Extract() + + if err != nil { + return nil, err + } + + return &batch[0], nil } func (c registeredlimitClient) DeleteRegisteredLimit(ctx context.Context, resourceID string) error { @@ -87,7 +93,7 @@ func (e registeredlimitErrorClient) ListRegisteredLimits(_ context.Context, _ re } } -func (e registeredlimitErrorClient) CreateRegisteredLimit(_ context.Context, _ registeredlimits.CreateOptsBuilder) (*registeredlimits.RegisteredLimit, error) { +func (e registeredlimitErrorClient) CreateRegisteredLimit(_ context.Context, _ registeredlimits.BatchCreateOptsBuilder) (*registeredlimits.RegisteredLimit, error) { return nil, e.error } diff --git a/test/apivalidations/registeredlimit_test.go b/test/apivalidations/registeredlimit_test.go index c5773ffa1..9808a9b83 100644 --- a/test/apivalidations/registeredlimit_test.go +++ b/test/apivalidations/registeredlimit_test.go @@ -79,7 +79,7 @@ var _ = Describe("ORC RegisteredLimit API validations", func() { p.Spec.WithImport(applyconfigv1alpha1.RegisteredLimitImport().WithFilter(applyconfigv1alpha1.RegisteredLimitFilter())) }, applyValidFilter: func(p *applyconfigv1alpha1.RegisteredLimitApplyConfiguration) { - p.Spec.WithImport(applyconfigv1alpha1.RegisteredLimitImport().WithFilter(applyconfigv1alpha1.RegisteredLimitFilter().WithName("foo"))) + p.Spec.WithImport(applyconfigv1alpha1.RegisteredLimitImport().WithFilter(applyconfigv1alpha1.RegisteredLimitFilter().WithDescription("foo"))) }, applyManaged: func(p *applyconfigv1alpha1.RegisteredLimitApplyConfiguration) { p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged) From 390c88d4c44e3e3f5ea61789727e8b496effac15 Mon Sep 17 00:00:00 2001 From: Gondermann Date: Mon, 13 Jul 2026 12:06:22 +0200 Subject: [PATCH 06/10] RegisteredLimit Type Declaration On-behalf-of: SAP nils.gondermann@sap.com --- api/v1alpha1/registeredlimit_types.go | 67 +++++++++++-------- api/v1alpha1/zz_generated.deepcopy.go | 25 ++++--- cmd/models-schema/zz_generated.openapi.go | 60 ++++++++++++----- ...penstack.k-orc.cloud_registeredlimits.yaml | 53 +++++++++++---- .../api/v1alpha1/registeredlimitfilter.go | 29 +++++--- .../v1alpha1/registeredlimitresourcespec.go | 31 ++++++--- .../v1alpha1/registeredlimitresourcestatus.go | 40 ++++++++--- .../applyconfiguration/internal/internal.go | 18 ++++- website/docs/crd-reference.md | 15 +++-- 9 files changed, 229 insertions(+), 109 deletions(-) diff --git a/api/v1alpha1/registeredlimit_types.go b/api/v1alpha1/registeredlimit_types.go index 0514c787e..4dea489e3 100644 --- a/api/v1alpha1/registeredlimit_types.go +++ b/api/v1alpha1/registeredlimit_types.go @@ -18,11 +18,6 @@ package v1alpha1 // RegisteredLimitResourceSpec contains the desired state of the resource. type RegisteredLimitResourceSpec struct { - // name will be the name of the created resource. If not specified, the - // name of the ORC object will be used. - // +optional - Name *OpenStackName `json:"name,omitempty"` - // description is a human-readable description for the resource. // +kubebuilder:validation:MinLength:=1 // +kubebuilder:validation:MaxLength:=255 @@ -34,51 +29,65 @@ type RegisteredLimitResourceSpec struct { // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="serviceRef is immutable" ServiceRef KubernetesNameRef `json:"serviceRef,omitempty"` - // TODO(scaffolding): Add more types. - // To see what is supported, you can take inspiration from the CreateOpts structure from - // github.com/gophercloud/gophercloud/v2/openstack/identity/v3/registeredlimits - // - // Until you have implemented mutability for the field, you must add a CEL validation - // preventing the field being modified: - // `// +kubebuilder:validation:XValidation:rule="self == oldSelf",message=" is immutable"` + // resourceName is name of the resource to be limited. + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +required + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="resourceName is immutable" + ResourceName string `json:"resourceName,omitempty"` + + // defaultLimit is limit of the specified resource in the given context. + // +kubebuilder:validation:Minimum=-1 + // +kubebuilder:validation:Maximum=2147483647 + // +required + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="defaultLimit is immutable" + DefaultLimit *int32 `json:"defaultLimit,omitempty"` } // RegisteredLimitFilter defines an existing resource by its properties // +kubebuilder:validation:MinProperties:=1 type RegisteredLimitFilter struct { - // name of the existing resource - // +optional - Name *OpenStackName `json:"name,omitempty"` - // description of the existing resource // +kubebuilder:validation:MinLength:=1 // +kubebuilder:validation:MaxLength:=255 // +optional Description *string `json:"description,omitempty"` - // TODO(scaffolding): Add more types. - // To see what is supported, you can take inspiration from the ListOpts structure from - // github.com/gophercloud/gophercloud/v2/openstack/identity/v3/registeredlimits + // serviceRef is a reference to the ORC Service which this resource is associated with. + // +optional + ServiceRef *KubernetesNameRef `json:"serviceRef,omitempty"` + + // resourceName is name of the resource to be limited. + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +optional + ResourceName *string `json:"resourceName,omitempty"` } // RegisteredLimitResourceStatus represents the observed state of the resource. type RegisteredLimitResourceStatus struct { - // name is a Human-readable name for the resource. Might not be unique. - // +kubebuilder:validation:MaxLength=1024 - // +optional - Name string `json:"name,omitempty"` - // description is a human-readable description for the resource. // +kubebuilder:validation:MaxLength=1024 // +optional Description string `json:"description,omitempty"` - // serviceID is the ID of the Service to which the resource is associated. - // +kubebuilder:validation:MaxLength=1024 + // resourceName is name of the resource to be limited. + // +kubebuilder:validation:MinLength:=1 + // +kubebuilder:validation:MaxLength:=255 + // +optional + ResourceName string `json:"resourceName,omitempty"` + + // regionID is the ID of the region that contains the service endpoint. + // +kubebuilder:validation:MaxLength:=1024 + // +optional + RegionID string `json:"regionID,omitempty"` + + // serviceID is a reference to the ORC Service which this resource is associated with. + // +kubebuilder:validation:MaxLength:=1024 // +optional ServiceID string `json:"serviceID,omitempty"` - // TODO(scaffolding): Add more types. - // To see what is supported, you can take inspiration from the RegisteredLimit structure from - // github.com/gophercloud/gophercloud/v2/openstack/identity/v3/registeredlimits + // defaultLimit is limit of the specified resource in the given context. + // +optional + DefaultLimit int32 `json:"defaultLimit,omitempty"` } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 4326af491..a9caad25f 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -3938,16 +3938,21 @@ func (in *RegisteredLimit) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RegisteredLimitFilter) DeepCopyInto(out *RegisteredLimitFilter) { *out = *in - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(OpenStackName) - **out = **in - } if in.Description != nil { in, out := &in.Description, &out.Description *out = new(string) **out = **in } + if in.ServiceRef != nil { + in, out := &in.ServiceRef, &out.ServiceRef + *out = new(KubernetesNameRef) + **out = **in + } + if in.ResourceName != nil { + in, out := &in.ResourceName, &out.ResourceName + *out = new(string) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegisteredLimitFilter. @@ -4020,16 +4025,16 @@ func (in *RegisteredLimitList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RegisteredLimitResourceSpec) DeepCopyInto(out *RegisteredLimitResourceSpec) { *out = *in - if in.Name != nil { - in, out := &in.Name, &out.Name - *out = new(OpenStackName) - **out = **in - } if in.Description != nil { in, out := &in.Description, &out.Description *out = new(string) **out = **in } + if in.DefaultLimit != nil { + in, out := &in.DefaultLimit, &out.DefaultLimit + *out = new(int32) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegisteredLimitResourceSpec. diff --git a/cmd/models-schema/zz_generated.openapi.go b/cmd/models-schema/zz_generated.openapi.go index 46aee6d2f..3fb7ea11d 100644 --- a/cmd/models-schema/zz_generated.openapi.go +++ b/cmd/models-schema/zz_generated.openapi.go @@ -7481,16 +7481,23 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitFilter( Description: "RegisteredLimitFilter defines an existing resource by its properties", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "name of the existing resource", + Description: "description of the existing resource", Type: []string{"string"}, Format: "", }, }, - "description": { + "serviceRef": { SchemaProps: spec.SchemaProps{ - Description: "description of the existing resource", + Description: "serviceRef is a reference to the ORC Service which this resource is associated with.", + Type: []string{"string"}, + Format: "", + }, + }, + "resourceName": { + SchemaProps: spec.SchemaProps{ + Description: "resourceName is name of the resource to be limited.", Type: []string{"string"}, Format: "", }, @@ -7587,29 +7594,36 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitResourc Description: "RegisteredLimitResourceSpec contains the desired state of the resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "name will be the name of the created resource. If not specified, the name of the ORC object will be used.", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "description": { + "serviceRef": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "serviceRef is a reference to the ORC Service which this resource is associated with.", Type: []string{"string"}, Format: "", }, }, - "serviceRef": { + "resourceName": { SchemaProps: spec.SchemaProps{ - Description: "serviceRef is a reference to the ORC Service which this resource is associated with.", + Description: "resourceName is name of the resource to be limited.", Type: []string{"string"}, Format: "", }, }, + "defaultLimit": { + SchemaProps: spec.SchemaProps{ + Description: "defaultLimit is limit of the specified resource in the given context.", + Type: []string{"integer"}, + Format: "int32", + }, + }, }, - Required: []string{"serviceRef"}, + Required: []string{"serviceRef", "resourceName", "defaultLimit"}, }, }, } @@ -7622,27 +7636,41 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_RegisteredLimitResourc Description: "RegisteredLimitResourceStatus represents the observed state of the resource.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "description": { SchemaProps: spec.SchemaProps{ - Description: "name is a Human-readable name for the resource. Might not be unique.", + Description: "description is a human-readable description for the resource.", Type: []string{"string"}, Format: "", }, }, - "description": { + "resourceName": { SchemaProps: spec.SchemaProps{ - Description: "description is a human-readable description for the resource.", + Description: "resourceName is name of the resource to be limited.", + Type: []string{"string"}, + Format: "", + }, + }, + "regionID": { + SchemaProps: spec.SchemaProps{ + Description: "regionID is the ID of the region that contains the service endpoint.", Type: []string{"string"}, Format: "", }, }, "serviceID": { SchemaProps: spec.SchemaProps{ - Description: "serviceID is the ID of the Service to which the resource is associated.", + Description: "serviceID is a reference to the ORC Service which this resource is associated with.", Type: []string{"string"}, Format: "", }, }, + "defaultLimit": { + SchemaProps: spec.SchemaProps{ + Description: "defaultLimit is limit of the specified resource in the given context.", + Type: []string{"integer"}, + Format: "int32", + }, + }, }, }, }, diff --git a/config/crd/bases/openstack.k-orc.cloud_registeredlimits.yaml b/config/crd/bases/openstack.k-orc.cloud_registeredlimits.yaml index 00e1d5048..880266ea7 100644 --- a/config/crd/bases/openstack.k-orc.cloud_registeredlimits.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_registeredlimits.yaml @@ -96,11 +96,16 @@ spec: maxLength: 255 minLength: 1 type: string - name: - description: name of the existing resource + resourceName: + description: resourceName is name of the resource to be limited. maxLength: 255 minLength: 1 - pattern: ^[^,]+$ + type: string + serviceRef: + description: serviceRef is a reference to the ORC Service + which this resource is associated with. + maxLength: 253 + minLength: 1 type: string type: object id: @@ -150,20 +155,30 @@ spec: resource must be specified if the management policy is `managed`. properties: + defaultLimit: + description: defaultLimit is limit of the specified resource in + the given context. + format: int32 + maximum: 2147483647 + minimum: -1 + type: integer + x-kubernetes-validations: + - message: defaultLimit is immutable + rule: self == oldSelf description: description: description is a human-readable description for the resource. maxLength: 255 minLength: 1 type: string - name: - description: |- - name will be the name of the created resource. If not specified, the - name of the ORC object will be used. + resourceName: + description: resourceName is name of the resource to be limited. maxLength: 255 minLength: 1 - pattern: ^[^,]+$ type: string + x-kubernetes-validations: + - message: resourceName is immutable + rule: self == oldSelf serviceRef: description: serviceRef is a reference to the ORC Service which this resource is associated with. @@ -174,6 +189,8 @@ spec: - message: serviceRef is immutable rule: self == oldSelf required: + - defaultLimit + - resourceName - serviceRef type: object resyncPeriod: @@ -295,19 +312,29 @@ spec: description: resource contains the observed state of the OpenStack resource. properties: + defaultLimit: + description: defaultLimit is limit of the specified resource in + the given context. + format: int32 + type: integer description: description: description is a human-readable description for the resource. maxLength: 1024 type: string - name: - description: name is a Human-readable name for the resource. Might - not be unique. + regionID: + description: regionID is the ID of the region that contains the + service endpoint. maxLength: 1024 type: string + resourceName: + description: resourceName is name of the resource to be limited. + maxLength: 255 + minLength: 1 + type: string serviceID: - description: serviceID is the ID of the Service to which the resource - is associated. + description: serviceID is a reference to the ORC Service which + this resource is associated with. maxLength: 1024 type: string type: object diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitfilter.go index 1d77a6ad0..1a2ef227a 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitfilter.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitfilter.go @@ -25,8 +25,9 @@ import ( // RegisteredLimitFilterApplyConfiguration represents a declarative configuration of the RegisteredLimitFilter type for use // with apply. type RegisteredLimitFilterApplyConfiguration struct { - Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` - Description *string `json:"description,omitempty"` + Description *string `json:"description,omitempty"` + ServiceRef *apiv1alpha1.KubernetesNameRef `json:"serviceRef,omitempty"` + ResourceName *string `json:"resourceName,omitempty"` } // RegisteredLimitFilterApplyConfiguration constructs a declarative configuration of the RegisteredLimitFilter type for use with @@ -35,14 +36,6 @@ func RegisteredLimitFilter() *RegisteredLimitFilterApplyConfiguration { return &RegisteredLimitFilterApplyConfiguration{} } -// WithName sets the Name field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Name field is set to the value of the last call. -func (b *RegisteredLimitFilterApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *RegisteredLimitFilterApplyConfiguration { - b.Name = &value - return b -} - // WithDescription sets the Description field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Description field is set to the value of the last call. @@ -50,3 +43,19 @@ func (b *RegisteredLimitFilterApplyConfiguration) WithDescription(value string) b.Description = &value return b } + +// WithServiceRef sets the ServiceRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ServiceRef field is set to the value of the last call. +func (b *RegisteredLimitFilterApplyConfiguration) WithServiceRef(value apiv1alpha1.KubernetesNameRef) *RegisteredLimitFilterApplyConfiguration { + b.ServiceRef = &value + return b +} + +// WithResourceName sets the ResourceName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceName field is set to the value of the last call. +func (b *RegisteredLimitFilterApplyConfiguration) WithResourceName(value string) *RegisteredLimitFilterApplyConfiguration { + b.ResourceName = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcespec.go index f1208e30f..be484f744 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcespec.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcespec.go @@ -25,9 +25,10 @@ import ( // RegisteredLimitResourceSpecApplyConfiguration represents a declarative configuration of the RegisteredLimitResourceSpec type for use // with apply. type RegisteredLimitResourceSpecApplyConfiguration struct { - Name *apiv1alpha1.OpenStackName `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - ServiceRef *apiv1alpha1.KubernetesNameRef `json:"serviceRef,omitempty"` + Description *string `json:"description,omitempty"` + ServiceRef *apiv1alpha1.KubernetesNameRef `json:"serviceRef,omitempty"` + ResourceName *string `json:"resourceName,omitempty"` + DefaultLimit *int32 `json:"defaultLimit,omitempty"` } // RegisteredLimitResourceSpecApplyConfiguration constructs a declarative configuration of the RegisteredLimitResourceSpec type for use with @@ -36,14 +37,6 @@ func RegisteredLimitResourceSpec() *RegisteredLimitResourceSpecApplyConfiguratio return &RegisteredLimitResourceSpecApplyConfiguration{} } -// WithName sets the Name field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Name field is set to the value of the last call. -func (b *RegisteredLimitResourceSpecApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *RegisteredLimitResourceSpecApplyConfiguration { - b.Name = &value - return b -} - // WithDescription sets the Description field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Description field is set to the value of the last call. @@ -59,3 +52,19 @@ func (b *RegisteredLimitResourceSpecApplyConfiguration) WithServiceRef(value api b.ServiceRef = &value return b } + +// WithResourceName sets the ResourceName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceName field is set to the value of the last call. +func (b *RegisteredLimitResourceSpecApplyConfiguration) WithResourceName(value string) *RegisteredLimitResourceSpecApplyConfiguration { + b.ResourceName = &value + return b +} + +// WithDefaultLimit sets the DefaultLimit field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DefaultLimit field is set to the value of the last call. +func (b *RegisteredLimitResourceSpecApplyConfiguration) WithDefaultLimit(value int32) *RegisteredLimitResourceSpecApplyConfiguration { + b.DefaultLimit = &value + return b +} diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcestatus.go index a2e3077a2..bb47a1aab 100644 --- a/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcestatus.go +++ b/pkg/clients/applyconfiguration/api/v1alpha1/registeredlimitresourcestatus.go @@ -21,9 +21,11 @@ package v1alpha1 // RegisteredLimitResourceStatusApplyConfiguration represents a declarative configuration of the RegisteredLimitResourceStatus type for use // with apply. type RegisteredLimitResourceStatusApplyConfiguration struct { - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - ServiceID *string `json:"serviceID,omitempty"` + Description *string `json:"description,omitempty"` + ResourceName *string `json:"resourceName,omitempty"` + RegionID *string `json:"regionID,omitempty"` + ServiceID *string `json:"serviceID,omitempty"` + DefaultLimit *int32 `json:"defaultLimit,omitempty"` } // RegisteredLimitResourceStatusApplyConfiguration constructs a declarative configuration of the RegisteredLimitResourceStatus type for use with @@ -32,14 +34,6 @@ func RegisteredLimitResourceStatus() *RegisteredLimitResourceStatusApplyConfigur return &RegisteredLimitResourceStatusApplyConfiguration{} } -// WithName sets the Name field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Name field is set to the value of the last call. -func (b *RegisteredLimitResourceStatusApplyConfiguration) WithName(value string) *RegisteredLimitResourceStatusApplyConfiguration { - b.Name = &value - return b -} - // WithDescription sets the Description field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Description field is set to the value of the last call. @@ -48,6 +42,22 @@ func (b *RegisteredLimitResourceStatusApplyConfiguration) WithDescription(value return b } +// WithResourceName sets the ResourceName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceName field is set to the value of the last call. +func (b *RegisteredLimitResourceStatusApplyConfiguration) WithResourceName(value string) *RegisteredLimitResourceStatusApplyConfiguration { + b.ResourceName = &value + return b +} + +// WithRegionID sets the RegionID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the RegionID field is set to the value of the last call. +func (b *RegisteredLimitResourceStatusApplyConfiguration) WithRegionID(value string) *RegisteredLimitResourceStatusApplyConfiguration { + b.RegionID = &value + return b +} + // WithServiceID sets the ServiceID field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the ServiceID field is set to the value of the last call. @@ -55,3 +65,11 @@ func (b *RegisteredLimitResourceStatusApplyConfiguration) WithServiceID(value st b.ServiceID = &value return b } + +// WithDefaultLimit sets the DefaultLimit field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DefaultLimit field is set to the value of the last call. +func (b *RegisteredLimitResourceStatusApplyConfiguration) WithDefaultLimit(value int32) *RegisteredLimitResourceStatusApplyConfiguration { + b.DefaultLimit = &value + return b +} diff --git a/pkg/clients/applyconfiguration/internal/internal.go b/pkg/clients/applyconfiguration/internal/internal.go index 9ffa9f549..7ef95268d 100644 --- a/pkg/clients/applyconfiguration/internal/internal.go +++ b/pkg/clients/applyconfiguration/internal/internal.go @@ -2208,7 +2208,10 @@ var schemaYAML = typed.YAMLObject(`types: - name: description type: scalar: string - - name: name + - name: resourceName + type: + scalar: string + - name: serviceRef type: scalar: string - name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitImport @@ -2223,10 +2226,13 @@ var schemaYAML = typed.YAMLObject(`types: - name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitResourceSpec map: fields: + - name: defaultLimit + type: + scalar: numeric - name: description type: scalar: string - - name: name + - name: resourceName type: scalar: string - name: serviceRef @@ -2235,10 +2241,16 @@ var schemaYAML = typed.YAMLObject(`types: - name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.RegisteredLimitResourceStatus map: fields: + - name: defaultLimit + type: + scalar: numeric - name: description type: scalar: string - - name: name + - name: regionID + type: + scalar: string + - name: resourceName type: scalar: string - name: serviceID diff --git a/website/docs/crd-reference.md b/website/docs/crd-reference.md index 8b9486ded..7b4a4ecc3 100644 --- a/website/docs/crd-reference.md +++ b/website/docs/crd-reference.md @@ -2218,6 +2218,7 @@ _Appears in:_ - [PortResourceSpec](#portresourcespec) - [ProjectFilter](#projectfilter) - [ProjectResourceSpec](#projectresourcespec) +- [RegisteredLimitFilter](#registeredlimitfilter) - [RegisteredLimitResourceSpec](#registeredlimitresourcespec) - [RoleAssignmentFilter](#roleassignmentfilter) - [RoleAssignmentResourceSpec](#roleassignmentresourcespec) @@ -2649,8 +2650,6 @@ _Appears in:_ - [NetworkResourceSpec](#networkresourcespec) - [PortFilter](#portfilter) - [PortResourceSpec](#portresourcespec) -- [RegisteredLimitFilter](#registeredlimitfilter) -- [RegisteredLimitResourceSpec](#registeredlimitresourcespec) - [RouterFilter](#routerfilter) - [RouterResourceSpec](#routerresourcespec) - [SecurityGroupFilter](#securitygroupfilter) @@ -3164,8 +3163,9 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| | `description` _string_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `serviceRef` _[KubernetesNameRef](#kubernetesnameref)_ | serviceRef is a reference to the ORC Service which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
| +| `resourceName` _string_ | resourceName is name of the resource to be limited. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| #### RegisteredLimitImport @@ -3201,9 +3201,10 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _[OpenStackName](#openstackname)_ | name will be the name of the created resource. If not specified, the
name of the ORC object will be used. | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
| | `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| | `serviceRef` _[KubernetesNameRef](#kubernetesnameref)_ | serviceRef is a reference to the ORC Service which this resource is associated with. | | MaxLength: 253
MinLength: 1
Required: \{\}
| +| `resourceName` _string_ | resourceName is name of the resource to be limited. | | MaxLength: 255
MinLength: 1
Required: \{\}
| +| `defaultLimit` _integer_ | defaultLimit is limit of the specified resource in the given context. | | Maximum: 2.147483647e+09
Minimum: -1
Required: \{\}
| #### RegisteredLimitResourceStatus @@ -3219,9 +3220,11 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `name` _string_ | name is a Human-readable name for the resource. Might not be unique. | | MaxLength: 1024
Optional: \{\}
| | `description` _string_ | description is a human-readable description for the resource. | | MaxLength: 1024
Optional: \{\}
| -| `serviceID` _string_ | serviceID is the ID of the Service to which the resource is associated. | | MaxLength: 1024
Optional: \{\}
| +| `resourceName` _string_ | resourceName is name of the resource to be limited. | | MaxLength: 255
MinLength: 1
Optional: \{\}
| +| `regionID` _string_ | regionID is the ID of the region that contains the service endpoint. | | MaxLength: 1024
Optional: \{\}
| +| `serviceID` _string_ | serviceID is a reference to the ORC Service which this resource is associated with. | | MaxLength: 1024
Optional: \{\}
| +| `defaultLimit` _integer_ | defaultLimit is limit of the specified resource in the given context. | | Optional: \{\}
| #### RegisteredLimitSpec From 85327f8ecbf9fecd6beb5fb30a4c29d6996f0bfe Mon Sep 17 00:00:00 2001 From: Gondermann Date: Mon, 13 Jul 2026 12:13:11 +0200 Subject: [PATCH 07/10] RegisteredLimit Actuator and Status On-behalf-of: SAP nils.gondermann@sap.com --- .../controllers/registeredlimit/actuator.go | 68 +++++++++++++++---- .../controllers/registeredlimit/status.go | 7 +- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/internal/controllers/registeredlimit/actuator.go b/internal/controllers/registeredlimit/actuator.go index e1f09c959..a5c509c53 100644 --- a/internal/controllers/registeredlimit/actuator.go +++ b/internal/controllers/registeredlimit/actuator.go @@ -31,6 +31,7 @@ import ( "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/generic/progress" "github.com/k-orc/openstack-resource-controller/v2/internal/logging" "github.com/k-orc/openstack-resource-controller/v2/internal/osclients" + "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency" orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors" ) @@ -70,27 +71,64 @@ func (actuator registeredlimitActuator) ListOSResourcesForAdoption(ctx context.C return nil, false } - // TODO(scaffolding) If you need to filter resources on fields that the List() function - // of gophercloud does not support, it's possible to perform client-side filtering. - // Check osclients.ResourceFilter + service, _ := serviceDependency.GetDependency( + ctx, actuator.k8sClient, orcObject, orcv1alpha1.IsAvailable, + ) + + if service == nil { + return nil, false + } + + var filters []osclients.ResourceFilter[osResourceT] + + // Add client-side filters + if resourceSpec.Description != nil { + filters = append(filters, func(f *registeredlimits.RegisteredLimit) bool { + return f.Description == *resourceSpec.Description + }) + } listOpts := registeredlimits.ListOpts{ - // TODO(scaffolding): Add import filters + ResourceName: resourceSpec.ResourceName, + ServiceID: ptr.Deref(service.Status.ID, ""), } - return actuator.osClient.ListRegisteredLimits(ctx, listOpts), true + return actuator.listOSResources(ctx, filters, listOpts), true } func (actuator registeredlimitActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) { - // TODO(scaffolding) If you need to filter resources on fields that the List() function - // of gophercloud does not support, it's possible to perform client-side filtering. - // Check osclients.ResourceFilter + var reconcileStatus progress.ReconcileStatus + + service, rs := dependency.FetchDependency[*orcv1alpha1.Service]( + ctx, actuator.k8sClient, obj.Namespace, filter.ServiceRef, "Service", + orcv1alpha1.IsAvailable, + ) + reconcileStatus = reconcileStatus.WithReconcileStatus(rs) + + if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule { + return nil, reconcileStatus + } + + var filters []osclients.ResourceFilter[osResourceT] + + // Add client-side filters + if filter.Description != nil { + filters = append(filters, func(f *registeredlimits.RegisteredLimit) bool { + return f.Description == *filter.Description + }) + } listOpts := registeredlimits.ListOpts{ - // TODO(scaffolding): Add import filters + ResourceName: ptr.Deref(filter.ResourceName, ""), + ServiceID: ptr.Deref(service.Status.ID, ""), } - return actuator.osClient.ListRegisteredLimits(ctx, listOpts), nil + return actuator.listOSResources(ctx, filters, listOpts), nil +} + +func (actuator registeredlimitActuator) listOSResources(ctx context.Context, filters []osclients.ResourceFilter[osResourceT], listOpts registeredlimits.ListOptsBuilder) iter.Seq2[*registeredlimits.RegisteredLimit, error] { + registeredLimits := actuator.osClient.ListRegisteredLimits(ctx, listOpts) + return osclients.Filter(registeredLimits, filters...) } func (actuator registeredlimitActuator) CreateResource(ctx context.Context, obj orcObjectPT) (*osResourceT, progress.ReconcileStatus) { @@ -107,6 +145,7 @@ func (actuator registeredlimitActuator) CreateResource(ctx context.Context, obj service, serviceDepRS := serviceDependency.GetDependency( ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable, ) + reconcileStatus = reconcileStatus.WithReconcileStatus(serviceDepRS) if service != nil { serviceID = ptr.Deref(service.Status.ID, "") @@ -115,9 +154,10 @@ func (actuator registeredlimitActuator) CreateResource(ctx context.Context, obj return nil, reconcileStatus } createOpts := registeredlimits.CreateOpts{ - Description: ptr.Deref(resource.Description, ""), - ServiceID: serviceID, - // TODO(scaffolding): Add more fields + ServiceID: serviceID, + ResourceName: resource.ResourceName, + DefaultLimit: int(*resource.DefaultLimit), + Description: ptr.Deref(resource.Description, ""), } batchCreateOpts := registeredlimits.BatchCreateOpts{ createOpts, @@ -181,7 +221,7 @@ func needsUpdate(updateOpts registeredlimits.UpdateOpts) (bool, error) { return false, err } - updateMap, ok := updateOptsMap["registered_limits"].(map[string]any) + updateMap, ok := updateOptsMap["registered_limit"].(map[string]any) if !ok { updateMap = make(map[string]any) } diff --git a/internal/controllers/registeredlimit/status.go b/internal/controllers/registeredlimit/status.go index bf8118b23..d96826501 100644 --- a/internal/controllers/registeredlimit/status.go +++ b/internal/controllers/registeredlimit/status.go @@ -50,10 +50,9 @@ func (registeredlimitStatusWriter) ResourceAvailableStatus(orcObject *orcv1alpha func (registeredlimitStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResourceT, statusApply *statusApplyT) { resourceStatus := orcapplyconfigv1alpha1.RegisteredLimitResourceStatus(). - WithServiceID(osResource.ServiceID) - - // TODO(scaffolding): add all of the fields supported in the RegisteredLimitResourceStatus struct - // If a zero-value isn't expected in the response, place it behind a conditional + WithServiceID(osResource.ServiceID). + WithDefaultLimit(int32(osResource.DefaultLimit)). + WithResourceName(osResource.ResourceName) if osResource.Description != "" { resourceStatus.WithDescription(osResource.Description) From eec981dc7c6b2996b35f1ff55462ddad02bebde3 Mon Sep 17 00:00:00 2001 From: Gondermann Date: Mon, 13 Jul 2026 12:39:53 +0200 Subject: [PATCH 08/10] RegisteredLimit Tests and Config Samples On-behalf-of: SAP nils.gondermann@sap.com --- .../openstack_v1alpha1_registeredlimit.yaml | 20 ++++++++++++++++--- .../00-assert.yaml | 6 +++--- .../00-create-resource.yaml | 13 ++++++------ .../00-assert.yaml | 6 +++--- .../00-create-resource.yaml | 17 ++++++++-------- .../00-create-resources-missing-deps.yaml | 20 +++++++++---------- .../01-create-dependencies.yaml | 7 +++---- .../00-create-resources.yaml | 19 +++++++++--------- .../01-import-resource.yaml | 2 +- .../registeredlimit-import/00-assert.yaml | 4 ++-- .../00-import-resource.yaml | 18 ++++++++++++++--- .../registeredlimit-import/01-assert.yaml | 8 ++++---- .../01-create-trap-resource.yaml | 13 ++++++------ .../registeredlimit-import/02-assert.yaml | 4 ++-- .../02-create-resource.yaml | 19 +++--------------- test/apivalidations/registeredlimit_test.go | 4 +++- 16 files changed, 94 insertions(+), 86 deletions(-) diff --git a/config/samples/openstack_v1alpha1_registeredlimit.yaml b/config/samples/openstack_v1alpha1_registeredlimit.yaml index 37e036127..e70afca1b 100644 --- a/config/samples/openstack_v1alpha1_registeredlimit.yaml +++ b/config/samples/openstack_v1alpha1_registeredlimit.yaml @@ -1,14 +1,28 @@ --- apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: registeredlimit-sample +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: unmanaged + import: + filter: + type: "compute" +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RegisteredLimit metadata: name: registeredlimit-sample spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed resource: description: Sample RegisteredLimit - # TODO(scaffolding): Add all fields the resource supports + serviceRef: registeredlimit-sample + resourceName: vcpus + defaultLimit: 5 diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-assert.yaml index 1a3428e1a..c00c6fd8f 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-assert.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-assert.yaml @@ -5,9 +5,9 @@ metadata: name: registeredlimit-create-full status: resource: - name: registeredlimit-create-full-override description: RegisteredLimit from "create full" test - # TODO(scaffolding): Add all fields the resource supports + resourceName: vcpus + defaultLimit: 5 conditions: - type: Available status: "True" @@ -30,4 +30,4 @@ resourceRefs: assertAll: - celExpr: "registeredlimit.status.id != ''" - celExpr: "registeredlimit.status.resource.serviceID == service.status.id" - # TODO(scaffolding): Add more checks + - celExpr: "!has(registeredlimit.status.resource.name)" diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-create-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-create-resource.yaml index 9ee0e80a6..e09f379c3 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-create-resource.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-full/00-create-resource.yaml @@ -5,12 +5,11 @@ metadata: name: registeredlimit-create-full spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed - # TODO(scaffolding): Add the necessary fields to create the resource - resource: {} + resource: + type: registeredlimit-test --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RegisteredLimit @@ -18,12 +17,12 @@ metadata: name: registeredlimit-create-full spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed resource: name: registeredlimit-create-full-override description: RegisteredLimit from "create full" test serviceRef: registeredlimit-create-full - # TODO(scaffolding): Add all fields the resource supports + resourceName: vcpus + defaultLimit: 5 diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-assert.yaml index 41c81b5bc..a8ae9217a 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-assert.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-assert.yaml @@ -5,8 +5,8 @@ metadata: name: registeredlimit-create-minimal status: resource: - name: registeredlimit-create-minimal - # TODO(scaffolding): Add all fields the resource supports + resourceName: vcpus + defaultLimit: 5 conditions: - type: Available status: "True" @@ -29,4 +29,4 @@ resourceRefs: assertAll: - celExpr: "registeredlimit.status.id != ''" - celExpr: "registeredlimit.status.resource.serviceID == service.status.id" - # TODO(scaffolding): Add more checks + - celExpr: "!has(registeredlimit.status.resource.name)" diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-create-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-create-resource.yaml index e4eea36c6..0f2017df2 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-create-resource.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-create-minimal/00-create-resource.yaml @@ -5,12 +5,12 @@ metadata: name: registeredlimit-create-minimal spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds - managementPolicy: managed - # TODO(scaffolding): Add the necessary fields to create the resource - resource: {} + managementPolicy: unmanaged + import: + filter: + type: compute --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RegisteredLimit @@ -18,11 +18,10 @@ metadata: name: registeredlimit-create-minimal spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed - # TODO(scaffolding): Only add the mandatory fields. It's possible the resource - # doesn't have mandatory fields, in that case, leave it empty. resource: serviceRef: registeredlimit-create-minimal + resourceName: vcpus + defaultLimit: 5 diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-create-resources-missing-deps.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-create-resources-missing-deps.yaml index afef6b42a..81a9801dc 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-create-resources-missing-deps.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/00-create-resources-missing-deps.yaml @@ -5,12 +5,11 @@ metadata: name: registeredlimit-dependency spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed - # TODO(scaffolding): Add the necessary fields to create the resource - resource: {} + resource: + type: registeredlimit-test --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RegisteredLimit @@ -18,14 +17,13 @@ metadata: name: registeredlimit-dependency-no-service spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed resource: serviceRef: registeredlimit-dependency-pending - # TODO(scaffolding): Add the necessary fields to create the resource - + resourceName: vcpus + defaultLimit: 5 --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RegisteredLimit @@ -33,10 +31,10 @@ metadata: name: registeredlimit-dependency-no-secret spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: registeredlimit-dependency managementPolicy: managed - # TODO(scaffolding): Add the necessary fields to create the resource resource: serviceRef: registeredlimit-dependency + resourceName: memory + defaultLimit: 10 diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/01-create-dependencies.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/01-create-dependencies.yaml index 6c177cb7b..28f880a83 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-dependency/01-create-dependencies.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-dependency/01-create-dependencies.yaml @@ -11,9 +11,8 @@ metadata: name: registeredlimit-dependency-pending spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed - # TODO(scaffolding): Add the necessary fields to create the resource - resource: {} + resource: + type: registeredlimit-test diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-create-resources.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-create-resources.yaml index 4df73e9db..001a29ec0 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-create-resources.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/00-create-resources.yaml @@ -5,12 +5,11 @@ metadata: name: registeredlimit-import-error spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed - # TODO(scaffolding): Add the necessary fields to create the resource - resource: {} + resource: + type: registeredlimit-import-error --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RegisteredLimit @@ -18,14 +17,14 @@ metadata: name: registeredlimit-import-error-external-1 spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed resource: description: RegisteredLimit from "import error" test serviceRef: registeredlimit-import-error - # TODO(scaffolding): add any required field + resourceName: vcpus + defaultLimit: 5 --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RegisteredLimit @@ -33,11 +32,11 @@ metadata: name: registeredlimit-import-error-external-2 spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed resource: description: RegisteredLimit from "import error" test serviceRef: registeredlimit-import-error - # TODO(scaffolding): add any required field + resourceName: memory + defaultLimit: 10 diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import-error/01-import-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/01-import-resource.yaml index af79d8e58..16d705ec9 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-import-error/01-import-resource.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import-error/01-import-resource.yaml @@ -5,7 +5,7 @@ metadata: name: registeredlimit-import-error spec: cloudCredentialsRef: - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: unmanaged import: diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/00-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/00-assert.yaml index 9be45921a..a55ba02a4 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-import/00-assert.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/00-assert.yaml @@ -6,10 +6,10 @@ metadata: status: conditions: - type: Available - message: Waiting for OpenStack resource to be created externally + # message: Waiting for OpenStack resource to be created externally status: "False" reason: Progressing - type: Progressing - message: Waiting for OpenStack resource to be created externally + # message: Waiting for OpenStack resource to be created externally status: "True" reason: Progressing diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/00-import-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/00-import-resource.yaml index 6b56bbd1a..27ee0cef2 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-import/00-import-resource.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/00-import-resource.yaml @@ -1,15 +1,27 @@ --- apiVersion: openstack.k-orc.cloud/v1alpha1 +kind: Service +metadata: + name: registeredlimit-import +spec: + cloudCredentialsRef: + cloudName: openstack-admin + secretName: openstack-clouds + managementPolicy: managed + resource: + type: service-external +--- +apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RegisteredLimit metadata: name: registeredlimit-import spec: cloudCredentialsRef: - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: unmanaged import: filter: - name: registeredlimit-import-external description: RegisteredLimit registeredlimit-import-external from "registeredlimit-import" test - # TODO(scaffolding): Add all fields supported by the filter + resourceName: vcpus + serviceRef: registeredlimit-import diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/01-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/01-assert.yaml index 0d4faa09a..b602a3db3 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-import/01-assert.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/01-assert.yaml @@ -14,9 +14,9 @@ status: status: "False" reason: Success resource: - name: registeredlimit-import-external-not-this-one description: RegisteredLimit registeredlimit-import-external from "registeredlimit-import" test - # TODO(scaffolding): Add fields necessary to match filter + resourceName: vcpus + defaultLimit: 5 --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RegisteredLimit @@ -25,10 +25,10 @@ metadata: status: conditions: - type: Available - message: Waiting for OpenStack resource to be created externally + # message: Waiting for OpenStack resource to be created externally status: "False" reason: Progressing - type: Progressing - message: Waiting for OpenStack resource to be created externally + # message: Waiting for OpenStack resource to be created externally status: "True" reason: Progressing diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/01-create-trap-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/01-create-trap-resource.yaml index a9a1e630a..ca1a7278f 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-import/01-create-trap-resource.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/01-create-trap-resource.yaml @@ -5,12 +5,11 @@ metadata: name: registeredlimit-import-external-not-this-one spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed - # TODO(scaffolding): Add the necessary fields to create the resource - resource: {} + resource: + type: service-external-not-this-one --- # This `registeredlimit-import-external-not-this-one` resource serves two purposes: # - ensure that we can successfully create another resource which name is a substring of it (i.e. it's not being adopted) @@ -21,11 +20,11 @@ metadata: name: registeredlimit-import-external-not-this-one spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed resource: description: RegisteredLimit registeredlimit-import-external from "registeredlimit-import" test serviceRef: registeredlimit-import-external-not-this-one - # TODO(scaffolding): Add fields necessary to match filter + resourceName: vcpus + defaultLimit: 5 diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/02-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/02-assert.yaml index 516eb9a9d..de050e45f 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-import/02-assert.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/02-assert.yaml @@ -28,6 +28,6 @@ status: status: "False" reason: Success resource: - name: registeredlimit-import-external description: RegisteredLimit registeredlimit-import-external from "registeredlimit-import" test - # TODO(scaffolding): Add all fields the resource supports + resourceName: vcpus + defaultLimit: 5 diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-import/02-create-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-import/02-create-resource.yaml index cec0a745d..217e33768 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-import/02-create-resource.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-import/02-create-resource.yaml @@ -1,28 +1,15 @@ --- apiVersion: openstack.k-orc.cloud/v1alpha1 -kind: Service -metadata: - name: registeredlimit-import -spec: - cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack - secretName: openstack-clouds - managementPolicy: managed - # TODO(scaffolding): Add the necessary fields to create the resource - resource: {} ---- -apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RegisteredLimit metadata: name: registeredlimit-import-external spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed resource: description: RegisteredLimit registeredlimit-import-external from "registeredlimit-import" test serviceRef: registeredlimit-import - # TODO(scaffolding): Add fields necessary to match filter + resourceName: vcpus + defaultLimit: 5 diff --git a/test/apivalidations/registeredlimit_test.go b/test/apivalidations/registeredlimit_test.go index 9808a9b83..b19f8cd75 100644 --- a/test/apivalidations/registeredlimit_test.go +++ b/test/apivalidations/registeredlimit_test.go @@ -42,7 +42,9 @@ func registeredlimitStub(namespace *corev1.Namespace) *orcv1alpha1.RegisteredLim func testRegisteredLimitResource() *applyconfigv1alpha1.RegisteredLimitResourceSpecApplyConfiguration { return applyconfigv1alpha1.RegisteredLimitResourceSpec(). - WithServiceRef("service") + WithServiceRef("service"). + WithDefaultLimit(999). + WithResourceName("ports") } func baseRegisteredLimitPatch(obj client.Object) *applyconfigv1alpha1.RegisteredLimitApplyConfiguration { From 6a012112ac271dbd0d889c796622f467f2cd6bea Mon Sep 17 00:00:00 2001 From: Gondermann Date: Mon, 1 Jun 2026 15:20:23 +0200 Subject: [PATCH 09/10] RegisteredLimit Actuator mutability On-behalf-of: SAP nils.gondermann@sap.com --- api/v1alpha1/registeredlimit_types.go | 1 - ...penstack.k-orc.cloud_registeredlimits.yaml | 3 --- .../controllers/registeredlimit/actuator.go | 10 +++++-- .../registeredlimit/actuator_test.go | 27 +++++++++++++++++++ .../registeredlimit-update/00-assert.yaml | 4 +-- .../00-minimal-resource.yaml | 14 +++++----- .../registeredlimit-update/01-assert.yaml | 4 +-- .../01-updated-resource.yaml | 2 +- .../registeredlimit-update/02-assert.yaml | 4 +-- 9 files changed, 48 insertions(+), 21 deletions(-) diff --git a/api/v1alpha1/registeredlimit_types.go b/api/v1alpha1/registeredlimit_types.go index 4dea489e3..c098ffd4d 100644 --- a/api/v1alpha1/registeredlimit_types.go +++ b/api/v1alpha1/registeredlimit_types.go @@ -40,7 +40,6 @@ type RegisteredLimitResourceSpec struct { // +kubebuilder:validation:Minimum=-1 // +kubebuilder:validation:Maximum=2147483647 // +required - // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="defaultLimit is immutable" DefaultLimit *int32 `json:"defaultLimit,omitempty"` } diff --git a/config/crd/bases/openstack.k-orc.cloud_registeredlimits.yaml b/config/crd/bases/openstack.k-orc.cloud_registeredlimits.yaml index 880266ea7..906145eec 100644 --- a/config/crd/bases/openstack.k-orc.cloud_registeredlimits.yaml +++ b/config/crd/bases/openstack.k-orc.cloud_registeredlimits.yaml @@ -162,9 +162,6 @@ spec: maximum: 2147483647 minimum: -1 type: integer - x-kubernetes-validations: - - message: defaultLimit is immutable - rule: self == oldSelf description: description: description is a human-readable description for the resource. diff --git a/internal/controllers/registeredlimit/actuator.go b/internal/controllers/registeredlimit/actuator.go index a5c509c53..3ae1ef66c 100644 --- a/internal/controllers/registeredlimit/actuator.go +++ b/internal/controllers/registeredlimit/actuator.go @@ -190,8 +190,7 @@ func (actuator registeredlimitActuator) updateResource(ctx context.Context, obj updateOpts := registeredlimits.UpdateOpts{} handleDescriptionUpdate(&updateOpts, resource, osResource) - - // TODO(scaffolding): add handler for all fields supporting mutability + handleDefaultLimitUpdate(&updateOpts, resource, osResource) needsUpdate, err := needsUpdate(updateOpts) if err != nil { @@ -236,6 +235,13 @@ func handleDescriptionUpdate(updateOpts *registeredlimits.UpdateOpts, resource * } } +func handleDefaultLimitUpdate(updateOpts *registeredlimits.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) { + defaultLimit := int(*resource.DefaultLimit) + if osResource.DefaultLimit != defaultLimit { + updateOpts.DefaultLimit = &defaultLimit + } +} + func (actuator registeredlimitActuator) GetResourceReconcilers(ctx context.Context, orcObject orcObjectPT, osResource *osResourceT, controller interfaces.ResourceController) ([]resourceReconciler, progress.ReconcileStatus) { return []resourceReconciler{ actuator.updateResource, diff --git a/internal/controllers/registeredlimit/actuator_test.go b/internal/controllers/registeredlimit/actuator_test.go index a8410e1ce..7721d1621 100644 --- a/internal/controllers/registeredlimit/actuator_test.go +++ b/internal/controllers/registeredlimit/actuator_test.go @@ -52,6 +52,33 @@ func TestNeedsUpdate(t *testing.T) { } } +func TestHandleDefaultLimitUpdate(t *testing.T) { + testCases := []struct { + name string + newValue int + existingValue int + expectChange bool + }{ + {name: "Identical", newValue: 1, existingValue: 1, expectChange: false}, + {name: "Different", newValue: 2, existingValue: 1, expectChange: true}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + resource := &orcv1alpha1.RegisteredLimitResourceSpec{DefaultLimit: ptr.To(int32(tt.newValue))} + osResource := &osResourceT{DefaultLimit: tt.existingValue} + + updateOpts := registeredlimits.UpdateOpts{} + handleDefaultLimitUpdate(&updateOpts, resource, osResource) + + got, _ := needsUpdate(updateOpts) + if got != tt.expectChange { + t.Errorf("Expected change: %v, got: %v", tt.expectChange, got) + } + }) + } +} + func TestHandleDescriptionUpdate(t *testing.T) { ptrToDescription := ptr.To[string] testCases := []struct { diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/00-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-update/00-assert.yaml index 29f6774a3..df8144624 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-update/00-assert.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/00-assert.yaml @@ -15,8 +15,8 @@ metadata: name: registeredlimit-update status: resource: - name: registeredlimit-update - # TODO(scaffolding): Add matches for more fields + resourceName: vcpus + defaultLimit: 5 conditions: - type: Available status: "True" diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/00-minimal-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-update/00-minimal-resource.yaml index 25fdd17b4..f46c915d1 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-update/00-minimal-resource.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/00-minimal-resource.yaml @@ -5,12 +5,11 @@ metadata: name: registeredlimit-update spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed - # TODO(scaffolding): Add the necessary fields to create the resource - resource: {} + resource: + type: registeredlimit-update --- apiVersion: openstack.k-orc.cloud/v1alpha1 kind: RegisteredLimit @@ -18,11 +17,10 @@ metadata: name: registeredlimit-update spec: cloudCredentialsRef: - # TODO(scaffolding): Use openstack-admin if the resource needs admin credentials to be created or updated - cloudName: openstack + cloudName: openstack-admin secretName: openstack-clouds managementPolicy: managed - # TODO(scaffolding): Only add the mandatory fields. It's possible the resource - # doesn't have mandatory fields, in that case, leave it empty. resource: + resourceName: vcpus + defaultLimit: 5 serviceRef: registeredlimit-update diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/01-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-update/01-assert.yaml index c3346cc9a..bbad935f3 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-update/01-assert.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/01-assert.yaml @@ -5,9 +5,9 @@ metadata: name: registeredlimit-update status: resource: - name: registeredlimit-update-updated description: registeredlimit-update-updated - # TODO(scaffolding): match all fields that were modified + resourceName: vcpus + defaultLimit: 10 conditions: - type: Available status: "True" diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/01-updated-resource.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-update/01-updated-resource.yaml index aa31f5657..2ec27742f 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-update/01-updated-resource.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/01-updated-resource.yaml @@ -7,4 +7,4 @@ spec: resource: name: registeredlimit-update-updated description: registeredlimit-update-updated - # TODO(scaffolding): update all mutable fields + defaultLimit: 10 diff --git a/internal/controllers/registeredlimit/tests/registeredlimit-update/02-assert.yaml b/internal/controllers/registeredlimit/tests/registeredlimit-update/02-assert.yaml index 36ce759e6..df8144624 100644 --- a/internal/controllers/registeredlimit/tests/registeredlimit-update/02-assert.yaml +++ b/internal/controllers/registeredlimit/tests/registeredlimit-update/02-assert.yaml @@ -15,8 +15,8 @@ metadata: name: registeredlimit-update status: resource: - name: registeredlimit-update - # TODO(scaffolding): validate that updated fields were all reverted to their original value + resourceName: vcpus + defaultLimit: 5 conditions: - type: Available status: "True" From 8c90198006d3b9e0e15f166324909ac8e88661b4 Mon Sep 17 00:00:00 2001 From: Gondermann Date: Tue, 14 Jul 2026 09:10:17 +0200 Subject: [PATCH 10/10] Scaffolding for the RegisteredLimit controller Generate the OLM bundle On-behalf-of: SAP nils.gondermann@sap.com --- config/manifests/bases/orc.clusterserviceversion.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/manifests/bases/orc.clusterserviceversion.yaml b/config/manifests/bases/orc.clusterserviceversion.yaml index 410c09b66..37e8415e1 100644 --- a/config/manifests/bases/orc.clusterserviceversion.yaml +++ b/config/manifests/bases/orc.clusterserviceversion.yaml @@ -79,6 +79,11 @@ spec: kind: Project name: projects.openstack.k-orc.cloud version: v1alpha1 + - description: RegisteredLimit is the Schema for an ORC resource. + displayName: Registered Limit + kind: RegisteredLimit + name: registeredlimits.openstack.k-orc.cloud + version: v1alpha1 - description: RoleAssignment is the Schema for an ORC resource. displayName: Role Assignment kind: RoleAssignment