diff --git a/apis/ipam/v1alpha1/network_types.go b/apis/ipam/v1alpha1/network_types.go index 362ac6335a..b704173ce4 100644 --- a/apis/ipam/v1alpha1/network_types.go +++ b/apis/ipam/v1alpha1/network_types.go @@ -43,8 +43,8 @@ type NetworkSpec struct { // PreAllocated is the number of IPs to pre-allocate (reserve) in the CIDR, starting from the first IP. // +kubebuilder:validation:Optional // +kubebuilder:validation:Minimum=0 - // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Reserved field is immutable" - PreAllocated uint `json:"preAllocated"` + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="PreAllocated field is immutable" + PreAllocated uint32 `json:"preAllocated"` } // NetworkStatus defines the observed state of Network. diff --git a/cmd/liqo-controller-manager/main.go b/cmd/liqo-controller-manager/main.go index 8ea36a8a2c..3214430101 100644 --- a/cmd/liqo-controller-manager/main.go +++ b/cmd/liqo-controller-manager/main.go @@ -269,7 +269,7 @@ func main() { ipamClient = ipam.NewIPAMClient(conn) } - if err := modules.SetupNetworkingModule(mgr, &modules.NetworkingOption{ + if err := modules.SetupNetworkingModule(ctx, mgr, uncachedClient, &modules.NetworkingOption{ DynClient: dynClient, Factory: factory, diff --git a/cmd/liqo-controller-manager/modules/authentication.go b/cmd/liqo-controller-manager/modules/authentication.go index 5cae0f6046..47a1d80de6 100644 --- a/cmd/liqo-controller-manager/modules/authentication.go +++ b/cmd/liqo-controller-manager/modules/authentication.go @@ -61,6 +61,7 @@ func SetupAuthenticationModule(ctx context.Context, mgr manager.Manager, uncache } if err := enforceAuthenticationKeys(ctx, uncachedClient, opts.LiqoNamespace); err != nil { + klog.Errorf("Unable to enforce authentication keys: %v", err) return err } @@ -135,7 +136,7 @@ func SetupAuthenticationModule(ctx context.Context, mgr manager.Manager, uncache func enforceAuthenticationKeys(ctx context.Context, cl client.Client, liqoNamespace string) error { if err := authentication.InitClusterKeys(ctx, cl, liqoNamespace); err != nil { - klog.Errorf("Unable to initialize cluster authentication keys: %v", err) + return err } klog.Info("Enforced cluster authentication keys") diff --git a/cmd/liqo-controller-manager/modules/networking.go b/cmd/liqo-controller-manager/modules/networking.go index 6135df9ae1..10037a9675 100644 --- a/cmd/liqo-controller-manager/modules/networking.go +++ b/cmd/liqo-controller-manager/modules/networking.go @@ -15,10 +15,15 @@ package modules import ( + "context" + "fmt" + "k8s.io/client-go/dynamic" "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" "github.com/liqotech/liqo/pkg/ipam" clientoperator "github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/external-network/client-operator" configuration "github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/external-network/configuration" @@ -36,6 +41,7 @@ import ( ipctrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/ip-controller" networkctrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/networking/network-controller" dynamicutils "github.com/liqotech/liqo/pkg/utils/dynamic" + ipamutils "github.com/liqotech/liqo/pkg/utils/ipam" ) // NetworkingOption defines the options to setup the Networking module. @@ -59,7 +65,13 @@ type NetworkingOption struct { } // SetupNetworkingModule setup the networking module and initializes its controllers . -func SetupNetworkingModule(mgr manager.Manager, opts *NetworkingOption) error { +func SetupNetworkingModule(ctx context.Context, mgr manager.Manager, uncachedClient client.Client, opts *NetworkingOption) error { + // Initialize reserved networks + if err := initializeReservedNetworks(ctx, uncachedClient, opts.IpamClient); err != nil { + klog.Errorf("Unable to initialize reserved networks: %v", err) + return err + } + networkReconciler := networkctrl.NewNetworkReconciler(mgr.GetClient(), mgr.GetScheme(), opts.IpamClient) if err := networkReconciler.SetupWithManager(mgr, opts.NetworkWorkers); err != nil { klog.Errorf("Unable to start the networkReconciler: %v", err) @@ -209,3 +221,73 @@ func SetupNetworkingModule(mgr manager.Manager, opts *NetworkingOption) error { return nil } + +func initializeReservedNetworks(ctx context.Context, cl client.Client, ipamClient ipam.IPAMClient) error { + var networksToReserve []ipamv1alpha1.Network + + // PodCIDR is a special case of reserved network + podCidr, err := ipamutils.GetPodCIDRNetwork(ctx, cl) + if err != nil { + return err + } + networksToReserve = append(networksToReserve, *podCidr) + + // ServiceCIDR is a special case of reserved network + serviceCidr, err := ipamutils.GetServiceCIDRNetwork(ctx, cl) + if err != nil { + return err + } + networksToReserve = append(networksToReserve, *serviceCidr) + + // Get the reserved networks + reservedNetworks, err := ipamutils.GetReservedSubnetNetworks(ctx, cl) + if err != nil { + return err + } + networksToReserve = append(networksToReserve, reservedNetworks...) + + // Reserve the networks and fill their status CIDR. + for i := range networksToReserve { + nw := &networksToReserve[i] + + // If the status CIDR is already set, we do not need to reserve the network + // as it will be reserved when the ipam server is initialized. + if nw.Status.CIDR != "" { + continue + } + + if ipamClient == nil { + nw.Status.CIDR = nw.Spec.CIDR + } else { + // First check if the network is already reserved + res, err := ipamClient.NetworkIsAvailable(ctx, &ipam.NetworkAvailableRequest{ + Cidr: nw.Spec.CIDR.String(), + }) + if err != nil { + return err + } + + if res.Available { + // Network is not reserved, reserve it + _, err := ipamClient.NetworkAcquire(ctx, &ipam.NetworkAcquireRequest{ + Cidr: nw.Spec.CIDR.String(), + Immutable: true, + PreAllocated: nw.Spec.PreAllocated, + }) + if err != nil { + return err + } + } + + // Since reserved network must not be remapped (immutable), we can set the status CIDR to the spec CIDR + nw.Status.CIDR = nw.Spec.CIDR + } + + if err := cl.Status().Update(ctx, nw); err != nil { + return fmt.Errorf("unable to update the reserved network %s: %w", nw.Name, err) + } + } + + klog.Info("Reserved networks initialized") + return nil +} diff --git a/deployments/liqo/charts/liqo-crds/crds/ipam.liqo.io_networks.yaml b/deployments/liqo/charts/liqo-crds/crds/ipam.liqo.io_networks.yaml index b7567b8954..15a858592e 100644 --- a/deployments/liqo/charts/liqo-crds/crds/ipam.liqo.io_networks.yaml +++ b/deployments/liqo/charts/liqo-crds/crds/ipam.liqo.io_networks.yaml @@ -63,10 +63,11 @@ spec: preAllocated: description: PreAllocated is the number of IPs to pre-allocate (reserve) in the CIDR, starting from the first IP. + format: int32 minimum: 0 type: integer x-kubernetes-validations: - - message: Reserved field is immutable + - message: PreAllocated field is immutable rule: self == oldSelf required: - cidr diff --git a/deployments/liqo/templates/liqo-ipam-networks.yaml b/deployments/liqo/templates/liqo-ipam-networks.yaml index a0b96b89dd..cae42f4504 100644 --- a/deployments/liqo/templates/liqo-ipam-networks.yaml +++ b/deployments/liqo/templates/liqo-ipam-networks.yaml @@ -54,4 +54,5 @@ metadata: ipam.liqo.io/network-not-remapped: "true" spec: cidr: {{ $value }} +--- {{- end }} diff --git a/pkg/ipam/networks.go b/pkg/ipam/networks.go index f81fd592fa..78262ca891 100644 --- a/pkg/ipam/networks.go +++ b/pkg/ipam/networks.go @@ -98,9 +98,9 @@ func (lipam *LiqoIPAM) isNetworkAvailable(nw network) bool { if lipam.cacheNetworks == nil { return true } - _, ok := lipam.cacheNetworks[nw.String()] + _, exists := lipam.cacheNetworks[nw.String()] - return ok + return !exists } func listNetworksOnCluster(ctx context.Context, cl client.Client) ([]network, error) {