diff --git a/PROJECT b/PROJECT
index 357849779..e4dc0a8fb 100644
--- a/PROJECT
+++ b/PROJECT
@@ -184,6 +184,14 @@ resources:
kind: Subnet
path: github.com/k-orc/openstack-resource-controller/api/v1alpha1
version: v1alpha1
+- api:
+ crdVersion: v1
+ namespaced: true
+ domain: k-orc.cloud
+ group: openstack
+ kind: SubnetPool
+ path: github.com/k-orc/openstack-resource-controller/api/v1alpha1
+ version: v1alpha1
- api:
crdVersion: v1
namespaced: true
diff --git a/README.md b/README.md
index a5663e5fd..284281a5e 100644
--- a/README.md
+++ b/README.md
@@ -93,6 +93,7 @@ kubectl delete -f $ORC_RELEASE
| service | | ✔ | ✔ |
| share network | | | ◐ |
| subnet | | ◐ | ◐ |
+| subnetpool | | ✔ | ✔ |
| trunk | | ✔ | ✔ |
| user | | ◐ | ◐ |
| volume | | ◐ | ◐ |
diff --git a/api/v1alpha1/subnetpool_types.go b/api/v1alpha1/subnetpool_types.go
new file mode 100644
index 000000000..d663d5c3f
--- /dev/null
+++ b/api/v1alpha1/subnetpool_types.go
@@ -0,0 +1,223 @@
+/*
+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
+
+// SubnetPoolResourceSpec contains the desired state of the resource.
+type SubnetPoolResourceSpec 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"`
+
+ // projectRef is a reference to the ORC Project which this resource is associated with.
+ // +optional
+ // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="projectRef is immutable"
+ ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"`
+
+ // addressScopeRef is a reference to the ORC AddressScope which this resource is associated with.
+ // +optional
+ // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="addressScopeRef is immutable"
+ AddressScopeRef *KubernetesNameRef `json:"addressScopeRef,omitempty"`
+
+ // defaultQuota is a per-project quota on the prefix space that
+ // can be allocated from the SubnetPool for project subnets. Its
+ // value represents the number of absolute addresses any given
+ // project is allowed to consume from the pool.
+ // +optional
+ // TODO(winiciusallan): Add this field when fixing bug in gophercloud
+ // DefaultQuota int32 `json:"defaultQuota,omitempty"`
+
+ // prefixes is the list of subnet prefixes to assign to the subnet
+ // pool. The API merges adjacent prefixes and treats them as a
+ // single prefix. Each subnet prefix must be unique across all
+ // subnet pools associated with address scope.
+ // +kubebuilder:validation:MinItems:=1
+ // +kubebuilder:validation:MaxItems:=64
+ // +listType=set
+ // +required
+ Prefixes []CIDR `json:"prefixes,omitempty"`
+
+ // minPrefixLength is the smallest prefix that can be allocated
+ // from a subnet pool. For IPv4 subnet pools, default is 8. For
+ // IPv6 subnet pools, default is 64.
+ // +kubebuilder:validation:Minimum=1
+ // +required
+ MinPrefixLength int32 `json:"minPrefixLength,omitempty"`
+
+ // maxPrefixLength is the maximum prefix size that can be allocated
+ // from the subnet pool. For IPv4 subnet pools, default is 32. For
+ // IPv6 subnet pools, default is 128.
+ // +kubebuilder:validation:Minimum=1
+ // +required
+ MaxPrefixLength int32 `json:"maxPrefixLength,omitempty"`
+
+ // shared indicates whether this resource is shared across all projects.
+ // By default, it is false, and only administrative users can
+ // change this value.
+ // +optional
+ Shared *bool `json:"shared,omitempty"`
+
+ // defaultPrefixLength is the size of the prefix to allocate when
+ // the cidr or prefixlen attributes are omitted when you create
+ // the subnet. Default is MinPrefixLength.
+ // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="defaultPrefixLength is immutable"
+ // +optional
+ DefaultPrefixLength int32 `json:"defaultPrefixLength,omitempty"`
+
+ // isDefault defines whether the subnetpool is default pool or
+ // not.
+ // +optional
+ IsDefault *bool `json:"isDefault,omitempty"`
+}
+
+// SubnetPoolFilter defines an existing resource by its properties
+// +kubebuilder:validation:MinProperties:=1
+type SubnetPoolFilter struct {
+ // name of the existing resource
+ // +optional
+ Name *OpenStackName `json:"name,omitempty"`
+
+ // description of the existing resource
+ // +optional
+ Description *NeutronDescription `json:"description,omitempty"`
+
+ // projectRef is a reference to the ORC Project which this resource is associated with.
+ // +optional
+ ProjectRef *KubernetesNameRef `json:"projectRef,omitempty"`
+
+ // addressScopeRef is a reference to the ORC AddressScope which this resource is associated with.
+ // +optional
+ AddressScopeRef *KubernetesNameRef `json:"addressScopeRef,omitempty"`
+
+ // minPrefixLength allows filtering the subnet pool list result by
+ // the smallest prefix that can be allocated from a subnet pool.
+ // +optional
+ MinPrefixLength int32 `json:"minPrefixLength,omitempty"`
+
+ // maxPrefixLength allows filtering the subnet pool list result by
+ // the maximum prefix size that can be allocated from the subnet
+ // pool.
+ // +optional
+ MaxPrefixLength int32 `json:"maxPrefixLength,omitempty"`
+
+ // ipVersion is the IP protocol version. It can be either 4 or 6
+ // +optional
+ IPVersion IPVersion `json:"ipVersion,omitempty"`
+
+ // shared allows filtering the list result based on whether the
+ // resource is shared across all projects. This field is
+ // admin-only.
+ // +optional
+ Shared *bool `json:"shared,omitempty"`
+
+ // defaultPrefixLength allows filtering the subnet pool list
+ // result by the size of the prefix to allocate when the cidr or
+ // prefixlen attributes are omitted when you create the subnet.
+ // +optional
+ DefaultPrefixLength int32 `json:"defaultPrefixLength,omitempty"`
+
+ // isDefault allows filtering the subnet pool list result based on
+ // if it is a default pool or not.
+ // +optional
+ IsDefault *bool `json:"isDefault,omitempty"`
+
+ // revisionNumber allows filtering the list result by the revision
+ // number of the resource.
+ // +optional
+ RevisionNumber int64 `json:"revisionNumber,omitempty"`
+
+ FilterByNeutronTags `json:",inline"`
+}
+
+// SubnetPoolResourceStatus represents the observed state of the resource.
+type SubnetPoolResourceStatus 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"`
+
+ // projectID is the ID of the Project to which the resource is associated.
+ // +kubebuilder:validation:MaxLength=1024
+ // +optional
+ ProjectID string `json:"projectID,omitempty"`
+
+ // addressScopeID is the ID of the AddressScope to which the resource is associated.
+ // +kubebuilder:validation:MaxLength=1024
+ // +optional
+ AddressScopeID string `json:"addressScopeID,omitempty"`
+
+ // prefixes is a list of prefixes to assign to the SubnetPool.
+ // +listType=atomic
+ // +kubebuilder:validation:MaxItems:=1024
+ // +kubebuilder:validation:items:MaxLength:=64
+ // +optional
+ Prefixes []string `json:"prefixes,omitempty"`
+
+ // defaultQuota is a per-project quota on the prefix space that
+ // can be allocated from the SubnetPool for project subnets.
+ // +optional
+ DefaultQuota int32 `json:"defaultQuota,omitempty"`
+
+ // minPrefixLength is the smallest prefix that can be allocated
+ // from a subnet pool.
+ // +optional
+ MinPrefixLength int32 `json:"minPrefixLength,omitempty"`
+
+ // maxPrefixLength is the maximum prefix size that can be
+ // allocated from the subnet pool.
+ // +optional
+ MaxPrefixLength int32 `json:"maxPrefixLength,omitempty"`
+
+ // defaultPrefixLength is the size of the prefix to allocate when
+ // the cidr or prefixlen attributes are omitted when you create
+ // the subnet.
+ // +optional
+ DefaultPrefixLength int32 `json:"defaultPrefixLength,omitempty"`
+
+ // isDefault indicates whether the SubnetPool is the default pool
+ // when creating subnets.
+ // +optional
+ IsDefault bool `json:"isDefault,omitempty"`
+
+ // shared indicates whether the SubnetPool is shared across all projects.
+ // +optional
+ Shared bool `json:"shared,omitempty"`
+
+ // ipVersion is the IP protocol version. It can be either 4 or 6
+ // +optional
+ IPVersion int32 `json:"ipVersion,omitempty"`
+
+ // tags is the list of tags on the resource.
+ // +kubebuilder:validation:MaxItems=64
+ // +kubebuilder:validation:items:MaxLength=1024
+ // +listType=atomic
+ // +optional
+ Tags []string `json:"tags,omitempty"`
+
+ NeutronStatusMetadata `json:",inline"`
+}
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index bb7d1b67d..b7e9dd58b 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -6266,6 +6266,275 @@ func (in *SubnetList) DeepCopyObject() runtime.Object {
return nil
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SubnetPool) DeepCopyInto(out *SubnetPool) {
+ *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 SubnetPool.
+func (in *SubnetPool) DeepCopy() *SubnetPool {
+ if in == nil {
+ return nil
+ }
+ out := new(SubnetPool)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SubnetPool) 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 *SubnetPoolFilter) DeepCopyInto(out *SubnetPoolFilter) {
+ *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(NeutronDescription)
+ **out = **in
+ }
+ if in.ProjectRef != nil {
+ in, out := &in.ProjectRef, &out.ProjectRef
+ *out = new(KubernetesNameRef)
+ **out = **in
+ }
+ if in.AddressScopeRef != nil {
+ in, out := &in.AddressScopeRef, &out.AddressScopeRef
+ *out = new(KubernetesNameRef)
+ **out = **in
+ }
+ if in.Shared != nil {
+ in, out := &in.Shared, &out.Shared
+ *out = new(bool)
+ **out = **in
+ }
+ if in.IsDefault != nil {
+ in, out := &in.IsDefault, &out.IsDefault
+ *out = new(bool)
+ **out = **in
+ }
+ in.FilterByNeutronTags.DeepCopyInto(&out.FilterByNeutronTags)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPoolFilter.
+func (in *SubnetPoolFilter) DeepCopy() *SubnetPoolFilter {
+ if in == nil {
+ return nil
+ }
+ out := new(SubnetPoolFilter)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SubnetPoolImport) DeepCopyInto(out *SubnetPoolImport) {
+ *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(SubnetPoolFilter)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPoolImport.
+func (in *SubnetPoolImport) DeepCopy() *SubnetPoolImport {
+ if in == nil {
+ return nil
+ }
+ out := new(SubnetPoolImport)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SubnetPoolList) DeepCopyInto(out *SubnetPoolList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]SubnetPool, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPoolList.
+func (in *SubnetPoolList) DeepCopy() *SubnetPoolList {
+ if in == nil {
+ return nil
+ }
+ out := new(SubnetPoolList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *SubnetPoolList) 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 *SubnetPoolResourceSpec) DeepCopyInto(out *SubnetPoolResourceSpec) {
+ *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.ProjectRef != nil {
+ in, out := &in.ProjectRef, &out.ProjectRef
+ *out = new(KubernetesNameRef)
+ **out = **in
+ }
+ if in.AddressScopeRef != nil {
+ in, out := &in.AddressScopeRef, &out.AddressScopeRef
+ *out = new(KubernetesNameRef)
+ **out = **in
+ }
+ if in.Prefixes != nil {
+ in, out := &in.Prefixes, &out.Prefixes
+ *out = make([]CIDR, len(*in))
+ copy(*out, *in)
+ }
+ if in.Shared != nil {
+ in, out := &in.Shared, &out.Shared
+ *out = new(bool)
+ **out = **in
+ }
+ if in.IsDefault != nil {
+ in, out := &in.IsDefault, &out.IsDefault
+ *out = new(bool)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPoolResourceSpec.
+func (in *SubnetPoolResourceSpec) DeepCopy() *SubnetPoolResourceSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(SubnetPoolResourceSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SubnetPoolResourceStatus) DeepCopyInto(out *SubnetPoolResourceStatus) {
+ *out = *in
+ if in.Prefixes != nil {
+ in, out := &in.Prefixes, &out.Prefixes
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+ if in.Tags != nil {
+ in, out := &in.Tags, &out.Tags
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+ in.NeutronStatusMetadata.DeepCopyInto(&out.NeutronStatusMetadata)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPoolResourceStatus.
+func (in *SubnetPoolResourceStatus) DeepCopy() *SubnetPoolResourceStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(SubnetPoolResourceStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SubnetPoolSpec) DeepCopyInto(out *SubnetPoolSpec) {
+ *out = *in
+ if in.Import != nil {
+ in, out := &in.Import, &out.Import
+ *out = new(SubnetPoolImport)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Resource != nil {
+ in, out := &in.Resource, &out.Resource
+ *out = new(SubnetPoolResourceSpec)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.ManagedOptions != nil {
+ in, out := &in.ManagedOptions, &out.ManagedOptions
+ *out = new(ManagedOptions)
+ **out = **in
+ }
+ out.CloudCredentialsRef = in.CloudCredentialsRef
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPoolSpec.
+func (in *SubnetPoolSpec) DeepCopy() *SubnetPoolSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(SubnetPoolSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SubnetPoolStatus) DeepCopyInto(out *SubnetPoolStatus) {
+ *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(SubnetPoolResourceStatus)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetPoolStatus.
+func (in *SubnetPoolStatus) DeepCopy() *SubnetPoolStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(SubnetPoolStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SubnetResourceSpec) DeepCopyInto(out *SubnetResourceSpec) {
*out = *in
diff --git a/api/v1alpha1/zz_generated.subnetpool-resource.go b/api/v1alpha1/zz_generated.subnetpool-resource.go
new file mode 100644
index 000000000..fb592254a
--- /dev/null
+++ b/api/v1alpha1/zz_generated.subnetpool-resource.go
@@ -0,0 +1,179 @@
+// 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"
+)
+
+// SubnetPoolImport specifies an existing resource which will be imported instead of
+// creating a new one
+// +kubebuilder:validation:MinProperties:=1
+// +kubebuilder:validation:MaxProperties:=1
+type SubnetPoolImport 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 *SubnetPoolFilter `json:"filter,omitempty"`
+}
+
+// SubnetPoolSpec 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 SubnetPoolSpec struct {
+ // import refers to an existing OpenStack resource which will be imported instead of
+ // creating a new one.
+ // +optional
+ Import *SubnetPoolImport `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 *SubnetPoolResourceSpec `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"`
+
+ // cloudCredentialsRef points to a secret containing OpenStack credentials
+ // +required
+ CloudCredentialsRef CloudCredentialsReference `json:"cloudCredentialsRef,omitzero"`
+}
+
+// SubnetPoolStatus defines the observed state of an ORC resource.
+type SubnetPoolStatus 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 *SubnetPoolResourceStatus `json:"resource,omitempty"`
+}
+
+var _ ObjectWithConditions = &SubnetPool{}
+
+func (i *SubnetPool) 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"
+
+// SubnetPool is the Schema for an ORC resource.
+type SubnetPool 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 SubnetPoolSpec `json:"spec,omitzero"`
+
+ // status defines the observed state of the resource.
+ // +optional
+ Status SubnetPoolStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// SubnetPoolList contains a list of SubnetPool.
+type SubnetPoolList struct {
+ metav1.TypeMeta `json:",inline"`
+
+ // metadata contains the list metadata
+ // +optional
+ metav1.ListMeta `json:"metadata,omitempty"`
+
+ // items contains a list of SubnetPool.
+ // +required
+ Items []SubnetPool `json:"items"`
+}
+
+func (l *SubnetPoolList) GetItems() []SubnetPool {
+ return l.Items
+}
+
+func init() {
+ SchemeBuilder.Register(&SubnetPool{}, &SubnetPoolList{})
+}
+
+func (i *SubnetPool) GetCloudCredentialsRef() (*string, *CloudCredentialsReference) {
+ if i == nil {
+ return nil, nil
+ }
+
+ return &i.Namespace, &i.Spec.CloudCredentialsRef
+}
+
+var _ CloudCredentialsRefProvider = &SubnetPool{}
diff --git a/cmd/manager/main.go b/cmd/manager/main.go
index 97cd7e73a..07433c3d7 100644
--- a/cmd/manager/main.go
+++ b/cmd/manager/main.go
@@ -50,6 +50,7 @@ import (
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/service"
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/sharenetwork"
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/subnet"
+ "github.com/k-orc/openstack-resource-controller/v2/internal/controllers/subnetpool"
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/trunk"
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/user"
"github.com/k-orc/openstack-resource-controller/v2/internal/controllers/volume"
@@ -129,6 +130,7 @@ func main() {
securitygroup.New(scopeFactory),
server.New(scopeFactory),
servergroup.New(scopeFactory),
+ subnetpool.New(scopeFactory),
project.New(scopeFactory),
user.New(scopeFactory),
volume.New(scopeFactory),
diff --git a/cmd/models-schema/zz_generated.openapi.go b/cmd/models-schema/zz_generated.openapi.go
index 439fca722..54dd762ec 100644
--- a/cmd/models-schema/zz_generated.openapi.go
+++ b/cmd/models-schema/zz_generated.openapi.go
@@ -246,6 +246,14 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
"github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetGateway": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetGateway(ref),
"github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetImport": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetImport(ref),
"github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetList": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetList(ref),
+ "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPool": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPool(ref),
+ "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPoolFilter": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolFilter(ref),
+ "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPoolImport": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolImport(ref),
+ "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPoolList": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolList(ref),
+ "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPoolResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolResourceSpec(ref),
+ "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPoolResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolResourceStatus(ref),
+ "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPoolSpec": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolSpec(ref),
+ "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPoolStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolStatus(ref),
"github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceSpec": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetResourceSpec(ref),
"github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetResourceStatus": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetResourceStatus(ref),
"github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetSpec": schema_openstack_resource_controller_v2_api_v1alpha1_SubnetSpec(ref),
@@ -11757,6 +11765,654 @@ func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetList(ref common.
}
}
+func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPool(ref common.ReferenceCallback) common.OpenAPIDefinition {
+ return common.OpenAPIDefinition{
+ Schema: spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Description: "SubnetPool 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.SubnetPoolSpec"),
+ },
+ },
+ "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.SubnetPoolStatus"),
+ },
+ },
+ },
+ Required: []string{"spec"},
+ },
+ },
+ Dependencies: []string{
+ "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPoolSpec", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPoolStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
+ }
+}
+
+func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolFilter(ref common.ReferenceCallback) common.OpenAPIDefinition {
+ return common.OpenAPIDefinition{
+ Schema: spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Description: "SubnetPoolFilter 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: "",
+ },
+ },
+ "projectRef": {
+ SchemaProps: spec.SchemaProps{
+ Description: "projectRef is a reference to the ORC Project which this resource is associated with.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ "addressScopeRef": {
+ SchemaProps: spec.SchemaProps{
+ Description: "addressScopeRef is a reference to the ORC AddressScope which this resource is associated with.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ "minPrefixLength": {
+ SchemaProps: spec.SchemaProps{
+ Description: "minPrefixLength allows filtering the subnet pool list result by the smallest prefix that can be allocated from a subnet pool.",
+ Type: []string{"integer"},
+ Format: "int32",
+ },
+ },
+ "maxPrefixLength": {
+ SchemaProps: spec.SchemaProps{
+ Description: "maxPrefixLength allows filtering the subnet pool list result by the maximum prefix size that can be allocated from the subnet pool.",
+ Type: []string{"integer"},
+ Format: "int32",
+ },
+ },
+ "ipVersion": {
+ SchemaProps: spec.SchemaProps{
+ Description: "ipVersion is the IP protocol version. It can be either 4 or 6",
+ Type: []string{"integer"},
+ Format: "int32",
+ },
+ },
+ "shared": {
+ SchemaProps: spec.SchemaProps{
+ Description: "shared allows filtering the list result based on whether the resource is shared across all projects. This field is admin-only.",
+ Type: []string{"boolean"},
+ Format: "",
+ },
+ },
+ "defaultPrefixLength": {
+ SchemaProps: spec.SchemaProps{
+ Description: "defaultPrefixLength allows filtering the subnet pool list result by the size of the prefix to allocate when the cidr or prefixlen attributes are omitted when you create the subnet.",
+ Type: []string{"integer"},
+ Format: "int32",
+ },
+ },
+ "isDefault": {
+ SchemaProps: spec.SchemaProps{
+ Description: "isDefault allows filtering the subnet pool list result based on if it is a default pool or not.",
+ Type: []string{"boolean"},
+ Format: "",
+ },
+ },
+ "revisionNumber": {
+ SchemaProps: spec.SchemaProps{
+ Description: "revisionNumber allows filtering the list result by the revision number of the resource.",
+ Type: []string{"integer"},
+ Format: "int64",
+ },
+ },
+ "tags": {
+ VendorExtensible: spec.VendorExtensible{
+ Extensions: spec.Extensions{
+ "x-kubernetes-list-type": "set",
+ },
+ },
+ SchemaProps: spec.SchemaProps{
+ Description: "tags is a list of tags to filter by. If specified, the resource must have all of the tags specified to be included in the result.",
+ Type: []string{"array"},
+ Items: &spec.SchemaOrArray{
+ Schema: &spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Default: "",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ },
+ },
+ },
+ "tagsAny": {
+ VendorExtensible: spec.VendorExtensible{
+ Extensions: spec.Extensions{
+ "x-kubernetes-list-type": "set",
+ },
+ },
+ SchemaProps: spec.SchemaProps{
+ Description: "tagsAny is a list of tags to filter by. If specified, the resource must have at least one of the tags specified to be included in the result.",
+ Type: []string{"array"},
+ Items: &spec.SchemaOrArray{
+ Schema: &spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Default: "",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ },
+ },
+ },
+ "notTags": {
+ VendorExtensible: spec.VendorExtensible{
+ Extensions: spec.Extensions{
+ "x-kubernetes-list-type": "set",
+ },
+ },
+ SchemaProps: spec.SchemaProps{
+ Description: "notTags is a list of tags to filter by. If specified, resources which contain all of the given tags will be excluded from the result.",
+ Type: []string{"array"},
+ Items: &spec.SchemaOrArray{
+ Schema: &spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Default: "",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ },
+ },
+ },
+ "notTagsAny": {
+ VendorExtensible: spec.VendorExtensible{
+ Extensions: spec.Extensions{
+ "x-kubernetes-list-type": "set",
+ },
+ },
+ SchemaProps: spec.SchemaProps{
+ Description: "notTagsAny is a list of tags to filter by. If specified, resources which contain any of the given tags will be excluded from the result.",
+ Type: []string{"array"},
+ Items: &spec.SchemaOrArray{
+ Schema: &spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Default: "",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolImport(ref common.ReferenceCallback) common.OpenAPIDefinition {
+ return common.OpenAPIDefinition{
+ Schema: spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Description: "SubnetPoolImport 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.SubnetPoolFilter"),
+ },
+ },
+ },
+ },
+ },
+ Dependencies: []string{
+ "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPoolFilter"},
+ }
+}
+
+func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolList(ref common.ReferenceCallback) common.OpenAPIDefinition {
+ return common.OpenAPIDefinition{
+ Schema: spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Description: "SubnetPoolList contains a list of SubnetPool.",
+ 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 SubnetPool.",
+ 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.SubnetPool"),
+ },
+ },
+ },
+ },
+ },
+ },
+ Required: []string{"items"},
+ },
+ },
+ Dependencies: []string{
+ "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPool", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
+ }
+}
+
+func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolResourceSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
+ return common.OpenAPIDefinition{
+ Schema: spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Description: "SubnetPoolResourceSpec 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: "",
+ },
+ },
+ "projectRef": {
+ SchemaProps: spec.SchemaProps{
+ Description: "projectRef is a reference to the ORC Project which this resource is associated with.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ "addressScopeRef": {
+ SchemaProps: spec.SchemaProps{
+ Description: "addressScopeRef is a reference to the ORC AddressScope which this resource is associated with.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ "prefixes": {
+ VendorExtensible: spec.VendorExtensible{
+ Extensions: spec.Extensions{
+ "x-kubernetes-list-type": "set",
+ },
+ },
+ SchemaProps: spec.SchemaProps{
+ Description: "prefixes is the list of subnet prefixes to assign to the subnet pool. The API merges adjacent prefixes and treats them as a single prefix. Each subnet prefix must be unique across all subnet pools associated with address scope.",
+ Type: []string{"array"},
+ Items: &spec.SchemaOrArray{
+ Schema: &spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Default: "",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ },
+ },
+ },
+ "minPrefixLength": {
+ SchemaProps: spec.SchemaProps{
+ Description: "minPrefixLength is the smallest prefix that can be allocated from a subnet pool. For IPv4 subnet pools, default is 8. For IPv6 subnet pools, default is 64.",
+ Type: []string{"integer"},
+ Format: "int32",
+ },
+ },
+ "maxPrefixLength": {
+ SchemaProps: spec.SchemaProps{
+ Description: "maxPrefixLength is the maximum prefix size that can be allocated from the subnet pool. For IPv4 subnet pools, default is 32. For IPv6 subnet pools, default is 128.",
+ Type: []string{"integer"},
+ Format: "int32",
+ },
+ },
+ "shared": {
+ SchemaProps: spec.SchemaProps{
+ Description: "shared indicates whether this resource is shared across all projects. By default, it is false, and only administrative users can change this value.",
+ Type: []string{"boolean"},
+ Format: "",
+ },
+ },
+ "defaultPrefixLength": {
+ SchemaProps: spec.SchemaProps{
+ Description: "defaultPrefixLength is the size of the prefix to allocate when the cidr or prefixlen attributes are omitted when you create the subnet. Default is MinPrefixLength.",
+ Type: []string{"integer"},
+ Format: "int32",
+ },
+ },
+ "isDefault": {
+ SchemaProps: spec.SchemaProps{
+ Description: "isDefault defines whether the subnetpool is default pool or not.",
+ Type: []string{"boolean"},
+ Format: "",
+ },
+ },
+ },
+ Required: []string{"prefixes", "minPrefixLength", "maxPrefixLength"},
+ },
+ },
+ }
+}
+
+func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolResourceStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
+ return common.OpenAPIDefinition{
+ Schema: spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Description: "SubnetPoolResourceStatus 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: "",
+ },
+ },
+ "projectID": {
+ SchemaProps: spec.SchemaProps{
+ Description: "projectID is the ID of the Project to which the resource is associated.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ "addressScopeID": {
+ SchemaProps: spec.SchemaProps{
+ Description: "addressScopeID is the ID of the AddressScope to which the resource is associated.",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ "prefixes": {
+ VendorExtensible: spec.VendorExtensible{
+ Extensions: spec.Extensions{
+ "x-kubernetes-list-type": "atomic",
+ },
+ },
+ SchemaProps: spec.SchemaProps{
+ Description: "prefixes is a list of prefixes to assign to the SubnetPool.",
+ Type: []string{"array"},
+ Items: &spec.SchemaOrArray{
+ Schema: &spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Default: "",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ },
+ },
+ },
+ "defaultQuota": {
+ SchemaProps: spec.SchemaProps{
+ Description: "defaultQuota is a per-project quota on the prefix space that can be allocated from the SubnetPool for project subnets.",
+ Type: []string{"integer"},
+ Format: "int32",
+ },
+ },
+ "minPrefixLength": {
+ SchemaProps: spec.SchemaProps{
+ Description: "minPrefixLength is the smallest prefix that can be allocated from a subnet pool.",
+ Type: []string{"integer"},
+ Format: "int32",
+ },
+ },
+ "maxPrefixLength": {
+ SchemaProps: spec.SchemaProps{
+ Description: "maxPrefixLength is the maximum prefix size that can be allocated from the subnet pool.",
+ Type: []string{"integer"},
+ Format: "int32",
+ },
+ },
+ "defaultPrefixLength": {
+ SchemaProps: spec.SchemaProps{
+ Description: "defaultPrefixLength is the size of the prefix to allocate when the cidr or prefixlen attributes are omitted when you create the subnet.",
+ Type: []string{"integer"},
+ Format: "int32",
+ },
+ },
+ "isDefault": {
+ SchemaProps: spec.SchemaProps{
+ Description: "isDefault indicates whether the SubnetPool is the default pool when creating subnets.",
+ Type: []string{"boolean"},
+ Format: "",
+ },
+ },
+ "shared": {
+ SchemaProps: spec.SchemaProps{
+ Description: "shared indicates whether the SubnetPool is shared across all projects.",
+ Type: []string{"boolean"},
+ Format: "",
+ },
+ },
+ "ipVersion": {
+ SchemaProps: spec.SchemaProps{
+ Description: "ipVersion is the IP protocol version. It can be either 4 or 6",
+ Type: []string{"integer"},
+ Format: "int32",
+ },
+ },
+ "tags": {
+ VendorExtensible: spec.VendorExtensible{
+ Extensions: spec.Extensions{
+ "x-kubernetes-list-type": "atomic",
+ },
+ },
+ SchemaProps: spec.SchemaProps{
+ Description: "tags is the list of tags on the resource.",
+ Type: []string{"array"},
+ Items: &spec.SchemaOrArray{
+ Schema: &spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Default: "",
+ Type: []string{"string"},
+ Format: "",
+ },
+ },
+ },
+ },
+ },
+ "createdAt": {
+ SchemaProps: spec.SchemaProps{
+ Description: "createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601",
+ Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
+ },
+ },
+ "updatedAt": {
+ SchemaProps: spec.SchemaProps{
+ Description: "updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601",
+ Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
+ },
+ },
+ "revisionNumber": {
+ SchemaProps: spec.SchemaProps{
+ Description: "revisionNumber optionally set via extensions/standard-attr-revisions",
+ Type: []string{"integer"},
+ Format: "int64",
+ },
+ },
+ },
+ },
+ },
+ Dependencies: []string{
+ "k8s.io/apimachinery/pkg/apis/meta/v1.Time"},
+ }
+}
+
+func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
+ return common.OpenAPIDefinition{
+ Schema: spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Description: "SubnetPoolSpec 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.SubnetPoolImport"),
+ },
+ },
+ "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.SubnetPoolResourceSpec"),
+ },
+ },
+ "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"),
+ },
+ },
+ "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.SubnetPoolImport", "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPoolResourceSpec"},
+ }
+}
+
+func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetPoolStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
+ return common.OpenAPIDefinition{
+ Schema: spec.Schema{
+ SchemaProps: spec.SchemaProps{
+ Description: "SubnetPoolStatus 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.SubnetPoolResourceStatus"),
+ },
+ },
+ },
+ },
+ },
+ Dependencies: []string{
+ "github.com/k-orc/openstack-resource-controller/v2/api/v1alpha1.SubnetPoolResourceStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"},
+ }
+}
+
func schema_openstack_resource_controller_v2_api_v1alpha1_SubnetResourceSpec(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..1042cea72 100644
--- a/cmd/resource-generator/main.go
+++ b/cmd/resource-generator/main.go
@@ -189,6 +189,9 @@ var resources []templateFields = []templateFields{
{
Name: "ApplicationCredential",
},
+ {
+ Name: "SubnetPool",
+ },
}
// These resources won't be generated
diff --git a/config/crd/bases/openstack.k-orc.cloud_subnetpools.yaml b/config/crd/bases/openstack.k-orc.cloud_subnetpools.yaml
new file mode 100644
index 000000000..6bf448104
--- /dev/null
+++ b/config/crd/bases/openstack.k-orc.cloud_subnetpools.yaml
@@ -0,0 +1,555 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.20.1
+ name: subnetpools.openstack.k-orc.cloud
+spec:
+ group: openstack.k-orc.cloud
+ names:
+ categories:
+ - openstack
+ kind: SubnetPool
+ listKind: SubnetPoolList
+ plural: subnetpools
+ singular: subnetpool
+ 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: SubnetPool 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:
+ addressScopeRef:
+ description: addressScopeRef is a reference to the ORC AddressScope
+ which this resource is associated with.
+ maxLength: 253
+ minLength: 1
+ type: string
+ defaultPrefixLength:
+ description: |-
+ defaultPrefixLength allows filtering the subnet pool list
+ result by the size of the prefix to allocate when the cidr or
+ prefixlen attributes are omitted when you create the subnet.
+ format: int32
+ type: integer
+ description:
+ description: description of the existing resource
+ maxLength: 255
+ minLength: 1
+ type: string
+ ipVersion:
+ description: ipVersion is the IP protocol version. It can
+ be either 4 or 6
+ enum:
+ - 4
+ - 6
+ format: int32
+ type: integer
+ isDefault:
+ description: |-
+ isDefault allows filtering the subnet pool list result based on
+ if it is a default pool or not.
+ type: boolean
+ maxPrefixLength:
+ description: |-
+ maxPrefixLength allows filtering the subnet pool list result by
+ the maximum prefix size that can be allocated from the subnet
+ pool.
+ format: int32
+ type: integer
+ minPrefixLength:
+ description: |-
+ minPrefixLength allows filtering the subnet pool list result by
+ the smallest prefix that can be allocated from a subnet pool.
+ format: int32
+ type: integer
+ name:
+ description: name of the existing resource
+ maxLength: 255
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ notTags:
+ description: |-
+ notTags is a list of tags to filter by. If specified, resources which
+ contain all of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ maxLength: 255
+ minLength: 1
+ type: string
+ maxItems: 64
+ type: array
+ x-kubernetes-list-type: set
+ notTagsAny:
+ description: |-
+ notTagsAny is a list of tags to filter by. If specified, resources
+ which contain any of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ maxLength: 255
+ minLength: 1
+ type: string
+ maxItems: 64
+ type: array
+ x-kubernetes-list-type: set
+ projectRef:
+ description: projectRef is a reference to the ORC Project
+ which this resource is associated with.
+ maxLength: 253
+ minLength: 1
+ type: string
+ revisionNumber:
+ description: |-
+ revisionNumber allows filtering the list result by the revision
+ number of the resource.
+ format: int64
+ type: integer
+ shared:
+ description: |-
+ shared allows filtering the list result based on whether the
+ resource is shared across all projects. This field is
+ admin-only.
+ type: boolean
+ tags:
+ description: |-
+ tags is a list of tags to filter by. If specified, the resource must
+ have all of the tags specified to be included in the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ maxLength: 255
+ minLength: 1
+ type: string
+ maxItems: 64
+ type: array
+ x-kubernetes-list-type: set
+ tagsAny:
+ description: |-
+ tagsAny is a list of tags to filter by. If specified, the resource
+ must have at least one of the tags specified to be included in the
+ result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ maxLength: 255
+ minLength: 1
+ type: string
+ maxItems: 64
+ type: array
+ x-kubernetes-list-type: set
+ 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:
+ addressScopeRef:
+ description: addressScopeRef is a reference to the ORC AddressScope
+ which this resource is associated with.
+ maxLength: 253
+ minLength: 1
+ type: string
+ x-kubernetes-validations:
+ - message: addressScopeRef is immutable
+ rule: self == oldSelf
+ defaultPrefixLength:
+ description: |-
+ defaultPrefixLength is the size of the prefix to allocate when
+ the cidr or prefixlen attributes are omitted when you create
+ the subnet. Default is MinPrefixLength.
+ format: int32
+ type: integer
+ x-kubernetes-validations:
+ - message: defaultPrefixLength is immutable
+ rule: self == oldSelf
+ description:
+ description: description is a human-readable description for the
+ resource.
+ maxLength: 255
+ minLength: 1
+ type: string
+ isDefault:
+ description: |-
+ isDefault defines whether the subnetpool is default pool or
+ not.
+ type: boolean
+ maxPrefixLength:
+ description: |-
+ maxPrefixLength is the maximum prefix size that can be allocated
+ from the subnet pool. For IPv4 subnet pools, default is 32. For
+ IPv6 subnet pools, default is 128.
+ format: int32
+ minimum: 1
+ type: integer
+ minPrefixLength:
+ description: |-
+ minPrefixLength is the smallest prefix that can be allocated
+ from a subnet pool. For IPv4 subnet pools, default is 8. For
+ IPv6 subnet pools, default is 64.
+ format: int32
+ minimum: 1
+ type: integer
+ 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
+ prefixes:
+ description: |-
+ prefixes is the list of subnet prefixes to assign to the subnet
+ pool. The API merges adjacent prefixes and treats them as a
+ single prefix. Each subnet prefix must be unique across all
+ subnet pools associated with address scope.
+ items:
+ format: cidr
+ maxLength: 49
+ minLength: 1
+ type: string
+ maxItems: 64
+ minItems: 1
+ type: array
+ x-kubernetes-list-type: set
+ projectRef:
+ description: projectRef is a reference to the ORC Project which
+ this resource is associated with.
+ maxLength: 253
+ minLength: 1
+ type: string
+ x-kubernetes-validations:
+ - message: projectRef is immutable
+ rule: self == oldSelf
+ shared:
+ description: |-
+ shared indicates whether this resource is shared across all projects.
+ By default, it is false, and only administrative users can
+ change this value.
+ type: boolean
+ required:
+ - maxPrefixLength
+ - minPrefixLength
+ type: object
+ 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
+ resource:
+ description: resource contains the observed state of the OpenStack
+ resource.
+ properties:
+ addressScopeID:
+ description: addressScopeID is the ID of the AddressScope to which
+ the resource is associated.
+ maxLength: 1024
+ type: string
+ createdAt:
+ description: createdAt shows the date and time when the resource
+ was created. The date and time stamp format is ISO 8601
+ format: date-time
+ type: string
+ defaultPrefixLength:
+ description: |-
+ defaultPrefixLength is the size of the prefix to allocate when
+ the cidr or prefixlen attributes are omitted when you create
+ the subnet.
+ format: int32
+ type: integer
+ defaultQuota:
+ description: |-
+ defaultQuota is a per-project quota on the prefix space that
+ can be allocated from the SubnetPool for project subnets.
+ format: int32
+ type: integer
+ description:
+ description: description is a human-readable description for the
+ resource.
+ maxLength: 1024
+ type: string
+ ipVersion:
+ description: ipVersion is the IP protocol version. It can be either
+ 4 or 6
+ format: int32
+ type: integer
+ isDefault:
+ description: |-
+ isDefault indicates whether the SubnetPool is the default pool
+ when creating subnets.
+ type: boolean
+ maxPrefixLength:
+ description: |-
+ maxPrefixLength is the maximum prefix size that can be
+ allocated from the subnet pool.
+ format: int32
+ type: integer
+ minPrefixLength:
+ description: |-
+ minPrefixLength is the smallest prefix that can be allocated
+ from a subnet pool.
+ format: int32
+ type: integer
+ name:
+ description: name is a Human-readable name for the resource. Might
+ not be unique.
+ maxLength: 1024
+ type: string
+ prefixes:
+ description: prefixes is a list of prefixes to assign to the SubnetPool.
+ items:
+ maxLength: 64
+ type: string
+ maxItems: 1024
+ type: array
+ x-kubernetes-list-type: atomic
+ projectID:
+ description: projectID is the ID of the Project to which the resource
+ is associated.
+ maxLength: 1024
+ type: string
+ revisionNumber:
+ description: revisionNumber optionally set via extensions/standard-attr-revisions
+ format: int64
+ type: integer
+ shared:
+ description: shared indicates whether the SubnetPool is shared
+ across all projects.
+ type: boolean
+ tags:
+ description: tags is the list of tags on the resource.
+ items:
+ maxLength: 1024
+ type: string
+ maxItems: 64
+ type: array
+ x-kubernetes-list-type: atomic
+ updatedAt:
+ description: updatedAt shows the date and time when the resource
+ was updated. The date and time stamp format is ISO 8601
+ format: date-time
+ 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..ad643f647 100644
--- a/config/crd/kustomization.yaml
+++ b/config/crd/kustomization.yaml
@@ -25,6 +25,7 @@ resources:
- bases/openstack.k-orc.cloud_services.yaml
- bases/openstack.k-orc.cloud_sharenetworks.yaml
- bases/openstack.k-orc.cloud_subnets.yaml
+- bases/openstack.k-orc.cloud_subnetpools.yaml
- bases/openstack.k-orc.cloud_trunks.yaml
- bases/openstack.k-orc.cloud_users.yaml
- bases/openstack.k-orc.cloud_volumes.yaml
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
index a04a488e2..8e416daee 100644
--- a/config/rbac/role.yaml
+++ b/config/rbac/role.yaml
@@ -38,6 +38,7 @@ rules:
- servers
- services
- sharenetworks
+ - subnetpools
- subnets
- trunks
- users
@@ -75,6 +76,7 @@ rules:
- servers/status
- services/status
- sharenetworks/status
+ - subnetpools/status
- subnets/status
- trunks/status
- users/status
diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml
index ceb05e15e..848ebfb34 100644
--- a/config/samples/kustomization.yaml
+++ b/config/samples/kustomization.yaml
@@ -23,6 +23,7 @@ resources:
- openstack_v1alpha1_service.yaml
- openstack_v1alpha1_sharenetwork.yaml
- openstack_v1alpha1_subnet.yaml
+- openstack_v1alpha1_subnetpool.yaml
- openstack_v1alpha1_trunk.yaml
- openstack_v1alpha1_user.yaml
- openstack_v1alpha1_volume.yaml
diff --git a/config/samples/openstack_v1alpha1_subnetpool.yaml b/config/samples/openstack_v1alpha1_subnetpool.yaml
new file mode 100644
index 000000000..c5facc980
--- /dev/null
+++ b/config/samples/openstack_v1alpha1_subnetpool.yaml
@@ -0,0 +1,17 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-sample
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ description: Sample SubnetPool
+ prefixes:
+ - 10.0.0.0/24
+ minPrefixLength: 8
+ minPrefixLength: 32
+ defaultPrefixLen: 24
diff --git a/internal/controllers/subnetpool/actuator.go b/internal/controllers/subnetpool/actuator.go
new file mode 100644
index 000000000..806c4d7bf
--- /dev/null
+++ b/internal/controllers/subnetpool/actuator.go
@@ -0,0 +1,362 @@
+/*
+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 subnetpool
+
+import (
+ "context"
+ "iter"
+ "slices"
+
+ "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/subnetpools"
+ 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"
+ "github.com/k-orc/openstack-resource-controller/v2/internal/util/dependency"
+ orcerrors "github.com/k-orc/openstack-resource-controller/v2/internal/util/errors"
+ "github.com/k-orc/openstack-resource-controller/v2/internal/util/tags"
+)
+
+// OpenStack resource types
+type (
+ osResourceT = subnetpools.SubnetPool
+
+ 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 subnetpoolActuator struct {
+ osClient osclients.SubnetPoolClient
+ k8sClient client.Client
+}
+
+var (
+ _ createResourceActuator = subnetpoolActuator{}
+ _ deleteResourceActuator = subnetpoolActuator{}
+)
+
+func (subnetpoolActuator) GetResourceID(osResource *osResourceT) string {
+ return osResource.ID
+}
+
+func (actuator subnetpoolActuator) GetOSResourceByID(ctx context.Context, id string) (*osResourceT, progress.ReconcileStatus) {
+ resource, err := actuator.osClient.GetSubnetPool(ctx, id)
+ if err != nil {
+ return nil, progress.WrapError(err)
+ }
+ return resource, nil
+}
+
+func (actuator subnetpoolActuator) ListOSResourcesForAdoption(ctx context.Context, orcObject orcObjectPT) (iter.Seq2[*osResourceT, error], bool) {
+ resourceSpec := orcObject.Spec.Resource
+ if resourceSpec == nil {
+ return nil, false
+ }
+
+ var projectID string
+ if resourceSpec.ProjectRef != nil {
+ project, rs := dependency.FetchDependency(
+ ctx, actuator.k8sClient, orcObject.Namespace, resourceSpec.ProjectRef, "Project",
+ func(dep *orcv1alpha1.Project) bool {
+ return orcv1alpha1.IsAvailable(dep) && dep.Status.ID != nil
+ },
+ )
+ if needsReschedule, _ := rs.NeedsReschedule(); needsReschedule {
+ return nil, false
+ }
+ projectID = ptr.Deref(project.Status.ID, "")
+ }
+
+ listOpts := subnetpools.ListOpts{
+ Name: getResourceName(orcObject),
+ ProjectID: projectID,
+ }
+
+ return actuator.osClient.ListSubnetPools(ctx, listOpts), true
+}
+
+func (actuator subnetpoolActuator) ListOSResourcesForImport(ctx context.Context, obj orcObjectPT, filter filterT) (iter.Seq2[*osResourceT, error], progress.ReconcileStatus) {
+ var reconcileStatus progress.ReconcileStatus
+
+ project, rs := dependency.FetchDependency[*orcv1alpha1.Project](
+ ctx, actuator.k8sClient, obj.Namespace,
+ filter.ProjectRef, "Project",
+ orcv1alpha1.IsAvailable,
+ )
+ reconcileStatus = reconcileStatus.WithReconcileStatus(rs)
+
+ addressScope, rs := dependency.FetchDependency[*orcv1alpha1.AddressScope](
+ ctx, actuator.k8sClient, obj.Namespace,
+ filter.AddressScopeRef, "AddressScope",
+ orcv1alpha1.IsAvailable,
+ )
+ reconcileStatus = reconcileStatus.WithReconcileStatus(rs)
+
+ if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule {
+ return nil, reconcileStatus
+ }
+
+ listOpts := subnetpools.ListOpts{
+ Name: string(ptr.Deref(filter.Name, "")),
+ Description: string(ptr.Deref(filter.Description, "")),
+ ProjectID: ptr.Deref(project.Status.ID, ""),
+ AddressScopeID: ptr.Deref(addressScope.Status.ID, ""),
+ MinPrefixLen: int(filter.MinPrefixLength),
+ MaxPrefixLen: int(filter.MaxPrefixLength),
+ IPVersion: int(filter.IPVersion),
+ Shared: filter.Shared,
+ DefaultPrefixLen: int(filter.DefaultPrefixLength),
+ IsDefault: filter.IsDefault,
+ RevisionNumber: int(filter.RevisionNumber),
+ Tags: tags.Join(filter.Tags),
+ TagsAny: tags.Join(filter.TagsAny),
+ NotTags: tags.Join(filter.NotTags),
+ NotTagsAny: tags.Join(filter.NotTagsAny),
+ }
+
+ return actuator.osClient.ListSubnetPools(ctx, listOpts), reconcileStatus
+}
+
+func (actuator subnetpoolActuator) 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 projectID string
+ if resource.ProjectRef != nil {
+ project, projectDepRS := projectDependency.GetDependency(
+ ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable,
+ )
+ reconcileStatus = reconcileStatus.WithReconcileStatus(projectDepRS)
+ if project != nil {
+ projectID = ptr.Deref(project.Status.ID, "")
+ }
+ }
+
+ var addressScopeID string
+ if resource.AddressScopeRef != nil {
+ addressScope, addressScopeDepRS := addressScopeDependency.GetDependency(
+ ctx, actuator.k8sClient, obj, orcv1alpha1.IsAvailable,
+ )
+ reconcileStatus = reconcileStatus.WithReconcileStatus(addressScopeDepRS)
+ if addressScope != nil {
+ addressScopeID = ptr.Deref(addressScope.Status.ID, "")
+ }
+ }
+ if needsReschedule, _ := reconcileStatus.NeedsReschedule(); needsReschedule {
+ return nil, reconcileStatus
+ }
+
+ prefixes := make([]string, len(resource.Prefixes))
+ for i, prefix := range resource.Prefixes {
+ prefixes[i] = string(prefix)
+ }
+
+ createOpts := subnetpools.CreateOpts{
+ Name: getResourceName(obj),
+ Description: ptr.Deref(resource.Description, ""),
+ ProjectID: projectID,
+ AddressScopeID: addressScopeID,
+ Prefixes: prefixes,
+ MinPrefixLen: int(resource.MinPrefixLength),
+ MaxPrefixLen: int(resource.MaxPrefixLength),
+ Shared: ptr.Deref(resource.Shared, false),
+ DefaultPrefixLen: int(resource.DefaultPrefixLength),
+ IsDefault: ptr.Deref(resource.IsDefault, false),
+ }
+
+ osResource, err := actuator.osClient.CreateSubnetPool(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 subnetpoolActuator) DeleteResource(ctx context.Context, _ orcObjectPT, resource *osResourceT) progress.ReconcileStatus {
+ return progress.WrapError(actuator.osClient.DeleteSubnetPool(ctx, resource.ID))
+}
+
+func (actuator subnetpoolActuator) 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 := subnetpools.UpdateOpts{}
+
+ handleNameUpdate(&updateOpts, obj, osResource)
+ handleDescriptionUpdate(&updateOpts, resource, osResource)
+ handlePrefixesUpdate(&updateOpts, resource, osResource)
+ handleMinPrefixLengthUpdate(&updateOpts, resource, osResource)
+ handleMaxPrefixLengthUpdate(&updateOpts, resource, osResource)
+ handleIsDefaultUpdate(&updateOpts, resource, osResource)
+
+ 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.UpdateSubnetPool(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 subnetpools.UpdateOpts) (bool, error) {
+ updateOptsMap, err := updateOpts.ToSubnetPoolUpdateMap()
+ if err != nil {
+ return false, err
+ }
+
+ updateMap, ok := updateOptsMap["subnetpool"].(map[string]any)
+ if !ok {
+ updateMap = make(map[string]any)
+ }
+
+ return len(updateMap) > 0, nil
+}
+
+func handleNameUpdate(updateOpts *subnetpools.UpdateOpts, obj orcObjectPT, osResource *osResourceT) {
+ name := getResourceName(obj)
+ if osResource.Name != name {
+ updateOpts.Name = name
+ }
+}
+
+func handleDescriptionUpdate(updateOpts *subnetpools.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) {
+ description := ptr.Deref(resource.Description, "")
+ if osResource.Description != description {
+ updateOpts.Description = &description
+ }
+}
+
+func handleMinPrefixLengthUpdate(updateOpts *subnetpools.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) {
+ minPrefixLen := resource.MinPrefixLength
+ if minPrefixLen != int32(osResource.MinPrefixLen) {
+ updateOpts.MinPrefixLen = int(minPrefixLen)
+ }
+}
+
+func handleMaxPrefixLengthUpdate(updateOpts *subnetpools.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) {
+ maxPrefixLength := resource.MaxPrefixLength
+ if maxPrefixLength != int32(osResource.MaxPrefixLen) {
+ updateOpts.MaxPrefixLen = int(maxPrefixLength)
+ }
+}
+
+func handlePrefixesUpdate(updateOpts *subnetpools.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) {
+ desiredPrefixes := make([]string, len(resource.Prefixes))
+ for i := range resource.Prefixes {
+ desiredPrefixes[i] = string(resource.Prefixes[i])
+ }
+ slices.Sort(desiredPrefixes)
+
+ currentPrefixes := make([]string, len(osResource.Prefixes))
+ copy(currentPrefixes, osResource.Prefixes)
+ slices.Sort(currentPrefixes)
+
+ if !slices.Equal(desiredPrefixes, currentPrefixes) {
+ updateOpts.Prefixes = desiredPrefixes
+ }
+}
+
+func handleIsDefaultUpdate(updateOpts *subnetpools.UpdateOpts, resource *resourceSpecT, osResource *osResourceT) {
+ // fallback to the default value if unset.
+ isDefault := ptr.Deref(resource.IsDefault, false)
+ if isDefault != osResource.IsDefault {
+ updateOpts.IsDefault = &isDefault
+ }
+}
+
+func (actuator subnetpoolActuator) GetResourceReconcilers(ctx context.Context, orcObject orcObjectPT, osResource *osResourceT, controller interfaces.ResourceController) ([]resourceReconciler, progress.ReconcileStatus) {
+ return []resourceReconciler{
+ actuator.updateResource,
+ }, nil
+}
+
+type subnetpoolHelperFactory struct{}
+
+var _ helperFactory = subnetpoolHelperFactory{}
+
+func newActuator(ctx context.Context, orcObject *orcv1alpha1.SubnetPool, controller interfaces.ResourceController) (subnetpoolActuator, 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 subnetpoolActuator{}, reconcileStatus
+ }
+
+ clientScope, err := controller.GetScopeFactory().NewClientScopeFromObject(ctx, controller.GetK8sClient(), log, orcObject)
+ if err != nil {
+ return subnetpoolActuator{}, progress.WrapError(err)
+ }
+ osClient, err := clientScope.NewSubnetPoolClient()
+ if err != nil {
+ return subnetpoolActuator{}, progress.WrapError(err)
+ }
+
+ return subnetpoolActuator{
+ osClient: osClient,
+ k8sClient: controller.GetK8sClient(),
+ }, nil
+}
+
+func (subnetpoolHelperFactory) NewAPIObjectAdapter(obj orcObjectPT) adapterI {
+ return subnetpoolAdapter{obj}
+}
+
+func (subnetpoolHelperFactory) NewCreateActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (createResourceActuator, progress.ReconcileStatus) {
+ return newActuator(ctx, orcObject, controller)
+}
+
+func (subnetpoolHelperFactory) NewDeleteActuator(ctx context.Context, orcObject orcObjectPT, controller interfaces.ResourceController) (deleteResourceActuator, progress.ReconcileStatus) {
+ return newActuator(ctx, orcObject, controller)
+}
diff --git a/internal/controllers/subnetpool/actuator_test.go b/internal/controllers/subnetpool/actuator_test.go
new file mode 100644
index 000000000..c600e893d
--- /dev/null
+++ b/internal/controllers/subnetpool/actuator_test.go
@@ -0,0 +1,266 @@
+/*
+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 subnetpool
+
+import (
+ "testing"
+
+ "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/subnetpools"
+ 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 subnetpools.UpdateOpts
+ expectChange bool
+ }{
+ {
+ name: "Empty base opts",
+ updateOpts: subnetpools.UpdateOpts{},
+ expectChange: false,
+ },
+ {
+ name: "Updated opts",
+ updateOpts: subnetpools.UpdateOpts{Name: "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.SubnetPool{}
+ resource.Name = "object-name"
+ resource.Spec = orcv1alpha1.SubnetPoolSpec{
+ Resource: &orcv1alpha1.SubnetPoolResourceSpec{Name: tt.newValue},
+ }
+ osResource := &osResourceT{Name: tt.existingValue}
+
+ updateOpts := subnetpools.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.SubnetPoolResourceSpec{Description: tt.newValue}
+ osResource := &osResourceT{Description: tt.existingValue}
+
+ updateOpts := subnetpools.UpdateOpts{}
+ handleDescriptionUpdate(&updateOpts, resource, osResource)
+
+ got, _ := needsUpdate(updateOpts)
+ if got != tt.expectChange {
+ t.Errorf("Expected change: %v, got: %v", tt.expectChange, got)
+ }
+ })
+ }
+}
+
+func TestHandleMinPrefixLengthUpdate(t *testing.T) {
+ testCases := []struct {
+ name string
+ newValue int32
+ existingValue int
+ expectChange bool
+ }{
+ {name: "Identical", newValue: 8, existingValue: 8, expectChange: false},
+ {name: "Different", newValue: 16, existingValue: 8, expectChange: true},
+ {name: "Increased", newValue: 24, existingValue: 16, expectChange: true},
+ {name: "Decreased", newValue: 8, existingValue: 16, expectChange: true},
+ }
+
+ for _, tt := range testCases {
+ t.Run(tt.name, func(t *testing.T) {
+ resource := &orcv1alpha1.SubnetPoolResourceSpec{MinPrefixLength: tt.newValue}
+ osResource := &osResourceT{MinPrefixLen: tt.existingValue}
+
+ updateOpts := subnetpools.UpdateOpts{}
+ handleMinPrefixLengthUpdate(&updateOpts, resource, osResource)
+
+ got, _ := needsUpdate(updateOpts)
+ if got != tt.expectChange {
+ t.Errorf("Expected change: %v, got: %v", tt.expectChange, got)
+ }
+ })
+ }
+}
+
+func TestHandleMaxPrefixLengthUpdate(t *testing.T) {
+ testCases := []struct {
+ name string
+ newValue int32
+ existingValue int
+ expectChange bool
+ }{
+ {name: "Identical", newValue: 32, existingValue: 32, expectChange: false},
+ {name: "Different", newValue: 28, existingValue: 32, expectChange: true},
+ {name: "Increased", newValue: 128, existingValue: 32, expectChange: true},
+ {name: "Decreased", newValue: 24, existingValue: 32, expectChange: true},
+ }
+
+ for _, tt := range testCases {
+ t.Run(tt.name, func(t *testing.T) {
+ resource := &orcv1alpha1.SubnetPoolResourceSpec{MaxPrefixLength: tt.newValue}
+ osResource := &osResourceT{MaxPrefixLen: tt.existingValue}
+
+ updateOpts := subnetpools.UpdateOpts{}
+ handleMaxPrefixLengthUpdate(&updateOpts, resource, osResource)
+
+ got, _ := needsUpdate(updateOpts)
+ if got != tt.expectChange {
+ t.Errorf("Expected change: %v, got: %v", tt.expectChange, got)
+ }
+ })
+ }
+}
+
+func TestHandlePrefixesUpdate(t *testing.T) {
+ testCases := []struct {
+ name string
+ newPrefixes []orcv1alpha1.CIDR
+ existingPrefixes []string
+ expectChange bool
+ }{
+ {
+ name: "Identical prefixes",
+ newPrefixes: []orcv1alpha1.CIDR{"192.168.0.0/24", "10.0.0.0/16"},
+ existingPrefixes: []string{"192.168.0.0/24", "10.0.0.0/16"},
+ expectChange: false,
+ },
+ {
+ name: "Different prefixes",
+ newPrefixes: []orcv1alpha1.CIDR{"192.168.0.0/24"},
+ existingPrefixes: []string{"10.0.0.0/16"},
+ expectChange: true,
+ },
+ {
+ name: "Prefixes out of order",
+ newPrefixes: []orcv1alpha1.CIDR{"10.0.0.0/16", "192.168.0.0/24"},
+ existingPrefixes: []string{"192.168.0.0/24", "10.0.0.0/16"},
+ expectChange: false,
+ },
+ {
+ name: "Extra prefix in existing",
+ newPrefixes: []orcv1alpha1.CIDR{"192.168.0.0/24"},
+ existingPrefixes: []string{"192.168.0.0/24", "10.0.0.0/16"},
+ expectChange: true,
+ },
+ {
+ name: "Extra prefix in new",
+ newPrefixes: []orcv1alpha1.CIDR{"192.168.0.0/24", "10.0.0.0/16"},
+ existingPrefixes: []string{"192.168.0.0/24"},
+ expectChange: true,
+ },
+ {
+ name: "Empty prefixes",
+ newPrefixes: []orcv1alpha1.CIDR{},
+ existingPrefixes: []string{},
+ expectChange: false,
+ },
+ }
+
+ for _, tt := range testCases {
+ t.Run(tt.name, func(t *testing.T) {
+ resource := &orcv1alpha1.SubnetPoolResourceSpec{Prefixes: tt.newPrefixes}
+ osResource := &osResourceT{Prefixes: tt.existingPrefixes}
+
+ updateOpts := subnetpools.UpdateOpts{}
+ handlePrefixesUpdate(&updateOpts, resource, osResource)
+
+ got, _ := needsUpdate(updateOpts)
+ if got != tt.expectChange {
+ t.Errorf("Expected change: %v, got: %v", tt.expectChange, got)
+ }
+ })
+ }
+}
+
+func TestHandleIsDefaultUpdate(t *testing.T) {
+ ptrToBool := ptr.To[bool]
+ testCases := []struct {
+ name string
+ newValue *bool
+ existingValue bool
+ expectChange bool
+ }{
+ {name: "Identical", newValue: ptrToBool(true), existingValue: true, expectChange: false},
+ {name: "Different", newValue: ptrToBool(true), existingValue: false, expectChange: true},
+ {name: "No value provided, existing is set", newValue: nil, existingValue: true, expectChange: true},
+ {name: "No value provided, existing is default", newValue: nil, existingValue: false, expectChange: false},
+ }
+
+ for _, tt := range testCases {
+ t.Run(tt.name, func(t *testing.T) {
+ resource := &orcv1alpha1.SubnetPoolResourceSpec{IsDefault: tt.newValue}
+ osResource := &osResourceT{IsDefault: tt.existingValue}
+
+ updateOpts := subnetpools.UpdateOpts{}
+ handleIsDefaultUpdate(&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/subnetpool/controller.go b/internal/controllers/subnetpool/controller.go
new file mode 100644
index 000000000..49fce022d
--- /dev/null
+++ b/internal/controllers/subnetpool/controller.go
@@ -0,0 +1,156 @@
+/*
+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 subnetpool
+
+import (
+ "context"
+ "errors"
+
+ 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 = "subnetpool"
+
+// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=subnetpools,verbs=get;list;watch;create;update;patch;delete
+// +kubebuilder:rbac:groups=openstack.k-orc.cloud,resources=subnetpools/status,verbs=get;update;patch
+
+type subnetpoolReconcilerConstructor struct {
+ scopeFactory scope.Factory
+}
+
+func New(scopeFactory scope.Factory) interfaces.Controller {
+ return subnetpoolReconcilerConstructor{scopeFactory: scopeFactory}
+}
+
+func (subnetpoolReconcilerConstructor) GetName() string {
+ return controllerName
+}
+
+var projectDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.SubnetPoolList, *orcv1alpha1.Project](
+ "spec.resource.projectRef",
+ func(subnetpool *orcv1alpha1.SubnetPool) []string {
+ resource := subnetpool.Spec.Resource
+ if resource == nil || resource.ProjectRef == nil {
+ return nil
+ }
+ return []string{string(*resource.ProjectRef)}
+ },
+ finalizer, externalObjectFieldOwner,
+)
+
+var addressScopeDependency = dependency.NewDeletionGuardDependency[*orcv1alpha1.SubnetPoolList, *orcv1alpha1.AddressScope](
+ "spec.resource.addressScopeRef",
+ func(subnetpool *orcv1alpha1.SubnetPool) []string {
+ resource := subnetpool.Spec.Resource
+ if resource == nil || resource.AddressScopeRef == nil {
+ return nil
+ }
+ return []string{string(*resource.AddressScopeRef)}
+ },
+ finalizer, externalObjectFieldOwner,
+)
+
+var projectImportDependency = dependency.NewDependency[*orcv1alpha1.SubnetPoolList, *orcv1alpha1.Project](
+ "spec.import.filter.projectRef",
+ func(subnetpool *orcv1alpha1.SubnetPool) []string {
+ resource := subnetpool.Spec.Import
+ if resource == nil || resource.Filter == nil || resource.Filter.ProjectRef == nil {
+ return nil
+ }
+ return []string{string(*resource.Filter.ProjectRef)}
+ },
+)
+
+var addressScopeImportDependency = dependency.NewDependency[*orcv1alpha1.SubnetPoolList, *orcv1alpha1.AddressScope](
+ "spec.import.filter.addressScopeRef",
+ func(subnetpool *orcv1alpha1.SubnetPool) []string {
+ resource := subnetpool.Spec.Import
+ if resource == nil || resource.Filter == nil || resource.Filter.AddressScopeRef == nil {
+ return nil
+ }
+ return []string{string(*resource.Filter.AddressScopeRef)}
+ },
+)
+
+// SetupWithManager sets up the controller with the Manager.
+func (c subnetpoolReconcilerConstructor) SetupWithManager(ctx context.Context, mgr ctrl.Manager, options controller.Options) error {
+ log := ctrl.LoggerFrom(ctx)
+ k8sClient := mgr.GetClient()
+
+ projectWatchEventHandler, err := projectDependency.WatchEventHandler(log, k8sClient)
+ if err != nil {
+ return err
+ }
+
+ addressScopeWatchEventHandler, err := addressScopeDependency.WatchEventHandler(log, k8sClient)
+ if err != nil {
+ return err
+ }
+
+ projectImportWatchEventHandler, err := projectImportDependency.WatchEventHandler(log, k8sClient)
+ if err != nil {
+ return err
+ }
+
+ addressScopeImportWatchEventHandler, err := addressScopeImportDependency.WatchEventHandler(log, k8sClient)
+ if err != nil {
+ return err
+ }
+
+ builder := ctrl.NewControllerManagedBy(mgr).
+ WithOptions(options).
+ Watches(&orcv1alpha1.Project{}, projectWatchEventHandler,
+ builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Project{})),
+ ).
+ Watches(&orcv1alpha1.AddressScope{}, addressScopeWatchEventHandler,
+ builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.AddressScope{})),
+ ).
+ // A second watch is necessary because we need a different handler that omits deletion guards
+ Watches(&orcv1alpha1.Project{}, projectImportWatchEventHandler,
+ builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.Project{})),
+ ).
+ // A second watch is necessary because we need a different handler that omits deletion guards
+ Watches(&orcv1alpha1.AddressScope{}, addressScopeImportWatchEventHandler,
+ builder.WithPredicates(predicates.NewBecameAvailable(log, &orcv1alpha1.AddressScope{})),
+ ).
+ For(&orcv1alpha1.SubnetPool{})
+
+ if err := errors.Join(
+ projectDependency.AddToManager(ctx, mgr),
+ addressScopeDependency.AddToManager(ctx, mgr),
+ projectImportDependency.AddToManager(ctx, mgr),
+ addressScopeImportDependency.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, subnetpoolHelperFactory{}, subnetpoolStatusWriter{})
+ return builder.Complete(&r)
+}
diff --git a/internal/controllers/subnetpool/status.go b/internal/controllers/subnetpool/status.go
new file mode 100644
index 000000000..837c0a1da
--- /dev/null
+++ b/internal/controllers/subnetpool/status.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 subnetpool
+
+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 subnetpoolStatusWriter struct{}
+
+type objectApplyT = orcapplyconfigv1alpha1.SubnetPoolApplyConfiguration
+type statusApplyT = orcapplyconfigv1alpha1.SubnetPoolStatusApplyConfiguration
+
+var _ interfaces.ResourceStatusWriter[*orcv1alpha1.SubnetPool, *osResourceT, *objectApplyT, *statusApplyT] = subnetpoolStatusWriter{}
+
+func (subnetpoolStatusWriter) GetApplyConfig(name, namespace string) *objectApplyT {
+ return orcapplyconfigv1alpha1.SubnetPool(name, namespace)
+}
+
+func (subnetpoolStatusWriter) ResourceAvailableStatus(orcObject *orcv1alpha1.SubnetPool, 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 (subnetpoolStatusWriter) ApplyResourceStatus(log logr.Logger, osResource *osResourceT, statusApply *statusApplyT) {
+ resourceStatus := orcapplyconfigv1alpha1.SubnetPoolResourceStatus().
+ WithProjectID(osResource.ProjectID).
+ WithName(osResource.Name).
+ WithPrefixes(osResource.Prefixes...).
+ WithMinPrefixLength(int32(osResource.MinPrefixLen)).
+ WithMaxPrefixLength(int32(osResource.MaxPrefixLen)).
+ WithDefaultPrefixLength(int32(osResource.DefaultPrefixLen)).
+ WithIsDefault(osResource.IsDefault).
+ WithShared(osResource.Shared).
+ WithDefaultQuota(int32(osResource.DefaultQuota)).
+ WithRevisionNumber(int64(osResource.RevisionNumber)).
+ WithCreatedAt(metav1.NewTime(osResource.CreatedAt)).
+ WithUpdatedAt(metav1.NewTime(osResource.UpdatedAt)).
+ WithIPVersion(int32(osResource.IPversion))
+
+ if osResource.Description != "" {
+ resourceStatus.WithDescription(osResource.Description)
+ }
+
+ if osResource.AddressScopeID != "" {
+ resourceStatus.WithAddressScopeID(osResource.AddressScopeID)
+ }
+
+ if osResource.ProjectID != "" {
+ resourceStatus.WithProjectID(osResource.ProjectID)
+ }
+
+ if len(osResource.Tags) != 0 {
+ resourceStatus.WithTags(osResource.Tags...)
+ }
+
+ statusApply.WithResource(resourceStatus)
+}
diff --git a/internal/controllers/subnetpool/tests/subnetpool-create-full/00-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-create-full/00-assert.yaml
new file mode 100644
index 000000000..517419331
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-create-full/00-assert.yaml
@@ -0,0 +1,62 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-create-full
+status:
+ resource:
+ name: subnetpool-create-full-override
+ description: SubnetPool from "create full" test
+ prefixes:
+ - 192.168.11.0/24
+ minPrefixLength: 16
+ maxPrefixLength: 28
+ defaultPrefixLength: 24
+ conditions:
+ - type: Available
+ status: "True"
+ reason: Success
+ - type: Progressing
+ status: "False"
+ reason: Success
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-create-full-admin
+status:
+ resource:
+ name: subnetpool-create-full-admin
+ isDefault: false
+ shared: true
+ 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: SubnetPool
+ name: subnetpool-create-full
+ ref: subnetpool
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: SubnetPool
+ name: subnetpool-create-full-admin
+ ref: subnetpoolAdmin
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: Project
+ name: subnetpool-create-full
+ ref: project
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: AddressScope
+ name: subnetpool-create-full
+ ref: addressScope
+assertAll:
+ - celExpr: "subnetpool.status.id != ''"
+ - celExpr: "subnetpoolAdmin.status.resource.projectID == project.status.id"
+ - celExpr: "subnetpool.status.resource.addressScopeID == addressScope.status.id"
diff --git a/internal/controllers/subnetpool/tests/subnetpool-create-full/00-create-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-create-full/00-create-resource.yaml
new file mode 100644
index 000000000..725eeed7b
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-create-full/00-create-resource.yaml
@@ -0,0 +1,65 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: Project
+metadata:
+ name: subnetpool-create-full
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack-admin
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource: {}
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: AddressScope
+metadata:
+ name: subnetpool-create-full
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ ipVersion: 4
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-create-full
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ name: subnetpool-create-full-override
+ description: SubnetPool from "create full" test
+ addressScopeRef: subnetpool-create-full
+ prefixes:
+ - 192.168.11.0/24
+ minPrefixLength: 16
+ maxPrefixLength: 28
+ defaultPrefixLength: 24
+ isDefault: false
+---
+# Creating a SubnetPool as admin to test `projectRef` and `shared`
+# fields.
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-create-full-admin
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack-admin
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ projectRef: subnetpool-create-full
+ prefixes:
+ - 192.168.12.0/24
+ minPrefixLength: 16
+ maxPrefixLength: 28
+ # Devstack automatically creates a default subnet pool that
+ # prevent us to create a new default pool.
+ isDefault: false
+ shared: true
diff --git a/internal/controllers/subnetpool/tests/subnetpool-create-full/00-secret.yaml b/internal/controllers/subnetpool/tests/subnetpool-create-full/00-secret.yaml
new file mode 100644
index 000000000..045711ee7
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-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/subnetpool/tests/subnetpool-create-full/README.md b/internal/controllers/subnetpool/tests/subnetpool-create-full/README.md
new file mode 100644
index 000000000..8417e6f4c
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-create-full/README.md
@@ -0,0 +1,11 @@
+# Create a SubnetPool with all the options
+
+## Step 00
+
+Create a SubnetPool 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/subnetpool/tests/subnetpool-create-minimal/00-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-create-minimal/00-assert.yaml
new file mode 100644
index 000000000..bf95b0a85
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-create-minimal/00-assert.yaml
@@ -0,0 +1,31 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-create-minimal
+status:
+ resource:
+ name: subnetpool-create-minimal
+ prefixes:
+ - 192.168.10.0/24
+ minPrefixLength: 8
+ maxPrefixLength: 32
+ 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: SubnetPool
+ name: subnetpool-create-minimal
+ ref: subnetpool
+assertAll:
+ - celExpr: "subnetpool.status.id != ''"
+ - celExpr: "!has(subnetpool.status.resource.description)"
+ - celExpr: "!has(subnetpool.status.resource.addressScopeID)"
diff --git a/internal/controllers/subnetpool/tests/subnetpool-create-minimal/00-create-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-create-minimal/00-create-resource.yaml
new file mode 100644
index 000000000..381802380
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-create-minimal/00-create-resource.yaml
@@ -0,0 +1,15 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-create-minimal
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ prefixes:
+ - 192.168.10.0/24
+ minPrefixLength: 8
+ maxPrefixLength: 32
diff --git a/internal/controllers/subnetpool/tests/subnetpool-create-minimal/00-secret.yaml b/internal/controllers/subnetpool/tests/subnetpool-create-minimal/00-secret.yaml
new file mode 100644
index 000000000..045711ee7
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-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/subnetpool/tests/subnetpool-create-minimal/01-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-create-minimal/01-assert.yaml
new file mode 100644
index 000000000..f79ffcfb9
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-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/subnetpool' in secret.metadata.finalizers"
diff --git a/internal/controllers/subnetpool/tests/subnetpool-create-minimal/01-delete-secret.yaml b/internal/controllers/subnetpool/tests/subnetpool-create-minimal/01-delete-secret.yaml
new file mode 100644
index 000000000..1620791b9
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-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/subnetpool/tests/subnetpool-create-minimal/README.md b/internal/controllers/subnetpool/tests/subnetpool-create-minimal/README.md
new file mode 100644
index 000000000..81a800c0c
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-create-minimal/README.md
@@ -0,0 +1,15 @@
+# Create a SubnetPool with the minimum options
+
+## Step 00
+
+Create a minimal SubnetPool, 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/subnetpool/tests/subnetpool-dependency/00-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-dependency/00-assert.yaml
new file mode 100644
index 000000000..6b3795a60
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-dependency/00-assert.yaml
@@ -0,0 +1,45 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-dependency-no-secret
+status:
+ conditions:
+ - type: Available
+ message: Waiting for Secret/subnetpool-dependency to be created
+ status: "False"
+ reason: Progressing
+ - type: Progressing
+ message: Waiting for Secret/subnetpool-dependency to be created
+ status: "True"
+ reason: Progressing
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-dependency-no-project
+status:
+ conditions:
+ - type: Available
+ message: Waiting for Project/subnetpool-dependency to be created
+ status: "False"
+ reason: Progressing
+ - type: Progressing
+ message: Waiting for Project/subnetpool-dependency to be created
+ status: "True"
+ reason: Progressing
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-dependency-no-addressscope
+status:
+ conditions:
+ - type: Available
+ message: Waiting for AddressScope/subnetpool-dependency to be created
+ status: "False"
+ reason: Progressing
+ - type: Progressing
+ message: Waiting for AddressScope/subnetpool-dependency to be created
+ status: "True"
+ reason: Progressing
diff --git a/internal/controllers/subnetpool/tests/subnetpool-dependency/00-create-resources-missing-deps.yaml b/internal/controllers/subnetpool/tests/subnetpool-dependency/00-create-resources-missing-deps.yaml
new file mode 100644
index 000000000..66e197db9
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-dependency/00-create-resources-missing-deps.yaml
@@ -0,0 +1,47 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-dependency-no-project
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack-admin
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ projectRef: subnetpool-dependency
+ prefixes:
+ - 192.168.15.0/24
+ minPrefixLength: 16
+ maxPrefixLength: 32
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-dependency-no-addressscope
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ addressScopeRef: subnetpool-dependency
+ prefixes:
+ - 192.168.16.0/24
+ minPrefixLength: 16
+ maxPrefixLength: 32
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-dependency-no-secret
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: subnetpool-dependency
+ managementPolicy: managed
+ resource:
+ prefixes:
+ - 192.168.17.0/24
+ minPrefixLength: 16
+ maxPrefixLength: 32
diff --git a/internal/controllers/subnetpool/tests/subnetpool-dependency/00-secret.yaml b/internal/controllers/subnetpool/tests/subnetpool-dependency/00-secret.yaml
new file mode 100644
index 000000000..045711ee7
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-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/subnetpool/tests/subnetpool-dependency/01-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-dependency/01-assert.yaml
new file mode 100644
index 000000000..e40d8acf3
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-dependency/01-assert.yaml
@@ -0,0 +1,45 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-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: SubnetPool
+metadata:
+ name: subnetpool-dependency-no-project
+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: SubnetPool
+metadata:
+ name: subnetpool-dependency-no-addressscope
+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/subnetpool/tests/subnetpool-dependency/01-create-dependencies.yaml b/internal/controllers/subnetpool/tests/subnetpool-dependency/01-create-dependencies.yaml
new file mode 100644
index 000000000..1f50fc888
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-dependency/01-create-dependencies.yaml
@@ -0,0 +1,29 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+commands:
+ - command: kubectl create secret generic subnetpool-dependency --from-file=clouds.yaml=${E2E_KUTTL_OSCLOUDS} ${E2E_KUTTL_CACERT_OPT}
+ namespaced: true
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: Project
+metadata:
+ name: subnetpool-dependency
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack-admin
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource: {}
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: AddressScope
+metadata:
+ name: subnetpool-dependency
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ ipVersion: 4
diff --git a/internal/controllers/subnetpool/tests/subnetpool-dependency/02-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-dependency/02-assert.yaml
new file mode 100644
index 000000000..81b68de1c
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-dependency/02-assert.yaml
@@ -0,0 +1,23 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+resourceRefs:
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: Project
+ name: subnetpool-dependency
+ ref: project
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: AddressScope
+ name: subnetpool-dependency
+ ref: addressScope
+ - apiVersion: v1
+ kind: Secret
+ name: subnetpool-dependency
+ ref: secret
+assertAll:
+ - celExpr: "project.metadata.deletionTimestamp != 0"
+ - celExpr: "'openstack.k-orc.cloud/subnetpool' in project.metadata.finalizers"
+ - celExpr: "addressScope.metadata.deletionTimestamp != 0"
+ - celExpr: "'openstack.k-orc.cloud/subnetpool' in addressScope.metadata.finalizers"
+ - celExpr: "secret.metadata.deletionTimestamp != 0"
+ - celExpr: "'openstack.k-orc.cloud/subnetpool' in secret.metadata.finalizers"
diff --git a/internal/controllers/subnetpool/tests/subnetpool-dependency/02-delete-dependencies.yaml b/internal/controllers/subnetpool/tests/subnetpool-dependency/02-delete-dependencies.yaml
new file mode 100644
index 000000000..67c0843d3
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-dependency/02-delete-dependencies.yaml
@@ -0,0 +1,11 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+commands:
+ # We expect the deletion to hang due to the finalizer, so use --wait=false
+ - command: kubectl delete project.openstack.k-orc.cloud subnetpool-dependency --wait=false
+ namespaced: true
+ - command: kubectl delete addressscope.openstack.k-orc.cloud subnetpool-dependency --wait=false
+ namespaced: true
+ - command: kubectl delete secret subnetpool-dependency --wait=false
+ namespaced: true
diff --git a/internal/controllers/subnetpool/tests/subnetpool-dependency/03-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-dependency/03-assert.yaml
new file mode 100644
index 000000000..64848c23e
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-dependency/03-assert.yaml
@@ -0,0 +1,11 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+commands:
+# Dependencies that were prevented deletion before should now be gone
+- script: "! kubectl get project.openstack.k-orc.cloud subnetpool-dependency --namespace $NAMESPACE"
+ skipLogOutput: true
+- script: "! kubectl get addressscope.openstack.k-orc.cloud subnetpool-dependency --namespace $NAMESPACE"
+ skipLogOutput: true
+- script: "! kubectl get secret subnetpool-dependency --namespace $NAMESPACE"
+ skipLogOutput: true
diff --git a/internal/controllers/subnetpool/tests/subnetpool-dependency/03-delete-resources.yaml b/internal/controllers/subnetpool/tests/subnetpool-dependency/03-delete-resources.yaml
new file mode 100644
index 000000000..e59c6326a
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-dependency/03-delete-resources.yaml
@@ -0,0 +1,13 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+delete:
+- apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: SubnetPool
+ name: subnetpool-dependency-no-secret
+- apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: SubnetPool
+ name: subnetpool-dependency-no-project
+- apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: SubnetPool
+ name: subnetpool-dependency-no-addressscope
diff --git a/internal/controllers/subnetpool/tests/subnetpool-dependency/README.md b/internal/controllers/subnetpool/tests/subnetpool-dependency/README.md
new file mode 100644
index 000000000..3a7a5fcbf
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-dependency/README.md
@@ -0,0 +1,21 @@
+# Creation and deletion dependencies
+
+## Step 00
+
+Create SubnetPools referencing non-existing resources. Each SubnetPool is dependent on other non-existing resource. Verify that the SubnetPools are waiting for the needed resources to be created externally.
+
+## Step 01
+
+Create the missing dependencies and verify all the SubnetPools 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 SubnetPools and validate that all resources are gone.
+
+## Reference
+
+https://k-orc.cloud/development/writing-tests/#dependency
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-dependency/00-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/00-assert.yaml
new file mode 100644
index 000000000..3f1e47d95
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/00-assert.yaml
@@ -0,0 +1,19 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import-dependency
+status:
+ conditions:
+ - type: Available
+ message: |-
+ Waiting for Project/subnetpool-import-dependency to be ready
+ Waiting for AddressScope/subnetpool-import-dependency to be ready
+ status: "False"
+ reason: Progressing
+ - type: Progressing
+ message: |-
+ Waiting for Project/subnetpool-import-dependency to be ready
+ Waiting for AddressScope/subnetpool-import-dependency to be ready
+ status: "True"
+ reason: Progressing
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-dependency/00-import-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/00-import-resource.yaml
new file mode 100644
index 000000000..d1e586130
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/00-import-resource.yaml
@@ -0,0 +1,42 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: Project
+metadata:
+ name: subnetpool-import-dependency
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack-admin
+ secretName: openstack-clouds
+ managementPolicy: unmanaged
+ import:
+ filter:
+ name: subnetpool-import-dependency-external
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: AddressScope
+metadata:
+ name: subnetpool-import-dependency
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: unmanaged
+ import:
+ filter:
+ name: subnetpool-import-dependency-external
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import-dependency
+spec:
+ cloudCredentialsRef:
+ # Using admin credentials so we can pass a different project than
+ # the authenticated one.
+ cloudName: openstack-admin
+ secretName: openstack-clouds
+ managementPolicy: unmanaged
+ import:
+ filter:
+ projectRef: subnetpool-import-dependency
+ addressScopeRef: subnetpool-import-dependency
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-dependency/00-secret.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/00-secret.yaml
new file mode 100644
index 000000000..045711ee7
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-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/subnetpool/tests/subnetpool-import-dependency/01-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/01-assert.yaml
new file mode 100644
index 000000000..9733da4e6
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/01-assert.yaml
@@ -0,0 +1,34 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import-dependency-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
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import-dependency
+status:
+ conditions:
+ - type: Available
+ message: |-
+ Waiting for Project/subnetpool-import-dependency to be ready
+ Waiting for AddressScope/subnetpool-import-dependency to be ready
+ status: "False"
+ reason: Progressing
+ - type: Progressing
+ message: |-
+ Waiting for Project/subnetpool-import-dependency to be ready
+ Waiting for AddressScope/subnetpool-import-dependency to be ready
+ status: "True"
+ reason: Progressing
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-dependency/01-create-trap-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/01-create-trap-resource.yaml
new file mode 100644
index 000000000..24c4517f7
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/01-create-trap-resource.yaml
@@ -0,0 +1,41 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: Project
+metadata:
+ name: subnetpool-import-dependency-not-this-one
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack-admin
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource: {}
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: AddressScope
+metadata:
+ name: subnetpool-import-dependency-not-this-one
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ ipVersion: 4
+---
+# This `subnetpool-import-dependency-not-this-one` should not be picked by the import filter
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import-dependency-not-this-one
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack-admin
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ projectRef: subnetpool-import-dependency-not-this-one
+ addressScopeRef: subnetpool-import-dependency-not-this-one
+ prefixes:
+ - 192.168.12.0/24
+ minPrefixLength: 8
+ maxPrefixLength: 32
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-dependency/02-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/02-assert.yaml
new file mode 100644
index 000000000..959f27d17
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/02-assert.yaml
@@ -0,0 +1,39 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+resourceRefs:
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: SubnetPool
+ name: subnetpool-import-dependency
+ ref: subnetpool1
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: SubnetPool
+ name: subnetpool-import-dependency-not-this-one
+ ref: subnetpool2
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: Project
+ name: subnetpool-import-dependency
+ ref: project
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: AddressScope
+ name: subnetpool-import-dependency
+ ref: addressScope
+assertAll:
+ - celExpr: "subnetpool1.status.id != subnetpool2.status.id"
+ - celExpr: "subnetpool1.status.resource.projectID == project.status.id"
+ - celExpr: "subnetpool1.status.resource.addressScopeID == addressScope.status.id"
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import-dependency
+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/subnetpool/tests/subnetpool-import-dependency/02-create-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/02-create-resource.yaml
new file mode 100644
index 000000000..d0a33f520
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/02-create-resource.yaml
@@ -0,0 +1,42 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: Project
+metadata:
+ name: subnetpool-import-dependency-external
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack-admin
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource: {}
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: AddressScope
+metadata:
+ name: subnetpool-import-dependency-external
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ ipVersion: 4
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import-dependency-external
+spec:
+ cloudCredentialsRef:
+ # Using admin credentials so we can pass a different project than
+ # the authenticated one.
+ cloudName: openstack-admin
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ projectRef: subnetpool-import-dependency-external
+ addressScopeRef: subnetpool-import-dependency-external
+ prefixes:
+ - 192.168.13.0/24
+ minPrefixLength: 8
+ maxPrefixLength: 32
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-dependency/03-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/03-assert.yaml
new file mode 100644
index 000000000..106c0761d
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/03-assert.yaml
@@ -0,0 +1,8 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+commands:
+- script: "! kubectl get project.openstack.k-orc.cloud subnetpool-import-dependency --namespace $NAMESPACE"
+ skipLogOutput: true
+- script: "! kubectl get addressscope.openstack.k-orc.cloud subnetpool-import-dependency --namespace $NAMESPACE"
+ skipLogOutput: true
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-dependency/03-delete-import-dependencies.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/03-delete-import-dependencies.yaml
new file mode 100644
index 000000000..db6708813
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/03-delete-import-dependencies.yaml
@@ -0,0 +1,9 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+commands:
+ # We should be able to delete the import dependencies
+ - command: kubectl delete project.openstack.k-orc.cloud subnetpool-import-dependency
+ namespaced: true
+ - command: kubectl delete addressscope.openstack.k-orc.cloud subnetpool-import-dependency
+ namespaced: true
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-dependency/04-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/04-assert.yaml
new file mode 100644
index 000000000..10b8fe016
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/04-assert.yaml
@@ -0,0 +1,6 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+commands:
+- script: "! kubectl get subnetpool.openstack.k-orc.cloud subnetpool-import-dependency --namespace $NAMESPACE"
+ skipLogOutput: true
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-dependency/04-delete-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/04-delete-resource.yaml
new file mode 100644
index 000000000..23f809d2f
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/04-delete-resource.yaml
@@ -0,0 +1,7 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+delete:
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: SubnetPool
+ name: subnetpool-import-dependency
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-dependency/README.md b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/README.md
new file mode 100644
index 000000000..e58429fba
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-dependency/README.md
@@ -0,0 +1,29 @@
+# Check dependency handling for imported SubnetPool
+
+## Step 00
+
+Import a SubnetPool that references other imported resources. The referenced imported resources have no matching resources yet.
+Verify the SubnetPool is waiting for the dependency to be ready.
+
+## Step 01
+
+Create a SubnetPool matching the import filter, except for referenced resources, and verify that it's not being imported.
+
+## Step 02
+
+Create the referenced resources and a SubnetPool matching the import filters.
+
+Verify that the observed status on the imported SubnetPool corresponds to the spec of the created SubnetPool.
+
+## Step 03
+
+Delete the referenced resources and check that ORC does not prevent deletion. The OpenStack resources still exist because they
+were imported resources and we only deleted the ORC representation of it.
+
+## Step 04
+
+Delete the SubnetPool and validate that all resources are gone.
+
+## Reference
+
+https://k-orc.cloud/development/writing-tests/#import-dependency
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-error/00-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-error/00-assert.yaml
new file mode 100644
index 000000000..9eee57ee6
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-error/00-assert.yaml
@@ -0,0 +1,30 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-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: SubnetPool
+metadata:
+ name: subnetpool-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/subnetpool/tests/subnetpool-import-error/00-create-resources.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-error/00-create-resources.yaml
new file mode 100644
index 000000000..19da06f6d
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-error/00-create-resources.yaml
@@ -0,0 +1,32 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import-error-external-1
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ minPrefixLength: 8
+ maxPrefixLength: 32
+ prefixes:
+ - 192.168.10.0/24
+ description: SubnetPool from "import error" test
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import-error-external-2
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ minPrefixLength: 8
+ maxPrefixLength: 32
+ prefixes:
+ - 192.168.10.0/24
+ description: SubnetPool from "import error" test
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-error/00-secret.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-error/00-secret.yaml
new file mode 100644
index 000000000..045711ee7
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-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/subnetpool/tests/subnetpool-import-error/01-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-error/01-assert.yaml
new file mode 100644
index 000000000..bcb0e2104
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-error/01-assert.yaml
@@ -0,0 +1,15 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-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/subnetpool/tests/subnetpool-import-error/01-import-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-import-error/01-import-resource.yaml
new file mode 100644
index 000000000..a91e9cbf5
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-error/01-import-resource.yaml
@@ -0,0 +1,13 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import-error
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: unmanaged
+ import:
+ filter:
+ description: SubnetPool from "import error" test
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import-error/README.md b/internal/controllers/subnetpool/tests/subnetpool-import-error/README.md
new file mode 100644
index 000000000..f59b2a79a
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import-error/README.md
@@ -0,0 +1,13 @@
+# Import SubnetPool with more than one matching resources
+
+## Step 00
+
+Create two SubnetPools with identical specs.
+
+## Step 01
+
+Ensure that an imported SubnetPool with a filter matching the resources returns an error.
+
+## Reference
+
+https://k-orc.cloud/development/writing-tests/#import-error
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import/00-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-import/00-assert.yaml
new file mode 100644
index 000000000..22212cdac
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import/00-assert.yaml
@@ -0,0 +1,15 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-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/subnetpool/tests/subnetpool-import/00-import-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-import/00-import-resource.yaml
new file mode 100644
index 000000000..e5e7e56d5
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import/00-import-resource.yaml
@@ -0,0 +1,20 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: unmanaged
+ import:
+ filter:
+ name: subnetpool-import-external
+ description: SubnetPool subnetpool-import-external from "subnetpool-import" test
+ minPrefixLength: 16
+ maxPrefixLength: 32
+ ipVersion: 4
+ shared: false
+ isDefault: false
+ revisionNumber: 0
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import/00-secret.yaml b/internal/controllers/subnetpool/tests/subnetpool-import/00-secret.yaml
new file mode 100644
index 000000000..045711ee7
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-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/subnetpool/tests/subnetpool-import/01-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-import/01-assert.yaml
new file mode 100644
index 000000000..cdd66075e
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import/01-assert.yaml
@@ -0,0 +1,41 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-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: subnetpool-import-external-not-this-one
+ description: SubnetPool subnetpool-import-external from "subnetpool-import" test
+ prefixes:
+ - 10.0.0.0/16
+ minPrefixLength: 16
+ maxPrefixLength: 28
+ ipVersion: 4
+ shared: false
+ isDefault: false
+ revisionNumber: 0
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-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/subnetpool/tests/subnetpool-import/01-create-trap-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-import/01-create-trap-resource.yaml
new file mode 100644
index 000000000..3453f0632
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import/01-create-trap-resource.yaml
@@ -0,0 +1,23 @@
+---
+# This `subnetpool-import-external-not-this-one` resource serves two purposes:
+# - ensure that we can successfully create another resource which name is a superstring of it (i.e. it's not being adopted)
+# - ensure that importing a resource which name is a superstring of it will not pick this one.
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import-external-not-this-one
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ description: SubnetPool subnetpool-import-external from "subnetpool-import" test
+ prefixes:
+ - 10.0.0.0/16
+ minPrefixLength: 16
+ maxPrefixLength: 28
+ ipVersion: 4
+ shared: false
+ isDefault: false
+ revisionNumber: 1
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import/02-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-import/02-assert.yaml
new file mode 100644
index 000000000..8ad8bce85
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import/02-assert.yaml
@@ -0,0 +1,40 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+resourceRefs:
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: SubnetPool
+ name: subnetpool-import-external
+ ref: subnetpool1
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: SubnetPool
+ name: subnetpool-import-external-not-this-one
+ ref: subnetpool2
+assertAll:
+ - celExpr: "subnetpool1.status.id != subnetpool2.status.id"
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-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: subnetpool-import-external
+ description: SubnetPool subnetpool-import-external from "subnetpool-import" test
+ prefixes:
+ - 192.168.10.0/24
+ minPrefixLength: 16
+ maxPrefixLength: 32
+ defaultPrefixLength: 16
+ shared: false
+ isDefault: false
+ revisionNumber: 0
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import/02-create-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-import/02-create-resource.yaml
new file mode 100644
index 000000000..0733d8f51
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import/02-create-resource.yaml
@@ -0,0 +1,18 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-import-external
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ description: SubnetPool subnetpool-import-external from "subnetpool-import" test
+ prefixes:
+ - 192.168.10.0/24
+ minPrefixLength: 16
+ maxPrefixLength: 32
+ shared: false
+ isDefault: false
diff --git a/internal/controllers/subnetpool/tests/subnetpool-import/README.md b/internal/controllers/subnetpool/tests/subnetpool-import/README.md
new file mode 100644
index 000000000..e063e5a8f
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-import/README.md
@@ -0,0 +1,18 @@
+# Import SubnetPool
+
+## Step 00
+
+Import a subnetpool that matches all fields in the filter (name, description, minPrefixLength), and verify it is waiting for the external resource to be created.
+
+## Step 01
+
+Create a subnetpool 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 subnetpool matching the filter and verify that the observed status on the imported subnetpool corresponds to the spec of the created subnetpool.
+Also, confirm that it does not adopt any subnetpool whose name is a superstring of its own.
+
+## Reference
+
+https://k-orc.cloud/development/writing-tests/#import
diff --git a/internal/controllers/subnetpool/tests/subnetpool-update/00-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-update/00-assert.yaml
new file mode 100644
index 000000000..323942e49
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-update/00-assert.yaml
@@ -0,0 +1,31 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+resourceRefs:
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: SubnetPool
+ name: subnetpool-update
+ ref: subnetpool
+assertAll:
+ - celExpr: "subnetpool.status.id != ''"
+ - celExpr: "!has(subnetpool.status.resource.description)"
+ - celExpr: "!has(subnetpool.status.resource.addressScopeID)"
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-update
+status:
+ resource:
+ name: subnetpool-update
+ prefixes:
+ - 192.168.10.0/24
+ minPrefixLength: 8
+ maxPrefixLength: 32
+ conditions:
+ - type: Available
+ status: "True"
+ reason: Success
+ - type: Progressing
+ status: "False"
+ reason: Success
diff --git a/internal/controllers/subnetpool/tests/subnetpool-update/00-minimal-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-update/00-minimal-resource.yaml
new file mode 100644
index 000000000..a808a54e5
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-update/00-minimal-resource.yaml
@@ -0,0 +1,15 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-update
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ prefixes:
+ - 192.168.10.0/24
+ minPrefixLength: 8
+ maxPrefixLength: 32
diff --git a/internal/controllers/subnetpool/tests/subnetpool-update/00-secret.yaml b/internal/controllers/subnetpool/tests/subnetpool-update/00-secret.yaml
new file mode 100644
index 000000000..045711ee7
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-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/subnetpool/tests/subnetpool-update/01-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-update/01-assert.yaml
new file mode 100644
index 000000000..cd1dcd5f1
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-update/01-assert.yaml
@@ -0,0 +1,21 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-update
+status:
+ resource:
+ name: subnetpool-update-updated
+ description: subnetpool-update-updated
+ prefixes:
+ - 10.0.0.0/16
+ - 192.168.10.0/24
+ minPrefixLength: 7
+ maxPrefixLength: 30
+ conditions:
+ - type: Available
+ status: "True"
+ reason: Success
+ - type: Progressing
+ status: "False"
+ reason: Success
diff --git a/internal/controllers/subnetpool/tests/subnetpool-update/01-updated-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-update/01-updated-resource.yaml
new file mode 100644
index 000000000..964cd5518
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-update/01-updated-resource.yaml
@@ -0,0 +1,16 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-update
+spec:
+ resource:
+ name: subnetpool-update-updated
+ description: subnetpool-update-updated
+ prefixes:
+ - 10.0.0.0/16
+ - 192.168.10.0/24
+ minPrefixLength: 7
+ maxPrefixLength: 30
+
+
diff --git a/internal/controllers/subnetpool/tests/subnetpool-update/02-assert.yaml b/internal/controllers/subnetpool/tests/subnetpool-update/02-assert.yaml
new file mode 100644
index 000000000..51d6d0768
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-update/02-assert.yaml
@@ -0,0 +1,31 @@
+---
+apiVersion: kuttl.dev/v1beta1
+kind: TestAssert
+resourceRefs:
+ - apiVersion: openstack.k-orc.cloud/v1alpha1
+ kind: SubnetPool
+ name: subnetpool-update
+ ref: subnetpool
+assertAll:
+ - celExpr: "!has(subnetpool.status.resource.description)"
+ - celExpr: "!has(subnetpool.status.resource.addressScopeID)"
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-update
+status:
+ resource:
+ name: subnetpool-update
+ prefixes:
+ - 10.0.0.0/16
+ - 192.168.10.0/24
+ minPrefixLength: 8
+ maxPrefixLength: 32
+ conditions:
+ - type: Available
+ status: "True"
+ reason: Success
+ - type: Progressing
+ status: "False"
+ reason: Success
diff --git a/internal/controllers/subnetpool/tests/subnetpool-update/02-reverted-resource.yaml b/internal/controllers/subnetpool/tests/subnetpool-update/02-reverted-resource.yaml
new file mode 100644
index 000000000..f555eaeca
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-update/02-reverted-resource.yaml
@@ -0,0 +1,9 @@
+# NOTE: kuttl only does patch updates, which means we can't delete a field.
+# We have to use a kubectl apply command instead.
+# NOTE: prefixes must be a superset of the previous value because OpenStack
+# does not allow removing existing prefixes from a subnet pool.
+apiVersion: kuttl.dev/v1beta1
+kind: TestStep
+commands:
+ - command: kubectl replace -f 02-reverted-subnetpool.yaml
+ namespaced: true
diff --git a/internal/controllers/subnetpool/tests/subnetpool-update/02-reverted-subnetpool.yaml b/internal/controllers/subnetpool/tests/subnetpool-update/02-reverted-subnetpool.yaml
new file mode 100644
index 000000000..c1f0226a7
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-update/02-reverted-subnetpool.yaml
@@ -0,0 +1,19 @@
+---
+apiVersion: openstack.k-orc.cloud/v1alpha1
+kind: SubnetPool
+metadata:
+ name: subnetpool-update
+spec:
+ cloudCredentialsRef:
+ cloudName: openstack
+ secretName: openstack-clouds
+ managementPolicy: managed
+ resource:
+ # prefixes must be a superset of the previous value because
+ # OpenStack does not allow removing existing prefixes from a
+ # subnet pool. Thus, using a separated file to revert changes.
+ prefixes:
+ - 10.0.0.0/16
+ - 192.168.10.0/24
+ minPrefixLength: 8
+ maxPrefixLength: 32
diff --git a/internal/controllers/subnetpool/tests/subnetpool-update/README.md b/internal/controllers/subnetpool/tests/subnetpool-update/README.md
new file mode 100644
index 000000000..6a9909325
--- /dev/null
+++ b/internal/controllers/subnetpool/tests/subnetpool-update/README.md
@@ -0,0 +1,17 @@
+# Update SubnetPool
+
+## Step 00
+
+Create a SubnetPool 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/controllers/subnetpool/zz_generated.adapter.go b/internal/controllers/subnetpool/zz_generated.adapter.go
new file mode 100644
index 000000000..31912efdf
--- /dev/null
+++ b/internal/controllers/subnetpool/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 subnetpool
+
+import (
+ 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.SubnetPool
+ orcObjectListT = orcv1alpha1.SubnetPoolList
+ resourceSpecT = orcv1alpha1.SubnetPoolResourceSpec
+ filterT = orcv1alpha1.SubnetPoolFilter
+)
+
+// Derived types
+type (
+ orcObjectPT = *orcObjectT
+ adapterI = interfaces.APIObjectAdapter[orcObjectPT, resourceSpecT, filterT]
+ adapterT = subnetpoolAdapter
+)
+
+type subnetpoolAdapter struct {
+ *orcv1alpha1.SubnetPool
+}
+
+var _ adapterI = &adapterT{}
+
+func (f adapterT) GetObject() orcObjectPT {
+ return f.SubnetPool
+}
+
+func (f adapterT) GetManagementPolicy() orcv1alpha1.ManagementPolicy {
+ return f.Spec.ManagementPolicy
+}
+
+func (f adapterT) GetManagedOptions() *orcv1alpha1.ManagedOptions {
+ return f.Spec.ManagedOptions
+}
+
+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
+}
+
+// getResourceName returns the name of the OpenStack resource we should use.
+// This method is not implemented as part of APIObjectAdapter as it is intended
+// to be used by resource actuators, which don't use the adapter.
+func getResourceName(orcObject orcObjectPT) string {
+ if orcObject.Spec.Resource.Name != nil {
+ return string(*orcObject.Spec.Resource.Name)
+ }
+ return orcObject.Name
+}
diff --git a/internal/controllers/subnetpool/zz_generated.controller.go b/internal/controllers/subnetpool/zz_generated.controller.go
new file mode 100644
index 000000000..fb70e1b8f
--- /dev/null
+++ b/internal/controllers/subnetpool/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 subnetpool
+
+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..5125ce45f 100644
--- a/internal/osclients/mock/doc.go
+++ b/internal/osclients/mock/doc.go
@@ -65,6 +65,9 @@ import (
//go:generate mockgen -package mock -destination=sharenetwork.go -source=../sharenetwork.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock ShareNetworkClient
//go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt sharenetwork.go > _sharenetwork.go && mv _sharenetwork.go sharenetwork.go"
+//go:generate mockgen -package mock -destination=subnetpool.go -source=../subnetpool.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock SubnetPoolClient
+//go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt subnetpool.go > _subnetpool.go && mv _subnetpool.go subnetpool.go"
+
//go:generate mockgen -package mock -destination=user.go -source=../user.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock UserClient
//go:generate /usr/bin/env bash -c "cat ../../../hack/boilerplate.go.txt user.go > _user.go && mv _user.go user.go"
diff --git a/internal/osclients/mock/subnetpool.go b/internal/osclients/mock/subnetpool.go
new file mode 100644
index 000000000..f6c687c72
--- /dev/null
+++ b/internal/osclients/mock/subnetpool.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: ../subnetpool.go
+//
+// Generated by this command:
+//
+// mockgen -package mock -destination=subnetpool.go -source=../subnetpool.go github.com/k-orc/openstack-resource-controller/internal/osclients/mock SubnetPoolClient
+//
+
+// Package mock is a generated GoMock package.
+package mock
+
+import (
+ context "context"
+ iter "iter"
+ reflect "reflect"
+
+ subnetpools "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/subnetpools"
+ gomock "go.uber.org/mock/gomock"
+)
+
+// MockSubnetPoolClient is a mock of SubnetPoolClient interface.
+type MockSubnetPoolClient struct {
+ ctrl *gomock.Controller
+ recorder *MockSubnetPoolClientMockRecorder
+ isgomock struct{}
+}
+
+// MockSubnetPoolClientMockRecorder is the mock recorder for MockSubnetPoolClient.
+type MockSubnetPoolClientMockRecorder struct {
+ mock *MockSubnetPoolClient
+}
+
+// NewMockSubnetPoolClient creates a new mock instance.
+func NewMockSubnetPoolClient(ctrl *gomock.Controller) *MockSubnetPoolClient {
+ mock := &MockSubnetPoolClient{ctrl: ctrl}
+ mock.recorder = &MockSubnetPoolClientMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockSubnetPoolClient) EXPECT() *MockSubnetPoolClientMockRecorder {
+ return m.recorder
+}
+
+// CreateSubnetPool mocks base method.
+func (m *MockSubnetPoolClient) CreateSubnetPool(ctx context.Context, opts subnetpools.CreateOptsBuilder) (*subnetpools.SubnetPool, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "CreateSubnetPool", ctx, opts)
+ ret0, _ := ret[0].(*subnetpools.SubnetPool)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// CreateSubnetPool indicates an expected call of CreateSubnetPool.
+func (mr *MockSubnetPoolClientMockRecorder) CreateSubnetPool(ctx, opts any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSubnetPool", reflect.TypeOf((*MockSubnetPoolClient)(nil).CreateSubnetPool), ctx, opts)
+}
+
+// DeleteSubnetPool mocks base method.
+func (m *MockSubnetPoolClient) DeleteSubnetPool(ctx context.Context, resourceID string) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "DeleteSubnetPool", ctx, resourceID)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// DeleteSubnetPool indicates an expected call of DeleteSubnetPool.
+func (mr *MockSubnetPoolClientMockRecorder) DeleteSubnetPool(ctx, resourceID any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSubnetPool", reflect.TypeOf((*MockSubnetPoolClient)(nil).DeleteSubnetPool), ctx, resourceID)
+}
+
+// GetSubnetPool mocks base method.
+func (m *MockSubnetPoolClient) GetSubnetPool(ctx context.Context, resourceID string) (*subnetpools.SubnetPool, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetSubnetPool", ctx, resourceID)
+ ret0, _ := ret[0].(*subnetpools.SubnetPool)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetSubnetPool indicates an expected call of GetSubnetPool.
+func (mr *MockSubnetPoolClientMockRecorder) GetSubnetPool(ctx, resourceID any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnetPool", reflect.TypeOf((*MockSubnetPoolClient)(nil).GetSubnetPool), ctx, resourceID)
+}
+
+// ListSubnetPools mocks base method.
+func (m *MockSubnetPoolClient) ListSubnetPools(ctx context.Context, listOpts subnetpools.ListOptsBuilder) iter.Seq2[*subnetpools.SubnetPool, error] {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "ListSubnetPools", ctx, listOpts)
+ ret0, _ := ret[0].(iter.Seq2[*subnetpools.SubnetPool, error])
+ return ret0
+}
+
+// ListSubnetPools indicates an expected call of ListSubnetPools.
+func (mr *MockSubnetPoolClientMockRecorder) ListSubnetPools(ctx, listOpts any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSubnetPools", reflect.TypeOf((*MockSubnetPoolClient)(nil).ListSubnetPools), ctx, listOpts)
+}
+
+// UpdateSubnetPool mocks base method.
+func (m *MockSubnetPoolClient) UpdateSubnetPool(ctx context.Context, id string, opts subnetpools.UpdateOptsBuilder) (*subnetpools.SubnetPool, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "UpdateSubnetPool", ctx, id, opts)
+ ret0, _ := ret[0].(*subnetpools.SubnetPool)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// UpdateSubnetPool indicates an expected call of UpdateSubnetPool.
+func (mr *MockSubnetPoolClientMockRecorder) UpdateSubnetPool(ctx, id, opts any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateSubnetPool", reflect.TypeOf((*MockSubnetPoolClient)(nil).UpdateSubnetPool), ctx, id, opts)
+}
diff --git a/internal/osclients/subnetpool.go b/internal/osclients/subnetpool.go
new file mode 100644
index 000000000..601aa622b
--- /dev/null
+++ b/internal/osclients/subnetpool.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/networking/v2/extensions/subnetpools"
+ "github.com/gophercloud/utils/v2/openstack/clientconfig"
+)
+
+type SubnetPoolClient interface {
+ ListSubnetPools(ctx context.Context, listOpts subnetpools.ListOptsBuilder) iter.Seq2[*subnetpools.SubnetPool, error]
+ CreateSubnetPool(ctx context.Context, opts subnetpools.CreateOptsBuilder) (*subnetpools.SubnetPool, error)
+ DeleteSubnetPool(ctx context.Context, resourceID string) error
+ GetSubnetPool(ctx context.Context, resourceID string) (*subnetpools.SubnetPool, error)
+ UpdateSubnetPool(ctx context.Context, id string, opts subnetpools.UpdateOptsBuilder) (*subnetpools.SubnetPool, error)
+}
+
+type subnetpoolClient struct{ client *gophercloud.ServiceClient }
+
+// NewSubnetPoolClient returns a new OpenStack client.
+func NewSubnetPoolClient(providerClient *gophercloud.ProviderClient, providerClientOpts *clientconfig.ClientOpts) (SubnetPoolClient, error) {
+ client, err := openstack.NewNetworkV2(providerClient, gophercloud.EndpointOpts{
+ Region: providerClientOpts.RegionName,
+ Availability: clientconfig.GetEndpointType(providerClientOpts.EndpointType),
+ })
+
+ if err != nil {
+ return nil, fmt.Errorf("failed to create subnetpool service client: %v", err)
+ }
+
+ return &subnetpoolClient{client}, nil
+}
+
+func (c subnetpoolClient) ListSubnetPools(ctx context.Context, listOpts subnetpools.ListOptsBuilder) iter.Seq2[*subnetpools.SubnetPool, error] {
+ pager := subnetpools.List(c.client, listOpts)
+ return func(yield func(*subnetpools.SubnetPool, error) bool) {
+ _ = pager.EachPage(ctx, yieldPage(subnetpools.ExtractSubnetPools, yield))
+ }
+}
+
+func (c subnetpoolClient) CreateSubnetPool(ctx context.Context, opts subnetpools.CreateOptsBuilder) (*subnetpools.SubnetPool, error) {
+ return subnetpools.Create(ctx, c.client, opts).Extract()
+}
+
+func (c subnetpoolClient) DeleteSubnetPool(ctx context.Context, resourceID string) error {
+ return subnetpools.Delete(ctx, c.client, resourceID).ExtractErr()
+}
+
+func (c subnetpoolClient) GetSubnetPool(ctx context.Context, resourceID string) (*subnetpools.SubnetPool, error) {
+ return subnetpools.Get(ctx, c.client, resourceID).Extract()
+}
+
+func (c subnetpoolClient) UpdateSubnetPool(ctx context.Context, id string, opts subnetpools.UpdateOptsBuilder) (*subnetpools.SubnetPool, error) {
+ return subnetpools.Update(ctx, c.client, id, opts).Extract()
+}
+
+type subnetpoolErrorClient struct{ error }
+
+// NewSubnetPoolErrorClient returns a SubnetPoolClient in which every method returns the given error.
+func NewSubnetPoolErrorClient(e error) SubnetPoolClient {
+ return subnetpoolErrorClient{e}
+}
+
+func (e subnetpoolErrorClient) ListSubnetPools(_ context.Context, _ subnetpools.ListOptsBuilder) iter.Seq2[*subnetpools.SubnetPool, error] {
+ return func(yield func(*subnetpools.SubnetPool, error) bool) {
+ yield(nil, e.error)
+ }
+}
+
+func (e subnetpoolErrorClient) CreateSubnetPool(_ context.Context, _ subnetpools.CreateOptsBuilder) (*subnetpools.SubnetPool, error) {
+ return nil, e.error
+}
+
+func (e subnetpoolErrorClient) DeleteSubnetPool(_ context.Context, _ string) error {
+ return e.error
+}
+
+func (e subnetpoolErrorClient) GetSubnetPool(_ context.Context, _ string) (*subnetpools.SubnetPool, error) {
+ return nil, e.error
+}
+
+func (e subnetpoolErrorClient) UpdateSubnetPool(_ context.Context, _ string, _ subnetpools.UpdateOptsBuilder) (*subnetpools.SubnetPool, error) {
+ return nil, e.error
+}
diff --git a/internal/scope/mock.go b/internal/scope/mock.go
index e57e4da58..8c4441e47 100644
--- a/internal/scope/mock.go
+++ b/internal/scope/mock.go
@@ -47,6 +47,7 @@ type MockScopeFactory struct {
RoleClient *mock.MockRoleClient
RoleAssignmentClient *mock.MockRoleAssignmentClient
ServiceClient *mock.MockServiceClient
+ SubnetPoolClient *mock.MockSubnetPoolClient
UserClient *mock.MockUserClient
VolumeClient *mock.MockVolumeClient
VolumeTypeClient *mock.MockVolumeTypeClient
@@ -69,6 +70,7 @@ func NewMockScopeFactory(mockCtrl *gomock.Controller) *MockScopeFactory {
roleClient := mock.NewMockRoleClient(mockCtrl)
roleassignmentClient := mock.NewMockRoleAssignmentClient(mockCtrl)
serviceClient := mock.NewMockServiceClient(mockCtrl)
+ subnetPoolClient := mock.NewMockSubnetPoolClient(mockCtrl)
userClient := mock.NewMockUserClient(mockCtrl)
sharenetworkClient := mock.NewMockShareNetworkClient(mockCtrl)
volumeClient := mock.NewMockVolumeClient(mockCtrl)
@@ -89,6 +91,7 @@ func NewMockScopeFactory(mockCtrl *gomock.Controller) *MockScopeFactory {
RoleAssignmentClient: roleassignmentClient,
ServiceClient: serviceClient,
ShareNetworkClient: sharenetworkClient,
+ SubnetPoolClient: subnetPoolClient,
UserClient: userClient,
VolumeClient: volumeClient,
VolumeTypeClient: volumetypeClient,
@@ -150,6 +153,10 @@ func (f *MockScopeFactory) NewShareNetworkClient() (osclients.ShareNetworkClient
return f.ShareNetworkClient, nil
}
+func (f *MockScopeFactory) NewSubnetPoolClient() (osclients.SubnetPoolClient, error) {
+ return f.SubnetPoolClient, nil
+}
+
func (f *MockScopeFactory) NewKeyPairClient() (osclients.KeyPairClient, error) {
return f.KeyPairClient, nil
}
diff --git a/internal/scope/provider.go b/internal/scope/provider.go
index f1207bd6c..17a46d2da 100644
--- a/internal/scope/provider.go
+++ b/internal/scope/provider.go
@@ -181,6 +181,10 @@ func (s *providerScope) NewServiceClient() (clients.ServiceClient, error) {
return clients.NewServiceClient(s.providerClient, s.providerClientOpts)
}
+func (s *providerScope) NewSubnetPoolClient() (clients.SubnetPoolClient, error) {
+ return clients.NewSubnetPoolClient(s.providerClient, s.providerClientOpts)
+}
+
func (s *providerScope) NewEndpointClient() (clients.EndpointClient, error) {
return clients.NewEndpointClient(s.providerClient, s.providerClientOpts)
}
diff --git a/internal/scope/scope.go b/internal/scope/scope.go
index 4f093fe9a..be6946a34 100644
--- a/internal/scope/scope.go
+++ b/internal/scope/scope.go
@@ -62,6 +62,7 @@ type Scope interface {
NewRoleAssignmentClient() (osclients.RoleAssignmentClient, error)
NewServiceClient() (osclients.ServiceClient, error)
NewShareNetworkClient() (osclients.ShareNetworkClient, error)
+ NewSubnetPoolClient() (osclients.SubnetPoolClient, error)
NewUserClient() (osclients.UserClient, error)
NewVolumeClient() (osclients.VolumeClient, error)
NewVolumeTypeClient() (osclients.VolumeTypeClient, error)
diff --git a/kuttl-test.yaml b/kuttl-test.yaml
index 90fc98dde..16fda5d2e 100644
--- a/kuttl-test.yaml
+++ b/kuttl-test.yaml
@@ -24,6 +24,7 @@ testDirs:
- ./internal/controllers/service/tests/
- ./internal/controllers/sharenetwork/tests/
- ./internal/controllers/subnet/tests/
+- ./internal/controllers/subnetpool/tests/
- ./internal/controllers/trunk/tests/
- ./internal/controllers/user/tests/
- ./internal/controllers/volume/tests/
diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetpool.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpool.go
new file mode 100644
index 000000000..dbd410292
--- /dev/null
+++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpool.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"
+)
+
+// SubnetPoolApplyConfiguration represents a declarative configuration of the SubnetPool type for use
+// with apply.
+type SubnetPoolApplyConfiguration struct {
+ v1.TypeMetaApplyConfiguration `json:",inline"`
+ *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"`
+ Spec *SubnetPoolSpecApplyConfiguration `json:"spec,omitempty"`
+ Status *SubnetPoolStatusApplyConfiguration `json:"status,omitempty"`
+}
+
+// SubnetPool constructs a declarative configuration of the SubnetPool type for use with
+// apply.
+func SubnetPool(name, namespace string) *SubnetPoolApplyConfiguration {
+ b := &SubnetPoolApplyConfiguration{}
+ b.WithName(name)
+ b.WithNamespace(namespace)
+ b.WithKind("SubnetPool")
+ b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1")
+ return b
+}
+
+// ExtractSubnetPool extracts the applied configuration owned by fieldManager from
+// subnetPool. If no managedFields are found in subnetPool for fieldManager, a
+// SubnetPoolApplyConfiguration 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.
+// subnetPool must be a unmodified SubnetPool API object that was retrieved from the Kubernetes API.
+// ExtractSubnetPool 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 ExtractSubnetPool(subnetPool *apiv1alpha1.SubnetPool, fieldManager string) (*SubnetPoolApplyConfiguration, error) {
+ return extractSubnetPool(subnetPool, fieldManager, "")
+}
+
+// ExtractSubnetPoolStatus is the same as ExtractSubnetPool except
+// that it extracts the status subresource applied configuration.
+// Experimental!
+func ExtractSubnetPoolStatus(subnetPool *apiv1alpha1.SubnetPool, fieldManager string) (*SubnetPoolApplyConfiguration, error) {
+ return extractSubnetPool(subnetPool, fieldManager, "status")
+}
+
+func extractSubnetPool(subnetPool *apiv1alpha1.SubnetPool, fieldManager string, subresource string) (*SubnetPoolApplyConfiguration, error) {
+ b := &SubnetPoolApplyConfiguration{}
+ err := managedfields.ExtractInto(subnetPool, internal.Parser().Type("com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetPool"), fieldManager, b, subresource)
+ if err != nil {
+ return nil, err
+ }
+ b.WithName(subnetPool.Name)
+ b.WithNamespace(subnetPool.Namespace)
+
+ b.WithKind("SubnetPool")
+ b.WithAPIVersion("openstack.k-orc.cloud/v1alpha1")
+ return b, nil
+}
+func (b SubnetPoolApplyConfiguration) 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 *SubnetPoolApplyConfiguration) WithKind(value string) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithAPIVersion(value string) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithName(value string) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithGenerateName(value string) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithNamespace(value string) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithUID(value types.UID) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithResourceVersion(value string) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithGeneration(value int64) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithCreationTimestamp(value metav1.Time) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithLabels(entries map[string]string) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithAnnotations(entries map[string]string) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithFinalizers(values ...string) *SubnetPoolApplyConfiguration {
+ b.ensureObjectMetaApplyConfigurationExists()
+ for i := range values {
+ b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i])
+ }
+ return b
+}
+
+func (b *SubnetPoolApplyConfiguration) 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 *SubnetPoolApplyConfiguration) WithSpec(value *SubnetPoolSpecApplyConfiguration) *SubnetPoolApplyConfiguration {
+ 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 *SubnetPoolApplyConfiguration) WithStatus(value *SubnetPoolStatusApplyConfiguration) *SubnetPoolApplyConfiguration {
+ b.Status = value
+ return b
+}
+
+// GetKind retrieves the value of the Kind field in the declarative configuration.
+func (b *SubnetPoolApplyConfiguration) GetKind() *string {
+ return b.TypeMetaApplyConfiguration.Kind
+}
+
+// GetAPIVersion retrieves the value of the APIVersion field in the declarative configuration.
+func (b *SubnetPoolApplyConfiguration) GetAPIVersion() *string {
+ return b.TypeMetaApplyConfiguration.APIVersion
+}
+
+// GetName retrieves the value of the Name field in the declarative configuration.
+func (b *SubnetPoolApplyConfiguration) GetName() *string {
+ b.ensureObjectMetaApplyConfigurationExists()
+ return b.ObjectMetaApplyConfiguration.Name
+}
+
+// GetNamespace retrieves the value of the Namespace field in the declarative configuration.
+func (b *SubnetPoolApplyConfiguration) GetNamespace() *string {
+ b.ensureObjectMetaApplyConfigurationExists()
+ return b.ObjectMetaApplyConfiguration.Namespace
+}
diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolfilter.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolfilter.go
new file mode 100644
index 000000000..82cb28a46
--- /dev/null
+++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolfilter.go
@@ -0,0 +1,174 @@
+/*
+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"
+)
+
+// SubnetPoolFilterApplyConfiguration represents a declarative configuration of the SubnetPoolFilter type for use
+// with apply.
+type SubnetPoolFilterApplyConfiguration struct {
+ Name *apiv1alpha1.OpenStackName `json:"name,omitempty"`
+ Description *apiv1alpha1.NeutronDescription `json:"description,omitempty"`
+ ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"`
+ AddressScopeRef *apiv1alpha1.KubernetesNameRef `json:"addressScopeRef,omitempty"`
+ MinPrefixLength *int32 `json:"minPrefixLength,omitempty"`
+ MaxPrefixLength *int32 `json:"maxPrefixLength,omitempty"`
+ IPVersion *apiv1alpha1.IPVersion `json:"ipVersion,omitempty"`
+ Shared *bool `json:"shared,omitempty"`
+ DefaultPrefixLength *int32 `json:"defaultPrefixLength,omitempty"`
+ IsDefault *bool `json:"isDefault,omitempty"`
+ RevisionNumber *int64 `json:"revisionNumber,omitempty"`
+ FilterByNeutronTagsApplyConfiguration `json:",inline"`
+}
+
+// SubnetPoolFilterApplyConfiguration constructs a declarative configuration of the SubnetPoolFilter type for use with
+// apply.
+func SubnetPoolFilter() *SubnetPoolFilterApplyConfiguration {
+ return &SubnetPoolFilterApplyConfiguration{}
+}
+
+// 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 *SubnetPoolFilterApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *SubnetPoolFilterApplyConfiguration {
+ 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 *SubnetPoolFilterApplyConfiguration) WithDescription(value apiv1alpha1.NeutronDescription) *SubnetPoolFilterApplyConfiguration {
+ b.Description = &value
+ return b
+}
+
+// WithProjectRef sets the ProjectRef 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 ProjectRef field is set to the value of the last call.
+func (b *SubnetPoolFilterApplyConfiguration) WithProjectRef(value apiv1alpha1.KubernetesNameRef) *SubnetPoolFilterApplyConfiguration {
+ b.ProjectRef = &value
+ return b
+}
+
+// WithAddressScopeRef sets the AddressScopeRef 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 AddressScopeRef field is set to the value of the last call.
+func (b *SubnetPoolFilterApplyConfiguration) WithAddressScopeRef(value apiv1alpha1.KubernetesNameRef) *SubnetPoolFilterApplyConfiguration {
+ b.AddressScopeRef = &value
+ return b
+}
+
+// WithMinPrefixLength sets the MinPrefixLength 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 MinPrefixLength field is set to the value of the last call.
+func (b *SubnetPoolFilterApplyConfiguration) WithMinPrefixLength(value int32) *SubnetPoolFilterApplyConfiguration {
+ b.MinPrefixLength = &value
+ return b
+}
+
+// WithMaxPrefixLength sets the MaxPrefixLength 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 MaxPrefixLength field is set to the value of the last call.
+func (b *SubnetPoolFilterApplyConfiguration) WithMaxPrefixLength(value int32) *SubnetPoolFilterApplyConfiguration {
+ b.MaxPrefixLength = &value
+ return b
+}
+
+// WithIPVersion sets the IPVersion 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 IPVersion field is set to the value of the last call.
+func (b *SubnetPoolFilterApplyConfiguration) WithIPVersion(value apiv1alpha1.IPVersion) *SubnetPoolFilterApplyConfiguration {
+ b.IPVersion = &value
+ return b
+}
+
+// WithShared sets the Shared 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 Shared field is set to the value of the last call.
+func (b *SubnetPoolFilterApplyConfiguration) WithShared(value bool) *SubnetPoolFilterApplyConfiguration {
+ b.Shared = &value
+ return b
+}
+
+// WithDefaultPrefixLength sets the DefaultPrefixLength 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 DefaultPrefixLength field is set to the value of the last call.
+func (b *SubnetPoolFilterApplyConfiguration) WithDefaultPrefixLength(value int32) *SubnetPoolFilterApplyConfiguration {
+ b.DefaultPrefixLength = &value
+ return b
+}
+
+// WithIsDefault sets the IsDefault 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 IsDefault field is set to the value of the last call.
+func (b *SubnetPoolFilterApplyConfiguration) WithIsDefault(value bool) *SubnetPoolFilterApplyConfiguration {
+ b.IsDefault = &value
+ return b
+}
+
+// WithRevisionNumber sets the RevisionNumber 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 RevisionNumber field is set to the value of the last call.
+func (b *SubnetPoolFilterApplyConfiguration) WithRevisionNumber(value int64) *SubnetPoolFilterApplyConfiguration {
+ b.RevisionNumber = &value
+ return b
+}
+
+// WithTags adds the given value to the Tags 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 Tags field.
+func (b *SubnetPoolFilterApplyConfiguration) WithTags(values ...apiv1alpha1.NeutronTag) *SubnetPoolFilterApplyConfiguration {
+ for i := range values {
+ b.FilterByNeutronTagsApplyConfiguration.Tags = append(b.FilterByNeutronTagsApplyConfiguration.Tags, values[i])
+ }
+ return b
+}
+
+// WithTagsAny adds the given value to the TagsAny 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 TagsAny field.
+func (b *SubnetPoolFilterApplyConfiguration) WithTagsAny(values ...apiv1alpha1.NeutronTag) *SubnetPoolFilterApplyConfiguration {
+ for i := range values {
+ b.FilterByNeutronTagsApplyConfiguration.TagsAny = append(b.FilterByNeutronTagsApplyConfiguration.TagsAny, values[i])
+ }
+ return b
+}
+
+// WithNotTags adds the given value to the NotTags 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 NotTags field.
+func (b *SubnetPoolFilterApplyConfiguration) WithNotTags(values ...apiv1alpha1.NeutronTag) *SubnetPoolFilterApplyConfiguration {
+ for i := range values {
+ b.FilterByNeutronTagsApplyConfiguration.NotTags = append(b.FilterByNeutronTagsApplyConfiguration.NotTags, values[i])
+ }
+ return b
+}
+
+// WithNotTagsAny adds the given value to the NotTagsAny 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 NotTagsAny field.
+func (b *SubnetPoolFilterApplyConfiguration) WithNotTagsAny(values ...apiv1alpha1.NeutronTag) *SubnetPoolFilterApplyConfiguration {
+ for i := range values {
+ b.FilterByNeutronTagsApplyConfiguration.NotTagsAny = append(b.FilterByNeutronTagsApplyConfiguration.NotTagsAny, values[i])
+ }
+ return b
+}
diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolimport.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolimport.go
new file mode 100644
index 000000000..6af1f0ba1
--- /dev/null
+++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolimport.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
+
+// SubnetPoolImportApplyConfiguration represents a declarative configuration of the SubnetPoolImport type for use
+// with apply.
+type SubnetPoolImportApplyConfiguration struct {
+ ID *string `json:"id,omitempty"`
+ Filter *SubnetPoolFilterApplyConfiguration `json:"filter,omitempty"`
+}
+
+// SubnetPoolImportApplyConfiguration constructs a declarative configuration of the SubnetPoolImport type for use with
+// apply.
+func SubnetPoolImport() *SubnetPoolImportApplyConfiguration {
+ return &SubnetPoolImportApplyConfiguration{}
+}
+
+// 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 *SubnetPoolImportApplyConfiguration) WithID(value string) *SubnetPoolImportApplyConfiguration {
+ 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 *SubnetPoolImportApplyConfiguration) WithFilter(value *SubnetPoolFilterApplyConfiguration) *SubnetPoolImportApplyConfiguration {
+ b.Filter = value
+ return b
+}
diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolresourcespec.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolresourcespec.go
new file mode 100644
index 000000000..cadbdfea6
--- /dev/null
+++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolresourcespec.go
@@ -0,0 +1,126 @@
+/*
+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"
+)
+
+// SubnetPoolResourceSpecApplyConfiguration represents a declarative configuration of the SubnetPoolResourceSpec type for use
+// with apply.
+type SubnetPoolResourceSpecApplyConfiguration struct {
+ Name *apiv1alpha1.OpenStackName `json:"name,omitempty"`
+ Description *string `json:"description,omitempty"`
+ ProjectRef *apiv1alpha1.KubernetesNameRef `json:"projectRef,omitempty"`
+ AddressScopeRef *apiv1alpha1.KubernetesNameRef `json:"addressScopeRef,omitempty"`
+ Prefixes []apiv1alpha1.CIDR `json:"prefixes,omitempty"`
+ MinPrefixLength *int32 `json:"minPrefixLength,omitempty"`
+ MaxPrefixLength *int32 `json:"maxPrefixLength,omitempty"`
+ Shared *bool `json:"shared,omitempty"`
+ DefaultPrefixLength *int32 `json:"defaultPrefixLength,omitempty"`
+ IsDefault *bool `json:"isDefault,omitempty"`
+}
+
+// SubnetPoolResourceSpecApplyConfiguration constructs a declarative configuration of the SubnetPoolResourceSpec type for use with
+// apply.
+func SubnetPoolResourceSpec() *SubnetPoolResourceSpecApplyConfiguration {
+ return &SubnetPoolResourceSpecApplyConfiguration{}
+}
+
+// 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 *SubnetPoolResourceSpecApplyConfiguration) WithName(value apiv1alpha1.OpenStackName) *SubnetPoolResourceSpecApplyConfiguration {
+ 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 *SubnetPoolResourceSpecApplyConfiguration) WithDescription(value string) *SubnetPoolResourceSpecApplyConfiguration {
+ b.Description = &value
+ return b
+}
+
+// WithProjectRef sets the ProjectRef 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 ProjectRef field is set to the value of the last call.
+func (b *SubnetPoolResourceSpecApplyConfiguration) WithProjectRef(value apiv1alpha1.KubernetesNameRef) *SubnetPoolResourceSpecApplyConfiguration {
+ b.ProjectRef = &value
+ return b
+}
+
+// WithAddressScopeRef sets the AddressScopeRef 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 AddressScopeRef field is set to the value of the last call.
+func (b *SubnetPoolResourceSpecApplyConfiguration) WithAddressScopeRef(value apiv1alpha1.KubernetesNameRef) *SubnetPoolResourceSpecApplyConfiguration {
+ b.AddressScopeRef = &value
+ return b
+}
+
+// WithPrefixes adds the given value to the Prefixes 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 Prefixes field.
+func (b *SubnetPoolResourceSpecApplyConfiguration) WithPrefixes(values ...apiv1alpha1.CIDR) *SubnetPoolResourceSpecApplyConfiguration {
+ for i := range values {
+ b.Prefixes = append(b.Prefixes, values[i])
+ }
+ return b
+}
+
+// WithMinPrefixLength sets the MinPrefixLength 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 MinPrefixLength field is set to the value of the last call.
+func (b *SubnetPoolResourceSpecApplyConfiguration) WithMinPrefixLength(value int32) *SubnetPoolResourceSpecApplyConfiguration {
+ b.MinPrefixLength = &value
+ return b
+}
+
+// WithMaxPrefixLength sets the MaxPrefixLength 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 MaxPrefixLength field is set to the value of the last call.
+func (b *SubnetPoolResourceSpecApplyConfiguration) WithMaxPrefixLength(value int32) *SubnetPoolResourceSpecApplyConfiguration {
+ b.MaxPrefixLength = &value
+ return b
+}
+
+// WithShared sets the Shared 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 Shared field is set to the value of the last call.
+func (b *SubnetPoolResourceSpecApplyConfiguration) WithShared(value bool) *SubnetPoolResourceSpecApplyConfiguration {
+ b.Shared = &value
+ return b
+}
+
+// WithDefaultPrefixLength sets the DefaultPrefixLength 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 DefaultPrefixLength field is set to the value of the last call.
+func (b *SubnetPoolResourceSpecApplyConfiguration) WithDefaultPrefixLength(value int32) *SubnetPoolResourceSpecApplyConfiguration {
+ b.DefaultPrefixLength = &value
+ return b
+}
+
+// WithIsDefault sets the IsDefault 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 IsDefault field is set to the value of the last call.
+func (b *SubnetPoolResourceSpecApplyConfiguration) WithIsDefault(value bool) *SubnetPoolResourceSpecApplyConfiguration {
+ b.IsDefault = &value
+ return b
+}
diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolresourcestatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolresourcestatus.go
new file mode 100644
index 000000000..de6cf0803
--- /dev/null
+++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolresourcestatus.go
@@ -0,0 +1,180 @@
+/*
+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 (
+ v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// SubnetPoolResourceStatusApplyConfiguration represents a declarative configuration of the SubnetPoolResourceStatus type for use
+// with apply.
+type SubnetPoolResourceStatusApplyConfiguration struct {
+ Name *string `json:"name,omitempty"`
+ Description *string `json:"description,omitempty"`
+ ProjectID *string `json:"projectID,omitempty"`
+ AddressScopeID *string `json:"addressScopeID,omitempty"`
+ Prefixes []string `json:"prefixes,omitempty"`
+ DefaultQuota *int32 `json:"defaultQuota,omitempty"`
+ MinPrefixLength *int32 `json:"minPrefixLength,omitempty"`
+ MaxPrefixLength *int32 `json:"maxPrefixLength,omitempty"`
+ DefaultPrefixLength *int32 `json:"defaultPrefixLength,omitempty"`
+ IsDefault *bool `json:"isDefault,omitempty"`
+ Shared *bool `json:"shared,omitempty"`
+ IPVersion *int32 `json:"ipVersion,omitempty"`
+ Tags []string `json:"tags,omitempty"`
+ NeutronStatusMetadataApplyConfiguration `json:",inline"`
+}
+
+// SubnetPoolResourceStatusApplyConfiguration constructs a declarative configuration of the SubnetPoolResourceStatus type for use with
+// apply.
+func SubnetPoolResourceStatus() *SubnetPoolResourceStatusApplyConfiguration {
+ return &SubnetPoolResourceStatusApplyConfiguration{}
+}
+
+// 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 *SubnetPoolResourceStatusApplyConfiguration) WithName(value string) *SubnetPoolResourceStatusApplyConfiguration {
+ 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 *SubnetPoolResourceStatusApplyConfiguration) WithDescription(value string) *SubnetPoolResourceStatusApplyConfiguration {
+ b.Description = &value
+ return b
+}
+
+// WithProjectID sets the ProjectID 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 ProjectID field is set to the value of the last call.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithProjectID(value string) *SubnetPoolResourceStatusApplyConfiguration {
+ b.ProjectID = &value
+ return b
+}
+
+// WithAddressScopeID sets the AddressScopeID 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 AddressScopeID field is set to the value of the last call.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithAddressScopeID(value string) *SubnetPoolResourceStatusApplyConfiguration {
+ b.AddressScopeID = &value
+ return b
+}
+
+// WithPrefixes adds the given value to the Prefixes 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 Prefixes field.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithPrefixes(values ...string) *SubnetPoolResourceStatusApplyConfiguration {
+ for i := range values {
+ b.Prefixes = append(b.Prefixes, values[i])
+ }
+ return b
+}
+
+// WithDefaultQuota sets the DefaultQuota 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 DefaultQuota field is set to the value of the last call.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithDefaultQuota(value int32) *SubnetPoolResourceStatusApplyConfiguration {
+ b.DefaultQuota = &value
+ return b
+}
+
+// WithMinPrefixLength sets the MinPrefixLength 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 MinPrefixLength field is set to the value of the last call.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithMinPrefixLength(value int32) *SubnetPoolResourceStatusApplyConfiguration {
+ b.MinPrefixLength = &value
+ return b
+}
+
+// WithMaxPrefixLength sets the MaxPrefixLength 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 MaxPrefixLength field is set to the value of the last call.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithMaxPrefixLength(value int32) *SubnetPoolResourceStatusApplyConfiguration {
+ b.MaxPrefixLength = &value
+ return b
+}
+
+// WithDefaultPrefixLength sets the DefaultPrefixLength 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 DefaultPrefixLength field is set to the value of the last call.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithDefaultPrefixLength(value int32) *SubnetPoolResourceStatusApplyConfiguration {
+ b.DefaultPrefixLength = &value
+ return b
+}
+
+// WithIsDefault sets the IsDefault 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 IsDefault field is set to the value of the last call.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithIsDefault(value bool) *SubnetPoolResourceStatusApplyConfiguration {
+ b.IsDefault = &value
+ return b
+}
+
+// WithShared sets the Shared 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 Shared field is set to the value of the last call.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithShared(value bool) *SubnetPoolResourceStatusApplyConfiguration {
+ b.Shared = &value
+ return b
+}
+
+// WithIPVersion sets the IPVersion 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 IPVersion field is set to the value of the last call.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithIPVersion(value int32) *SubnetPoolResourceStatusApplyConfiguration {
+ b.IPVersion = &value
+ return b
+}
+
+// WithTags adds the given value to the Tags 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 Tags field.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithTags(values ...string) *SubnetPoolResourceStatusApplyConfiguration {
+ for i := range values {
+ b.Tags = append(b.Tags, values[i])
+ }
+ return b
+}
+
+// WithCreatedAt sets the CreatedAt 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 CreatedAt field is set to the value of the last call.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithCreatedAt(value v1.Time) *SubnetPoolResourceStatusApplyConfiguration {
+ b.NeutronStatusMetadataApplyConfiguration.CreatedAt = &value
+ return b
+}
+
+// WithUpdatedAt sets the UpdatedAt 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 UpdatedAt field is set to the value of the last call.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithUpdatedAt(value v1.Time) *SubnetPoolResourceStatusApplyConfiguration {
+ b.NeutronStatusMetadataApplyConfiguration.UpdatedAt = &value
+ return b
+}
+
+// WithRevisionNumber sets the RevisionNumber 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 RevisionNumber field is set to the value of the last call.
+func (b *SubnetPoolResourceStatusApplyConfiguration) WithRevisionNumber(value int64) *SubnetPoolResourceStatusApplyConfiguration {
+ b.NeutronStatusMetadataApplyConfiguration.RevisionNumber = &value
+ return b
+}
diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolspec.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolspec.go
new file mode 100644
index 000000000..2ec290331
--- /dev/null
+++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolspec.go
@@ -0,0 +1,79 @@
+/*
+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"
+)
+
+// SubnetPoolSpecApplyConfiguration represents a declarative configuration of the SubnetPoolSpec type for use
+// with apply.
+type SubnetPoolSpecApplyConfiguration struct {
+ Import *SubnetPoolImportApplyConfiguration `json:"import,omitempty"`
+ Resource *SubnetPoolResourceSpecApplyConfiguration `json:"resource,omitempty"`
+ ManagementPolicy *apiv1alpha1.ManagementPolicy `json:"managementPolicy,omitempty"`
+ ManagedOptions *ManagedOptionsApplyConfiguration `json:"managedOptions,omitempty"`
+ CloudCredentialsRef *CloudCredentialsReferenceApplyConfiguration `json:"cloudCredentialsRef,omitempty"`
+}
+
+// SubnetPoolSpecApplyConfiguration constructs a declarative configuration of the SubnetPoolSpec type for use with
+// apply.
+func SubnetPoolSpec() *SubnetPoolSpecApplyConfiguration {
+ return &SubnetPoolSpecApplyConfiguration{}
+}
+
+// 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 *SubnetPoolSpecApplyConfiguration) WithImport(value *SubnetPoolImportApplyConfiguration) *SubnetPoolSpecApplyConfiguration {
+ 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 *SubnetPoolSpecApplyConfiguration) WithResource(value *SubnetPoolResourceSpecApplyConfiguration) *SubnetPoolSpecApplyConfiguration {
+ 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 *SubnetPoolSpecApplyConfiguration) WithManagementPolicy(value apiv1alpha1.ManagementPolicy) *SubnetPoolSpecApplyConfiguration {
+ 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 *SubnetPoolSpecApplyConfiguration) WithManagedOptions(value *ManagedOptionsApplyConfiguration) *SubnetPoolSpecApplyConfiguration {
+ b.ManagedOptions = 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 *SubnetPoolSpecApplyConfiguration) WithCloudCredentialsRef(value *CloudCredentialsReferenceApplyConfiguration) *SubnetPoolSpecApplyConfiguration {
+ b.CloudCredentialsRef = value
+ return b
+}
diff --git a/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolstatus.go b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolstatus.go
new file mode 100644
index 000000000..ba58679ca
--- /dev/null
+++ b/pkg/clients/applyconfiguration/api/v1alpha1/subnetpoolstatus.go
@@ -0,0 +1,66 @@
+/*
+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 (
+ v1 "k8s.io/client-go/applyconfigurations/meta/v1"
+)
+
+// SubnetPoolStatusApplyConfiguration represents a declarative configuration of the SubnetPoolStatus type for use
+// with apply.
+type SubnetPoolStatusApplyConfiguration struct {
+ Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"`
+ ID *string `json:"id,omitempty"`
+ Resource *SubnetPoolResourceStatusApplyConfiguration `json:"resource,omitempty"`
+}
+
+// SubnetPoolStatusApplyConfiguration constructs a declarative configuration of the SubnetPoolStatus type for use with
+// apply.
+func SubnetPoolStatus() *SubnetPoolStatusApplyConfiguration {
+ return &SubnetPoolStatusApplyConfiguration{}
+}
+
+// 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 *SubnetPoolStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *SubnetPoolStatusApplyConfiguration {
+ 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 *SubnetPoolStatusApplyConfiguration) WithID(value string) *SubnetPoolStatusApplyConfiguration {
+ 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 *SubnetPoolStatusApplyConfiguration) WithResource(value *SubnetPoolResourceStatusApplyConfiguration) *SubnetPoolStatusApplyConfiguration {
+ b.Resource = value
+ return b
+}
diff --git a/pkg/clients/applyconfiguration/internal/internal.go b/pkg/clients/applyconfiguration/internal/internal.go
index 8c0bc8003..e53f25975 100644
--- a/pkg/clients/applyconfiguration/internal/internal.go
+++ b/pkg/clients/applyconfiguration/internal/internal.go
@@ -3513,6 +3513,225 @@ var schemaYAML = typed.YAMLObject(`types:
- name: id
type:
scalar: string
+- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetPool
+ 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.SubnetPoolSpec
+ default: {}
+ - name: status
+ type:
+ namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetPoolStatus
+ default: {}
+- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetPoolFilter
+ map:
+ fields:
+ - name: addressScopeRef
+ type:
+ scalar: string
+ - name: defaultPrefixLength
+ type:
+ scalar: numeric
+ - name: description
+ type:
+ scalar: string
+ - name: ipVersion
+ type:
+ scalar: numeric
+ - name: isDefault
+ type:
+ scalar: boolean
+ - name: maxPrefixLength
+ type:
+ scalar: numeric
+ - name: minPrefixLength
+ type:
+ scalar: numeric
+ - name: name
+ type:
+ scalar: string
+ - name: notTags
+ type:
+ list:
+ elementType:
+ scalar: string
+ elementRelationship: associative
+ - name: notTagsAny
+ type:
+ list:
+ elementType:
+ scalar: string
+ elementRelationship: associative
+ - name: projectRef
+ type:
+ scalar: string
+ - name: revisionNumber
+ type:
+ scalar: numeric
+ - name: shared
+ type:
+ scalar: boolean
+ - name: tags
+ type:
+ list:
+ elementType:
+ scalar: string
+ elementRelationship: associative
+ - name: tagsAny
+ type:
+ list:
+ elementType:
+ scalar: string
+ elementRelationship: associative
+- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetPoolImport
+ map:
+ fields:
+ - name: filter
+ type:
+ namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetPoolFilter
+ - name: id
+ type:
+ scalar: string
+- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetPoolResourceSpec
+ map:
+ fields:
+ - name: addressScopeRef
+ type:
+ scalar: string
+ - name: defaultPrefixLength
+ type:
+ scalar: numeric
+ - name: description
+ type:
+ scalar: string
+ - name: isDefault
+ type:
+ scalar: boolean
+ - name: maxPrefixLength
+ type:
+ scalar: numeric
+ - name: minPrefixLength
+ type:
+ scalar: numeric
+ - name: name
+ type:
+ scalar: string
+ - name: prefixes
+ type:
+ list:
+ elementType:
+ scalar: string
+ elementRelationship: associative
+ - name: projectRef
+ type:
+ scalar: string
+ - name: shared
+ type:
+ scalar: boolean
+- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetPoolResourceStatus
+ map:
+ fields:
+ - name: addressScopeID
+ type:
+ scalar: string
+ - name: createdAt
+ type:
+ namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time
+ - name: defaultPrefixLength
+ type:
+ scalar: numeric
+ - name: defaultQuota
+ type:
+ scalar: numeric
+ - name: description
+ type:
+ scalar: string
+ - name: ipVersion
+ type:
+ scalar: numeric
+ - name: isDefault
+ type:
+ scalar: boolean
+ - name: maxPrefixLength
+ type:
+ scalar: numeric
+ - name: minPrefixLength
+ type:
+ scalar: numeric
+ - name: name
+ type:
+ scalar: string
+ - name: prefixes
+ type:
+ list:
+ elementType:
+ scalar: string
+ elementRelationship: atomic
+ - name: projectID
+ type:
+ scalar: string
+ - name: revisionNumber
+ type:
+ scalar: numeric
+ - name: shared
+ type:
+ scalar: boolean
+ - name: tags
+ type:
+ list:
+ elementType:
+ scalar: string
+ elementRelationship: atomic
+ - name: updatedAt
+ type:
+ namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Time
+- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetPoolSpec
+ 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.SubnetPoolImport
+ - 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.SubnetPoolResourceSpec
+- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetPoolStatus
+ 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: resource
+ type:
+ namedType: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetPoolResourceStatus
- name: com.github.k-orc.openstack-resource-controller.v2.api.v1alpha1.SubnetResourceSpec
map:
fields:
diff --git a/pkg/clients/applyconfiguration/utils.go b/pkg/clients/applyconfiguration/utils.go
index 22e66aea0..58078d6bd 100644
--- a/pkg/clients/applyconfiguration/utils.go
+++ b/pkg/clients/applyconfiguration/utils.go
@@ -420,6 +420,20 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
return &apiv1alpha1.SubnetGatewayApplyConfiguration{}
case v1alpha1.SchemeGroupVersion.WithKind("SubnetImport"):
return &apiv1alpha1.SubnetImportApplyConfiguration{}
+ case v1alpha1.SchemeGroupVersion.WithKind("SubnetPool"):
+ return &apiv1alpha1.SubnetPoolApplyConfiguration{}
+ case v1alpha1.SchemeGroupVersion.WithKind("SubnetPoolFilter"):
+ return &apiv1alpha1.SubnetPoolFilterApplyConfiguration{}
+ case v1alpha1.SchemeGroupVersion.WithKind("SubnetPoolImport"):
+ return &apiv1alpha1.SubnetPoolImportApplyConfiguration{}
+ case v1alpha1.SchemeGroupVersion.WithKind("SubnetPoolResourceSpec"):
+ return &apiv1alpha1.SubnetPoolResourceSpecApplyConfiguration{}
+ case v1alpha1.SchemeGroupVersion.WithKind("SubnetPoolResourceStatus"):
+ return &apiv1alpha1.SubnetPoolResourceStatusApplyConfiguration{}
+ case v1alpha1.SchemeGroupVersion.WithKind("SubnetPoolSpec"):
+ return &apiv1alpha1.SubnetPoolSpecApplyConfiguration{}
+ case v1alpha1.SchemeGroupVersion.WithKind("SubnetPoolStatus"):
+ return &apiv1alpha1.SubnetPoolStatusApplyConfiguration{}
case v1alpha1.SchemeGroupVersion.WithKind("SubnetResourceSpec"):
return &apiv1alpha1.SubnetResourceSpecApplyConfiguration{}
case v1alpha1.SchemeGroupVersion.WithKind("SubnetResourceStatus"):
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..b22e1e2fd 100644
--- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/api_client.go
+++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/api_client.go
@@ -50,6 +50,7 @@ type OpenstackV1alpha1Interface interface {
ServicesGetter
ShareNetworksGetter
SubnetsGetter
+ SubnetPoolsGetter
TrunksGetter
UsersGetter
VolumesGetter
@@ -149,6 +150,10 @@ func (c *OpenstackV1alpha1Client) Subnets(namespace string) SubnetInterface {
return newSubnets(c, namespace)
}
+func (c *OpenstackV1alpha1Client) SubnetPools(namespace string) SubnetPoolInterface {
+ return newSubnetPools(c, namespace)
+}
+
func (c *OpenstackV1alpha1Client) Trunks(namespace string) TrunkInterface {
return newTrunks(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..8343fcfba 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
@@ -116,6 +116,10 @@ func (c *FakeOpenstackV1alpha1) Subnets(namespace string) v1alpha1.SubnetInterfa
return newFakeSubnets(c, namespace)
}
+func (c *FakeOpenstackV1alpha1) SubnetPools(namespace string) v1alpha1.SubnetPoolInterface {
+ return newFakeSubnetPools(c, namespace)
+}
+
func (c *FakeOpenstackV1alpha1) Trunks(namespace string) v1alpha1.TrunkInterface {
return newFakeTrunks(c, namespace)
}
diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_subnetpool.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_subnetpool.go
new file mode 100644
index 000000000..6c9a0629e
--- /dev/null
+++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/fake/fake_subnetpool.go
@@ -0,0 +1,51 @@
+/*
+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"
+)
+
+// fakeSubnetPools implements SubnetPoolInterface
+type fakeSubnetPools struct {
+ *gentype.FakeClientWithListAndApply[*v1alpha1.SubnetPool, *v1alpha1.SubnetPoolList, *apiv1alpha1.SubnetPoolApplyConfiguration]
+ Fake *FakeOpenstackV1alpha1
+}
+
+func newFakeSubnetPools(fake *FakeOpenstackV1alpha1, namespace string) typedapiv1alpha1.SubnetPoolInterface {
+ return &fakeSubnetPools{
+ gentype.NewFakeClientWithListAndApply[*v1alpha1.SubnetPool, *v1alpha1.SubnetPoolList, *apiv1alpha1.SubnetPoolApplyConfiguration](
+ fake.Fake,
+ namespace,
+ v1alpha1.SchemeGroupVersion.WithResource("subnetpools"),
+ v1alpha1.SchemeGroupVersion.WithKind("SubnetPool"),
+ func() *v1alpha1.SubnetPool { return &v1alpha1.SubnetPool{} },
+ func() *v1alpha1.SubnetPoolList { return &v1alpha1.SubnetPoolList{} },
+ func(dst, src *v1alpha1.SubnetPoolList) { dst.ListMeta = src.ListMeta },
+ func(list *v1alpha1.SubnetPoolList) []*v1alpha1.SubnetPool { return gentype.ToPointerSlice(list.Items) },
+ func(list *v1alpha1.SubnetPoolList, items []*v1alpha1.SubnetPool) {
+ 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..0bb200231 100644
--- a/pkg/clients/clientset/clientset/typed/api/v1alpha1/generated_expansion.go
+++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/generated_expansion.go
@@ -62,6 +62,8 @@ type ShareNetworkExpansion interface{}
type SubnetExpansion interface{}
+type SubnetPoolExpansion interface{}
+
type TrunkExpansion interface{}
type UserExpansion interface{}
diff --git a/pkg/clients/clientset/clientset/typed/api/v1alpha1/subnetpool.go b/pkg/clients/clientset/clientset/typed/api/v1alpha1/subnetpool.go
new file mode 100644
index 000000000..36f102c55
--- /dev/null
+++ b/pkg/clients/clientset/clientset/typed/api/v1alpha1/subnetpool.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"
+)
+
+// SubnetPoolsGetter has a method to return a SubnetPoolInterface.
+// A group's client should implement this interface.
+type SubnetPoolsGetter interface {
+ SubnetPools(namespace string) SubnetPoolInterface
+}
+
+// SubnetPoolInterface has methods to work with SubnetPool resources.
+type SubnetPoolInterface interface {
+ Create(ctx context.Context, subnetPool *apiv1alpha1.SubnetPool, opts v1.CreateOptions) (*apiv1alpha1.SubnetPool, error)
+ Update(ctx context.Context, subnetPool *apiv1alpha1.SubnetPool, opts v1.UpdateOptions) (*apiv1alpha1.SubnetPool, error)
+ // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
+ UpdateStatus(ctx context.Context, subnetPool *apiv1alpha1.SubnetPool, opts v1.UpdateOptions) (*apiv1alpha1.SubnetPool, 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.SubnetPool, error)
+ List(ctx context.Context, opts v1.ListOptions) (*apiv1alpha1.SubnetPoolList, 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.SubnetPool, err error)
+ Apply(ctx context.Context, subnetPool *applyconfigurationapiv1alpha1.SubnetPoolApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.SubnetPool, err error)
+ // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
+ ApplyStatus(ctx context.Context, subnetPool *applyconfigurationapiv1alpha1.SubnetPoolApplyConfiguration, opts v1.ApplyOptions) (result *apiv1alpha1.SubnetPool, err error)
+ SubnetPoolExpansion
+}
+
+// subnetPools implements SubnetPoolInterface
+type subnetPools struct {
+ *gentype.ClientWithListAndApply[*apiv1alpha1.SubnetPool, *apiv1alpha1.SubnetPoolList, *applyconfigurationapiv1alpha1.SubnetPoolApplyConfiguration]
+}
+
+// newSubnetPools returns a SubnetPools
+func newSubnetPools(c *OpenstackV1alpha1Client, namespace string) *subnetPools {
+ return &subnetPools{
+ gentype.NewClientWithListAndApply[*apiv1alpha1.SubnetPool, *apiv1alpha1.SubnetPoolList, *applyconfigurationapiv1alpha1.SubnetPoolApplyConfiguration](
+ "subnetpools",
+ c.RESTClient(),
+ scheme.ParameterCodec,
+ namespace,
+ func() *apiv1alpha1.SubnetPool { return &apiv1alpha1.SubnetPool{} },
+ func() *apiv1alpha1.SubnetPoolList { return &apiv1alpha1.SubnetPoolList{} },
+ ),
+ }
+}
diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/interface.go b/pkg/clients/informers/externalversions/api/v1alpha1/interface.go
index 69d2bdeaf..8542cf6bb 100644
--- a/pkg/clients/informers/externalversions/api/v1alpha1/interface.go
+++ b/pkg/clients/informers/externalversions/api/v1alpha1/interface.go
@@ -68,6 +68,8 @@ type Interface interface {
ShareNetworks() ShareNetworkInformer
// Subnets returns a SubnetInformer.
Subnets() SubnetInformer
+ // SubnetPools returns a SubnetPoolInformer.
+ SubnetPools() SubnetPoolInformer
// Trunks returns a TrunkInformer.
Trunks() TrunkInformer
// Users returns a UserInformer.
@@ -199,6 +201,11 @@ func (v *version) Subnets() SubnetInformer {
return &subnetInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
+// SubnetPools returns a SubnetPoolInformer.
+func (v *version) SubnetPools() SubnetPoolInformer {
+ return &subnetPoolInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
+}
+
// Trunks returns a TrunkInformer.
func (v *version) Trunks() TrunkInformer {
return &trunkInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
diff --git a/pkg/clients/informers/externalversions/api/v1alpha1/subnetpool.go b/pkg/clients/informers/externalversions/api/v1alpha1/subnetpool.go
new file mode 100644
index 000000000..cf4f96556
--- /dev/null
+++ b/pkg/clients/informers/externalversions/api/v1alpha1/subnetpool.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"
+)
+
+// SubnetPoolInformer provides access to a shared informer and lister for
+// SubnetPools.
+type SubnetPoolInformer interface {
+ Informer() cache.SharedIndexInformer
+ Lister() apiv1alpha1.SubnetPoolLister
+}
+
+type subnetPoolInformer struct {
+ factory internalinterfaces.SharedInformerFactory
+ tweakListOptions internalinterfaces.TweakListOptionsFunc
+ namespace string
+}
+
+// NewSubnetPoolInformer constructs a new informer for SubnetPool 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 NewSubnetPoolInformer(client clientset.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
+ return NewFilteredSubnetPoolInformer(client, namespace, resyncPeriod, indexers, nil)
+}
+
+// NewFilteredSubnetPoolInformer constructs a new informer for SubnetPool 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 NewFilteredSubnetPoolInformer(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().SubnetPools(namespace).List(context.Background(), options)
+ },
+ WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
+ if tweakListOptions != nil {
+ tweakListOptions(&options)
+ }
+ return client.OpenstackV1alpha1().SubnetPools(namespace).Watch(context.Background(), options)
+ },
+ ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) {
+ if tweakListOptions != nil {
+ tweakListOptions(&options)
+ }
+ return client.OpenstackV1alpha1().SubnetPools(namespace).List(ctx, options)
+ },
+ WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) {
+ if tweakListOptions != nil {
+ tweakListOptions(&options)
+ }
+ return client.OpenstackV1alpha1().SubnetPools(namespace).Watch(ctx, options)
+ },
+ },
+ &v2apiv1alpha1.SubnetPool{},
+ resyncPeriod,
+ indexers,
+ )
+}
+
+func (f *subnetPoolInformer) defaultInformer(client clientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
+ return NewFilteredSubnetPoolInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+}
+
+func (f *subnetPoolInformer) Informer() cache.SharedIndexInformer {
+ return f.factory.InformerFor(&v2apiv1alpha1.SubnetPool{}, f.defaultInformer)
+}
+
+func (f *subnetPoolInformer) Lister() apiv1alpha1.SubnetPoolLister {
+ return apiv1alpha1.NewSubnetPoolLister(f.Informer().GetIndexer())
+}
diff --git a/pkg/clients/informers/externalversions/generic.go b/pkg/clients/informers/externalversions/generic.go
index f58420886..833e0c310 100644
--- a/pkg/clients/informers/externalversions/generic.go
+++ b/pkg/clients/informers/externalversions/generic.go
@@ -97,6 +97,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().ShareNetworks().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("subnets"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Subnets().Informer()}, nil
+ case v1alpha1.SchemeGroupVersion.WithResource("subnetpools"):
+ return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().SubnetPools().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("trunks"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Openstack().V1alpha1().Trunks().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("users"):
diff --git a/pkg/clients/listers/api/v1alpha1/expansion_generated.go b/pkg/clients/listers/api/v1alpha1/expansion_generated.go
index 76fec1603..59fb24f24 100644
--- a/pkg/clients/listers/api/v1alpha1/expansion_generated.go
+++ b/pkg/clients/listers/api/v1alpha1/expansion_generated.go
@@ -194,6 +194,14 @@ type SubnetListerExpansion interface{}
// SubnetNamespaceLister.
type SubnetNamespaceListerExpansion interface{}
+// SubnetPoolListerExpansion allows custom methods to be added to
+// SubnetPoolLister.
+type SubnetPoolListerExpansion interface{}
+
+// SubnetPoolNamespaceListerExpansion allows custom methods to be added to
+// SubnetPoolNamespaceLister.
+type SubnetPoolNamespaceListerExpansion interface{}
+
// TrunkListerExpansion allows custom methods to be added to
// TrunkLister.
type TrunkListerExpansion interface{}
diff --git a/pkg/clients/listers/api/v1alpha1/subnetpool.go b/pkg/clients/listers/api/v1alpha1/subnetpool.go
new file mode 100644
index 000000000..bd3b99f93
--- /dev/null
+++ b/pkg/clients/listers/api/v1alpha1/subnetpool.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"
+)
+
+// SubnetPoolLister helps list SubnetPools.
+// All objects returned here must be treated as read-only.
+type SubnetPoolLister interface {
+ // List lists all SubnetPools in the indexer.
+ // Objects returned here must be treated as read-only.
+ List(selector labels.Selector) (ret []*apiv1alpha1.SubnetPool, err error)
+ // SubnetPools returns an object that can list and get SubnetPools.
+ SubnetPools(namespace string) SubnetPoolNamespaceLister
+ SubnetPoolListerExpansion
+}
+
+// subnetPoolLister implements the SubnetPoolLister interface.
+type subnetPoolLister struct {
+ listers.ResourceIndexer[*apiv1alpha1.SubnetPool]
+}
+
+// NewSubnetPoolLister returns a new SubnetPoolLister.
+func NewSubnetPoolLister(indexer cache.Indexer) SubnetPoolLister {
+ return &subnetPoolLister{listers.New[*apiv1alpha1.SubnetPool](indexer, apiv1alpha1.Resource("subnetpool"))}
+}
+
+// SubnetPools returns an object that can list and get SubnetPools.
+func (s *subnetPoolLister) SubnetPools(namespace string) SubnetPoolNamespaceLister {
+ return subnetPoolNamespaceLister{listers.NewNamespaced[*apiv1alpha1.SubnetPool](s.ResourceIndexer, namespace)}
+}
+
+// SubnetPoolNamespaceLister helps list and get SubnetPools.
+// All objects returned here must be treated as read-only.
+type SubnetPoolNamespaceLister interface {
+ // List lists all SubnetPools in the indexer for a given namespace.
+ // Objects returned here must be treated as read-only.
+ List(selector labels.Selector) (ret []*apiv1alpha1.SubnetPool, err error)
+ // Get retrieves the SubnetPool from the indexer for a given namespace and name.
+ // Objects returned here must be treated as read-only.
+ Get(name string) (*apiv1alpha1.SubnetPool, error)
+ SubnetPoolNamespaceListerExpansion
+}
+
+// subnetPoolNamespaceLister implements the SubnetPoolNamespaceLister
+// interface.
+type subnetPoolNamespaceLister struct {
+ listers.ResourceIndexer[*apiv1alpha1.SubnetPool]
+}
diff --git a/test/apivalidations/subnetpool_test.go b/test/apivalidations/subnetpool_test.go
new file mode 100644
index 000000000..d20ebdf6b
--- /dev/null
+++ b/test/apivalidations/subnetpool_test.go
@@ -0,0 +1,132 @@
+/*
+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 (
+ subnetpoolName = "subnetpool"
+ subnetpoolID = "265c9e4f-0f5a-46e4-9f3f-fb8de25ae120"
+)
+
+func subnetpoolStub(namespace *corev1.Namespace) *orcv1alpha1.SubnetPool {
+ obj := &orcv1alpha1.SubnetPool{}
+ obj.Name = subnetpoolName
+ obj.Namespace = namespace.Name
+ return obj
+}
+
+func testSubnetPoolResource() *applyconfigv1alpha1.SubnetPoolResourceSpecApplyConfiguration {
+ return applyconfigv1alpha1.SubnetPoolResourceSpec()
+}
+
+func baseSubnetPoolPatch(obj client.Object) *applyconfigv1alpha1.SubnetPoolApplyConfiguration {
+ return applyconfigv1alpha1.SubnetPool(obj.GetName(), obj.GetNamespace()).
+ WithSpec(applyconfigv1alpha1.SubnetPoolSpec().
+ WithCloudCredentialsRef(testCredentials()))
+}
+
+func testSubnetPoolImport() *applyconfigv1alpha1.SubnetPoolImportApplyConfiguration {
+ return applyconfigv1alpha1.SubnetPoolImport().WithID(subnetpoolID)
+}
+
+var _ = Describe("ORC SubnetPool API validations", func() {
+ var namespace *corev1.Namespace
+ BeforeEach(func() {
+ namespace = createNamespace()
+ })
+
+ runManagementPolicyTests(func() *corev1.Namespace { return namespace }, managementPolicyTestArgs[*applyconfigv1alpha1.SubnetPoolApplyConfiguration]{
+ createObject: func(ns *corev1.Namespace) client.Object { return subnetpoolStub(ns) },
+ basePatch: func(obj client.Object) *applyconfigv1alpha1.SubnetPoolApplyConfiguration {
+ return baseSubnetPoolPatch(obj)
+ },
+ applyResource: func(p *applyconfigv1alpha1.SubnetPoolApplyConfiguration) {
+ p.Spec.WithResource(testSubnetPoolResource())
+ },
+ applyImport: func(p *applyconfigv1alpha1.SubnetPoolApplyConfiguration) {
+ p.Spec.WithImport(testSubnetPoolImport())
+ },
+ applyEmptyImport: func(p *applyconfigv1alpha1.SubnetPoolApplyConfiguration) {
+ p.Spec.WithImport(applyconfigv1alpha1.SubnetPoolImport())
+ },
+ applyEmptyFilter: func(p *applyconfigv1alpha1.SubnetPoolApplyConfiguration) {
+ p.Spec.WithImport(applyconfigv1alpha1.SubnetPoolImport().WithFilter(applyconfigv1alpha1.SubnetPoolFilter()))
+ },
+ applyValidFilter: func(p *applyconfigv1alpha1.SubnetPoolApplyConfiguration) {
+ p.Spec.WithImport(applyconfigv1alpha1.SubnetPoolImport().WithFilter(applyconfigv1alpha1.SubnetPoolFilter().WithName("foo")))
+ },
+ applyManaged: func(p *applyconfigv1alpha1.SubnetPoolApplyConfiguration) {
+ p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyManaged)
+ },
+ applyUnmanaged: func(p *applyconfigv1alpha1.SubnetPoolApplyConfiguration) {
+ p.Spec.WithManagementPolicy(orcv1alpha1.ManagementPolicyUnmanaged)
+ },
+ applyManagedOptions: func(p *applyconfigv1alpha1.SubnetPoolApplyConfiguration) {
+ p.Spec.WithManagedOptions(applyconfigv1alpha1.ManagedOptions().WithOnDelete(orcv1alpha1.OnDeleteDetach))
+ },
+ getManagementPolicy: func(obj client.Object) orcv1alpha1.ManagementPolicy {
+ return obj.(*orcv1alpha1.SubnetPool).Spec.ManagementPolicy
+ },
+ getOnDelete: func(obj client.Object) orcv1alpha1.OnDelete {
+ return obj.(*orcv1alpha1.SubnetPool).Spec.ManagedOptions.OnDelete
+ },
+ })
+
+ It("should have immutable projectRef", func(ctx context.Context) {
+ obj := subnetpoolStub(namespace)
+ patch := baseSubnetPoolPatch(obj)
+ patch.Spec.WithResource(testSubnetPoolResource().
+ WithProjectRef("project-a"))
+ Expect(applyObj(ctx, obj, patch)).To(Succeed())
+
+ patch.Spec.WithResource(testSubnetPoolResource().
+ WithProjectRef("project-b"))
+ Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("projectRef is immutable")))
+ })
+
+ It("should have immutable addressScopeRef", func(ctx context.Context) {
+ obj := subnetpoolStub(namespace)
+ patch := baseSubnetPoolPatch(obj)
+ patch.Spec.WithResource(testSubnetPoolResource().
+ WithAddressScopeRef("addressscope-a"))
+ Expect(applyObj(ctx, obj, patch)).To(Succeed())
+
+ patch.Spec.WithResource(testSubnetPoolResource().
+ WithAddressScopeRef("addressscope-b"))
+ Expect(applyObj(ctx, obj, patch)).To(MatchError(ContainSubstring("addressScopeRef 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 9209db468..43c78a9e4 100644
--- a/website/docs/crd-reference.md
+++ b/website/docs/crd-reference.md
@@ -32,6 +32,7 @@ Package v1alpha1 contains API Schema definitions for the openstack v1alpha1 API
- [Service](#service)
- [ShareNetwork](#sharenetwork)
- [Subnet](#subnet)
+- [SubnetPool](#subnetpool)
- [Trunk](#trunk)
- [User](#user)
- [Volume](#volume)
@@ -488,6 +489,7 @@ _Appears in:_
- [SecurityGroupRule](#securitygrouprule)
- [ServerSchedulerHints](#serverschedulerhints)
- [SubnetFilter](#subnetfilter)
+- [SubnetPoolResourceSpec](#subnetpoolresourcespec)
- [SubnetResourceSpec](#subnetresourcespec)
@@ -523,6 +525,7 @@ _Appears in:_
- [ServerSpec](#serverspec)
- [ServiceSpec](#servicespec)
- [ShareNetworkSpec](#sharenetworkspec)
+- [SubnetPoolSpec](#subnetpoolspec)
- [SubnetSpec](#subnetspec)
- [TrunkSpec](#trunkspec)
- [UserSpec](#userspec)
@@ -902,6 +905,7 @@ _Appears in:_
- [RouterFilter](#routerfilter)
- [SecurityGroupFilter](#securitygroupfilter)
- [SubnetFilter](#subnetfilter)
+- [SubnetPoolFilter](#subnetpoolfilter)
- [TrunkFilter](#trunkfilter)
| Field | Description | Default | Validation |
@@ -1505,6 +1509,7 @@ _Appears in:_
- [AddressScopeFilter](#addressscopefilter)
- [AddressScopeResourceSpec](#addressscoperesourcespec)
- [SubnetFilter](#subnetfilter)
+- [SubnetPoolFilter](#subnetpoolfilter)
- [SubnetResourceSpec](#subnetresourcespec)
@@ -2214,6 +2219,8 @@ _Appears in:_
- [ServerVolumeSpec](#servervolumespec)
- [ShareNetworkResourceSpec](#sharenetworkresourcespec)
- [SubnetFilter](#subnetfilter)
+- [SubnetPoolFilter](#subnetpoolfilter)
+- [SubnetPoolResourceSpec](#subnetpoolresourcespec)
- [SubnetResourceSpec](#subnetresourcespec)
- [TrunkFilter](#trunkfilter)
- [TrunkResourceSpec](#trunkresourcespec)
@@ -2284,6 +2291,7 @@ _Appears in:_
- [ServerSpec](#serverspec)
- [ServiceSpec](#servicespec)
- [ShareNetworkSpec](#sharenetworkspec)
+- [SubnetPoolSpec](#subnetpoolspec)
- [SubnetSpec](#subnetspec)
- [TrunkSpec](#trunkspec)
- [UserSpec](#userspec)
@@ -2325,6 +2333,7 @@ _Appears in:_
- [ServerSpec](#serverspec)
- [ServiceSpec](#servicespec)
- [ShareNetworkSpec](#sharenetworkspec)
+- [SubnetPoolSpec](#subnetpoolspec)
- [SubnetSpec](#subnetspec)
- [TrunkSpec](#trunkspec)
- [UserSpec](#userspec)
@@ -2519,6 +2528,7 @@ _Appears in:_
- [SecurityGroupResourceSpec](#securitygroupresourcespec)
- [SecurityGroupRule](#securitygrouprule)
- [SubnetFilter](#subnetfilter)
+- [SubnetPoolFilter](#subnetpoolfilter)
- [SubnetResourceSpec](#subnetresourcespec)
- [TrunkFilter](#trunkfilter)
- [TrunkResourceSpec](#trunkresourcespec)
@@ -2538,6 +2548,7 @@ _Appears in:_
- [NetworkResourceStatus](#networkresourcestatus)
- [PortResourceStatus](#portresourcestatus)
- [SecurityGroupResourceStatus](#securitygroupresourcestatus)
+- [SubnetPoolResourceStatus](#subnetpoolresourcestatus)
- [SubnetResourceStatus](#subnetresourcestatus)
- [TrunkResourceStatus](#trunkresourcestatus)
@@ -2572,6 +2583,7 @@ _Appears in:_
- [SecurityGroupFilter](#securitygroupfilter)
- [SecurityGroupResourceSpec](#securitygroupresourcespec)
- [SubnetFilter](#subnetfilter)
+- [SubnetPoolFilter](#subnetpoolfilter)
- [SubnetResourceSpec](#subnetresourcespec)
- [TrunkFilter](#trunkfilter)
- [TrunkResourceSpec](#trunkresourcespec)
@@ -2637,6 +2649,8 @@ _Appears in:_
- [ShareNetworkFilter](#sharenetworkfilter)
- [ShareNetworkResourceSpec](#sharenetworkresourcespec)
- [SubnetFilter](#subnetfilter)
+- [SubnetPoolFilter](#subnetpoolfilter)
+- [SubnetPoolResourceSpec](#subnetpoolresourcespec)
- [SubnetResourceSpec](#subnetresourcespec)
- [TrunkFilter](#trunkfilter)
- [TrunkResourceSpec](#trunkresourcespec)
@@ -4682,6 +4696,170 @@ _Appears in:_
| `filter` _[SubnetFilter](#subnetfilter)_ | 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: \{\}
|
+#### SubnetPool
+
+
+
+SubnetPool is the Schema for an ORC resource.
+
+
+
+
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `apiVersion` _string_ | `openstack.k-orc.cloud/v1alpha1` | | |
+| `kind` _string_ | `SubnetPool` | | |
+| `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` _[SubnetPoolSpec](#subnetpoolspec)_ | spec specifies the desired state of the resource. | | Required: \{\}
|
+| `status` _[SubnetPoolStatus](#subnetpoolstatus)_ | status defines the observed state of the resource. | | Optional: \{\}
|
+
+
+#### SubnetPoolFilter
+
+
+
+SubnetPoolFilter defines an existing resource by its properties
+
+_Validation:_
+- MinProperties: 1
+
+_Appears in:_
+- [SubnetPoolImport](#subnetpoolimport)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `name` _[OpenStackName](#openstackname)_ | name of the existing resource | | MaxLength: 255
MinLength: 1
Pattern: `^[^,]+$`
Optional: \{\}
|
+| `description` _[NeutronDescription](#neutrondescription)_ | description of the existing resource | | MaxLength: 255
MinLength: 1
Optional: \{\}
|
+| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
|
+| `addressScopeRef` _[KubernetesNameRef](#kubernetesnameref)_ | addressScopeRef is a reference to the ORC AddressScope which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
|
+| `minPrefixLength` _integer_ | minPrefixLength allows filtering the subnet pool list result by
the smallest prefix that can be allocated from a subnet pool. | | Optional: \{\}
|
+| `maxPrefixLength` _integer_ | maxPrefixLength allows filtering the subnet pool list result by
the maximum prefix size that can be allocated from the subnet
pool. | | Optional: \{\}
|
+| `ipVersion` _[IPVersion](#ipversion)_ | ipVersion is the IP protocol version. It can be either 4 or 6 | | Enum: [4 6]
Optional: \{\}
|
+| `shared` _boolean_ | shared allows filtering the list result based on whether the
resource is shared across all projects. This field is
admin-only. | | Optional: \{\}
|
+| `defaultPrefixLength` _integer_ | defaultPrefixLength allows filtering the subnet pool list
result by the size of the prefix to allocate when the cidr or
prefixlen attributes are omitted when you create the subnet. | | Optional: \{\}
|
+| `isDefault` _boolean_ | isDefault allows filtering the subnet pool list result based on
if it is a default pool or not. | | Optional: \{\}
|
+| `revisionNumber` _integer_ | revisionNumber allows filtering the list result by the revision
number of the resource. | | Optional: \{\}
|
+| `tags` _[NeutronTag](#neutrontag) array_ | tags is a list of tags to filter by. If specified, the resource must
have all of the tags specified to be included in the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
|
+| `tagsAny` _[NeutronTag](#neutrontag) array_ | tagsAny is a list of tags to filter by. If specified, the resource
must have at least one of the tags specified to be included in the
result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
|
+| `notTags` _[NeutronTag](#neutrontag) array_ | notTags is a list of tags to filter by. If specified, resources which
contain all of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
|
+| `notTagsAny` _[NeutronTag](#neutrontag) array_ | notTagsAny is a list of tags to filter by. If specified, resources
which contain any of the given tags will be excluded from the result. | | MaxItems: 64
MaxLength: 255
MinLength: 1
Optional: \{\}
|
+
+
+#### SubnetPoolImport
+
+
+
+SubnetPoolImport specifies an existing resource which will be imported instead of
+creating a new one
+
+_Validation:_
+- MaxProperties: 1
+- MinProperties: 1
+
+_Appears in:_
+- [SubnetPoolSpec](#subnetpoolspec)
+
+| 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` _[SubnetPoolFilter](#subnetpoolfilter)_ | 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: \{\}
|
+
+
+#### SubnetPoolResourceSpec
+
+
+
+SubnetPoolResourceSpec contains the desired state of the resource.
+
+
+
+_Appears in:_
+- [SubnetPoolSpec](#subnetpoolspec)
+
+| 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: \{\}
|
+| `projectRef` _[KubernetesNameRef](#kubernetesnameref)_ | projectRef is a reference to the ORC Project which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
|
+| `addressScopeRef` _[KubernetesNameRef](#kubernetesnameref)_ | addressScopeRef is a reference to the ORC AddressScope which this resource is associated with. | | MaxLength: 253
MinLength: 1
Optional: \{\}
|
+| `prefixes` _[CIDR](#cidr) array_ | prefixes is the list of subnet prefixes to assign to the subnet
pool. The API merges adjacent prefixes and treats them as a
single prefix. Each subnet prefix must be unique across all
subnet pools associated with address scope. | | Format: cidr
MaxItems: 64
MaxLength: 49
MinItems: 1
MinLength: 1
Optional: \{\}
Required: \{\}
|
+| `minPrefixLength` _integer_ | minPrefixLength is the smallest prefix that can be allocated
from a subnet pool. For IPv4 subnet pools, default is 8. For
IPv6 subnet pools, default is 64. | | Minimum: 1
Required: \{\}
|
+| `maxPrefixLength` _integer_ | maxPrefixLength is the maximum prefix size that can be allocated
from the subnet pool. For IPv4 subnet pools, default is 32. For
IPv6 subnet pools, default is 128. | | Minimum: 1
Required: \{\}
|
+| `shared` _boolean_ | shared indicates whether this resource is shared across all projects.
By default, it is false, and only administrative users can
change this value. | | Optional: \{\}
|
+| `defaultPrefixLength` _integer_ | defaultPrefixLength is the size of the prefix to allocate when
the cidr or prefixlen attributes are omitted when you create
the subnet. Default is MinPrefixLength. | | Optional: \{\}
|
+| `isDefault` _boolean_ | isDefault defines whether the subnetpool is default pool or
not. | | Optional: \{\}
|
+
+
+#### SubnetPoolResourceStatus
+
+
+
+SubnetPoolResourceStatus represents the observed state of the resource.
+
+
+
+_Appears in:_
+- [SubnetPoolStatus](#subnetpoolstatus)
+
+| 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: \{\}
|
+| `projectID` _string_ | projectID is the ID of the Project to which the resource is associated. | | MaxLength: 1024
Optional: \{\}
|
+| `addressScopeID` _string_ | addressScopeID is the ID of the AddressScope to which the resource is associated. | | MaxLength: 1024
Optional: \{\}
|
+| `prefixes` _string array_ | prefixes is a list of prefixes to assign to the SubnetPool. | | MaxItems: 1024
items:MaxLength: 64
Optional: \{\}
|
+| `defaultQuota` _integer_ | defaultQuota is a per-project quota on the prefix space that
can be allocated from the SubnetPool for project subnets. | | Optional: \{\}
|
+| `minPrefixLength` _integer_ | minPrefixLength is the smallest prefix that can be allocated
from a subnet pool. | | Optional: \{\}
|
+| `maxPrefixLength` _integer_ | maxPrefixLength is the maximum prefix size that can be
allocated from the subnet pool. | | Optional: \{\}
|
+| `defaultPrefixLength` _integer_ | defaultPrefixLength is the size of the prefix to allocate when
the cidr or prefixlen attributes are omitted when you create
the subnet. | | Optional: \{\}
|
+| `isDefault` _boolean_ | isDefault indicates whether the SubnetPool is the default pool
when creating subnets. | | Optional: \{\}
|
+| `shared` _boolean_ | shared indicates whether the SubnetPool is shared across all projects. | | Optional: \{\}
|
+| `ipVersion` _integer_ | ipVersion is the IP protocol version. It can be either 4 or 6 | | Optional: \{\}
|
+| `tags` _string array_ | tags is the list of tags on the resource. | | MaxItems: 64
items:MaxLength: 1024
Optional: \{\}
|
+| `createdAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | createdAt shows the date and time when the resource was created. The date and time stamp format is ISO 8601 | | Optional: \{\}
|
+| `updatedAt` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#time-v1-meta)_ | updatedAt shows the date and time when the resource was updated. The date and time stamp format is ISO 8601 | | Optional: \{\}
|
+| `revisionNumber` _integer_ | revisionNumber optionally set via extensions/standard-attr-revisions | | Optional: \{\}
|
+
+
+#### SubnetPoolSpec
+
+
+
+SubnetPoolSpec defines the desired state of an ORC object.
+
+
+
+_Appears in:_
+- [SubnetPool](#subnetpool)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `import` _[SubnetPoolImport](#subnetpoolimport)_ | import refers to an existing OpenStack resource which will be imported instead of
creating a new one. | | MaxProperties: 1
MinProperties: 1
Optional: \{\}
|
+| `resource` _[SubnetPoolResourceSpec](#subnetpoolresourcespec)_ | 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: \{\}
|
+| `cloudCredentialsRef` _[CloudCredentialsReference](#cloudcredentialsreference)_ | cloudCredentialsRef points to a secret containing OpenStack credentials | | Required: \{\}
|
+
+
+#### SubnetPoolStatus
+
+
+
+SubnetPoolStatus defines the observed state of an ORC resource.
+
+
+
+_Appears in:_
+- [SubnetPool](#subnetpool)
+
+| 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` _[SubnetPoolResourceStatus](#subnetpoolresourcestatus)_ | resource contains the observed state of the OpenStack resource. | | Optional: \{\}
|
+
+
#### SubnetResourceSpec