diff --git a/api/v1alpha7/openstackfloatingippool_webhook.go b/api/v1alpha7/openstackfloatingippool_webhook.go deleted file mode 100644 index 667f71f82c..0000000000 --- a/api/v1alpha7/openstackfloatingippool_webhook.go +++ /dev/null @@ -1,73 +0,0 @@ -/* -Copyright 2019 The Kubernetes 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 v1alpha7 - -import ( - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/webhook" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -// log is for logging in this package. -var openstackfloatingippoollog = logf.Log.WithName("openstackfloatingippool-resource") - -func (r *OpenStackFloatingIPPool) SetupWebhookWithManager(mgr ctrl.Manager) error { - return ctrl.NewWebhookManagedBy(mgr). - For(r). - Complete() -} - -//+kubebuilder:webhook:path=/mutate-infrastructure-cluster-x-k8s-io-v1alpha7-openstackfloatingippool,mutating=true,failurePolicy=fail,groups=infrastructure.cluster.x-k8s.io,resources=openstackfloatingippools,verbs=create;update,versions=v1alpha7,name=default.openstackfloatingippool.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1beta1 -//+kubebuilder:webhook:verbs=create;update,path=/validate-infrastructure-cluster-x-k8s-io-v1alpha7-openstackfloatingippool,mutating=false,failurePolicy=fail,groups=infrastructure.cluster.x-k8s.io,resources=openstackfloatingippools,versions=v1alpha7,name=validation.openstackfloatingippool.infrastructure.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1beta1 - -var ( - _ webhook.Defaulter = &OpenStackFloatingIPPool{} - _ webhook.Validator = &OpenStackFloatingIPPool{} -) - -// Default implements webhook.Defaulter so a webhook will be registered for the type. -func (r *OpenStackFloatingIPPool) Default() { - openstackfloatingippoollog.Info("default", "name", r.Name) -} - -// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. - -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type. -func (r *OpenStackFloatingIPPool) ValidateCreate() (admission.Warnings, error) { - openstackfloatingippoollog.Info("validate create", "name", r.Name) - - // TODO(user): fill in your validation logic upon object creation. - return nil, nil -} - -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type. -func (r *OpenStackFloatingIPPool) ValidateUpdate(_ runtime.Object) (admission.Warnings, error) { - openstackfloatingippoollog.Info("validate update", "name", r.Name) - - // TODO(user): fill in your validation logic upon object update. - return nil, nil -} - -// ValidateDelete implements webhook.Validator so a webhook will be registered for the type. -func (r *OpenStackFloatingIPPool) ValidateDelete() (admission.Warnings, error) { - openstackfloatingippoollog.Info("validate delete", "name", r.Name) - - // TODO(user): fill in your validation logic upon object deletion. - return nil, nil -} diff --git a/api/v1alpha7/zz_generated.deepcopy.go b/api/v1alpha7/zz_generated.deepcopy.go index 089a045290..daa1524d33 100644 --- a/api/v1alpha7/zz_generated.deepcopy.go +++ b/api/v1alpha7/zz_generated.deepcopy.go @@ -558,131 +558,6 @@ func (in *OpenStackClusterTemplateSpec) DeepCopy() *OpenStackClusterTemplateSpec return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OpenStackFloatingIPPool) DeepCopyInto(out *OpenStackFloatingIPPool) { - *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 OpenStackFloatingIPPool. -func (in *OpenStackFloatingIPPool) DeepCopy() *OpenStackFloatingIPPool { - if in == nil { - return nil - } - out := new(OpenStackFloatingIPPool) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *OpenStackFloatingIPPool) 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 *OpenStackFloatingIPPoolList) DeepCopyInto(out *OpenStackFloatingIPPoolList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]OpenStackFloatingIPPool, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackFloatingIPPoolList. -func (in *OpenStackFloatingIPPoolList) DeepCopy() *OpenStackFloatingIPPoolList { - if in == nil { - return nil - } - out := new(OpenStackFloatingIPPoolList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *OpenStackFloatingIPPoolList) 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 *OpenStackFloatingIPPoolSpec) DeepCopyInto(out *OpenStackFloatingIPPoolSpec) { - *out = *in - if in.PreAllocatedFloatingIPs != nil { - in, out := &in.PreAllocatedFloatingIPs, &out.PreAllocatedFloatingIPs - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.IdentityRef != nil { - in, out := &in.IdentityRef, &out.IdentityRef - *out = new(OpenStackIdentityReference) - **out = **in - } - out.FloatingIPNetwork = in.FloatingIPNetwork -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackFloatingIPPoolSpec. -func (in *OpenStackFloatingIPPoolSpec) DeepCopy() *OpenStackFloatingIPPoolSpec { - if in == nil { - return nil - } - out := new(OpenStackFloatingIPPoolSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OpenStackFloatingIPPoolStatus) DeepCopyInto(out *OpenStackFloatingIPPoolStatus) { - *out = *in - if in.ClaimedIPs != nil { - in, out := &in.ClaimedIPs, &out.ClaimedIPs - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.AvailableIPs != nil { - in, out := &in.AvailableIPs, &out.AvailableIPs - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.AllIPs != nil { - in, out := &in.AllIPs, &out.AllIPs - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.FailedIPs != nil { - in, out := &in.FailedIPs, &out.FailedIPs - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.FloatingIPNetwork != nil { - in, out := &in.FloatingIPNetwork, &out.FloatingIPNetwork - *out = new(NetworkStatus) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackFloatingIPPoolStatus. -func (in *OpenStackFloatingIPPoolStatus) DeepCopy() *OpenStackFloatingIPPoolStatus { - if in == nil { - return nil - } - out := new(OpenStackFloatingIPPoolStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenStackIdentityReference) DeepCopyInto(out *OpenStackIdentityReference) { *out = *in diff --git a/api/v1alpha7/openstackfloatingippool_types.go b/api/v1alpha8/openstackfloatingippool_types.go similarity index 98% rename from api/v1alpha7/openstackfloatingippool_types.go rename to api/v1alpha8/openstackfloatingippool_types.go index e062c06f18..ec2d04d514 100644 --- a/api/v1alpha7/openstackfloatingippool_types.go +++ b/api/v1alpha8/openstackfloatingippool_types.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha7 +package v1alpha8 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -50,6 +50,7 @@ type OpenStackFloatingIPPoolSpec struct { IdentityRef *OpenStackIdentityReference `json:"identityRef,omitempty"` // FloatingIPNetwork is the external network to use for floating ips, if there's only one external network it will be used by default + // +optional FloatingIPNetwork NetworkFilter `json:"floatingIPNetwork"` // The name of the cloud to use from the clouds secret @@ -86,6 +87,7 @@ type OpenStackFloatingIPPoolStatus struct { } //+kubebuilder:object:root=true +// +kubebuilder:storageversion //+kubebuilder:subresource:status // OpenStackFloatingIPPool is the Schema for the openstackfloatingippools API. diff --git a/api/v1alpha8/zz_generated.deepcopy.go b/api/v1alpha8/zz_generated.deepcopy.go index 3ded212691..8095e9c72a 100644 --- a/api/v1alpha8/zz_generated.deepcopy.go +++ b/api/v1alpha8/zz_generated.deepcopy.go @@ -558,6 +558,131 @@ func (in *OpenStackClusterTemplateSpec) DeepCopy() *OpenStackClusterTemplateSpec return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OpenStackFloatingIPPool) DeepCopyInto(out *OpenStackFloatingIPPool) { + *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 OpenStackFloatingIPPool. +func (in *OpenStackFloatingIPPool) DeepCopy() *OpenStackFloatingIPPool { + if in == nil { + return nil + } + out := new(OpenStackFloatingIPPool) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OpenStackFloatingIPPool) 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 *OpenStackFloatingIPPoolList) DeepCopyInto(out *OpenStackFloatingIPPoolList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]OpenStackFloatingIPPool, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackFloatingIPPoolList. +func (in *OpenStackFloatingIPPoolList) DeepCopy() *OpenStackFloatingIPPoolList { + if in == nil { + return nil + } + out := new(OpenStackFloatingIPPoolList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OpenStackFloatingIPPoolList) 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 *OpenStackFloatingIPPoolSpec) DeepCopyInto(out *OpenStackFloatingIPPoolSpec) { + *out = *in + if in.PreAllocatedFloatingIPs != nil { + in, out := &in.PreAllocatedFloatingIPs, &out.PreAllocatedFloatingIPs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.IdentityRef != nil { + in, out := &in.IdentityRef, &out.IdentityRef + *out = new(OpenStackIdentityReference) + **out = **in + } + out.FloatingIPNetwork = in.FloatingIPNetwork +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackFloatingIPPoolSpec. +func (in *OpenStackFloatingIPPoolSpec) DeepCopy() *OpenStackFloatingIPPoolSpec { + if in == nil { + return nil + } + out := new(OpenStackFloatingIPPoolSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OpenStackFloatingIPPoolStatus) DeepCopyInto(out *OpenStackFloatingIPPoolStatus) { + *out = *in + if in.ClaimedIPs != nil { + in, out := &in.ClaimedIPs, &out.ClaimedIPs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.AvailableIPs != nil { + in, out := &in.AvailableIPs, &out.AvailableIPs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.AllIPs != nil { + in, out := &in.AllIPs, &out.AllIPs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.FailedIPs != nil { + in, out := &in.FailedIPs, &out.FailedIPs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.FloatingIPNetwork != nil { + in, out := &in.FloatingIPNetwork, &out.FloatingIPNetwork + *out = new(NetworkStatus) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackFloatingIPPoolStatus. +func (in *OpenStackFloatingIPPoolStatus) DeepCopy() *OpenStackFloatingIPPoolStatus { + if in == nil { + return nil + } + out := new(OpenStackFloatingIPPoolStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenStackIdentityReference) DeepCopyInto(out *OpenStackIdentityReference) { *out = *in diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackfloatingippools.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackfloatingippools.yaml index fd17a14a46..c7f7864f42 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackfloatingippools.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackfloatingippools.yaml @@ -14,7 +14,7 @@ spec: singular: openstackfloatingippool scope: Namespaced versions: - - name: v1alpha7 + - name: v1alpha8 schema: openAPIV3Schema: description: OpenStackFloatingIPPool is the Schema for the openstackfloatingippools @@ -90,8 +90,6 @@ spec: - Retain - Delete type: string - required: - - floatingIPNetwork type: object status: description: OpenStackFloatingIPPoolStatus defines the observed state diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index ffe783563a..d65e84a9f2 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -121,31 +121,7 @@ webhooks: service: name: webhook-service namespace: system -<<<<<<< HEAD path: /validate-infrastructure-cluster-x-k8s-io-v1alpha8-openstackmachine -======= - path: /validate-infrastructure-cluster-x-k8s-io-v1alpha7-openstackfloatingippool - failurePolicy: Fail - name: validation.openstackfloatingippool.infrastructure.cluster.x-k8s.io - rules: - - apiGroups: - - infrastructure.cluster.x-k8s.io - apiVersions: - - v1alpha7 - operations: - - CREATE - - UPDATE - resources: - - openstackfloatingippools - sideEffects: None -- admissionReviewVersions: - - v1beta1 - clientConfig: - service: - name: webhook-service - namespace: system - path: /validate-infrastructure-cluster-x-k8s-io-v1alpha7-openstackmachine ->>>>>>> c42e6ad2 (IPAM provider for floating ips in openstack) failurePolicy: Fail matchPolicy: Equivalent name: validation.openstackmachine.infrastructure.cluster.x-k8s.io diff --git a/controllers/ipaddress_controller.go b/controllers/ipaddress_controller.go index 79e24010db..c1b22ced0e 100644 --- a/controllers/ipaddress_controller.go +++ b/controllers/ipaddress_controller.go @@ -31,7 +31,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7" + infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha8" "sigs.k8s.io/cluster-api-provider-openstack/pkg/cloud/services/networking" "sigs.k8s.io/cluster-api-provider-openstack/pkg/scope" ipamutils "sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/ipam" @@ -90,6 +90,12 @@ func (r *IPAddressReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( if err = networkingService.DeleteFloatingIP(pool, ipAddress.Spec.Address); err != nil { return ctrl.Result{}, fmt.Errorf("delete floating IP %q: %w", ipAddress.Spec.Address, err) } + } else if pool.Spec.ReclaimPolicy == infrav1.ReclaimRetain { + // Return the IP to available IPs. + pool.Status.AvailableIPs = append(pool.Status.AvailableIPs, ipAddress.Spec.Address) + if err := r.Client.Status().Update(ctx, pool); err != nil { + return ctrl.Result{}, err + } } controllerutil.RemoveFinalizer(ipAddress, infrav1.DeleteFloatingIPFinalizer) if err := r.Client.Update(ctx, ipAddress); err != nil { diff --git a/controllers/openstackfloatingippool_controller.go b/controllers/openstackfloatingippool_controller.go index a4f74829a1..cba3634fd5 100644 --- a/controllers/openstackfloatingippool_controller.go +++ b/controllers/openstackfloatingippool_controller.go @@ -22,14 +22,12 @@ import ( "fmt" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external" - "golang.org/x/exp/slices" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/record" "k8s.io/utils/pointer" - "k8s.io/utils/set" ipamv1 "sigs.k8s.io/cluster-api/exp/ipam/api/v1beta1" "sigs.k8s.io/cluster-api/util/patch" ctrl "sigs.k8s.io/controller-runtime" @@ -38,7 +36,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" - infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7" + infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha8" "sigs.k8s.io/cluster-api-provider-openstack/pkg/cloud/services/networking" "sigs.k8s.io/cluster-api-provider-openstack/pkg/scope" ) @@ -98,14 +96,11 @@ func (r *OpenStackFloatingIPPoolReconciler) Reconcile(ctx context.Context, req c } }() - set := set.New(pool.Spec.PreAllocatedFloatingIPs...) - fmt.Println(set) - if err := r.reconcileFloatingIPNetwork(scope, pool); err != nil { return ctrl.Result{}, err } - if err := r.setIPStatuses(ctx, pool); err != nil { + if err := r.reconcileIPAddresses(ctx, scope, pool); err != nil { return ctrl.Result{}, err } @@ -175,9 +170,6 @@ func (r *OpenStackFloatingIPPoolReconciler) Reconcile(ctx context.Context, req c scope.Logger().Info("Claimed IP", "ip", ipAddress.Spec.Address) } } - if err = r.setIPStatuses(ctx, pool); err != nil { - return ctrl.Result{}, err - } return ctrl.Result{}, nil } @@ -199,11 +191,12 @@ func (r *OpenStackFloatingIPPoolReconciler) reconcileDelete(ctx context.Context, return err } - // Clean up ips created by the pool - for _, ip := range set.New(pool.Status.AllIPs...).Difference(set.New(pool.Spec.PreAllocatedFloatingIPs...)).SortedList() { + for _, ip := range diff(pool.Status.AvailableIPs, pool.Spec.PreAllocatedFloatingIPs) { if err := networkingService.DeleteFloatingIP(pool, ip); err != nil { return fmt.Errorf("delete floating IP: %w", err) } + // Remove the IP from the available IPs, so we don't try to delete it again if the reconcile loop runs again + pool.Status.AvailableIPs = diff(pool.Status.AvailableIPs, []string{ip}) } if controllerutil.RemoveFinalizer(pool, infrav1.OpenStackFloatingIPPoolFinalizer) { @@ -213,21 +206,76 @@ func (r *OpenStackFloatingIPPoolReconciler) reconcileDelete(ctx context.Context, return nil } -func (r *OpenStackFloatingIPPoolReconciler) setIPStatuses(ctx context.Context, pool *infrav1.OpenStackFloatingIPPool) error { +func union(a []string, b []string) []string { + m := make(map[string]struct{}) + for _, item := range a { + m[item] = struct{}{} + } + for _, item := range b { + m[item] = struct{}{} + } + result := make([]string, 0, len(m)) + for item := range m { + result = append(result, item) + } + return result +} + +func diff(a []string, b []string) []string { + m := make(map[string]struct{}) + for _, item := range a { + m[item] = struct{}{} + } + for _, item := range b { + delete(m, item) + } + result := make([]string, 0, len(m)) + for item := range m { + result = append(result, item) + } + return result +} + +func (r *OpenStackFloatingIPPoolReconciler) reconcileIPAddresses(ctx context.Context, scope scope.Scope, pool *infrav1.OpenStackFloatingIPPool) error { ipAddresses := &ipamv1.IPAddressList{} if err := r.Client.List(ctx, ipAddresses, client.InNamespace(pool.Namespace), client.MatchingFields{infrav1.OpenStackFloatingIPPoolNameIndex: pool.Name}); err != nil { return err } - pool.Status.ClaimedIPs = make([]string, 0, len(ipAddresses.Items)) - for _, ip := range ipAddresses.Items { - pool.Status.ClaimedIPs = append(pool.Status.ClaimedIPs, ip.Spec.Address) + + networkingService, err := networking.NewService(scope) + if err != nil { + return err + } + pool.Status.ClaimedIPs = []string{} + if pool.Status.AvailableIPs == nil { + pool.Status.AvailableIPs = []string{} } - pool.Status.AllIPs = slices.Clone(pool.Spec.PreAllocatedFloatingIPs) - pool.Status.AllIPs = set.New(pool.Status.AllIPs...).Union(set.New(pool.Status.ClaimedIPs...)).SortedList() - pool.Status.FailedIPs = set.New(pool.Status.FailedIPs...).Difference(set.New(pool.Status.AllIPs...)).SortedList() - unclaimedIps := set.New(pool.Status.AllIPs...).Difference(set.New(pool.Status.ClaimedIPs...)) - pool.Status.AvailableIPs = unclaimedIps.Difference(set.New(pool.Status.FailedIPs...)).SortedList() + for i := 0; i < len(ipAddresses.Items); i++ { + ipAddress := &(ipAddresses.Items[i]) + if ipAddress.ObjectMeta.DeletionTimestamp.IsZero() { + pool.Status.ClaimedIPs = append(pool.Status.ClaimedIPs, ipAddress.Spec.Address) + continue + } + + if controllerutil.ContainsFinalizer(ipAddress, infrav1.DeleteFloatingIPFinalizer) { + if pool.Spec.ReclaimPolicy == infrav1.ReclaimDelete && !contains(pool.Spec.PreAllocatedFloatingIPs, ipAddress.Spec.Address) { + if err = networkingService.DeleteFloatingIP(pool, ipAddress.Spec.Address); err != nil { + return fmt.Errorf("delete floating IP %q: %w", ipAddress.Spec.Address, err) + } + } else { + pool.Status.AvailableIPs = append(pool.Status.AvailableIPs, ipAddress.Spec.Address) + } + } + + controllerutil.RemoveFinalizer(ipAddress, infrav1.DeleteFloatingIPFinalizer) + if err := r.Client.Update(ctx, ipAddress); err != nil { + return err + } + } + unclaimedPreAllocatedIPs := diff(pool.Spec.PreAllocatedFloatingIPs, pool.Status.ClaimedIPs) + unclaimedIPs := union(pool.Status.AvailableIPs, unclaimedPreAllocatedIPs) + pool.Status.AvailableIPs = diff(unclaimedIPs, pool.Status.FailedIPs) return nil } @@ -243,7 +291,6 @@ func (r *OpenStackFloatingIPPoolReconciler) getIP(scope scope.Scope, pool *infra if len(pool.Status.AvailableIPs) > 0 { ip = pool.Status.AvailableIPs[0] pool.Status.AvailableIPs = pool.Status.AvailableIPs[1:] - pool.Status.ClaimedIPs = append(pool.Status.ClaimedIPs, ip) } if ip != "" { @@ -256,7 +303,7 @@ func (r *OpenStackFloatingIPPoolReconciler) getIP(scope scope.Scope, pool *infra } } - fp, err := networkingService.CreateFloatingIPForPool(pool, "") + fp, err := networkingService.CreateFloatingIPForPool(pool) if err != nil { scope.Logger().Error(err, "Failed to create floating IP", "pool", pool.Name) if ip != "" { @@ -267,7 +314,6 @@ func (r *OpenStackFloatingIPPoolReconciler) getIP(scope scope.Scope, pool *infra ip = fp.FloatingIP pool.Status.ClaimedIPs = append(pool.Status.ClaimedIPs, ip) - pool.Status.AllIPs = append(pool.Status.AllIPs, ip) return ip, nil } diff --git a/go.mod b/go.mod index 711af29bf7..997f835404 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( k8s.io/component-base v0.28.4 k8s.io/klog/v2 v2.100.1 k8s.io/kubernetes v1.28.3 - k8s.io/utils v0.0.0-20240102154912-e7106e64919e + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 sigs.k8s.io/cluster-api v1.6.0 sigs.k8s.io/cluster-api/test v1.6.0 sigs.k8s.io/controller-runtime v0.16.3 diff --git a/main.go b/main.go index ac787d0b3a..7eecc997ca 100644 --- a/main.go +++ b/main.go @@ -297,16 +297,6 @@ func setupReconcilers(ctx context.Context, mgr ctrl.Manager, caCerts []byte, sco setupLog.Error(err, "unable to create controller", "controller", "FloatingIPPool") os.Exit(1) } - if err := (&controllers.IPAddressReconciler{ - Client: mgr.GetClient(), - Recorder: mgr.GetEventRecorderFor("ipaddress-controller"), - ScopeFactory: scopeFactory, - Scheme: mgr.GetScheme(), - CaCertificates: caCerts, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "IPAddress") - os.Exit(1) - } } func setupWebhooks(mgr ctrl.Manager) { @@ -338,11 +328,6 @@ func setupWebhooks(mgr ctrl.Manager) { setupLog.Error(err, "unable to create webhook", "webhook", "OpenStackClusterList") os.Exit(1) } - - if err := (&infrav1.OpenStackFloatingIPPool{}).SetupWebhookWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create webhook", "webhook", "OpenStackFloatingIPPool") - os.Exit(1) - } } func concurrency(c int) controller.Options { diff --git a/pkg/cloud/services/networking/floatingip.go b/pkg/cloud/services/networking/floatingip.go index 0b83f16c08..4bc660830d 100644 --- a/pkg/cloud/services/networking/floatingip.go +++ b/pkg/cloud/services/networking/floatingip.go @@ -71,18 +71,15 @@ func (s *Service) GetOrCreateFloatingIP(eventObject runtime.Object, openStackClu return fp, nil } -func (s *Service) CreateFloatingIPForPool(pool *infrav1.OpenStackFloatingIPPool, ip string) (*floatingips.FloatingIP, error) { +func (s *Service) CreateFloatingIPForPool(pool *infrav1.OpenStackFloatingIPPool) (*floatingips.FloatingIP, error) { var fpCreateOpts floatingips.CreateOpts fpCreateOpts.FloatingNetworkID = pool.Status.FloatingIPNetwork.ID fpCreateOpts.Description = fmt.Sprintf("Created by cluster-api-provider-openstack OpenStackFloatingIPPool %s", pool.Name) - if ip != "" { - fpCreateOpts.FloatingIP = ip - } fp, err := s.client.CreateFloatingIP(fpCreateOpts) if err != nil { - record.Warnf(pool, "FailedCreateFloatingIP", "%s failed to create floating IP %s: %v", pool.Name, ip, err) + record.Warnf(pool, "FailedCreateFloatingIP", "%s failed to create floating IP: %v", pool.Name, err) return nil, err }