diff --git a/Dockerfile b/Dockerfile index 5bb0963..b8b4d8b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,6 +36,7 @@ RUN go mod download COPY ./ ./ # Build +ARG ARCH ARG ldflags RUN CGO_ENABLED=0 GOOS=linux GOARCH=${ARCH} \ diff --git a/controllers/elfmachine_controller.go b/controllers/elfmachine_controller.go index 809873e..4006f55 100644 --- a/controllers/elfmachine_controller.go +++ b/controllers/elfmachine_controller.go @@ -43,6 +43,7 @@ import ( "github.com/smartxworks/cluster-api-provider-elf-static-ip/pkg/context" "github.com/smartxworks/cluster-api-provider-elf-static-ip/pkg/ipam" "github.com/smartxworks/cluster-api-provider-elf-static-ip/pkg/ipam/metal3io" + "github.com/smartxworks/cluster-api-provider-elf-static-ip/pkg/ipam/util" ipamutil "github.com/smartxworks/cluster-api-provider-elf-static-ip/pkg/ipam/util" ) @@ -191,24 +192,21 @@ func (r *ElfMachineReconciler) reconcileDelete(ctx *context.MachineContext) (rec return ctrl.Result{}, nil } - ipPool, err := r.getIPPool(ctx) - if err != nil { - return ctrl.Result{}, err - } - if ipPool == nil { - ctrlutil.RemoveFinalizer(ctx.ElfMachine, MachineStaticIPFinalizer) - - r.Logger.V(1).Info("IPPool is not found, remove MachineStaticIPFinalizer") - - return ctrl.Result{}, nil - } - var errs []error for i := 0; i < len(ctx.ElfMachine.Spec.Network.Devices); i++ { if !ipamutil.IsStaticIPDevice(ctx.ElfMachine.Spec.Network.Devices[i]) { continue } + ipPool, err := r.getIPPool(ctx, ctx.ElfMachine.Spec.Network.Devices[i]) + if err != nil { + return ctrl.Result{}, err + } else if ipPool == nil { + r.Logger.V(1).Info("IPPool is not found, so no need to release the IP", "claim", ipamutil.GetFormattedClaimName(ctx.ElfMachine.Namespace, ctx.ElfMachine.Name, i)) + + continue + } + if err := ctx.IPAMService.ReleaseIP(ctx, ipamutil.GetFormattedClaimName(ctx.ElfMachine.Namespace, ctx.ElfMachine.Name, i), ipPool); err != nil { errs = append(errs, err) } @@ -265,15 +263,6 @@ func (r *ElfMachineReconciler) reconcileIPAddress(ctx *context.MachineContext) ( return ctrl.Result{}, nil } - ipPool, err := r.getIPPool(ctx) - if err != nil { - return ctrl.Result{}, err - } - if ipPool == nil { - ctx.Logger.Info("Waiting for IPPool to be available") - return ctrl.Result{}, nil - } - defer func() { if len(ctx.ElfMachine.Spec.Network.Nameservers) > 0 { ctx.ElfMachine.Spec.Network.Nameservers = ipamutil.LimitDNSServers(ctx.ElfMachine.Spec.Network.Nameservers) @@ -286,21 +275,30 @@ func (r *ElfMachineReconciler) reconcileIPAddress(ctx *context.MachineContext) ( continue } + ipPool, err := r.getIPPool(ctx, ctx.ElfMachine.Spec.Network.Devices[i]) + if err != nil { + return ctrl.Result{}, err + } + if ipPool == nil { + ctx.Logger.Info("Waiting for IPPool to be available") + return ctrl.Result{}, nil + } + result, err := r.reconcileDeviceIPAddress(ctx, ipPool, i) if err != nil { ctx.Logger.Error(err, fmt.Sprintf("failed to set IP address for device %d", i)) return reconcile.Result{}, err } + if requeueAfter == 0 && len(ipPool.GetDNSServers()) > 0 { + ctx.ElfMachine.Spec.Network.Nameservers = append(ctx.ElfMachine.Spec.Network.Nameservers, ipPool.GetDNSServers()...) + } + if result.RequeueAfter != 0 { requeueAfter = result.RequeueAfter } } - if requeueAfter == 0 && len(ipPool.GetDNSServers()) > 0 { - ctx.ElfMachine.Spec.Network.Nameservers = append(ctx.ElfMachine.Spec.Network.Nameservers, ipPool.GetDNSServers()...) - } - return reconcile.Result{RequeueAfter: requeueAfter}, nil } @@ -337,11 +335,19 @@ func (r *ElfMachineReconciler) reconcileDeviceIPAddress(ctx *context.MachineCont return ctrl.Result{}, nil } -func (r *ElfMachineReconciler) getIPPool(ctx *context.MachineContext) (ipam.IPPool, error) { - poolMatchLabels, err := r.getIPPoolMatchLabels(ctx) - if err != nil { - ctx.Logger.Error(err, "failed to get IPPool match labels") - return nil, err +func (r *ElfMachineReconciler) getIPPool(ctx *context.MachineContext, device capev1.NetworkDeviceSpec) (ipam.IPPool, error) { + poolMatchLabels := make(map[string]string) + // Prefer IPPool of device. Only Metal3 IPPool is supported now. + if len(device.AddressesFromPools) > 0 && util.IsMetal3IPPoolRef(device.AddressesFromPools[0]) { + poolMatchLabels[ipam.ClusterIPPoolNamespaceKey] = ctx.ElfMachine.Namespace + poolMatchLabels[ipam.ClusterIPPoolNameKey] = device.AddressesFromPools[0].Name + } else { + var err error + poolMatchLabels, err = r.getIPPoolMatchLabels(ctx) + if err != nil { + ctx.Logger.Error(err, "failed to get IPPool match labels") + return nil, err + } } ipPool, err := ctx.IPAMService.GetAvailableIPPool(ctx, poolMatchLabels, ctx.Cluster.ObjectMeta) diff --git a/controllers/elfmachine_controller_test.go b/controllers/elfmachine_controller_test.go index b8bd40a..e36ee01 100644 --- a/controllers/elfmachine_controller_test.go +++ b/controllers/elfmachine_controller_test.go @@ -26,6 +26,8 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" capev1 "github.com/smartxworks/cluster-api-provider-elf/api/v1beta1" + capecontext "github.com/smartxworks/cluster-api-provider-elf/pkg/context" + corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" apitypes "k8s.io/apimachinery/pkg/types" @@ -37,7 +39,9 @@ import ( ctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "github.com/smartxworks/cluster-api-provider-elf-static-ip/pkg/config" + "github.com/smartxworks/cluster-api-provider-elf-static-ip/pkg/context" "github.com/smartxworks/cluster-api-provider-elf-static-ip/pkg/ipam" + "github.com/smartxworks/cluster-api-provider-elf-static-ip/pkg/ipam/metal3io" ipamutil "github.com/smartxworks/cluster-api-provider-elf-static-ip/pkg/ipam/util" "github.com/smartxworks/cluster-api-provider-elf-static-ip/test/fake" ) @@ -295,7 +299,7 @@ var _ = Describe("ElfMachineReconciler", func() { result, err := reconciler.Reconcile(ctx, ctrl.Request{NamespacedName: capiutil.ObjectKey(elfMachine)}) Expect(result).To(BeZero()) Expect(err).ToNot(HaveOccurred()) - Expect(logBuffer.String()).To(ContainSubstring("IPPool is not found, remove MachineStaticIPFinalizer")) + Expect(logBuffer.String()).To(ContainSubstring("IPPool is not found, so no need to release the IP")) Expect(apierrors.IsNotFound(ctrlContext.Client.Get(ctrlContext, capiutil.ObjectKey(elfMachine), elfMachine))).To(BeTrue()) }) @@ -330,4 +334,37 @@ var _ = Describe("ElfMachineReconciler", func() { Expect(apierrors.IsNotFound(ctrlContext.Client.Get(ctrlContext, capiutil.ObjectKey(metal3IPClaim), metal3IPClaim))).To(BeTrue()) }) }) + + Context("getIPPool", func() { + It("should prefer IPPool of device", func() { + metal3IPPool.Namespace = elfMachine.Namespace + elfMachine.Spec.Network.Devices = []capev1.NetworkDeviceSpec{ + {NetworkType: capev1.NetworkTypeIPV4, IPAddrs: []string{}, AddressesFromPools: []corev1.TypedLocalObjectReference{ + {APIGroup: pointer.String("ipam.metal3.io"), Kind: "IPPool", Name: metal3IPPool.Name}, + }}, + } + ctrlContext := newCtrlContexts(elfCluster, cluster, elfMachine, machine, elfMachineTemplate, metal3IPPool, metal3IPClaim, metal3IPAddress) + fake.InitOwnerReferences(ctrlContext, elfCluster, cluster, elfMachine, machine) + machineContext := &context.MachineContext{ + IPAMService: metal3io.NewIpam(ctrlContext.Client, ctrlContext.Logger), + MachineContext: &capecontext.MachineContext{ + ControllerContext: ctrlContext, + Cluster: cluster, + Machine: machine, + ElfMachine: elfMachine, + Logger: ctrlContext.Logger, + }, + } + reconciler := &ElfMachineReconciler{ControllerContext: ctrlContext} + ipPool, err := reconciler.getIPPool(machineContext, elfMachine.Spec.Network.Devices[0]) + Expect(err).ToNot(HaveOccurred()) + Expect(ipPool.GetNamespace()).To(Equal(metal3IPPool.Namespace)) + Expect(ipPool.GetName()).To(Equal(metal3IPPool.Name)) + + elfMachine.Spec.Network.Devices[0].AddressesFromPools[0].Name = "notfound" + ipPool, err = reconciler.getIPPool(machineContext, elfMachine.Spec.Network.Devices[0]) + Expect(err).ToNot(HaveOccurred()) + Expect(ipPool).To(BeNil()) + }) + }) }) diff --git a/go.mod b/go.mod index c1333ce..cfa571a 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/onsi/ginkgo/v2 v2.12.0 github.com/onsi/gomega v1.27.10 github.com/pkg/errors v0.9.1 - github.com/smartxworks/cluster-api-provider-elf v1.3.0-rc.2 + github.com/smartxworks/cluster-api-provider-elf v1.4.0-beta.0 github.com/spf13/pflag v1.0.5 golang.org/x/mod v0.12.0 k8s.io/apiextensions-apiserver v0.27.2 @@ -78,17 +78,17 @@ require ( github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect - github.com/smartxworks/cloudtower-go-sdk/v2 v2.11.1-rc-2023-09-14 // indirect + github.com/smartxworks/cloudtower-go-sdk/v2 v2.13.1-0.20231116110941-d411454388af // indirect github.com/spf13/cobra v1.7.0 // indirect go.mongodb.org/mongo-driver v1.12.1 // indirect go.opentelemetry.io/otel v1.17.0 // indirect go.opentelemetry.io/otel/metric v1.17.0 // indirect go.opentelemetry.io/otel/trace v1.17.0 // indirect - golang.org/x/net v0.14.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/term v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.12.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect diff --git a/go.sum b/go.sum index 5fbf0fc..db4836e 100644 --- a/go.sum +++ b/go.sum @@ -432,10 +432,10 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/smartxworks/cloudtower-go-sdk/v2 v2.11.1-rc-2023-09-14 h1:CHJLqIwjPHMKpnlR7wXmKUr9n2Ba7KhR5LG63S4TqQY= -github.com/smartxworks/cloudtower-go-sdk/v2 v2.11.1-rc-2023-09-14/go.mod h1:X6R9+L438SMnLJXykSCV3fJ+AZul0hlyjITsZgrSRtM= -github.com/smartxworks/cluster-api-provider-elf v1.3.0-rc.2 h1:lAhD4XA/slsDVrYjLJ6xIsm8DvT0WEBM+HNECivGBlY= -github.com/smartxworks/cluster-api-provider-elf v1.3.0-rc.2/go.mod h1:mh9l2f77aBqCIf4MkJYexP4dX5kNV7g21xXpTgb7yrI= +github.com/smartxworks/cloudtower-go-sdk/v2 v2.13.1-0.20231116110941-d411454388af h1:rV7FO8PZAzurE2zLEtXVrcKZkF544w98rXjvv2bDaqI= +github.com/smartxworks/cloudtower-go-sdk/v2 v2.13.1-0.20231116110941-d411454388af/go.mod h1:X6R9+L438SMnLJXykSCV3fJ+AZul0hlyjITsZgrSRtM= +github.com/smartxworks/cluster-api-provider-elf v1.4.0-beta.0 h1:aSVakeKqVzEOzSwn86J7hUVJibpnfSDq9IQdsqrfHn8= +github.com/smartxworks/cluster-api-provider-elf v1.4.0-beta.0/go.mod h1:7IFFlC0lBnaDS1t8RQp4SXzJ0PzPRsS403/WyPm4KK8= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -530,8 +530,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -599,8 +599,9 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -667,8 +668,9 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -679,8 +681,9 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -696,8 +699,9 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= diff --git a/metadata.yaml b/metadata.yaml index 122d61b..cf00c82 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -6,6 +6,9 @@ apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3 kind: Metadata releaseSeries: + - major: 0 + minor: 6 + contract: v1beta1 - major: 0 minor: 5 contract: v1beta1 diff --git a/pkg/ipam/util/util.go b/pkg/ipam/util/util.go index 43429c4..86e24d8 100644 --- a/pkg/ipam/util/util.go +++ b/pkg/ipam/util/util.go @@ -128,3 +128,9 @@ func GetObjRef(obj runtime.Object) corev1.ObjectReference { func GetFormattedClaimName(ownerNamespace, ownerName string, deviceCount int) string { return fmt.Sprintf("%s-%s-%d", ownerNamespace, ownerName, deviceCount) } + +// IsMetal3IPPoolRef returns whether the ref is Metal3 IPPool. +func IsMetal3IPPoolRef(ref corev1.TypedLocalObjectReference) bool { + return (ref.APIGroup != nil && *ref.APIGroup == "ipam.metal3.io" && ref.Kind == "IPPool") || + ((ref.APIGroup == nil || *ref.APIGroup == "") && ref.Kind == "") +} diff --git a/pkg/ipam/util/util_test.go b/pkg/ipam/util/util_test.go index 00d4ee5..ef5a152 100644 --- a/pkg/ipam/util/util_test.go +++ b/pkg/ipam/util/util_test.go @@ -20,6 +20,8 @@ import ( "testing" "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/pointer" ) func TestLimitDNSServers(t *testing.T) { @@ -43,3 +45,19 @@ func TestLimitDNSServers(t *testing.T) { }) } } + +func TestIsMetal3IPPoolRef(t *testing.T) { + g := gomega.NewGomegaWithT(t) + + t.Run("should return true if ref is Metal3 IPPool", func(t *testing.T) { + g.Expect(IsMetal3IPPoolRef(corev1.TypedLocalObjectReference{})).To(gomega.BeTrue()) + g.Expect(IsMetal3IPPoolRef(corev1.TypedLocalObjectReference{ + APIGroup: pointer.String("ipam.metal3.io"), + Kind: "IPPool", + })).To(gomega.BeTrue()) + g.Expect(IsMetal3IPPoolRef(corev1.TypedLocalObjectReference{ + APIGroup: pointer.String("ipam.metal3.io"), + Kind: "XPool", + })).To(gomega.BeFalse()) + }) +}