diff --git a/.gitignore b/.gitignore index d7a77cd042..f91711f3f6 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ token # test generated files coverage* +*.report # example kubeconfig generates by examples liqo_kubeconf* diff --git a/cmd/ipam/main.go b/cmd/ipam/main.go index 15feb530e3..4f29811261 100644 --- a/cmd/ipam/main.go +++ b/cmd/ipam/main.go @@ -77,9 +77,8 @@ func main() { cmd.Flags().DurationVar(&options.ServerOpts.SyncGracePeriod, "sync-graceperiod", consts.SyncGracePeriod, "The grace period the sync routine wait before releasing an ip or a network.") cmd.Flags().BoolVar(&options.ServerOpts.GraphvizEnabled, "enable-graphviz", false, "Enable the graphviz output for the IPAM.") - cmd.Flags().StringSliceVar(&options.ServerOpts.Pools, "pools", - []string{"10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"}, - "The pools used by the IPAM to acquire Networks and IPs from. Default: private addesses range.", + cmd.Flags().StringSliceVar(&options.ServerOpts.Pools, "pools", consts.PrivateAddressSpace, + "The pools used by the IPAM to acquire Networks and IPs from. Default: private addesses space.", ) // Leader election flags. @@ -145,7 +144,7 @@ func run(cmd *cobra.Command, _ []string) error { } } - liqoIPAM, err := ipam.New(ctx, cl, options.ServerOpts.Pools, &options.ServerOpts) + liqoIPAM, err := ipam.New(ctx, cl, &options.ServerOpts) if err != nil { return err } @@ -163,7 +162,7 @@ func run(cmd *cobra.Command, _ []string) error { // Register IPAM service ipam.RegisterIPAMServer(server, liqoIPAM) - if err := server.Serve(lis); err != nil { + if err := server.Serve(lis); err != nil { // we do not need to close the listener as Serve will close it when returning klog.Errorf("failed to serve: %v", err) return err } diff --git a/pkg/consts/ipam.go b/pkg/consts/ipam.go index 194d4bc4de..b468269845 100644 --- a/pkg/consts/ipam.go +++ b/pkg/consts/ipam.go @@ -59,3 +59,8 @@ const ( // DefaultCIDRValue is the default value for a string that contains a CIDR. DefaultCIDRValue = "None" ) + +var ( + // PrivateAddressSpace contains all the ranges for private addresses as defined in RFC1918. + PrivateAddressSpace = []string{"10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"} +) diff --git a/pkg/ipam/initialize.go b/pkg/ipam/initialize.go index 258bebe098..7c0aeb3c6e 100644 --- a/pkg/ipam/initialize.go +++ b/pkg/ipam/initialize.go @@ -45,7 +45,7 @@ func (lipam *LiqoIPAM) initialize(ctx context.Context) error { func (lipam *LiqoIPAM) initializeNetworks(ctx context.Context) error { // List all networks present in the cluster. - nets, err := lipam.listNetworksOnCluster(ctx, lipam.Client) + nets, err := lipam.listNetworksOnCluster(ctx) if err != nil { return err } @@ -67,7 +67,7 @@ func (lipam *LiqoIPAM) initializeNetworks(ctx context.Context) error { func (lipam *LiqoIPAM) initializeIPs(ctx context.Context) error { // List all IPs present in the cluster. - ips, err := lipam.listIPsOnCluster(ctx, lipam.Client) + ips, err := lipam.listIPsOnCluster(ctx) if err != nil { return err } diff --git a/pkg/ipam/initialize_test.go b/pkg/ipam/initialize_test.go index 8baed358f9..82d9a938f3 100644 --- a/pkg/ipam/initialize_test.go +++ b/pkg/ipam/initialize_test.go @@ -96,13 +96,13 @@ var _ = Describe("Initialize routine tests", func() { Expect(fakeIpamServer.networkIsAvailable(netip.MustParsePrefix("10.4.0.0/30"))).To(Equal(false)) Expect(fakeIpamServer.networkIsAvailable(netip.MustParsePrefix("10.3.0.0/16"))).To(Equal(false)) Expect(fakeIpamServer.networkIsAvailable(netip.MustParsePrefix("172.16.1.0/24"))).To(Equal(false)) - available, err := fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.3.0.0"), netip.MustParsePrefix("10.3.0.0/16")) + available, err := fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.3.0.0"), netip.MustParsePrefix("10.3.0.0/16")) Expect(err).To(BeNil()) Expect(available).To(Equal(false)) - available, err = fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.3.0.1"), netip.MustParsePrefix("10.3.0.0/16")) + available, err = fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.3.0.1"), netip.MustParsePrefix("10.3.0.0/16")) Expect(err).To(BeNil()) Expect(available).To(Equal(true)) - available, err = fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.3.0.2"), netip.MustParsePrefix("10.3.0.0/16")) + available, err = fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.3.0.2"), netip.MustParsePrefix("10.3.0.0/16")) Expect(err).To(BeNil()) Expect(available).To(Equal(false)) diff --git a/pkg/ipam/ipam.go b/pkg/ipam/ipam.go index b2ead93411..4f94e7aa66 100644 --- a/pkg/ipam/ipam.go +++ b/pkg/ipam/ipam.go @@ -52,12 +52,12 @@ type ServerOptions struct { } // New creates a new instance of the LiqoIPAM. -func New(ctx context.Context, cl client.Client, roots []string, opts *ServerOptions) (*LiqoIPAM, error) { +func New(ctx context.Context, cl client.Client, opts *ServerOptions) (*LiqoIPAM, error) { hs := health.NewServer() hs.SetServingStatus(IPAM_ServiceDesc.ServiceName, grpc_health_v1.HealthCheckResponse_NOT_SERVING) - prefixRoots := make([]netip.Prefix, len(roots)) - for i, r := range roots { + prefixRoots := make([]netip.Prefix, len(opts.Pools)) + for i, r := range opts.Pools { p, err := netip.ParsePrefix(r) if err != nil { return nil, fmt.Errorf("failed to parse pool with prefix %q: %w", r, err) diff --git a/pkg/ipam/ipam_test.go b/pkg/ipam/ipam_test.go new file mode 100644 index 0000000000..bd32aa4d26 --- /dev/null +++ b/pkg/ipam/ipam_test.go @@ -0,0 +1,671 @@ +// Copyright 2019-2024 The Liqo 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 ipam + +import ( + "context" + "fmt" + "net" + "net/netip" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + grpc "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/health/grpc_health_v1" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/liqotech/liqo/pkg/consts" + grpcutils "github.com/liqotech/liqo/pkg/utils/grpc" + "github.com/liqotech/liqo/pkg/utils/testutil" +) + +var _ = Describe("IPAM integration tests", func() { + const ( + grpcAddress = "0.0.0.0" + grpcPort = consts.IpamPort + ) + + var ( + ctx context.Context + fakeClientBuilder *fake.ClientBuilder + err error + + ipamServer *LiqoIPAM + serverOpts = &ServerOptions{ + Pools: consts.PrivateAddressSpace, + Port: grpcPort, + SyncInterval: time.Duration(0), // we disable sync routine as already tested in sync_test.go + SyncGracePeriod: time.Duration(0), // same as above + GraphvizEnabled: false, + } + server *grpc.Server + lis net.Listener + listenAddress = fmt.Sprintf("%s:%d", grpcAddress, grpcPort) + errServe error + + ipamClient IPAMClient + conn *grpc.ClientConn + ) + + BeforeEach(func() { + ctx = context.Background() + + // Build kubernetes (fake) client + fakeClientBuilder = fake.NewClientBuilder().WithScheme(scheme.Scheme) + cl := fakeClientBuilder.WithObjects( + testutil.FakeNetworkPodCIDR(), + testutil.FakeNetworkServiceCIDR(), + testutil.FakeNetworkExternalCIDR(), + testutil.FakeNetworkInternalCIDR(), + ).Build() + + // Start grpc ipam server + ipamServer, err = New(ctx, cl, serverOpts) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer).ToNot(BeNil()) + Expect(ipamServer.IpamCore).ToNot(BeNil()) + + server = grpc.NewServer() + Expect(server).ToNot(BeNil()) + grpc_health_v1.RegisterHealthServer(server, ipamServer.HealthServer) // register health service + RegisterIPAMServer(server, ipamServer) // register IPAM service + + lis, err = net.Listen("tcp", listenAddress) + Expect(err).ToNot(HaveOccurred()) + Expect(lis).ToNot(BeNil()) + go func() { + errServe = fmt.Errorf("server failed when serving") // set error to check if server fails + errServe = server.Serve(lis) + }() + + // Start gprc ipam client + conn, err = grpc.NewClient(listenAddress, grpc.WithTransportCredentials(insecure.NewCredentials())) + Expect(err).ToNot(HaveOccurred()) + Expect(conn).ToNot(BeNil()) + Expect(grpcutils.WaitForConnectionReady(ctx, conn, 10*time.Second)).To(Succeed()) + ipamClient = NewIPAMClient(conn) + }) + + AfterEach(func() { + Expect(conn.Close()).To(Succeed()) // close grpc client + server.GracefulStop() // graceful stop grpc server + time.Sleep(10 * time.Millisecond) // wait a bit for the gprc server to gracefully stop + Expect(errServe).ToNot(HaveOccurred()) + }) + + Describe("Preinstalled networks", func() { + It("should have reserved preinstalled networks", func() { + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix(testutil.PodCIDR))).To(BeFalse()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix(testutil.ServiceCIDR))).To(BeFalse()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix(testutil.ExternalCIDR))).To(BeFalse()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix(testutil.InternalCIDR))).To(BeFalse()) + }) + }) + + Describe("Acquiring networks", func() { + When("acquiring a network not occupied", func() { + When("remapping is allowed", func() { + It("should acquire the network without remapping", func() { + res, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/16", + Immutable: false, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + Expect(res.Cidr).To(Equal("10.20.0.0/16")) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/16"))).To(BeFalse()) + }) + }) + + When("remapping is not allowed", func() { + It("should acquire the network without remapping", func() { + res, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/16", + Immutable: true, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + Expect(res.Cidr).To(Equal("10.20.0.0/16")) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/16"))).To(BeFalse()) + }) + }) + }) + + When("acquiring a network already occupied", func() { + BeforeEach(func() { + res, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/16", + Immutable: true, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + Expect(res.Cidr).To(Equal("10.20.0.0/16")) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/16"))).To(BeFalse()) + }) + + When("remapping is allowed", func() { + It("should acquire the network and get a remapping", func() { + res, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/16", + Immutable: false, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + Expect(res.Cidr).ToNot(Equal("10.20.0.0/16")) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix(res.Cidr))).To(BeFalse()) + }) + + It("should acquire a network that contains it and get a remapping", func() { + res, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/17", + Immutable: false, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + Expect(res.Cidr).ToNot(Equal("10.20.0.0/17")) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix(res.Cidr))).To(BeFalse()) + }) + + It("should acquire a network that contains it and get a remapping", func() { + res, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/15", + Immutable: false, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + Expect(res.Cidr).ToNot(Equal("10.20.0.0/15")) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix(res.Cidr))).To(BeFalse()) + }) + }) + + When("remapping is not allowed", func() { + It("should not acquire the network and get an error", func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/16", + Immutable: true, + }) + Expect(err).To(HaveOccurred()) + }) + + It("should not acquire a network that is contained in and get an error", func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/17", + Immutable: true, + }) + Expect(err).To(HaveOccurred()) + }) + + It("should not acquire a network that contains it and get an error", func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/15", + Immutable: true, + }) + Expect(err).To(HaveOccurred()) + }) + }) + + }) + + When("acquiring a network out of the pools", func() { + It("should not acquire the network and get an error", func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "50.0.0.0/24", + Immutable: false, + }) + Expect(err).To(HaveOccurred()) + }) + }) + + When("acquiring a network bigger than a pool", func() { + It("should not acquire the network and get an error", func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "192.168.0.0/15", + Immutable: false, + }) + Expect(err).To(HaveOccurred()) + }) + }) + + When("acquiring a network equal to a pool", func() { + It("should acquire the network", func() { + res, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "192.168.0.0/16", + Immutable: true, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + Expect(res.Cidr).To(Equal("192.168.0.0/16")) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("192.168.0.0/16"))).To(BeFalse()) + }) + }) + + When("acquiring a network with preallocated IPs", func() { + It("should acquire the network and preallocate the IPs", func() { + res, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/16", + Immutable: true, + PreAllocated: 2, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + Expect(res.Cidr).To(Equal("10.20.0.0/16")) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix(res.Cidr))).To(BeFalse()) + available, err := ipamServer.ipIsAvailable(netip.MustParseAddr("10.20.0.0"), netip.MustParsePrefix("10.20.0.0/16")) + Expect(err).ToNot(HaveOccurred()) + Expect(available).To(BeFalse()) + available, err = ipamServer.ipIsAvailable(netip.MustParseAddr("10.20.0.1"), netip.MustParsePrefix("10.20.0.0/16")) + Expect(err).ToNot(HaveOccurred()) + Expect(available).To(BeFalse()) + available, err = ipamServer.ipIsAvailable(netip.MustParseAddr("10.20.0.2"), netip.MustParsePrefix("10.20.0.0/16")) + Expect(err).ToNot(HaveOccurred()) + Expect(available).To(BeTrue()) + }) + + It("should not acquire the network if the preallocated IPs are more than the network size", func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "192.168.1.0/31", + Immutable: true, + PreAllocated: 3, + }) + Expect(err).To(HaveOccurred()) + // if at least one preAllocated IP was not acquired, the entire network and the IPs allocated should be released (atomicity) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("192.168.1.0/31"))).To(BeTrue()) + available, err := ipamServer.ipIsAvailable(netip.MustParseAddr("192.168.1.0"), netip.MustParsePrefix("192.168.1.0/31")) + Expect(err).ToNot(HaveOccurred()) + Expect(available).To(BeTrue()) + available, err = ipamServer.ipIsAvailable(netip.MustParseAddr("192.168.1.1"), netip.MustParsePrefix("192.168.1.0/31")) + Expect(err).ToNot(HaveOccurred()) + Expect(available).To(BeTrue()) + }) + }) + + When("acquiring an invalid network", func() { + It("should not acquire the network and get an error", func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.0.0.256/16", + Immutable: false, + }) + Expect(err).To(HaveOccurred()) + }) + }) + }) + + Describe("Releasing networks", func() { + When("releasing an allocated network", func() { + BeforeEach(func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/16", + Immutable: true, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/16"))).To(BeFalse()) + }) + + It("should release the network", func() { + _, err := ipamClient.NetworkRelease(ctx, &NetworkReleaseRequest{ + Cidr: "10.20.0.0/16", + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/16"))).To(BeTrue()) + }) + }) + + When("releasing an unallocated network", func() { + It("should do nothing and succeed without errors for idempotency", func() { + _, err := ipamClient.NetworkRelease(ctx, &NetworkReleaseRequest{ + Cidr: "10.20.0.0/16", + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/16"))).To(BeTrue()) + }) + }) + + When("releasing a network with preallocated IPs", func() { + BeforeEach(func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/16", + Immutable: true, + PreAllocated: 2, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/16"))).To(BeFalse()) + available, err := ipamServer.ipIsAvailable(netip.MustParseAddr("10.20.0.0"), netip.MustParsePrefix("10.20.0.0/16")) + Expect(err).ToNot(HaveOccurred()) + Expect(available).To(BeFalse()) + available, err = ipamServer.ipIsAvailable(netip.MustParseAddr("10.20.0.1"), netip.MustParsePrefix("10.20.0.0/16")) + Expect(err).ToNot(HaveOccurred()) + Expect(available).To(BeFalse()) + }) + + It("should release the network and the preallocated IPs", func() { + _, err := ipamClient.NetworkRelease(ctx, &NetworkReleaseRequest{ + Cidr: "10.20.0.0/16", + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/16"))).To(BeTrue()) + available, err := ipamServer.ipIsAvailable(netip.MustParseAddr("10.20.0.0"), netip.MustParsePrefix("10.20.0.0/16")) + Expect(err).ToNot(HaveOccurred()) + Expect(available).To(BeTrue()) + available, err = ipamServer.ipIsAvailable(netip.MustParseAddr("10.20.0.1"), netip.MustParsePrefix("10.20.0.0/16")) + Expect(err).ToNot(HaveOccurred()) + Expect(available).To(BeTrue()) + }) + }) + + When("releasing an invalid network", func() { + It("should get an error", func() { + _, err := ipamClient.NetworkRelease(ctx, &NetworkReleaseRequest{ + Cidr: "10.0.0.256/16", + }) + Expect(err).To(HaveOccurred()) + }) + }) + }) + + Describe("Checking for networks availability", func() { + // normal + When("checking for an available network", func() { + It("should return true", func() { + res, err := ipamClient.NetworkIsAvailable(ctx, &NetworkAvailableRequest{ + Cidr: "10.20.0.0/16", + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + Expect(res.Available).To(BeTrue()) + }) + }) + + When("checking for an occupied network", func() { + BeforeEach(func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/16", + Immutable: true, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/16"))).To(BeFalse()) + }) + + When("checking for the same network", func() { + It("should return false", func() { + res, err := ipamClient.NetworkIsAvailable(ctx, &NetworkAvailableRequest{ + Cidr: "10.20.0.0/16", + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + Expect(res.Available).To(BeFalse()) + }) + }) + + When("checking for a network that is contained in", func() { + It("should return false", func() { + res, err := ipamClient.NetworkIsAvailable(ctx, &NetworkAvailableRequest{ + Cidr: "10.20.0.0/17", + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + Expect(res.Available).To(BeFalse()) + }) + }) + + When("checking for a network that contains it", func() { + It("should return false", func() { + res, err := ipamClient.NetworkIsAvailable(ctx, &NetworkAvailableRequest{ + Cidr: "10.20.0.0/15", + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + Expect(res.Available).To(BeFalse()) + }) + }) + }) + + When("checking for an out of pool network", func() { + It("should get an error", func() { + _, err := ipamClient.NetworkIsAvailable(ctx, &NetworkAvailableRequest{ + Cidr: "50.0.0.0/24", + }) + Expect(err).To(HaveOccurred()) + }) + }) + + When("checking for a network bigger than a pool", func() { + It("should get an error", func() { + _, err := ipamClient.NetworkIsAvailable(ctx, &NetworkAvailableRequest{ + Cidr: "192.168.0.0/15", + }) + Expect(err).To(HaveOccurred()) + }) + }) + + When("checking for an invalid network", func() { + It("should get an error", func() { + _, err := ipamClient.NetworkIsAvailable(ctx, &NetworkAvailableRequest{ + Cidr: "10.0.0.256/16", + }) + Expect(err).To(HaveOccurred()) + }) + }) + }) + + Describe("Acquiring IPs", func() { + When("acquiring IPs from an allocated network", func() { + var firstIP, secondIP string + + BeforeEach(func() { + // Allocate network of size 4, with 2 preallocated IPs + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/30", + Immutable: true, + PreAllocated: 2, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/30"))).To(BeFalse()) + + // First IP + res, err := ipamClient.IPAcquire(ctx, &IPAcquireRequest{ + Cidr: "10.20.0.0/30", + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + firstIP = res.Ip + + // Second IP + res, err = ipamClient.IPAcquire(ctx, &IPAcquireRequest{ + Cidr: "10.20.0.0/30", + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + secondIP = res.Ip + }) + + It("the preAllocated IPs should be allocated", func() { + Expect(ipamServer.ipIsAvailable(netip.MustParseAddr("10.20.0.0"), netip.MustParsePrefix("10.20.0.0/30"))).To(BeFalse()) + Expect(ipamServer.ipIsAvailable(netip.MustParseAddr("10.20.0.1"), netip.MustParsePrefix("10.20.0.0/30"))).To(BeFalse()) + }) + + It("should have acquired IPs", func() { + Expect(firstIP).ToNot(Equal(secondIP)) + Expect(ipamServer.ipIsAvailable(netip.MustParseAddr(firstIP), netip.MustParsePrefix("10.20.0.0/30"))).To(BeFalse()) + Expect(ipamServer.ipIsAvailable(netip.MustParseAddr(secondIP), netip.MustParsePrefix("10.20.0.0/30"))).To(BeFalse()) + Expect(firstIP).ToNot(BeEmpty()) + Expect(secondIP).ToNot(BeEmpty()) + Expect(firstIP).ToNot(Or(Equal("10.20.0.0"), Equal("10.20.0.1"))) // allocated IPs should differ from preAllocated ones + Expect(secondIP).ToNot(Or(Equal("10.20.0.0"), Equal("10.20.0.1"))) // allocated IPs should differ from preAllocated ones + + }) + + It("should not acquire an IP if network is full", func() { + _, err := ipamClient.IPAcquire(ctx, &IPAcquireRequest{ + Cidr: "10.20.0.0/30", + }) + Expect(err).To(HaveOccurred()) + }) + }) + + When("acquiring a free IP from a network contained in an allocated one", func() { + BeforeEach(func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/16", + Immutable: true, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/16"))).To(BeFalse()) + }) + + It("should not acquire the IP and get an error", func() { + _, err := ipamClient.IPAcquire(ctx, &IPAcquireRequest{ + Cidr: "10.20.0.0/24", + }) + Expect(err).To(HaveOccurred()) + }) + }) + + When("acquiring an IP from a network not allocated", func() { + It("should get an error", func() { + _, err := ipamClient.IPAcquire(ctx, &IPAcquireRequest{ + Cidr: "10.20.0.0/16", + }) + Expect(err).To(HaveOccurred()) + }) + }) + + When("acquiring an IP from a network out of the pools", func() { + It("should get an error", func() { + _, err := ipamClient.IPAcquire(ctx, &IPAcquireRequest{ + Cidr: "50.0.0.0/24", + }) + Expect(err).To(HaveOccurred()) + }) + }) + + When("acquiring an IP from a network bigger than a pool", func() { + It("should get an error", func() { + _, err := ipamClient.IPAcquire(ctx, &IPAcquireRequest{ + Cidr: "192.168.0.0/15", + }) + Expect(err).To(HaveOccurred()) + }) + }) + + When("acquiring an IP from an invalid network", func() { + It("should get an error", func() { + _, err := ipamClient.IPAcquire(ctx, &IPAcquireRequest{ + Cidr: "10.0.0.256/16", + }) + Expect(err).To(HaveOccurred()) + }) + }) + }) + + Describe("Releasing IPs", func() { + When("releasing an allocated IP", func() { + var ip string + + BeforeEach(func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/16", + Immutable: true, + PreAllocated: 1, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/16"))).To(BeFalse()) + Expect(ipamServer.ipIsAvailable(netip.MustParseAddr("10.20.0.0"), netip.MustParsePrefix("10.20.0.0/16"))).To(BeFalse()) // preAllocated + + res, err := ipamClient.IPAcquire(ctx, &IPAcquireRequest{ + Cidr: "10.20.0.0/16", + }) + Expect(err).ToNot(HaveOccurred()) + Expect(res).ToNot(BeNil()) + ip = res.Ip + Expect(ip).ToNot(Equal("10.20.0.0")) // allocated IP should differ from preAllocated one + }) + + It("should release the allocated IP and guarantee idempotency", func() { + // Release the IP + _, err := ipamClient.IPRelease(ctx, &IPReleaseRequest{ + Cidr: "10.20.0.0/16", + Ip: ip, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.ipIsAvailable(netip.MustParseAddr(ip), netip.MustParsePrefix("10.20.0.0/16"))).To(BeTrue()) + + // Release the IP again. It should not return an error and the IP should still be available (idempotency) + _, err = ipamClient.IPRelease(ctx, &IPReleaseRequest{ + Cidr: "10.20.0.0/16", + Ip: ip, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.ipIsAvailable(netip.MustParseAddr(ip), netip.MustParsePrefix("10.20.0.0/16"))).To(BeTrue()) + // should not interfere with preAllocated IP + Expect(ipamServer.ipIsAvailable(netip.MustParseAddr("10.20.0.0"), netip.MustParsePrefix("10.20.0.0/16"))).To(BeFalse()) + }) + }) + + When("releasing an IP from an unallocated network", func() { + It("should do nothing and succeed without errors for idempotency", func() { + _, err := ipamClient.IPRelease(ctx, &IPReleaseRequest{ + Cidr: "10.20.0.0/16", + Ip: "10.20.0.0", + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.ipIsAvailable(netip.MustParseAddr("10.20.0.0"), netip.MustParsePrefix("10.20.0.0/16"))).To(BeTrue()) + }) + }) + + When("releasing an IP outside of the pools", func() { + It("should get an error", func() { + _, err := ipamClient.IPRelease(ctx, &IPReleaseRequest{ + Cidr: "50.0.0.0/16", + Ip: "50.0.0.0", + }) + Expect(err).To(HaveOccurred()) + }) + }) + + When("input is valid", func() { + BeforeEach(func() { + _, err := ipamClient.NetworkAcquire(ctx, &NetworkAcquireRequest{ + Cidr: "10.20.0.0/16", + Immutable: true, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(ipamServer.networkIsAvailable(netip.MustParsePrefix("10.20.0.0/16"))).To(BeFalse()) + }) + + When("releasing an invalid ip", func() { + It("should get an error", func() { + _, err := ipamClient.IPRelease(ctx, &IPReleaseRequest{ + Cidr: "10.20.0.0/16", + Ip: "10.0.0.256", + }) + Expect(err).To(HaveOccurred()) + }) + }) + + When("releasing an ip from an invalid network", func() { + It("should get an error", func() { + _, err := ipamClient.IPRelease(ctx, &IPReleaseRequest{ + Cidr: "10.0.0.256/16", + Ip: "10.0.0.0", + }) + Expect(err).To(HaveOccurred()) + }) + }) + }) + }) +}) diff --git a/pkg/ipam/ips.go b/pkg/ipam/ips.go index 51694c855c..8e0a39191d 100644 --- a/pkg/ipam/ips.go +++ b/pkg/ipam/ips.go @@ -21,7 +21,6 @@ import ( "time" klog "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" ) @@ -79,16 +78,16 @@ func (lipam *LiqoIPAM) ipRelease(addr netip.Addr, prefix netip.Prefix, gracePeri return nil } -// isIPAvailable checks if an IP is available. -func (lipam *LiqoIPAM) isIPAvailable(addr netip.Addr, prefix netip.Prefix) (bool, error) { +// ipIsAvailable checks if an IP is available. +func (lipam *LiqoIPAM) ipIsAvailable(addr netip.Addr, prefix netip.Prefix) (bool, error) { allocated, err := lipam.IpamCore.IPIsAllocated(prefix, addr) return !allocated, err } -func (lipam *LiqoIPAM) listIPsOnCluster(ctx context.Context, cl client.Client) (map[netip.Addr]netip.Prefix, error) { +func (lipam *LiqoIPAM) listIPsOnCluster(ctx context.Context) (map[netip.Addr]netip.Prefix, error) { result := make(map[netip.Addr]netip.Prefix) var ipList ipamv1alpha1.IPList - if err := cl.List(ctx, &ipList); err != nil { + if err := lipam.Client.List(ctx, &ipList); err != nil { return nil, err } diff --git a/pkg/ipam/ips_test.go b/pkg/ipam/ips_test.go new file mode 100644 index 0000000000..0f5dd609e0 --- /dev/null +++ b/pkg/ipam/ips_test.go @@ -0,0 +1,103 @@ +// Copyright 2019-2024 The Liqo 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 ipam + +import ( + "context" + "net/netip" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" + ipamcore "github.com/liqotech/liqo/pkg/ipam/core" + "github.com/liqotech/liqo/pkg/utils/testutil" +) + +var _ = Describe("IPs tests", func() { + const ( + testNamespace = "test" + ) + + var ( + ctx context.Context + fakeClientBuilder *fake.ClientBuilder + err error + + ipamServer *LiqoIPAM + ipamCore *ipamcore.Ipam + + emptyIPStatus = func(ip *ipamv1alpha1.IP) *ipamv1alpha1.IP { + ip.Status = ipamv1alpha1.IPStatus{} + return ip + } + + addDeletionTimestamp = func(ip *ipamv1alpha1.IP) *ipamv1alpha1.IP { + ip.SetDeletionTimestamp(ptr.To(metav1.NewTime(time.Now()))) + ip.SetFinalizers([]string{"test-finalizer"}) // fake client requires at least one finalizer if deletion timestamp is set + return ip + } + ) + + BeforeEach(func() { + ctx = context.Background() + fakeClientBuilder = fake.NewClientBuilder().WithScheme(scheme.Scheme) + ipamCore, err = ipamcore.NewIpam([]netip.Prefix{netip.MustParsePrefix("10.0.0.0/8")}) + Expect(err).ToNot(HaveOccurred()) + }) + + Context("List ips on cluster", func() { + BeforeEach(func() { + // Add in-cluster ips + client := fakeClientBuilder.WithObjects( + testutil.FakeIP("ip1", testNamespace, "10.1.0.0", "10.1.0.0/16", nil, nil, false), + testutil.FakeIP("ip2", testNamespace, "10.1.0.1", "10.1.0.0/16", nil, nil, false), + testutil.FakeIP("ip3", testNamespace, "10.2.0.0", "10.2.0.0/16", nil, nil, false), + + // IP with no status + emptyIPStatus(testutil.FakeIP("ip4", testNamespace, "10.3.0.0", "10.3.0.0/16", nil, nil, false)), + + // IP with deletion timestamp + addDeletionTimestamp(testutil.FakeIP("ip5", testNamespace, "10.3.0.1", "10.3.0.0/16", nil, nil, false)), + ).Build() + + ipamServer = &LiqoIPAM{ + Client: client, + IpamCore: ipamCore, + opts: &ServerOptions{ + GraphvizEnabled: false, + }, + } + }) + + It("should correctly list ips on cluster", func() { + ips, err := ipamServer.listIPsOnCluster(ctx) + Expect(err).ToNot(HaveOccurred()) + Expect(ips).To(HaveLen(3)) + + Expect(ips).To(HaveKeyWithValue(netip.MustParseAddr("10.1.0.0"), netip.MustParsePrefix("10.1.0.0/16"))) + Expect(ips).To(HaveKeyWithValue(netip.MustParseAddr("10.1.0.1"), netip.MustParsePrefix("10.1.0.0/16"))) + Expect(ips).To(HaveKeyWithValue(netip.MustParseAddr("10.2.0.0"), netip.MustParsePrefix("10.2.0.0/16"))) + Expect(ips).ToNot(HaveKey(netip.MustParseAddr("10.3.0.0"))) + Expect(ips).ToNot(HaveKey(netip.MustParseAddr("10.3.0.1"))) + }) + }) + +}) diff --git a/pkg/ipam/networks.go b/pkg/ipam/networks.go index 3fd4cfc301..a12ae87ee5 100644 --- a/pkg/ipam/networks.go +++ b/pkg/ipam/networks.go @@ -21,7 +21,6 @@ import ( "time" klog "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/client" ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" ) @@ -84,10 +83,10 @@ type prefixDetails struct { preallocated uint32 } -func (lipam *LiqoIPAM) listNetworksOnCluster(ctx context.Context, cl client.Client) (map[netip.Prefix]prefixDetails, error) { +func (lipam *LiqoIPAM) listNetworksOnCluster(ctx context.Context) (map[netip.Prefix]prefixDetails, error) { result := make(map[netip.Prefix]prefixDetails) var networks ipamv1alpha1.NetworkList - if err := cl.List(ctx, &networks); err != nil { + if err := lipam.Client.List(ctx, &networks); err != nil { return nil, err } diff --git a/pkg/ipam/networks_test.go b/pkg/ipam/networks_test.go new file mode 100644 index 0000000000..73875e8045 --- /dev/null +++ b/pkg/ipam/networks_test.go @@ -0,0 +1,112 @@ +// Copyright 2019-2024 The Liqo 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 ipam + +import ( + "context" + "net/netip" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" + ipamcore "github.com/liqotech/liqo/pkg/ipam/core" + "github.com/liqotech/liqo/pkg/utils/testutil" +) + +var _ = Describe("Networks tests", func() { + const ( + testNamespace = "test" + ) + + var ( + ctx context.Context + fakeClientBuilder *fake.ClientBuilder + err error + + ipamServer *LiqoIPAM + ipamCore *ipamcore.Ipam + + addPreAllocated = func(nw *ipamv1alpha1.Network, preAllocated uint32) *ipamv1alpha1.Network { + nw.Spec.PreAllocated = preAllocated + return nw + } + + emptyNetworkStatus = func(nw *ipamv1alpha1.Network) *ipamv1alpha1.Network { + nw.Status = ipamv1alpha1.NetworkStatus{} + return nw + } + + addDeletionTimestamp = func(nw *ipamv1alpha1.Network) *ipamv1alpha1.Network { + nw.SetDeletionTimestamp(ptr.To(metav1.NewTime(time.Now()))) + nw.SetFinalizers([]string{"test-finalizer"}) // fake client requires at least one finalizer if deletion timestamp is set + return nw + } + ) + + BeforeEach(func() { + ctx = context.Background() + fakeClientBuilder = fake.NewClientBuilder().WithScheme(scheme.Scheme) + ipamCore, err = ipamcore.NewIpam([]netip.Prefix{netip.MustParsePrefix("10.0.0.0/8")}) + Expect(err).ToNot(HaveOccurred()) + }) + + Context("List networks on cluster", func() { + BeforeEach(func() { + // Add in-cluster networks + client := fakeClientBuilder.WithObjects( + testutil.FakeNetwork("net1", testNamespace, "10.1.0.0/16", nil), + testutil.FakeNetwork("net2", testNamespace, "10.2.0.0/16", nil), + testutil.FakeNetwork("net3", testNamespace, "10.3.0.0/16", nil), + + // Network with preAllocated fields + addPreAllocated(testutil.FakeNetwork("net4", testNamespace, "10.4.0.0/16", nil), 10), + + // Network with no status + emptyNetworkStatus(testutil.FakeNetwork("net5", testNamespace, "10.5.0.0/16)", nil)), + + // Network in deletion + addDeletionTimestamp(testutil.FakeNetwork("net6", testNamespace, "10.6.0.0/16", nil)), + ).Build() + + ipamServer = &LiqoIPAM{ + Client: client, + IpamCore: ipamCore, + opts: &ServerOptions{ + GraphvizEnabled: false, + }, + } + }) + + It("should correctly list networks on cluster", func() { + nets, err := ipamServer.listNetworksOnCluster(ctx) + Expect(err).ToNot(HaveOccurred()) + Expect(nets).To(HaveLen(4)) + + Expect(nets).To(HaveKey(netip.MustParsePrefix("10.1.0.0/16"))) + Expect(nets).To(HaveKey(netip.MustParsePrefix("10.2.0.0/16"))) + Expect(nets).To(HaveKey(netip.MustParsePrefix("10.3.0.0/16"))) + Expect(nets).To(HaveKeyWithValue(netip.MustParsePrefix("10.4.0.0/16"), prefixDetails{10})) // network with preAllocated field + Expect(nets).ToNot(HaveKey(netip.MustParsePrefix(("10.5.0.0/16")))) // network with no status + Expect(nets).ToNot(HaveKey(netip.MustParsePrefix(("10.6.0.0/16")))) // network in deletion + }) + }) + +}) diff --git a/pkg/ipam/sync.go b/pkg/ipam/sync.go index 7bae8528b5..f1ae04ef1f 100644 --- a/pkg/ipam/sync.go +++ b/pkg/ipam/sync.go @@ -98,7 +98,7 @@ func syncNetworkFree(lipam *LiqoIPAM, clusterNetworks map[netip.Prefix]prefixDet func (lipam *LiqoIPAM) syncNetworks(ctx context.Context) error { // List all networks present in the cluster. - clusterNetworksMap, err := lipam.listNetworksOnCluster(ctx, lipam.Client) + clusterNetworksMap, err := lipam.listNetworksOnCluster(ctx) if err != nil { return err } @@ -155,12 +155,12 @@ func syncIPsFree(lipam *LiqoIPAM, clusterIPs, cachedIPs map[netip.Addr]netip.Pre func (lipam *LiqoIPAM) syncIPs(ctx context.Context) error { // List all IPs present in the cluster. - clusterIPsMap, err := lipam.listIPsOnCluster(ctx, lipam.Client) + clusterIPsMap, err := lipam.listIPsOnCluster(ctx) if err != nil { return err } - clusterNetworksMap, err := lipam.listNetworksOnCluster(ctx, lipam.Client) + clusterNetworksMap, err := lipam.listNetworksOnCluster(ctx) if err != nil { return err } diff --git a/pkg/ipam/sync_test.go b/pkg/ipam/sync_test.go index 1f36e20cb7..2a81241358 100644 --- a/pkg/ipam/sync_test.go +++ b/pkg/ipam/sync_test.go @@ -181,19 +181,19 @@ var _ = Describe("Sync routine tests", func() { newCreationTimestamp := time.Now().Add(-syncGracePeriod) // Check the cache before grace period - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.0"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.1"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.2"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(true)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.3"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.4"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.0"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.1"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.2"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(true)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.3"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.4"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) Expect(fakeIpamServer.syncIPs(ctx)).To(Succeed()) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.0"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.1"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.2"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.3"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.4"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.0"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.1"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.2"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.3"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.4"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) // Update the creation timestamp of the IPs Expect(fakeIpamServer.IpamCore.IPSetCreationTimestamp( @@ -209,11 +209,11 @@ var _ = Describe("Sync routine tests", func() { Expect(fakeIpamServer.syncIPs(ctx)).To(Succeed()) // Check the cache after grace period - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.0"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.1"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.2"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.3"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.4"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(true)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.0"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.1"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.2"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.3"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.4"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(true)) // Update the creation timestamp of the IPs Expect(fakeIpamServer.IpamCore.IPSetCreationTimestamp( @@ -223,11 +223,11 @@ var _ = Describe("Sync routine tests", func() { Expect(fakeIpamServer.syncIPs(ctx)).To(Succeed()) // Check the cache after grace period - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.0"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.1"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.2"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.3"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(true)) - Expect(fakeIpamServer.isIPAvailable(netip.MustParseAddr("10.0.0.4"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(true)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.0"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.1"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.2"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(false)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.3"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(true)) + Expect(fakeIpamServer.ipIsAvailable(netip.MustParseAddr("10.0.0.4"), netip.MustParsePrefix("10.0.0.0/24"))).To(Equal(true)) }) }) }) diff --git a/pkg/utils/testutil/consts.go b/pkg/utils/testutil/consts.go index 3db913695c..35237b9dbf 100644 --- a/pkg/utils/testutil/consts.go +++ b/pkg/utils/testutil/consts.go @@ -18,13 +18,13 @@ const ( // EndpointIP simulate a node or a load balancer IP. EndpointIP = "1.0.0.1" // PodCIDR is the CIDR of the pod network used for testing. - PodCIDR = "fake pod CIDR" + PodCIDR = "10.10.0.0/16" // ServiceCIDR is the CIDR of the service network used for testing. - ServiceCIDR = "fake service CIDR" + ServiceCIDR = "10.11.0.0/16" // ExternalCIDR is the external CIDR used for testing. - ExternalCIDR = "fake external CIDR" + ExternalCIDR = "10.12.0.0/16" // InternalCIDR is the internal CIDR used for testing. - InternalCIDR = "fake internal CIDR" + InternalCIDR = "10.13.0.0/16" // OverrideAPIAddress is the overrided address of the API server used for testing. OverrideAPIAddress = "1.0.0.2:6443" // ForeignAuthURL is the URL of the foreign cluster used for testing.