Skip to content

Commit

Permalink
PodCIDR and ExternalCIDR allocated as Network
Browse files Browse the repository at this point in the history
  • Loading branch information
fra98 committed Dec 5, 2023
1 parent 4ea4194 commit 64dc8d5
Show file tree
Hide file tree
Showing 11 changed files with 259 additions and 27 deletions.
5 changes: 5 additions & 0 deletions apis/ipam/v1alpha1/network_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ import (
v1alpha1networking "github.com/liqotech/liqo/apis/networking/v1alpha1"
)

const (
// NetworkLocalLabel is the label used to mark a Network intended to use locally to the cluster.
NetworkLocalLabel = "ipam.liqo.io/network-local"
)

var (
// NetworkKind is the kind name used to register the Network CRD.
NetworkKind = "Network"
Expand Down
71 changes: 65 additions & 6 deletions cmd/ipam/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@
package main

import (
"context"
"flag"
"fmt"
"os"

"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
Expand All @@ -31,9 +33,13 @@ import (
"k8s.io/client-go/tools/record"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/log"

ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1"
netv1alpha1 "github.com/liqotech/liqo/apis/net/v1alpha1"
networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1"
"github.com/liqotech/liqo/pkg/consts"
liqoipam "github.com/liqotech/liqo/pkg/ipam"
"github.com/liqotech/liqo/pkg/leaderelection"
Expand All @@ -42,12 +48,15 @@ import (
"github.com/liqotech/liqo/pkg/utils/restcfg"
)

const leaderElectorName = "liqo-ipam-leader-election"
const (
leaderElectorName = "liqo-ipam-leader-election"
)

var (
addToSchemeFunctions = []func(*runtime.Scheme) error{
clientgoscheme.AddToScheme,
netv1alpha1.AddToScheme,
ipamv1alpha1.AddToScheme,
}

options = liqoipam.NewOptions()
Expand All @@ -57,6 +66,7 @@ var (
// +kubebuilder:rbac:groups=core,resources=events,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=net.liqo.io,resources=ipamstorages,verbs=get;list;watch;create;update;patch
// +kubebuilder:rbac:groups=net.liqo.io,resources=natmappings,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=ipam.liqo.io,resources=networks,verbs=get;list;watch;create;update;patch;delete

func main() {
var cmd = cobra.Command{
Expand Down Expand Up @@ -84,6 +94,7 @@ func main() {
func run(_ *cobra.Command, _ []string) error {
var err error
scheme := runtime.NewScheme()
ctx := ctrl.SetupSignalHandler()

// Adds the APIs to the scheme.
for _, addToScheme := range addToSchemeFunctions {
Expand All @@ -101,12 +112,18 @@ func run(_ *cobra.Command, _ []string) error {
// Get dynamic client.
dynClient := dynamic.NewForConfigOrDie(cfg)

// Get controller-runtime client
cl, err := client.New(cfg, client.Options{Scheme: scheme})
if err != nil {
return fmt.Errorf("unable to create client: %w", err)
}

// Setup IPAM.
ipam := liqoipam.NewIPAM()

startIPAMServer := func() {
// Initialize and start IPAM server.
if err = initializeIPAM(ipam, options, dynClient); err != nil {
if err = initializeIPAM(ctx, ipam, options, dynClient, cl); err != nil {
klog.Errorf("Failed to initialize IPAM: %s", err)
os.Exit(1)
}
Expand All @@ -116,8 +133,6 @@ func run(_ *cobra.Command, _ []string) error {
ipam.Terminate()
}

ctx := ctrl.SetupSignalHandler()

// If the lease is disabled, start IPAM server without leader election mechanism (i.e., do not support IPAM high-availability).
if !options.LeaseEnabled {
startIPAMServer()
Expand Down Expand Up @@ -153,7 +168,7 @@ func run(_ *cobra.Command, _ []string) error {
return nil
}

func initializeIPAM(ipam *liqoipam.IPAM, opts *liqoipam.Options, dynClient dynamic.Interface) error {
func initializeIPAM(ctx context.Context, ipam *liqoipam.IPAM, opts *liqoipam.Options, dynClient dynamic.Interface, cl client.Client) error {
if ipam == nil {
return fmt.Errorf("IPAM pointer is nil. Initialize it before calling this function")
}
Expand All @@ -165,21 +180,65 @@ func initializeIPAM(ipam *liqoipam.IPAM, opts *liqoipam.Options, dynClient dynam
if err := ipam.SetPodCIDR(opts.PodCIDR.String()); err != nil {
return err
}
if err := createReservedNetwork(ctx, cl, "local-pod", consts.NetworkTypePodCIDR, opts.PodCIDR.String()); err != nil {
return err
}

if err := ipam.SetServiceCIDR(opts.ServiceCIDR.String()); err != nil {
return err
}
if err := createReservedNetwork(ctx, cl, "local-service", consts.NetworkTypeServiceCIDR, opts.ServiceCIDR.String()); err != nil {
return err
}

for _, pool := range opts.AdditionalPools.StringList.StringList {
if err := ipam.AddNetworkPool(pool); err != nil {
return err
}
if err := createReservedNetwork(ctx, cl, fmt.Sprintf("pool-%s", pool), consts.NetworkTypePool, pool); err != nil {
return err
}
}

if err := ipam.SetReservedSubnets(opts.ReservedPools.StringList.StringList); err != nil {
return err
}
for _, pool := range opts.ReservedPools.StringList.StringList {
if err := createReservedNetwork(ctx, cl, fmt.Sprintf("reserved-%s", pool), consts.NetworkTypeReservedSubnet, pool); err != nil {
return err
}
}

externalCIDR, err := ipam.GetExternalCIDR(liqonetutils.GetMask(options.PodCIDR.String()))
if err != nil {
return err
}
if err := createReservedNetwork(ctx, cl, "local-external", consts.NetworkTypeExternalCIDR, externalCIDR); err != nil {
return err
}

return nil
}

func createReservedNetwork(ctx context.Context, cl client.Client, name, networkType, cidr string) error {
network := &ipamv1alpha1.Network{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: os.Getenv("POD_NAMESPACE"),
},
}

if _, err := ipam.GetExternalCIDR(liqonetutils.GetMask(options.PodCIDR.String())); err != nil {
if _, err := controllerutil.CreateOrUpdate(ctx, cl, network, func() error {
if network.Labels == nil {
network.Labels = map[string]string{}
}
network.Labels[ipamv1alpha1.NetworkLocalLabel] = networkType

network.Spec = ipamv1alpha1.NetworkSpec{
CIDR: networkingv1alpha1.CIDR(cidr),
}
return nil
}); err != nil {
return err
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,14 +359,6 @@ rules:
- patch
- update
- watch
- apiGroups:
- net.liqo.io
resources:
- ipamstorages
verbs:
- get
- list
- watch
- apiGroups:
- net.liqo.io
resources:
Expand Down
12 changes: 12 additions & 0 deletions deployments/liqo/files/liqo-ipam-ClusterRole.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ rules:
- patch
- update
- watch
- apiGroups:
- ipam.liqo.io
resources:
- networks
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- net.liqo.io
resources:
Expand Down
10 changes: 10 additions & 0 deletions pkg/consts/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,14 @@ package consts
const (
// IpamPort is the port used by the IPAM gRPC server.
IpamPort = 6000
// NetworkTypePodCIDR is the constant representing a network of type podCIDR.
NetworkTypePodCIDR = "pod-cidr"
// NetworkTypeServiceCIDR is the constant representing a network of type serviceCIDR.
NetworkTypeServiceCIDR = "service-cidr"
// NetworkTypeExternalCIDR is the constant representing a network of type externalCIDR.
NetworkTypeExternalCIDR = "external-cidr"
// NetworkTypePool is the constant representing a network of type pool.
NetworkTypePool = "pool"
// NetworkTypeReservedSubnet is the constant representing a network of type reserved subnet.
NetworkTypeReservedSubnet = "reserved-subnet"
)
7 changes: 3 additions & 4 deletions pkg/ipam/ipam.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,9 +378,8 @@ func (liqoIPAM *IPAM) clusterSubnetEqualToPool(pool string) (string, error) {
return mappedNetwork, nil
}

// MapNetworkCIDR receives a network CIDR and a cluster identifier and,
// return the network CIDR to use for the remote cluster, remapped if
// necessary.
// MapNetworkCIDR receives a network CIDR and return the network CIDR to use for the remote cluster,
// remapped if necessary.
func (liqoIPAM *IPAM) MapNetworkCIDR(_ context.Context, mapCIDRRequest *MapCIDRRequest) (*MapCIDRResponse, error) {
mappedCIDR, err := liqoIPAM.getOrRemapNetwork(mapCIDRRequest.GetCidr())
if err != nil {
Expand All @@ -389,7 +388,7 @@ func (liqoIPAM *IPAM) MapNetworkCIDR(_ context.Context, mapCIDRRequest *MapCIDRR
return &MapCIDRResponse{Cidr: mappedCIDR}, nil
}

// UnmapNetworkCIDR set the network CIDR as unused for a specific cluster.
// UnmapNetworkCIDR set the network CIDR as unused.
func (liqoIPAM *IPAM) UnmapNetworkCIDR(_ context.Context, unmapCIDRRequest *UnmapCIDRRequest) (*UnmapCIDRResponse, error) {
err := liqoIPAM.FreeReservedSubnet(unmapCIDRRequest.GetCidr())
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"fmt"

apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/record"
"k8s.io/klog/v2"
Expand All @@ -29,7 +28,7 @@ import (
ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1"
networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1"
"github.com/liqotech/liqo/pkg/utils/events"
liqogetters "github.com/liqotech/liqo/pkg/utils/getters"
ipamutils "github.com/liqotech/liqo/pkg/utils/ipam"
)

// ConfigurationReconciler manage Configuration lifecycle.
Expand Down Expand Up @@ -57,7 +56,6 @@ func NewConfigurationReconciler(cl client.Client, s *runtime.Scheme, er record.E
// +kubebuilder:rbac:groups=networking.liqo.io,resources=configurations/status,verbs=get;list;watch;update;patch
// +kubebuilder:rbac:groups=ipam.liqo.io,resources=networks,verbs=get;list;watch;create
// +kubebuilder:rbac:groups=ipam.liqo.io,resources=networks/status,verbs=get;list;watch
// +kubebuilder:rbac:groups=net.liqo.io,resources=ipamstorages,verbs=get;list;watch

// Reconcile manage Configurations, remapping cidrs with Networks resources.
func (r *ConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
Expand Down Expand Up @@ -99,14 +97,19 @@ func (r *ConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.Reques

func (r *ConfigurationReconciler) defaultLocalNetwork(ctx context.Context, cfg *networkingv1alpha1.Configuration) error {
if r.localCIDR == nil {
ipamStorage, err := liqogetters.GetIPAMStorageByLabel(ctx, r.Client, labels.NewSelector())
podCIDR, err := ipamutils.RetrievePodCIDR(ctx, r.Client)
if err != nil {
return fmt.Errorf("unable to get IPAM storage: %w", err)
return fmt.Errorf("unable to retrieve the podCIDR: %w", err)
}

externalCIDR, err := ipamutils.RetrieveExternalCIDR(ctx, r.Client)
if err != nil {
return fmt.Errorf("unable to retrieve the externalCIDR: %w", err)
}

r.localCIDR = &networkingv1alpha1.ClusterConfigCIDR{
Pod: networkingv1alpha1.CIDR(ipamStorage.Spec.PodCIDR),
External: networkingv1alpha1.CIDR(ipamStorage.Spec.ExternalCIDR),
Pod: networkingv1alpha1.CIDR(podCIDR),
External: networkingv1alpha1.CIDR(externalCIDR),
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@ func (r *NetworkReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct

desiredCIDR = nw.Spec.CIDR

_, localNetwork := nw.Labels[ipamv1alpha1.NetworkLocalLabel]
if localNetwork {
nw.Status.CIDR = desiredCIDR
if err := r.Status().Update(ctx, &nw); err != nil {
klog.Errorf("error while updating Network %q status: %v", req.NamespacedName, err)
return ctrl.Result{}, err
}
klog.Infof("updated Network %q status (spec: %s -> status: %s)", req.NamespacedName, nw.Spec.CIDR, nw.Status.CIDR)
return ctrl.Result{}, nil
}

if nw.GetDeletionTimestamp().IsZero() {
if !controllerutil.ContainsFinalizer(&nw, ipamNetworkFinalizer) {
// Add finalizer to prevent deletion without unmapping the Network.
Expand Down Expand Up @@ -135,7 +146,7 @@ func (r *NetworkReconciler) SetupWithManager(mgr ctrl.Manager, workers int) erro
Complete(r)
}

// getRemappedCIDR returns the remapped CIDR for the given CIDR and remote clusterID.
// getRemappedCIDR returns the remapped CIDR for the given CIDR.
func getRemappedCIDR(ctx context.Context, ipamClient ipam.IpamClient, desiredCIDR networkingv1alpha1.CIDR) (networkingv1alpha1.CIDR, error) {
switch ipamClient.(type) {
case nil:
Expand All @@ -153,7 +164,7 @@ func getRemappedCIDR(ctx context.Context, ipamClient ipam.IpamClient, desiredCID
}
}

// deleteRemappedCIDR unmaps the CIDR for the given remote clusterID.
// deleteRemappedCIDR unmaps the given CIDR.
func deleteRemappedCIDR(ctx context.Context, ipamClient ipam.IpamClient, remappedCIDR networkingv1alpha1.CIDR) error {
switch ipamClient.(type) {
case nil:
Expand Down
27 changes: 27 additions & 0 deletions pkg/utils/getters/k8sGetters.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,3 +397,30 @@ func GetGatewayClientByClusterID(ctx context.Context, cl client.Client,
return nil, fmt.Errorf("multiple GatewayClients found for ForeignCluster %s", clusterID)
}
}

// RetrieveUniqueNetworkByLabel retrieves the Network resource with the given label selector.
// It returns error if multiple resources are found.
func RetrieveUniqueNetworkByLabel(ctx context.Context, cl client.Client, lSelector labels.Selector) (*ipamv1alpha1.Network, error) {
networks, err := RetrieveNetworksByLabel(ctx, cl, lSelector)
if err != nil {
return nil, err
}

switch len(networks.Items) {
case 0:
return nil, kerrors.NewNotFound(ipamv1alpha1.NetworkGroupResource, ipamv1alpha1.NetworkResource)
case 1:
return &networks.Items[0], nil
default:
return nil, fmt.Errorf("multiple Network resources found for label selector %q", lSelector)
}
}

// RetrieveNetworksByLabel retrieves the Network resources with the given labelSelector.
func RetrieveNetworksByLabel(ctx context.Context, cl client.Client, lSelector labels.Selector) (*ipamv1alpha1.NetworkList, error) {
var networks ipamv1alpha1.NetworkList
if err := cl.List(ctx, &networks, &client.ListOptions{LabelSelector: lSelector}); err != nil {
return nil, err
}
return &networks, nil
}
16 changes: 16 additions & 0 deletions pkg/utils/ipam/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2019-2023 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 contains utility functions to deal with resources of the IPAM API.
package ipam
Loading

0 comments on commit 64dc8d5

Please sign in to comment.