From 239dba0925d06c5b6a633847c6c3f9241e8a8ff7 Mon Sep 17 00:00:00 2001 From: Francesco Torta <62566275+fra98@users.noreply.github.com> Date: Fri, 1 Dec 2023 11:55:10 +0100 Subject: [PATCH] PodCIDR, ServiceCIDR, ExternalCIDR, ReservedCIDRs as Networks --- cmd/ipam/main.go | 10 +- cmd/liqo-controller-manager/main.go | 12 +- cmd/liqoctl/main.go | 2 + cmd/liqonet/network-manager.go | 8 +- deployments/liqo/README.md | 1 + .../liqo-controller-manager-ClusterRole.yaml | 8 - .../liqo/templates/liqo-ipam-networks.yaml | 52 ++++ deployments/liqo/values.yaml | 2 + pkg/consts/ipam.go | 19 ++ pkg/ipam/fake/ipam.go | 6 + pkg/ipam/ipam.go | 55 ++++- pkg/ipam/ipam.pb.go | 225 ++++++++++++++---- pkg/ipam/ipam.proto | 11 +- pkg/ipam/ipam_grpc.pb.go | 49 +++- pkg/ipam/ipam_test.go | 8 +- .../configuration_controller.go | 17 +- .../ip-controller/ip_controller.go | 38 ++- .../network-controller/network_controller.go | 164 +++++++++---- pkg/liqoctl/rest/configuration/create.go | 35 +-- pkg/liqoctl/rest/configuration/utils.go | 49 +++- pkg/utils/getters/k8sGetters.go | 27 +++ pkg/utils/ipam/doc.go | 16 ++ pkg/utils/ipam/networks.go | 153 ++++++++++++ test/integration/integration_suite_test.go | 9 +- 24 files changed, 794 insertions(+), 182 deletions(-) create mode 100644 deployments/liqo/templates/liqo-ipam-networks.yaml create mode 100644 pkg/utils/ipam/doc.go create mode 100644 pkg/utils/ipam/networks.go diff --git a/cmd/ipam/main.go b/cmd/ipam/main.go index 5b56f15cab..42a030d2e1 100644 --- a/cmd/ipam/main.go +++ b/cmd/ipam/main.go @@ -37,7 +37,6 @@ import ( "github.com/liqotech/liqo/pkg/consts" liqoipam "github.com/liqotech/liqo/pkg/ipam" "github.com/liqotech/liqo/pkg/leaderelection" - liqonetutils "github.com/liqotech/liqo/pkg/liqonet/utils" flagsutils "github.com/liqotech/liqo/pkg/utils/flags" "github.com/liqotech/liqo/pkg/utils/restcfg" ) @@ -158,28 +157,33 @@ func initializeIPAM(ipam *liqoipam.IPAM, opts *liqoipam.Options, dynClient dynam return fmt.Errorf("IPAM pointer is nil. Initialize it before calling this function") } - if err := ipam.Init(liqoipam.Pools, dynClient, consts.IpamPort); err != nil { + if err := ipam.Init(liqoipam.Pools, dynClient); err != nil { return err } + // Configure PodCIDR if err := ipam.SetPodCIDR(opts.PodCIDR.String()); err != nil { return err } + + // Configure ServiceCIDR if err := ipam.SetServiceCIDR(opts.ServiceCIDR.String()); err != nil { return err } + // Configure additional network pools. for _, pool := range opts.AdditionalPools.StringList.StringList { if err := ipam.AddNetworkPool(pool); err != nil { return err } } + // Configure reserved subnets. if err := ipam.SetReservedSubnets(opts.ReservedPools.StringList.StringList); err != nil { return err } - if _, err := ipam.GetExternalCIDR(liqonetutils.GetMask(options.PodCIDR.String())); err != nil { + if err := ipam.Serve(consts.IpamPort); err != nil { return err } diff --git a/cmd/liqo-controller-manager/main.go b/cmd/liqo-controller-manager/main.go index 3c20c76753..67f6804b45 100644 --- a/cmd/liqo-controller-manager/main.go +++ b/cmd/liqo-controller-manager/main.go @@ -675,21 +675,13 @@ func main() { } if !*disableInternalNetwork { - networkReconciler := &networkctrl.NetworkReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - IpamClient: ipamClient, - } + networkReconciler := networkctrl.NewNetworkReconciler(mgr.GetClient(), mgr.GetScheme(), ipamClient) if err = networkReconciler.SetupWithManager(mgr, *networkWorkers); err != nil { klog.Errorf("Unable to start the networkReconciler", err) os.Exit(1) } - ipReconciler := &ipctrl.IPReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - IpamClient: ipamClient, - } + ipReconciler := ipctrl.NewIPReconciler(mgr.GetClient(), mgr.GetScheme(), ipamClient) if err = ipReconciler.SetupWithManager(ctx, mgr, *ipWorkers); err != nil { klog.Errorf("Unable to start the ipReconciler", err) os.Exit(1) diff --git a/cmd/liqoctl/main.go b/cmd/liqoctl/main.go index e3f62d9bff..4fe3f9b840 100644 --- a/cmd/liqoctl/main.go +++ b/cmd/liqoctl/main.go @@ -25,6 +25,7 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth" discoveryv1alpha1 "github.com/liqotech/liqo/apis/discovery/v1alpha1" + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" netv1alpha1 "github.com/liqotech/liqo/apis/net/v1alpha1" networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" offloadingv1alpha1 "github.com/liqotech/liqo/apis/offloading/v1alpha1" @@ -40,6 +41,7 @@ func init() { utilruntime.Must(sharingv1alpha1.AddToScheme(scheme.Scheme)) utilruntime.Must(virtualkubeletv1alpha1.AddToScheme(scheme.Scheme)) utilruntime.Must(networkingv1alpha1.AddToScheme(scheme.Scheme)) + utilruntime.Must(ipamv1alpha1.AddToScheme(scheme.Scheme)) } func main() { diff --git a/cmd/liqonet/network-manager.go b/cmd/liqonet/network-manager.go index 96efac84b8..1bc2b889d6 100644 --- a/cmd/liqonet/network-manager.go +++ b/cmd/liqonet/network-manager.go @@ -30,7 +30,7 @@ import ( "github.com/liqotech/liqo/internal/liqonet/network-manager/netcfgcreator" "github.com/liqotech/liqo/internal/liqonet/network-manager/tunnelendpointcreator" - liqoconst "github.com/liqotech/liqo/pkg/consts" + "github.com/liqotech/liqo/pkg/consts" liqoipam "github.com/liqotech/liqo/pkg/ipam" liqonetutils "github.com/liqotech/liqo/pkg/liqonet/utils" "github.com/liqotech/liqo/pkg/utils/args" @@ -132,7 +132,7 @@ func runNetworkManager(commonFlags *liqonetCommonFlags, managerFlags *networkMan func initializeIPAM(dynClient dynamic.Interface, managerFlags *networkManagerFlags) (*liqoipam.IPAM, error) { ipam := liqoipam.NewIPAM() - if err := ipam.Init(liqoipam.Pools, dynClient, liqoconst.IpamPort); err != nil { + if err := ipam.Init(liqoipam.Pools, dynClient); err != nil { return nil, err } @@ -153,5 +153,9 @@ func initializeIPAM(dynClient dynamic.Interface, managerFlags *networkManagerFla return nil, err } + if err := ipam.Serve(consts.IpamPort); err != nil { + return nil, err + } + return ipam, nil } diff --git a/deployments/liqo/README.md b/deployments/liqo/README.md index c47183282d..dc583eaac9 100644 --- a/deployments/liqo/README.md +++ b/deployments/liqo/README.md @@ -102,6 +102,7 @@ | ipam.additionalPools | list | `[]` | Set of additional network pools to perform the automatic address mapping in Liqo. Network pools are used to map a cluster network into another one in order to prevent conflicts. Default set of network pools is: [10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12] | | ipam.external.enabled | bool | `false` | Use an external IPAM to allocate the IP addresses for the pods. Enabling it will disable the internal IPAM. | | ipam.external.url | string | `""` | The URL of the external IPAM. | +| ipam.externalCIDR | string | `""` | The subnet used for the external CIDR. If empty, the default value (10.70.0.0/16) is used. | | ipam.internal.enabled | bool | `true` | Use the default Liqo IPAM. | | ipam.internal.image.name | string | `"ghcr.io/liqotech/ipam"` | Image repository for the IPAM pod. | | ipam.internal.image.version | string | `""` | Custom version for the IPAM image. If not specified, the global tag is used. | diff --git a/deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml b/deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml index 7c0f86845a..caea1add1c 100644 --- a/deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml +++ b/deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml @@ -359,14 +359,6 @@ rules: - patch - update - watch -- apiGroups: - - net.liqo.io - resources: - - ipamstorages - verbs: - - get - - list - - watch - apiGroups: - net.liqo.io resources: diff --git a/deployments/liqo/templates/liqo-ipam-networks.yaml b/deployments/liqo/templates/liqo-ipam-networks.yaml new file mode 100644 index 0000000000..10705bad60 --- /dev/null +++ b/deployments/liqo/templates/liqo-ipam-networks.yaml @@ -0,0 +1,52 @@ +{{- $ipamConfig := (merge (dict "name" "ipam" "module" "ipam") .) -}} +--- +apiVersion: ipam.liqo.io/v1alpha1 +kind: Network +metadata: + name: pod-cidr + labels: + {{- include "liqo.labels" $ipamConfig | nindent 4 }} + ipam.liqo.io/network-type: pod-cidr + ipam.liqo.io/network-not-remapped: "true" +spec: + cidr: {{ .Values.ipam.podCIDR }} +--- +apiVersion: ipam.liqo.io/v1alpha1 +kind: Network +metadata: + name: service-cidr + labels: + {{- include "liqo.labels" $ipamConfig | nindent 4 }} + ipam.liqo.io/network-type: service-cidr + ipam.liqo.io/network-not-remapped: "true" +spec: + cidr: {{ .Values.ipam.serviceCIDR }} +--- +apiVersion: ipam.liqo.io/v1alpha1 +kind: Network +metadata: + name: external-cidr + labels: + {{- include "liqo.labels" $ipamConfig | nindent 4 }} + ipam.liqo.io/network-type: external-cidr +spec: + {{- if .Values.ipam.externalCIDR }} + cidr: {{ .Values.ipam.externalCIDR }} + {{- else }} + cidr: 10.70.0.0/16 + {{- end }} +--- +{{- range $i, $value := .Values.ipam.reservedSubnets }} +apiVersion: ipam.liqo.io/v1alpha1 +kind: Network +metadata: + name: reserved-{{ add $i 1 }} + labels: + {{- include "liqo.labels" $ipamConfig | nindent 4 }} + ipam.liqo.io/network-type: reserved + ipam.liqo.io/network-not-remapped: "true" +spec: + cidr: {{ $value }} +--- +{{- end }} + diff --git a/deployments/liqo/values.yaml b/deployments/liqo/values.yaml index faebbe624b..70eb2a3f3d 100644 --- a/deployments/liqo/values.yaml +++ b/deployments/liqo/values.yaml @@ -204,6 +204,8 @@ ipam: podCIDR: "" # -- The subnet used by the services in you cluster, in CIDR notation (e.g., 172.16.0.0/16). serviceCIDR: "" + # -- The subnet used for the external CIDR. If empty, the default value (10.70.0.0/16) is used. + externalCIDR: "" # -- List of IP subnets that do not have to be used by Liqo. # Liqo can perform automatic IP address remapping when a remote cluster is peering with you, e.g., in case IP address spaces (e.g., PodCIDR) overlaps. # In order to prevent IP conflicting between locally used private subnets in your infrastructure and private subnets belonging to remote clusters diff --git a/pkg/consts/ipam.go b/pkg/consts/ipam.go index aa6845b521..4b3c998769 100644 --- a/pkg/consts/ipam.go +++ b/pkg/consts/ipam.go @@ -14,7 +14,26 @@ package consts +// NetworkType indicates the type of Network. +type NetworkType string + const ( // IpamPort is the port used by the IPAM gRPC server. IpamPort = 6000 + + // NetworkNotRemappedLabelKey is the label key used to mark a Network that does not need CIDR remapping. + NetworkNotRemappedLabelKey = "ipam.liqo.io/network-not-remapped" + // NetworkNotRemappedLabelValue is the label value used to mark a Network that does not need CIDR remapping. + NetworkNotRemappedLabelValue = "true" + + // NetworkTypeLabelKey is the label key used to indicate the type of a Network. + NetworkTypeLabelKey = "ipam.liqo.io/network-type" + // NetworkTypePodCIDR is the constant representing a network of type podCIDR. + NetworkTypePodCIDR NetworkType = "pod-cidr" + // NetworkTypeServiceCIDR is the constant representing a network of type serviceCIDR. + NetworkTypeServiceCIDR NetworkType = "service-cidr" + // NetworkTypeExternalCIDR is the constant representing a network of type externalCIDR. + NetworkTypeExternalCIDR NetworkType = "external-cidr" + // NetworkTypeReserved is the constant representing a network of type reserved subnet. + NetworkTypeReserved NetworkType = "reserved" ) diff --git a/pkg/ipam/fake/ipam.go b/pkg/ipam/fake/ipam.go index 017d214900..acfd51b2cf 100644 --- a/pkg/ipam/fake/ipam.go +++ b/pkg/ipam/fake/ipam.go @@ -115,3 +115,9 @@ func (mock *IPAMClient) MapNetworkCIDR(_ context.Context, req *ipam.MapCIDRReque func (mock *IPAMClient) UnmapNetworkCIDR(_ context.Context, _ *ipam.UnmapCIDRRequest, _ ...grpc.CallOption) (*ipam.UnmapCIDRResponse, error) { return &ipam.UnmapCIDRResponse{}, nil } + +// GetOrSetExternalCIDR mocks the corresponding IPAMClient function. +func (mock *IPAMClient) GetOrSetExternalCIDR(_ context.Context, req *ipam.GetOrSetExtCIDRRequest, + _ ...grpc.CallOption) (*ipam.GetOrSetExtCIDRResponse, error) { + return &ipam.GetOrSetExtCIDRResponse{RemappedExtCIDR: req.DesiredExtCIDR}, nil +} diff --git a/pkg/ipam/ipam.go b/pkg/ipam/ipam.go index 77fa9e8f95..4abf04d97d 100644 --- a/pkg/ipam/ipam.go +++ b/pkg/ipam/ipam.go @@ -67,6 +67,7 @@ type Ipam interface { this function must not reserve it. If the remote cluster has not remapped a local subnet, then CIDR value should be equal to "None". */ AddLocalSubnetsPerCluster(podCIDR, externalCIDR, clusterID string) error + // GetExternalCIDR chooses and returns the local cluster's ExternalCIDR. GetExternalCIDR(mask uint8) (string, error) // SetPodCIDR sets the cluster PodCIDR. SetPodCIDR(podCIDR string) error @@ -104,7 +105,7 @@ var Pools = []string{ const emptyCIDR = "" // Init uses the Ipam resource to retrieve and allocate reserved networks. -func (liqoIPAM *IPAM) Init(pools []string, dynClient dynamic.Interface, listeningPort int) error { +func (liqoIPAM *IPAM) Init(pools []string, dynClient dynamic.Interface) error { var err error // Set up storage liqoIPAM.ipamStorage, err = NewIPAMStorage(dynClient) @@ -130,17 +131,26 @@ func (liqoIPAM *IPAM) Init(pools []string, dynClient dynamic.Interface, listenin return fmt.Errorf("cannot set pools: %w", err) } } - if listeningPort > 0 { - err = liqoIPAM.initRPCServer(listeningPort) - if err != nil { - return fmt.Errorf("cannot start gRPC server: %w", err) - } - } liqoIPAM.natMappingInflater = natmappinginflater.NewInflater(dynClient) return nil } +// Serve starts the gRPC server. +func (liqoIPAM *IPAM) Serve(listeningPort int) error { + if listeningPort <= 0 { + return fmt.Errorf("IPAM gRPC server not started: invalid listening port %d", listeningPort) + } + + if err := liqoIPAM.initRPCServer(listeningPort); err != nil { + return fmt.Errorf("cannot start gRPC server: %w", err) + } + + klog.Infof("IPAM gRPC server listening on port %d", listeningPort) + + return nil +} + // Terminate function stops the gRPC server. func (liqoIPAM *IPAM) Terminate() { // Stop GRPC server @@ -378,9 +388,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 { @@ -389,7 +398,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 { @@ -398,6 +407,28 @@ func (liqoIPAM *IPAM) UnmapNetworkCIDR(_ context.Context, unmapCIDRRequest *Unma return &UnmapCIDRResponse{}, nil } +// GetOrSetExternalCIDR get or set the external CIDR (eventually remapped) for the cluster. +func (liqoIPAM *IPAM) GetOrSetExternalCIDR(_ context.Context, getOrSetExtCIDRRequest *GetOrSetExtCIDRRequest) (*GetOrSetExtCIDRResponse, error) { + // Get cluster externalCIDR if already set + externalCIDR := liqoIPAM.ipamStorage.getExternalCIDR() + if externalCIDR != "" { + return &GetOrSetExtCIDRResponse{RemappedExtCIDR: externalCIDR}, nil + } + + // ExternalCIDR is not set: allocate a new network (eventually remapped if conflicts are found) + externalCIDR, err := liqoIPAM.getOrRemapNetwork(getOrSetExtCIDRRequest.GetDesiredExtCIDR()) + if err != nil { + return &GetOrSetExtCIDRResponse{}, fmt.Errorf("cannot map external CIDR %s: %w", getOrSetExtCIDRRequest.GetDesiredExtCIDR(), err) + } + + // Update ipamstorage with the new external CIDR + if err := liqoIPAM.ipamStorage.updateExternalCIDR(externalCIDR); err != nil { + _ = liqoIPAM.FreeReservedSubnet(externalCIDR) + return &GetOrSetExtCIDRResponse{}, fmt.Errorf("cannot update external CIDR in the ipam storage: %w", err) + } + return &GetOrSetExtCIDRResponse{RemappedExtCIDR: externalCIDR}, nil +} + // getOrRemapNetwork first tries to acquire the received network. // If conflicts are found, a new mapped network is returned. func (liqoIPAM *IPAM) getOrRemapNetwork(network string) (string, error) { @@ -1160,7 +1191,7 @@ func (liqoIPAM *IPAM) mapEndpointIPInternal(clusterID, ip string) (string, error // MapEndpointIP receives a service endpoint IP and a cluster identifier and, // if the endpoint IP does not belong to cluster PodCIDR, maps // the endpoint IP to a new IP taken from the remote ExternalCIDR of the remote cluster. -func (liqoIPAM *IPAM) MapEndpointIP(ctx context.Context, mapRequest *MapRequest) (*MapResponse, error) { +func (liqoIPAM *IPAM) MapEndpointIP(_ context.Context, mapRequest *MapRequest) (*MapResponse, error) { mappedIP, err := liqoIPAM.mapEndpointIPInternal(mapRequest.GetClusterID(), mapRequest.GetIp()) if err != nil { return &MapResponse{}, fmt.Errorf("cannot map endpoint IP to ExternalCIDR of cluster %s, %w", diff --git a/pkg/ipam/ipam.pb.go b/pkg/ipam/ipam.pb.go index 8992704d44..348228f8c0 100644 --- a/pkg/ipam/ipam.pb.go +++ b/pkg/ipam/ipam.pb.go @@ -591,6 +591,100 @@ func (x *BelongsResponse) GetBelongs() bool { return false } +type GetOrSetExtCIDRRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DesiredExtCIDR string `protobuf:"bytes,1,opt,name=desiredExtCIDR,proto3" json:"desiredExtCIDR,omitempty"` +} + +func (x *GetOrSetExtCIDRRequest) Reset() { + *x = GetOrSetExtCIDRRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_ipam_ipam_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetOrSetExtCIDRRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetOrSetExtCIDRRequest) ProtoMessage() {} + +func (x *GetOrSetExtCIDRRequest) ProtoReflect() protoreflect.Message { + mi := &file_pkg_ipam_ipam_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetOrSetExtCIDRRequest.ProtoReflect.Descriptor instead. +func (*GetOrSetExtCIDRRequest) Descriptor() ([]byte, []int) { + return file_pkg_ipam_ipam_proto_rawDescGZIP(), []int{12} +} + +func (x *GetOrSetExtCIDRRequest) GetDesiredExtCIDR() string { + if x != nil { + return x.DesiredExtCIDR + } + return "" +} + +type GetOrSetExtCIDRResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RemappedExtCIDR string `protobuf:"bytes,1,opt,name=remappedExtCIDR,proto3" json:"remappedExtCIDR,omitempty"` +} + +func (x *GetOrSetExtCIDRResponse) Reset() { + *x = GetOrSetExtCIDRResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_ipam_ipam_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetOrSetExtCIDRResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetOrSetExtCIDRResponse) ProtoMessage() {} + +func (x *GetOrSetExtCIDRResponse) ProtoReflect() protoreflect.Message { + mi := &file_pkg_ipam_ipam_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetOrSetExtCIDRResponse.ProtoReflect.Descriptor instead. +func (*GetOrSetExtCIDRResponse) Descriptor() ([]byte, []int) { + return file_pkg_ipam_ipam_proto_rawDescGZIP(), []int{13} +} + +func (x *GetOrSetExtCIDRResponse) GetRemappedExtCIDR() string { + if x != nil { + return x.RemappedExtCIDR + } + return "" +} + var File_pkg_ipam_ipam_proto protoreflect.FileDescriptor var file_pkg_ipam_ipam_proto_rawDesc = []byte{ @@ -626,29 +720,42 @@ var file_pkg_ipam_ipam_proto_rawDesc = []byte{ 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x2b, 0x0a, 0x0f, 0x42, 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x32, 0xc8, 0x02, - 0x0a, 0x04, 0x69, 0x70, 0x61, 0x6d, 0x12, 0x2a, 0x0a, 0x0d, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x64, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x49, 0x50, 0x12, 0x0b, 0x2e, 0x4d, 0x61, 0x70, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x4d, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x30, 0x0a, 0x0f, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x45, 0x6e, 0x64, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x49, 0x50, 0x12, 0x0d, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x43, 0x49, 0x44, 0x52, 0x12, 0x0f, 0x2e, 0x4d, 0x61, 0x70, 0x43, 0x49, 0x44, 0x52, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x4d, 0x61, 0x70, 0x43, 0x49, 0x44, - 0x52, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x10, 0x55, 0x6e, 0x6d, - 0x61, 0x70, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x43, 0x49, 0x44, 0x52, 0x12, 0x11, 0x2e, - 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x43, 0x49, 0x44, 0x52, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x12, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x43, 0x49, 0x44, 0x52, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x6d, 0x65, 0x50, - 0x6f, 0x64, 0x49, 0x50, 0x12, 0x14, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x6d, 0x65, 0x50, 0x6f, - 0x64, 0x49, 0x50, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x47, 0x65, 0x74, - 0x48, 0x6f, 0x6d, 0x65, 0x50, 0x6f, 0x64, 0x49, 0x50, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x35, 0x0a, 0x10, 0x42, 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x54, 0x6f, 0x50, 0x6f, - 0x64, 0x43, 0x49, 0x44, 0x52, 0x12, 0x0f, 0x2e, 0x42, 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x42, 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x69, 0x70, - 0x61, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x62, 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x22, 0x40, 0x0a, + 0x16, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x53, 0x65, 0x74, 0x45, 0x78, 0x74, 0x43, 0x49, 0x44, 0x52, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x64, 0x65, 0x73, 0x69, 0x72, + 0x65, 0x64, 0x45, 0x78, 0x74, 0x43, 0x49, 0x44, 0x52, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0e, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x45, 0x78, 0x74, 0x43, 0x49, 0x44, 0x52, 0x22, + 0x43, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x53, 0x65, 0x74, 0x45, 0x78, 0x74, 0x43, 0x49, + 0x44, 0x52, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, + 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x45, 0x78, 0x74, 0x43, 0x49, 0x44, 0x52, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x45, 0x78, 0x74, + 0x43, 0x49, 0x44, 0x52, 0x32, 0x93, 0x03, 0x0a, 0x04, 0x69, 0x70, 0x61, 0x6d, 0x12, 0x2a, 0x0a, + 0x0d, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x49, 0x50, 0x12, 0x0b, + 0x2e, 0x4d, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x4d, 0x61, + 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x0f, 0x55, 0x6e, 0x6d, + 0x61, 0x70, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x49, 0x50, 0x12, 0x0d, 0x2e, 0x55, + 0x6e, 0x6d, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x55, 0x6e, + 0x6d, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0e, 0x4d, + 0x61, 0x70, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x43, 0x49, 0x44, 0x52, 0x12, 0x0f, 0x2e, + 0x4d, 0x61, 0x70, 0x43, 0x49, 0x44, 0x52, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, + 0x2e, 0x4d, 0x61, 0x70, 0x43, 0x49, 0x44, 0x52, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x39, 0x0a, 0x10, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x43, 0x49, 0x44, 0x52, 0x12, 0x11, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x43, 0x49, 0x44, 0x52, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x43, + 0x49, 0x44, 0x52, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x47, + 0x65, 0x74, 0x48, 0x6f, 0x6d, 0x65, 0x50, 0x6f, 0x64, 0x49, 0x50, 0x12, 0x14, 0x2e, 0x47, 0x65, + 0x74, 0x48, 0x6f, 0x6d, 0x65, 0x50, 0x6f, 0x64, 0x49, 0x50, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x15, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x6d, 0x65, 0x50, 0x6f, 0x64, 0x49, 0x50, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x10, 0x42, 0x65, 0x6c, 0x6f, + 0x6e, 0x67, 0x73, 0x54, 0x6f, 0x50, 0x6f, 0x64, 0x43, 0x49, 0x44, 0x52, 0x12, 0x0f, 0x2e, 0x42, + 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, + 0x42, 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x49, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x53, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x43, 0x49, 0x44, 0x52, 0x12, 0x17, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x53, + 0x65, 0x74, 0x45, 0x78, 0x74, 0x43, 0x49, 0x44, 0x52, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x18, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x53, 0x65, 0x74, 0x45, 0x78, 0x74, 0x43, 0x49, + 0x44, 0x52, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, + 0x69, 0x70, 0x61, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -663,20 +770,22 @@ func file_pkg_ipam_ipam_proto_rawDescGZIP() []byte { return file_pkg_ipam_ipam_proto_rawDescData } -var file_pkg_ipam_ipam_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_pkg_ipam_ipam_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_pkg_ipam_ipam_proto_goTypes = []interface{}{ - (*MapRequest)(nil), // 0: MapRequest - (*MapResponse)(nil), // 1: MapResponse - (*UnmapRequest)(nil), // 2: UnmapRequest - (*UnmapResponse)(nil), // 3: UnmapResponse - (*MapCIDRRequest)(nil), // 4: MapCIDRRequest - (*MapCIDRResponse)(nil), // 5: MapCIDRResponse - (*UnmapCIDRRequest)(nil), // 6: UnmapCIDRRequest - (*UnmapCIDRResponse)(nil), // 7: UnmapCIDRResponse - (*GetHomePodIPRequest)(nil), // 8: GetHomePodIPRequest - (*GetHomePodIPResponse)(nil), // 9: GetHomePodIPResponse - (*BelongsRequest)(nil), // 10: BelongsRequest - (*BelongsResponse)(nil), // 11: BelongsResponse + (*MapRequest)(nil), // 0: MapRequest + (*MapResponse)(nil), // 1: MapResponse + (*UnmapRequest)(nil), // 2: UnmapRequest + (*UnmapResponse)(nil), // 3: UnmapResponse + (*MapCIDRRequest)(nil), // 4: MapCIDRRequest + (*MapCIDRResponse)(nil), // 5: MapCIDRResponse + (*UnmapCIDRRequest)(nil), // 6: UnmapCIDRRequest + (*UnmapCIDRResponse)(nil), // 7: UnmapCIDRResponse + (*GetHomePodIPRequest)(nil), // 8: GetHomePodIPRequest + (*GetHomePodIPResponse)(nil), // 9: GetHomePodIPResponse + (*BelongsRequest)(nil), // 10: BelongsRequest + (*BelongsResponse)(nil), // 11: BelongsResponse + (*GetOrSetExtCIDRRequest)(nil), // 12: GetOrSetExtCIDRRequest + (*GetOrSetExtCIDRResponse)(nil), // 13: GetOrSetExtCIDRResponse } var file_pkg_ipam_ipam_proto_depIdxs = []int32{ 0, // 0: ipam.MapEndpointIP:input_type -> MapRequest @@ -685,14 +794,16 @@ var file_pkg_ipam_ipam_proto_depIdxs = []int32{ 6, // 3: ipam.UnmapNetworkCIDR:input_type -> UnmapCIDRRequest 8, // 4: ipam.GetHomePodIP:input_type -> GetHomePodIPRequest 10, // 5: ipam.BelongsToPodCIDR:input_type -> BelongsRequest - 1, // 6: ipam.MapEndpointIP:output_type -> MapResponse - 3, // 7: ipam.UnmapEndpointIP:output_type -> UnmapResponse - 5, // 8: ipam.MapNetworkCIDR:output_type -> MapCIDRResponse - 7, // 9: ipam.UnmapNetworkCIDR:output_type -> UnmapCIDRResponse - 9, // 10: ipam.GetHomePodIP:output_type -> GetHomePodIPResponse - 11, // 11: ipam.BelongsToPodCIDR:output_type -> BelongsResponse - 6, // [6:12] is the sub-list for method output_type - 0, // [0:6] is the sub-list for method input_type + 12, // 6: ipam.GetOrSetExternalCIDR:input_type -> GetOrSetExtCIDRRequest + 1, // 7: ipam.MapEndpointIP:output_type -> MapResponse + 3, // 8: ipam.UnmapEndpointIP:output_type -> UnmapResponse + 5, // 9: ipam.MapNetworkCIDR:output_type -> MapCIDRResponse + 7, // 10: ipam.UnmapNetworkCIDR:output_type -> UnmapCIDRResponse + 9, // 11: ipam.GetHomePodIP:output_type -> GetHomePodIPResponse + 11, // 12: ipam.BelongsToPodCIDR:output_type -> BelongsResponse + 13, // 13: ipam.GetOrSetExternalCIDR:output_type -> GetOrSetExtCIDRResponse + 7, // [7:14] is the sub-list for method output_type + 0, // [0:7] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name @@ -848,6 +959,30 @@ func file_pkg_ipam_ipam_proto_init() { return nil } } + file_pkg_ipam_ipam_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetOrSetExtCIDRRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_ipam_ipam_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetOrSetExtCIDRResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -855,7 +990,7 @@ func file_pkg_ipam_ipam_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_pkg_ipam_ipam_proto_rawDesc, NumEnums: 0, - NumMessages: 12, + NumMessages: 14, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/ipam/ipam.proto b/pkg/ipam/ipam.proto index 924e97f5d5..f6221386f6 100644 --- a/pkg/ipam/ipam.proto +++ b/pkg/ipam/ipam.proto @@ -8,6 +8,7 @@ service ipam { rpc UnmapNetworkCIDR (UnmapCIDRRequest) returns (UnmapCIDRResponse); rpc GetHomePodIP (GetHomePodIPRequest) returns (GetHomePodIPResponse); rpc BelongsToPodCIDR (BelongsRequest) returns (BelongsResponse); + rpc GetOrSetExternalCIDR(GetOrSetExtCIDRRequest) returns (GetOrSetExtCIDRResponse); } message MapRequest { @@ -55,4 +56,12 @@ message BelongsRequest { message BelongsResponse { bool belongs = 1; -} \ No newline at end of file +} + +message GetOrSetExtCIDRRequest { + string desiredExtCIDR = 1; +} + +message GetOrSetExtCIDRResponse { + string remappedExtCIDR = 1; +} diff --git a/pkg/ipam/ipam_grpc.pb.go b/pkg/ipam/ipam_grpc.pb.go index e2e85df2f3..a7ccfe7e62 100644 --- a/pkg/ipam/ipam_grpc.pb.go +++ b/pkg/ipam/ipam_grpc.pb.go @@ -20,12 +20,13 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - Ipam_MapEndpointIP_FullMethodName = "/ipam/MapEndpointIP" - Ipam_UnmapEndpointIP_FullMethodName = "/ipam/UnmapEndpointIP" - Ipam_MapNetworkCIDR_FullMethodName = "/ipam/MapNetworkCIDR" - Ipam_UnmapNetworkCIDR_FullMethodName = "/ipam/UnmapNetworkCIDR" - Ipam_GetHomePodIP_FullMethodName = "/ipam/GetHomePodIP" - Ipam_BelongsToPodCIDR_FullMethodName = "/ipam/BelongsToPodCIDR" + Ipam_MapEndpointIP_FullMethodName = "/ipam/MapEndpointIP" + Ipam_UnmapEndpointIP_FullMethodName = "/ipam/UnmapEndpointIP" + Ipam_MapNetworkCIDR_FullMethodName = "/ipam/MapNetworkCIDR" + Ipam_UnmapNetworkCIDR_FullMethodName = "/ipam/UnmapNetworkCIDR" + Ipam_GetHomePodIP_FullMethodName = "/ipam/GetHomePodIP" + Ipam_BelongsToPodCIDR_FullMethodName = "/ipam/BelongsToPodCIDR" + Ipam_GetOrSetExternalCIDR_FullMethodName = "/ipam/GetOrSetExternalCIDR" ) // IpamClient is the client API for Ipam service. @@ -38,6 +39,7 @@ type IpamClient interface { UnmapNetworkCIDR(ctx context.Context, in *UnmapCIDRRequest, opts ...grpc.CallOption) (*UnmapCIDRResponse, error) GetHomePodIP(ctx context.Context, in *GetHomePodIPRequest, opts ...grpc.CallOption) (*GetHomePodIPResponse, error) BelongsToPodCIDR(ctx context.Context, in *BelongsRequest, opts ...grpc.CallOption) (*BelongsResponse, error) + GetOrSetExternalCIDR(ctx context.Context, in *GetOrSetExtCIDRRequest, opts ...grpc.CallOption) (*GetOrSetExtCIDRResponse, error) } type ipamClient struct { @@ -102,6 +104,15 @@ func (c *ipamClient) BelongsToPodCIDR(ctx context.Context, in *BelongsRequest, o return out, nil } +func (c *ipamClient) GetOrSetExternalCIDR(ctx context.Context, in *GetOrSetExtCIDRRequest, opts ...grpc.CallOption) (*GetOrSetExtCIDRResponse, error) { + out := new(GetOrSetExtCIDRResponse) + err := c.cc.Invoke(ctx, Ipam_GetOrSetExternalCIDR_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // IpamServer is the server API for Ipam service. // All implementations must embed UnimplementedIpamServer // for forward compatibility @@ -112,6 +123,7 @@ type IpamServer interface { UnmapNetworkCIDR(context.Context, *UnmapCIDRRequest) (*UnmapCIDRResponse, error) GetHomePodIP(context.Context, *GetHomePodIPRequest) (*GetHomePodIPResponse, error) BelongsToPodCIDR(context.Context, *BelongsRequest) (*BelongsResponse, error) + GetOrSetExternalCIDR(context.Context, *GetOrSetExtCIDRRequest) (*GetOrSetExtCIDRResponse, error) mustEmbedUnimplementedIpamServer() } @@ -137,6 +149,9 @@ func (UnimplementedIpamServer) GetHomePodIP(context.Context, *GetHomePodIPReques func (UnimplementedIpamServer) BelongsToPodCIDR(context.Context, *BelongsRequest) (*BelongsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method BelongsToPodCIDR not implemented") } +func (UnimplementedIpamServer) GetOrSetExternalCIDR(context.Context, *GetOrSetExtCIDRRequest) (*GetOrSetExtCIDRResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetOrSetExternalCIDR not implemented") +} func (UnimplementedIpamServer) mustEmbedUnimplementedIpamServer() {} // UnsafeIpamServer may be embedded to opt out of forward compatibility for this service. @@ -258,6 +273,24 @@ func _Ipam_BelongsToPodCIDR_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } +func _Ipam_GetOrSetExternalCIDR_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetOrSetExtCIDRRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IpamServer).GetOrSetExternalCIDR(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Ipam_GetOrSetExternalCIDR_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IpamServer).GetOrSetExternalCIDR(ctx, req.(*GetOrSetExtCIDRRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Ipam_ServiceDesc is the grpc.ServiceDesc for Ipam service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -289,6 +322,10 @@ var Ipam_ServiceDesc = grpc.ServiceDesc{ MethodName: "BelongsToPodCIDR", Handler: _Ipam_BelongsToPodCIDR_Handler, }, + { + MethodName: "GetOrSetExternalCIDR", + Handler: _Ipam_GetOrSetExternalCIDR_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "pkg/ipam/ipam.proto", diff --git a/pkg/ipam/ipam_test.go b/pkg/ipam/ipam_test.go index 60e6ee8adb..302bc3e6de 100644 --- a/pkg/ipam/ipam_test.go +++ b/pkg/ipam/ipam_test.go @@ -135,7 +135,9 @@ var _ = Describe("Ipam", func() { Expect(err).To(BeNil()) n, err := rand.Int(rand.Reader, big.NewInt(10000)) Expect(err).To(BeNil()) - err = ipam.Init(Pools, dynClient, 2000+int(n.Int64())) + err = ipam.Init(Pools, dynClient) + Expect(err).To(BeNil()) + err = ipam.Serve(2000 + int(n.Int64())) Expect(err).To(BeNil()) }) AfterEach(func() { @@ -621,7 +623,9 @@ var _ = Describe("Ipam", func() { ipam = NewIPAM() n, err := rand.Int(rand.Reader, big.NewInt(2000)) Expect(err).To(BeNil()) - err = ipam.Init(Pools, dynClient, 2000+int(n.Int64())) + err = ipam.Init(Pools, dynClient) + Expect(err).To(BeNil()) + err = ipam.Serve(2000 + int(n.Int64())) Expect(err).To(BeNil()) // Another cluster asks for the same networks diff --git a/pkg/liqo-controller-manager/external-network/configuration-controller/configuration_controller.go b/pkg/liqo-controller-manager/external-network/configuration-controller/configuration_controller.go index 5155d3c07b..a2f34a6852 100644 --- a/pkg/liqo-controller-manager/external-network/configuration-controller/configuration_controller.go +++ b/pkg/liqo-controller-manager/external-network/configuration-controller/configuration_controller.go @@ -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" @@ -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. @@ -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) { @@ -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), } } diff --git a/pkg/liqo-controller-manager/ip-controller/ip_controller.go b/pkg/liqo-controller-manager/ip-controller/ip_controller.go index 5ec49faae8..e448804ede 100644 --- a/pkg/liqo-controller-manager/ip-controller/ip_controller.go +++ b/pkg/liqo-controller-manager/ip-controller/ip_controller.go @@ -37,6 +37,7 @@ import ( virtualkubeletv1alpha1 "github.com/liqotech/liqo/apis/virtualkubelet/v1alpha1" "github.com/liqotech/liqo/pkg/ipam" "github.com/liqotech/liqo/pkg/utils/getters" + ipamutils "github.com/liqotech/liqo/pkg/utils/ipam" ) const ( @@ -46,8 +47,21 @@ const ( // IPReconciler reconciles a IP object. type IPReconciler struct { client.Client - Scheme *runtime.Scheme - IpamClient ipam.IpamClient + Scheme *runtime.Scheme + + ipamClient ipam.IpamClient + externalCIDRSet bool +} + +// NewIPReconciler returns a new IPReconciler. +func NewIPReconciler(cl client.Client, s *runtime.Scheme, ipamClient ipam.IpamClient) *IPReconciler { + return &IPReconciler{ + Client: cl, + Scheme: s, + + ipamClient: ipamClient, + externalCIDRSet: false, + } } // +kubebuilder:rbac:groups=ipam.liqo.io,resources=ips,verbs=get;list;watch;create;update;patch;delete @@ -72,6 +86,20 @@ func (r *IPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Re return ctrl.Result{}, err } + if !r.externalCIDRSet { + // Retrieve the externalCIDR of the local cluster + _, err := ipamutils.RetrieveExternalCIDR(ctx, r.Client) + if apierrors.IsNotFound(err) { + klog.Errorf("ExternalCIDR is not set yet. Configure it to correctly handle IP mappings") + return ctrl.Result{}, err + } else if err != nil { + klog.Errorf("error while retrieving externalCIDR: %v", err) + return ctrl.Result{}, err + } + // The external CIDR is set, we do not need to check it again in successive reconciliations. + r.externalCIDRSet = true + } + desiredIP = ip.Spec.IP // Get the clusterIDs of all remote clusters @@ -180,7 +208,7 @@ func (r *IPReconciler) forgeIPMappings(ctx context.Context, clusterIDs []string, // multiple times by checking if the IP for that remote cluster is already set. _, found := ip.Status.IPMappings[*remoteClusterID] if !found { - remappedIP, err := getRemappedIP(ctx, r.IpamClient, *remoteClusterID, desiredIP) + remappedIP, err := getRemappedIP(ctx, r.ipamClient, *remoteClusterID, desiredIP) if err != nil { return false, err } @@ -194,7 +222,7 @@ func (r *IPReconciler) forgeIPMappings(ctx context.Context, clusterIDs []string, if !slices.Contains(clusterIDs, entry) { // We ignore eventual errors from the IPAM because the entries in the NatMappaings and IpamStorage for that cluster // may have been already removed. - _ = deleteRemappedIP(ctx, r.IpamClient, entry, desiredIP) + _ = deleteRemappedIP(ctx, r.ipamClient, entry, desiredIP) delete(ip.Status.IPMappings, entry) needUpdate = true } @@ -207,7 +235,7 @@ func (r *IPReconciler) forgeIPMappings(ctx context.Context, clusterIDs []string, func (r *IPReconciler) handleDelete(ctx context.Context, clusterIDs []string, desiredIP networkingv1alpha1.IP, ip *ipamv1alpha1.IP) error { for i := range clusterIDs { remoteClusterID := &clusterIDs[i] - if err := deleteRemappedIP(ctx, r.IpamClient, *remoteClusterID, desiredIP); err != nil { + if err := deleteRemappedIP(ctx, r.ipamClient, *remoteClusterID, desiredIP); err != nil { return err } delete(ip.Status.IPMappings, *remoteClusterID) diff --git a/pkg/liqo-controller-manager/network-controller/network_controller.go b/pkg/liqo-controller-manager/network-controller/network_controller.go index ceb2c26bb7..d32248738b 100644 --- a/pkg/liqo-controller-manager/network-controller/network_controller.go +++ b/pkg/liqo-controller-manager/network-controller/network_controller.go @@ -29,6 +29,7 @@ import ( ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" "github.com/liqotech/liqo/pkg/ipam" + ipamutils "github.com/liqotech/liqo/pkg/utils/ipam" ) const ( @@ -38,8 +39,19 @@ const ( // NetworkReconciler reconciles a Network object. type NetworkReconciler struct { client.Client - Scheme *runtime.Scheme - IpamClient ipam.IpamClient + Scheme *runtime.Scheme + + ipamClient ipam.IpamClient +} + +// NewNetworkReconciler returns a new NetworkReconciler. +func NewNetworkReconciler(cl client.Client, s *runtime.Scheme, ipamClient ipam.IpamClient) *NetworkReconciler { + return &NetworkReconciler{ + Client: cl, + Scheme: s, + + ipamClient: ipamClient, + } } // +kubebuilder:rbac:groups=ipam.liqo.io,resources=networks,verbs=get;list;watch;create;update;patch;delete @@ -50,7 +62,6 @@ type NetworkReconciler struct { // Reconcile Network objects. func (r *NetworkReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { var nw ipamv1alpha1.Network - var desiredCIDR, remappedCIDR networkingv1alpha1.CIDR // Fetch the Network instance if err := r.Get(ctx, req.NamespacedName, &nw); err != nil { @@ -62,80 +73,153 @@ func (r *NetworkReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct return ctrl.Result{}, err } - desiredCIDR = nw.Spec.CIDR + switch { + case ipamutils.NetworkNotRemapped(&nw): + if err := r.handleNetworkNotRemappedStatus(ctx, &nw); err != nil { + return ctrl.Result{}, err + } + case ipamutils.IsExternalCIDR(&nw): + if err := r.handleNetworkExternalCIDRStatus(ctx, &nw); err != nil { + return ctrl.Result{}, err + } + default: + if err := r.handleNetworkStatus(ctx, &nw); err != nil { + return ctrl.Result{}, err + } + } + return ctrl.Result{}, nil +} + +// SetupWithManager monitors Network resources. +func (r *NetworkReconciler) SetupWithManager(mgr ctrl.Manager, workers int) error { + return ctrl.NewControllerManagedBy(mgr). + For(&ipamv1alpha1.Network{}). + WithOptions(controller.Options{MaxConcurrentReconciles: workers}). + Complete(r) +} + +// handleNetworkNotRemapped handles the status of a Network resource that does not need CIDR remapping. +func (r *NetworkReconciler) handleNetworkNotRemappedStatus(ctx context.Context, nw *ipamv1alpha1.Network) error { + nw.Status.CIDR = nw.Spec.CIDR // set the status to the desired CIDR. + if err := r.Status().Update(ctx, nw); err != nil { + klog.Errorf("error while updating Network %q status: %v", client.ObjectKeyFromObject(nw), err) + return err + } + klog.V(4).Infof("updated Network %q status (spec: %s -> status: %s)", client.ObjectKeyFromObject(nw), nw.Spec.CIDR, nw.Status.CIDR) + return nil +} + +// handleNetworkExternalCIDR handles the status of a Network resource of type ExternalCIDR. +func (r *NetworkReconciler) handleNetworkExternalCIDRStatus(ctx context.Context, nw *ipamv1alpha1.Network) error { if nw.GetDeletionTimestamp().IsZero() { - if !controllerutil.ContainsFinalizer(&nw, ipamNetworkFinalizer) { + // Update Network status if it is not set yet. + // The external CIDR can't change after it is set, so we avoid to call it + // multiple times by checking if the status is already set. + if nw.Status.CIDR == "" { + desiredCIDR := nw.Spec.CIDR + remappedCIDR, err := getOrSetExternalCIDR(ctx, r.ipamClient, desiredCIDR) + if err != nil { + return err + } + + // Update status + nw.Status.CIDR = remappedCIDR + if err := r.Client.Status().Update(ctx, nw); err != nil { + klog.Errorf("error while updating Network %q status: %v", client.ObjectKeyFromObject(nw), err) + return err + } + klog.Infof("updated Network %q status (spec: %s -> status: %s)", client.ObjectKeyFromObject(nw), desiredCIDR, remappedCIDR) + } + } + + return nil +} + +// getExternalCIDR returns the remapped external CIDR for the given CIDR. +func getOrSetExternalCIDR(ctx context.Context, ipamClient ipam.IpamClient, desiredCIDR networkingv1alpha1.CIDR) (networkingv1alpha1.CIDR, error) { + switch ipamClient.(type) { + case nil: + // IPAM is not enabled, use original CIDR from spec + return desiredCIDR, nil + default: + // interact with the IPAM to retrieve the correct mapping. + response, err := ipamClient.GetOrSetExternalCIDR(ctx, &ipam.GetOrSetExtCIDRRequest{DesiredExtCIDR: desiredCIDR.String()}) + if err != nil { + klog.Errorf("IPAM: error while mapping network external CIDR %s: %v", desiredCIDR, err) + return "", err + } + klog.Infof("IPAM: mapped network external CIDR %s to %s", desiredCIDR, response.RemappedExtCIDR) + return networkingv1alpha1.CIDR(response.RemappedExtCIDR), nil + } +} + +// handleNetworkStatus handles the status of a Network resource. +func (r *NetworkReconciler) handleNetworkStatus(ctx context.Context, nw *ipamv1alpha1.Network) error { + if nw.GetDeletionTimestamp().IsZero() { + if !controllerutil.ContainsFinalizer(nw, ipamNetworkFinalizer) { // Add finalizer to prevent deletion without unmapping the Network. - controllerutil.AddFinalizer(&nw, ipamNetworkFinalizer) + controllerutil.AddFinalizer(nw, ipamNetworkFinalizer) // Update the Network object - if err := r.Update(ctx, &nw); err != nil { - klog.Errorf("error while adding finalizers to Network %q: %v", req.NamespacedName, err) - return ctrl.Result{}, err + if err := r.Update(ctx, nw); err != nil { + klog.Errorf("error while adding finalizers to Network %q: %v", client.ObjectKeyFromObject(nw), err) + return err } - klog.Infof("finalizer %q correctly added to Network %q", ipamNetworkFinalizer, req.NamespacedName) + klog.Infof("finalizer %q correctly added to Network %q", ipamNetworkFinalizer, client.ObjectKeyFromObject(nw)) // We return immediately and wait for the next reconcile to eventually update the status. - return ctrl.Result{}, nil + return nil } // Update Network status if it is not set yet // The IPAM MapNetworkCIDR() function is not idempotent, so we avoid to call it // multiple times by checking if the status is already set. if nw.Status.CIDR == "" { - var err error - remappedCIDR, err = getRemappedCIDR(ctx, r.IpamClient, desiredCIDR) + desiredCIDR := nw.Spec.CIDR + remappedCIDR, err := getRemappedCIDR(ctx, r.ipamClient, desiredCIDR) if err != nil { - return ctrl.Result{}, err + return err } // Update status nw.Status.CIDR = remappedCIDR - if err := r.Client.Status().Update(ctx, &nw); err != nil { - klog.Errorf("error while updating Network %q status: %v", req.NamespacedName, err) - return ctrl.Result{}, err + if err := r.Client.Status().Update(ctx, nw); err != nil { + klog.Errorf("error while updating Network %q status: %v", client.ObjectKeyFromObject(nw), err) + return err } - klog.Infof("updated Network %q status (spec: %s -> status: %s)", req.NamespacedName, desiredCIDR, remappedCIDR) + klog.Infof("updated Network %q status (spec: %s -> status: %s)", client.ObjectKeyFromObject(nw), desiredCIDR, remappedCIDR) } - } else if controllerutil.ContainsFinalizer(&nw, ipamNetworkFinalizer) { + } else if controllerutil.ContainsFinalizer(nw, ipamNetworkFinalizer) { // The resource is being deleted and the finalizer is still present. Call the IPAM to unmap the network CIDR. - remappedCIDR = nw.Status.CIDR + remappedCIDR := nw.Status.CIDR if remappedCIDR != "" { if _, _, err := net.ParseCIDR(remappedCIDR.String()); err != nil { - klog.Errorf("Unable to unmap CIDR %s of Network %q (inavlid format): %v", remappedCIDR, req.NamespacedName, err) - return ctrl.Result{}, err + klog.Errorf("Unable to unmap CIDR %s of Network %q (inavlid format): %v", remappedCIDR, client.ObjectKeyFromObject(nw), err) + return err } - if err := deleteRemappedCIDR(ctx, r.IpamClient, remappedCIDR); err != nil { - return ctrl.Result{}, err + if err := deleteRemappedCIDR(ctx, r.ipamClient, remappedCIDR); err != nil { + return err } } // Remove status and finalizer, and update the object. nw.Status.CIDR = "" - controllerutil.RemoveFinalizer(&nw, ipamNetworkFinalizer) + controllerutil.RemoveFinalizer(nw, ipamNetworkFinalizer) - if err := r.Update(ctx, &nw); err != nil { - klog.Errorf("error while removing finalizer from Network %q: %v", req.NamespacedName, err) - return ctrl.Result{}, err + if err := r.Update(ctx, nw); err != nil { + klog.Errorf("error while removing finalizer from Network %q: %v", client.ObjectKeyFromObject(nw), err) + return err } - klog.Infof("finalizer correctly removed from Network %q", req.NamespacedName) + klog.Infof("finalizer correctly removed from Network %q", client.ObjectKeyFromObject(nw)) } - return ctrl.Result{}, nil -} - -// SetupWithManager monitors Network resources. -func (r *NetworkReconciler) SetupWithManager(mgr ctrl.Manager, workers int) error { - return ctrl.NewControllerManagedBy(mgr). - For(&ipamv1alpha1.Network{}). - WithOptions(controller.Options{MaxConcurrentReconciles: workers}). - Complete(r) + return nil } -// 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: @@ -153,7 +237,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: diff --git a/pkg/liqoctl/rest/configuration/create.go b/pkg/liqoctl/rest/configuration/create.go index bb80df8166..cb4153eb81 100644 --- a/pkg/liqoctl/rest/configuration/create.go +++ b/pkg/liqoctl/rest/configuration/create.go @@ -21,7 +21,6 @@ import ( "time" "github.com/spf13/cobra" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" @@ -29,7 +28,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" - liqoconsts "github.com/liqotech/liqo/pkg/consts" "github.com/liqotech/liqo/pkg/liqoctl/completion" "github.com/liqotech/liqo/pkg/liqoctl/output" "github.com/liqotech/liqo/pkg/liqoctl/rest" @@ -90,7 +88,7 @@ func (o *Options) Create(ctx context.Context, options *rest.CreateOptions) *cobr func (o *Options) handleCreate(ctx context.Context) error { opts := o.createOptions - conf := forgeConfiguration(o.createOptions.Name, o.createOptions.Namespace, + conf := ForgeConfiguration(o.createOptions.Name, o.createOptions.Namespace, o.RemoteClusterID, o.PodCIDR.String(), o.ExternalCIDR.String()) if opts.OutputFormat != "" { @@ -100,7 +98,7 @@ func (o *Options) handleCreate(ctx context.Context) error { s := opts.Printer.StartSpinner("Creating configuration") _, err := controllerutil.CreateOrUpdate(ctx, opts.CRClient, conf, func() error { - mutateConfiguration(conf, o.RemoteClusterID, o.PodCIDR.String(), o.ExternalCIDR.String()) + MutateConfiguration(conf, o.RemoteClusterID, o.PodCIDR.String(), o.ExternalCIDR.String()) return nil }) if err != nil { @@ -133,35 +131,6 @@ func (o *Options) handleCreate(ctx context.Context) error { return nil } -func forgeConfiguration(name, namespace, remoteClusterID, podCIDR, externalCIDR string) *networkingv1alpha1.Configuration { - conf := &networkingv1alpha1.Configuration{ - TypeMeta: metav1.TypeMeta{ - Kind: networkingv1alpha1.ConfigurationKind, - APIVersion: networkingv1alpha1.GroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - Labels: map[string]string{ - liqoconsts.RemoteClusterID: remoteClusterID, - }, - }, - } - mutateConfiguration(conf, remoteClusterID, podCIDR, externalCIDR) - return conf -} - -func mutateConfiguration(conf *networkingv1alpha1.Configuration, remoteClusterID, podCIDR, externalCIDR string) { - conf.Kind = networkingv1alpha1.ConfigurationKind - conf.APIVersion = networkingv1alpha1.GroupVersion.String() - if conf.Labels == nil { - conf.Labels = make(map[string]string) - } - conf.Labels[liqoconsts.RemoteClusterID] = remoteClusterID - conf.Spec.Remote.CIDR.Pod = networkingv1alpha1.CIDR(podCIDR) - conf.Spec.Remote.CIDR.External = networkingv1alpha1.CIDR(externalCIDR) -} - // output implements the logic to output the generated Configuration resource. func (o *Options) output(conf *networkingv1alpha1.Configuration) error { var outputFormat string diff --git a/pkg/liqoctl/rest/configuration/utils.go b/pkg/liqoctl/rest/configuration/utils.go index b9f2ad6cf6..2b7604da95 100644 --- a/pkg/liqoctl/rest/configuration/utils.go +++ b/pkg/liqoctl/rest/configuration/utils.go @@ -20,7 +20,6 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -28,10 +27,41 @@ import ( networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" liqoconsts "github.com/liqotech/liqo/pkg/consts" liqoutils "github.com/liqotech/liqo/pkg/utils" - liqogetters "github.com/liqotech/liqo/pkg/utils/getters" + ipamutils "github.com/liqotech/liqo/pkg/utils/ipam" ) -// ForgeConfigurationForRemoteCluster forges a configuration of the local cluster to be applied to a remote cluster. +// ForgeConfiguration forges a Configuration resource of a remote cluster. +func ForgeConfiguration(name, namespace, remoteClusterID, podCIDR, externalCIDR string) *networkingv1alpha1.Configuration { + conf := &networkingv1alpha1.Configuration{ + TypeMeta: metav1.TypeMeta{ + Kind: networkingv1alpha1.ConfigurationKind, + APIVersion: networkingv1alpha1.GroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + Labels: map[string]string{ + liqoconsts.RemoteClusterID: remoteClusterID, + }, + }, + } + MutateConfiguration(conf, remoteClusterID, podCIDR, externalCIDR) + return conf +} + +// MutateConfiguration mutates a Configuration resource of a remote cluster. +func MutateConfiguration(conf *networkingv1alpha1.Configuration, remoteClusterID, podCIDR, externalCIDR string) { + conf.Kind = networkingv1alpha1.ConfigurationKind + conf.APIVersion = networkingv1alpha1.GroupVersion.String() + if conf.Labels == nil { + conf.Labels = make(map[string]string) + } + conf.Labels[liqoconsts.RemoteClusterID] = remoteClusterID + conf.Spec.Remote.CIDR.Pod = networkingv1alpha1.CIDR(podCIDR) + conf.Spec.Remote.CIDR.External = networkingv1alpha1.CIDR(externalCIDR) +} + +// ForgeConfigurationForRemoteCluster forges a Configuration of the local cluster to be applied to a remote cluster. // It retrieves the local configuration settings starting from the cluster identity and the IPAM storage. func ForgeConfigurationForRemoteCluster(ctx context.Context, cl client.Client, namespace, liqoNamespace string) (*networkingv1alpha1.Configuration, error) { @@ -40,9 +70,14 @@ func ForgeConfigurationForRemoteCluster(ctx context.Context, cl client.Client, return nil, fmt.Errorf("unable to get cluster identity: %w", err) } - ipamStorage, err := liqogetters.GetIPAMStorageByLabel(ctx, cl, labels.NewSelector()) + podCIDR, err := ipamutils.RetrievePodCIDR(ctx, cl) + if err != nil { + return nil, fmt.Errorf("unable to retrieve pod CIDR: %w", err) + } + + externalCIDR, err := ipamutils.RetrieveExternalCIDR(ctx, cl) if err != nil { - return nil, fmt.Errorf("unable to get IPAM storage: %w", err) + return nil, fmt.Errorf("unable to retrieve external CIDR: %w", err) } cnf := &networkingv1alpha1.Configuration{ @@ -59,8 +94,8 @@ func ForgeConfigurationForRemoteCluster(ctx context.Context, cl client.Client, Spec: networkingv1alpha1.ConfigurationSpec{ Remote: networkingv1alpha1.ClusterConfig{ CIDR: networkingv1alpha1.ClusterConfigCIDR{ - Pod: networkingv1alpha1.CIDR(ipamStorage.Spec.PodCIDR), - External: networkingv1alpha1.CIDR(ipamStorage.Spec.ExternalCIDR), + Pod: networkingv1alpha1.CIDR(podCIDR), + External: networkingv1alpha1.CIDR(externalCIDR), }, }, }, diff --git a/pkg/utils/getters/k8sGetters.go b/pkg/utils/getters/k8sGetters.go index 771a01c947..3034ba783f 100644 --- a/pkg/utils/getters/k8sGetters.go +++ b/pkg/utils/getters/k8sGetters.go @@ -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 +} diff --git a/pkg/utils/ipam/doc.go b/pkg/utils/ipam/doc.go new file mode 100644 index 0000000000..14ee963514 --- /dev/null +++ b/pkg/utils/ipam/doc.go @@ -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 diff --git a/pkg/utils/ipam/networks.go b/pkg/utils/ipam/networks.go new file mode 100644 index 0000000000..911444fdfa --- /dev/null +++ b/pkg/utils/ipam/networks.go @@ -0,0 +1,153 @@ +// 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 + +import ( + "context" + "fmt" + "os" + "strings" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" + networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" + "github.com/liqotech/liqo/pkg/consts" + liqogetters "github.com/liqotech/liqo/pkg/utils/getters" +) + +// RetrievePodCIDR retrieves the podCIDR of the local cluster. +func RetrievePodCIDR(ctx context.Context, cl client.Client) (string, error) { + nw, err := liqogetters.RetrieveUniqueNetworkByLabel(ctx, cl, labels.SelectorFromSet(map[string]string{ + consts.NetworkTypeLabelKey: string(consts.NetworkTypePodCIDR), + })) + if err != nil { + return "", err + } + + return nw.Spec.CIDR.String(), nil +} + +// RetrieveServiceCIDR retrieves the serviceCIDR of the local cluster. +func RetrieveServiceCIDR(ctx context.Context, cl client.Client) (string, error) { + nw, err := liqogetters.RetrieveUniqueNetworkByLabel(ctx, cl, labels.SelectorFromSet(map[string]string{ + consts.NetworkTypeLabelKey: string(consts.NetworkTypeServiceCIDR), + })) + if err != nil { + return "", err + } + + return nw.Spec.CIDR.String(), nil +} + +// RetrieveExternalCIDR retrieves the externalCIDR of the local cluster. +func RetrieveExternalCIDR(ctx context.Context, cl client.Client) (string, error) { + nw, err := liqogetters.RetrieveUniqueNetworkByLabel(ctx, cl, labels.SelectorFromSet(map[string]string{ + consts.NetworkTypeLabelKey: string(consts.NetworkTypeExternalCIDR), + })) + if err != nil { + return "", err + } + + if nw.Status.CIDR == "" { + return "", fmt.Errorf("the external CIDR is not yet configured: missing status on the Network resource") + } + + return nw.Status.CIDR.String(), nil +} + +// RetrieveReservedSubnets retrieves the reserved subnets of the local cluster. +func RetrieveReservedSubnets(ctx context.Context, cl client.Client) ([]string, error) { + var reservedSubnets []string + + networks, err := liqogetters.RetrieveNetworksByLabel(ctx, cl, labels.SelectorFromSet(map[string]string{ + consts.NetworkTypeLabelKey: string(consts.NetworkTypeReserved), + })) + if err != nil { + return nil, err + } + + for i := range networks.Items { + reservedSubnets = append(reservedSubnets, networks.Items[i].Spec.CIDR.String()) + } + + return reservedSubnets, nil +} + +// NetworkNotRemapped returns whether the given Network does not need CIDR remapping. +func NetworkNotRemapped(nw *ipamv1alpha1.Network) bool { + value, ok := nw.Labels[consts.NetworkNotRemappedLabelKey] + return ok && !strings.EqualFold(value, "false") +} + +// IsPodCIDR returns whether the given Network is of type PodCIDR. +func IsPodCIDR(nw *ipamv1alpha1.Network) bool { + nwType, ok := nw.Labels[consts.NetworkTypeLabelKey] + return ok && nwType == string(consts.NetworkTypePodCIDR) +} + +// IsServiceCIDR returns whether the given Network is of type ServiceCIDR. +func IsServiceCIDR(nw *ipamv1alpha1.Network) bool { + nwType, ok := nw.Labels[consts.NetworkTypeLabelKey] + return ok && nwType == string(consts.NetworkTypeServiceCIDR) +} + +// IsExternalCIDR returns whether the given Network is of type ExternalCIDR. +func IsExternalCIDR(nw *ipamv1alpha1.Network) bool { + nwType, ok := nw.Labels[consts.NetworkTypeLabelKey] + return ok && nwType == string(consts.NetworkTypeExternalCIDR) +} + +// IsReservedNetwork returns whether the given Network is of type Reserved. +func IsReservedNetwork(nw *ipamv1alpha1.Network) bool { + nwType, ok := nw.Labels[consts.NetworkTypeLabelKey] + return ok && nwType == string(consts.NetworkTypeReserved) +} + +// CreateNetwork creates a Network resource with the given name and CIDR. +// NeedRemapping indicates whether the Network needs CIDR remapping from IPAM. +// NetworkType indicates the type of the Network (leave empty to not set the type). +func CreateNetwork(ctx context.Context, cl client.Client, name, cidr string, needRemapping bool, networkType *consts.NetworkType) error { + network := &ipamv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: os.Getenv("POD_NAMESPACE"), + }, + } + + if _, err := controllerutil.CreateOrUpdate(ctx, cl, network, func() error { + if network.Labels == nil { + network.Labels = map[string]string{} + } + if !needRemapping { + network.Labels[consts.NetworkNotRemappedLabelKey] = consts.NetworkNotRemappedLabelValue + } + if networkType != nil { + network.Labels[consts.NetworkTypeLabelKey] = string(*networkType) + } + + network.Spec = ipamv1alpha1.NetworkSpec{ + CIDR: networkingv1alpha1.CIDR(cidr), + } + return nil + }); err != nil { + return err + } + + return nil +} diff --git a/test/integration/integration_suite_test.go b/test/integration/integration_suite_test.go index 4255cf2ddc..f3908f7c7d 100644 --- a/test/integration/integration_suite_test.go +++ b/test/integration/integration_suite_test.go @@ -178,7 +178,7 @@ func initIpam() error { if err != nil { return err } - err = ipam.Init(liqoipam.Pools, dynClient, 2000+int(n.Int64())) + err = ipam.Init(liqoipam.Pools, dynClient) if err != nil { return err } @@ -187,10 +187,17 @@ func initIpam() error { if err != nil { return err } + + // TODO: update with new GetOrSetExternalCIDR method homeExternalCIDR, err = ipam.GetExternalCIDR(uint8(24)) if err != nil { return err } + + if err := ipam.Serve(2000 + int(n.Int64())); err != nil { + return err + } + // Assign networks to clusterID1 _, _, err = ipam.GetSubnetsPerCluster(remotePodCIDR, remoteExternalCIDR, clusterID1) if err != nil {