From d848fc1997692d34f0510769b0c7bba94b304173 Mon Sep 17 00:00:00 2001 From: Francesco Torta <62566275+fra98@users.noreply.github.com> Date: Wed, 6 Sep 2023 09:28:44 +0000 Subject: [PATCH] IPAM API and controllers (IPs, Networks) --- apis/ipam/v1alpha1/groupversion_info.go | 34 ++ apis/ipam/v1alpha1/ip_types.go | 74 ++++ apis/ipam/v1alpha1/network_types.go | 74 ++++ apis/ipam/v1alpha1/zz_generated.deepcopy.go | 209 ++++++++++ cmd/liqo-controller-manager/main.go | 57 ++- deployments/liqo/crds/ipam.liqo.io_ips.yaml | 71 ++++ .../liqo/crds/ipam.liqo.io_networks.yaml | 67 ++++ .../liqo-controller-manager-ClusterRole.yaml | 72 ++++ .../liqo-controller-manager-deployment.yaml | 6 +- .../webhooks/liqo-validating-webhook.yaml | 34 ++ .../ip-controller/doc.go | 16 + .../ip-controller/ip_controller.go | 245 ++++++++++++ .../network-controller/doc.go | 16 + .../network-controller/network_controller.go | 185 +++++++++ .../resource-monitors/resource-reader.pb.go | 2 +- .../webhooks/ip/doc.go | 16 + pkg/liqo-controller-manager/webhooks/ip/ip.go | 112 ++++++ .../webhooks/network/doc.go | 16 + .../webhooks/network/nw.go | 126 ++++++ pkg/liqonet/ipam/ipam.go | 20 + pkg/liqonet/ipam/ipam.pb.go | 377 +++++++++++++++--- pkg/liqonet/ipam/ipam.proto | 16 + pkg/liqonet/ipam/ipam_grpc.pb.go | 74 ++++ pkg/utils/foreignCluster/getForeignCluster.go | 13 + pkg/utils/mapper/mapper.go | 4 + 25 files changed, 1867 insertions(+), 69 deletions(-) create mode 100644 apis/ipam/v1alpha1/groupversion_info.go create mode 100644 apis/ipam/v1alpha1/ip_types.go create mode 100644 apis/ipam/v1alpha1/network_types.go create mode 100644 apis/ipam/v1alpha1/zz_generated.deepcopy.go create mode 100644 deployments/liqo/crds/ipam.liqo.io_ips.yaml create mode 100644 deployments/liqo/crds/ipam.liqo.io_networks.yaml create mode 100644 pkg/liqo-controller-manager/ip-controller/doc.go create mode 100644 pkg/liqo-controller-manager/ip-controller/ip_controller.go create mode 100644 pkg/liqo-controller-manager/network-controller/doc.go create mode 100644 pkg/liqo-controller-manager/network-controller/network_controller.go create mode 100644 pkg/liqo-controller-manager/webhooks/ip/doc.go create mode 100644 pkg/liqo-controller-manager/webhooks/ip/ip.go create mode 100644 pkg/liqo-controller-manager/webhooks/network/doc.go create mode 100644 pkg/liqo-controller-manager/webhooks/network/nw.go diff --git a/apis/ipam/v1alpha1/groupversion_info.go b/apis/ipam/v1alpha1/groupversion_info.go new file mode 100644 index 0000000000..6fb8fd75e6 --- /dev/null +++ b/apis/ipam/v1alpha1/groupversion_info.go @@ -0,0 +1,34 @@ +// 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 v1alpha1 contains API Schema definitions for the IPAM v1alpha1 API group +// +kubebuilder:object:generate=true +// +groupName=ipam.liqo.io +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects. + GroupVersion = schema.GroupVersion{Group: "ipam.liqo.io", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/apis/ipam/v1alpha1/ip_types.go b/apis/ipam/v1alpha1/ip_types.go new file mode 100644 index 0000000000..b95d403828 --- /dev/null +++ b/apis/ipam/v1alpha1/ip_types.go @@ -0,0 +1,74 @@ +// 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 v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + // IPKind is the kind name used to register the IP CRD. + IPKind = "IP" + + // IPResource is the resource name used to register the IP CRD. + IPResource = "ips" + + // IPGroupVersionResource is the group version resource used to register IP CRD. + IPGroupVersionResource = GroupVersion.WithResource(IPResource) + + // IPGroupResource is the group resource used to register IP CRD. + IPGroupResource = schema.GroupResource{Group: GroupVersion.Group, Resource: IPResource} +) + +// IPSpec defines a local IP. +type IPSpec struct { + // IP is the local IP. + IP string `json:"ip"` +} + +// IPStatus defines remapped IPs. +type IPStatus struct { + // IPMappings contains the mapping of the local IP for each remote cluster. + IPMappings map[string]string `json:"ipMappings,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Local IP",type=string,JSONPath=`.spec.ip` +// +kubebuilder:printcolumn:name="Remapped IPs",type=string,JSONPath=`.status.ipMappings`,priority=1 +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` + +// IP is the Schema for the IP API. +type IP struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec IPSpec `json:"spec"` + Status IPStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// IPList contains a list of IP. +type IPList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []IP `json:"items"` +} + +func init() { + SchemeBuilder.Register(&IP{}, &IPList{}) +} diff --git a/apis/ipam/v1alpha1/network_types.go b/apis/ipam/v1alpha1/network_types.go new file mode 100644 index 0000000000..e2bbd0e026 --- /dev/null +++ b/apis/ipam/v1alpha1/network_types.go @@ -0,0 +1,74 @@ +// 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 v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + // NetworkKind is the kind name used to register the Network CRD. + NetworkKind = "Network" + + // NetworkResource is the resource name used to register the Network CRD. + NetworkResource = "networks" + + // NetworkGroupVersionResource is the group version resource used to register the Network CRD. + NetworkGroupVersionResource = GroupVersion.WithResource(NetworkResource) + + // NetworkGroupResource is the group resource used to register the Network CRD. + NetworkGroupResource = schema.GroupResource{Group: GroupVersion.Group, Resource: NetworkResource} +) + +// NetworkSpec defines the desired state of Network. +type NetworkSpec struct { + // CIDR is the desired CIDR for the remote cluster. + CIDR string `json:"cidr"` +} + +// NetworkStatus defines the observed state of Network. +type NetworkStatus struct { + // CIDR is the remapped CIDR for the remote cluster. + CIDR string `json:"cidr,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Desired CIDR",type=string,JSONPath=`.spec.cidr` +// +kubebuilder:printcolumn:name="Remapped CIDR",type=string,JSONPath=`.status.cidr` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` + +// Network is the Schema for the Network API. +type Network struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec NetworkSpec `json:"spec"` + Status NetworkStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// NetworkList contains a list of Network. +type NetworkList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Network `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Network{}, &NetworkList{}) +} diff --git a/apis/ipam/v1alpha1/zz_generated.deepcopy.go b/apis/ipam/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..3e6627aca2 --- /dev/null +++ b/apis/ipam/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,209 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// 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. + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IP) DeepCopyInto(out *IP) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IP. +func (in *IP) DeepCopy() *IP { + if in == nil { + return nil + } + out := new(IP) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IP) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPList) DeepCopyInto(out *IPList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]IP, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPList. +func (in *IPList) DeepCopy() *IPList { + if in == nil { + return nil + } + out := new(IPList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *IPList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPSpec) DeepCopyInto(out *IPSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPSpec. +func (in *IPSpec) DeepCopy() *IPSpec { + if in == nil { + return nil + } + out := new(IPSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPStatus) DeepCopyInto(out *IPStatus) { + *out = *in + if in.IPMappings != nil { + in, out := &in.IPMappings, &out.IPMappings + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPStatus. +func (in *IPStatus) DeepCopy() *IPStatus { + if in == nil { + return nil + } + out := new(IPStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Network) DeepCopyInto(out *Network) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Network. +func (in *Network) DeepCopy() *Network { + if in == nil { + return nil + } + out := new(Network) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Network) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkList) DeepCopyInto(out *NetworkList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Network, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkList. +func (in *NetworkList) DeepCopy() *NetworkList { + if in == nil { + return nil + } + out := new(NetworkList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *NetworkList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkSpec. +func (in *NetworkSpec) DeepCopy() *NetworkSpec { + if in == nil { + return nil + } + out := new(NetworkSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkStatus) DeepCopyInto(out *NetworkStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkStatus. +func (in *NetworkStatus) DeepCopy() *NetworkStatus { + if in == nil { + return nil + } + out := new(NetworkStatus) + in.DeepCopyInto(out) + return out +} diff --git a/cmd/liqo-controller-manager/main.go b/cmd/liqo-controller-manager/main.go index b5705a2b51..24a6c4ffcd 100644 --- a/cmd/liqo-controller-manager/main.go +++ b/cmd/liqo-controller-manager/main.go @@ -16,6 +16,7 @@ package main import ( + "context" "crypto/tls" "flag" "fmt" @@ -25,6 +26,8 @@ import ( "sync" "time" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" certificates "k8s.io/api/certificates/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/fields" @@ -48,6 +51,7 @@ import ( "sigs.k8s.io/sig-storage-lib-external-provisioner/v7/controller" discoveryv1alpha1 "github.com/liqotech/liqo/apis/discovery/v1alpha1" + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" netv1alpha1 "github.com/liqotech/liqo/apis/net/v1alpha1" offloadingv1alpha1 "github.com/liqotech/liqo/apis/offloading/v1alpha1" sharingv1alpha1 "github.com/liqotech/liqo/apis/sharing/v1alpha1" @@ -56,8 +60,10 @@ import ( "github.com/liqotech/liqo/pkg/consts" identitymanager "github.com/liqotech/liqo/pkg/identityManager" foreignclusteroperator "github.com/liqotech/liqo/pkg/liqo-controller-manager/foreign-cluster-operator" + ipctrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/ip-controller" mapsctrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/namespacemap-controller" nsoffctrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/namespaceoffloading-controller" + networkctrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/network-controller" nodefailurectrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/nodefailure-controller" podstatusctrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/podstatus-controller" resourceRequestOperator "github.com/liqotech/liqo/pkg/liqo-controller-manager/resource-request-controller" @@ -68,10 +74,13 @@ import ( liqostorageprovisioner "github.com/liqotech/liqo/pkg/liqo-controller-manager/storageprovisioner" virtualnodectrl "github.com/liqotech/liqo/pkg/liqo-controller-manager/virtualnode-controller" fcwh "github.com/liqotech/liqo/pkg/liqo-controller-manager/webhooks/foreigncluster" + ipwh "github.com/liqotech/liqo/pkg/liqo-controller-manager/webhooks/ip" nsoffwh "github.com/liqotech/liqo/pkg/liqo-controller-manager/webhooks/namespaceoffloading" + nwwh "github.com/liqotech/liqo/pkg/liqo-controller-manager/webhooks/network" podwh "github.com/liqotech/liqo/pkg/liqo-controller-manager/webhooks/pod" shadowpodswh "github.com/liqotech/liqo/pkg/liqo-controller-manager/webhooks/shadowpod" virtualnodewh "github.com/liqotech/liqo/pkg/liqo-controller-manager/webhooks/virtualnode" + "github.com/liqotech/liqo/pkg/liqonet/ipam" peeringroles "github.com/liqotech/liqo/pkg/peering-roles" tenantnamespace "github.com/liqotech/liqo/pkg/tenantNamespace" argsutils "github.com/liqotech/liqo/pkg/utils/args" @@ -97,6 +106,7 @@ func init() { _ = discoveryv1alpha1.AddToScheme(scheme) _ = offloadingv1alpha1.AddToScheme(scheme) _ = virtualkubeletv1alpha1.AddToScheme(scheme) + _ = ipamv1alpha1.AddToScheme(scheme) } func main() { @@ -110,6 +120,7 @@ func main() { var kubeletMetricsEnabled bool var labelsNotReflected argsutils.StringList var annotationsNotReflected argsutils.StringList + var ipamClient ipam.IpamClient webhookPort := flag.Uint("webhook-port", 9443, "The port the webhook server binds to") metricsAddr := flag.String("metrics-address", ":8080", "The address the metric endpoint binds to") @@ -133,6 +144,8 @@ func main() { shadowPodWorkers := flag.Int("shadow-pod-ctrl-workers", 10, "The number of workers used to reconcile ShadowPod resources.") shadowEndpointSliceWorkers := flag.Int("shadow-endpointslice-ctrl-workers", 10, "The number of workers used to reconcile ShadowEndpointSlice resources.") + networkWorkers := flag.Int("network-ctrl-workers", 1, "The number of workers used to reconcile Network resources.") + ipWorkers := flag.Int("ip-ctrl-workers", 1, "The number of workers used to reconcile IP resources.") disableInternalNetwork := flag.Bool("disable-internal-network", false, "Disable the creation of the internal network") foreignClusterPingInterval := flag.Duration("foreign-cluster-ping-interval", 15*time.Second, "The frequency of the ForeignCluster API server readiness check. Set 0 to disable the check") @@ -176,7 +189,9 @@ func main() { flag.Var(&labelsNotReflected, "labels-not-reflected", "List of labels (key) that must not be reflected") flag.Var(&annotationsNotReflected, "annotations-not-reflected", "List of annotations (key) that must not be reflected") - kubeletIpamServer := flag.String("kubelet-ipam-server", "", + + // Ipam server endpoint + ipamServer := flag.String("ipam-server", "", "The address of the IPAM server to use for the virtual kubelet (set to empty string to disable IPAM)") // Storage Provisioner parameters @@ -207,7 +222,7 @@ func main() { RequestsRAM: kubeletRAMRequests.Quantity, LimitsCPU: kubeletCPULimits.Quantity, LimitsRAM: kubeletRAMLimits.Quantity, - IpamEndpoint: *kubeletIpamServer, + IpamEndpoint: *ipamServer, MetricsAddress: kubeletMetricsAddress, MetricsEnabled: kubeletMetricsEnabled, ReflectorsWorkers: reflectorsWorkers, @@ -334,6 +349,8 @@ func main() { mgr.GetWebhookServer().Register("/validate/namespace-offloading", nsoffwh.New()) mgr.GetWebhookServer().Register("/mutate/pod", podwh.New(mgr.GetClient())) mgr.GetWebhookServer().Register("/mutate/virtualnodes", virtualnodewh.New(mgr.GetClient(), &clusterIdentity, virtualKubeletOpts)) + mgr.GetWebhookServer().Register("/validate/networks", nwwh.NewValidator()) + mgr.GetWebhookServer().Register("/validate/ips", ipwh.NewValidator()) if err := indexer.IndexField(ctx, mgr, &corev1.Pod{}, indexer.FieldNodeNameFromPod, indexer.ExtractNodeName); err != nil { klog.Errorf("Unable to setup the indexer for the Pod nodeName field: %v", err) @@ -537,6 +554,42 @@ func main() { } } + // Connect to the IPAM server if specified. + if *ipamServer != "" { + klog.Infof("connecting to the IPAM server %q", *ipamServer) + dialctx, cancel := context.WithTimeout(ctx, 10*time.Second) + connection, err := grpc.DialContext(dialctx, *ipamServer, + grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock()) + cancel() + if err != nil { + klog.Errorf("failed to establish a connection to the IPAM %q", *ipamServer) + os.Exit(1) + } + ipamClient = ipam.NewIpamClient(connection) + } + + if !*disableInternalNetwork { + networkReconciler := &networkctrl.NetworkReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + IpamClient: 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, + } + if err = ipReconciler.SetupWithManager(ctx, mgr, *ipWorkers); err != nil { + klog.Errorf("Unable to start the ipReconciler", err) + os.Exit(1) + } + } + klog.Info("starting manager as controller manager") if err := mgr.Start(ctx); err != nil { klog.Error(err) diff --git a/deployments/liqo/crds/ipam.liqo.io_ips.yaml b/deployments/liqo/crds/ipam.liqo.io_ips.yaml new file mode 100644 index 0000000000..00ddee8198 --- /dev/null +++ b/deployments/liqo/crds/ipam.liqo.io_ips.yaml @@ -0,0 +1,71 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: ips.ipam.liqo.io +spec: + group: ipam.liqo.io + names: + kind: IP + listKind: IPList + plural: ips + singular: ip + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.ip + name: Local IP + type: string + - jsonPath: .status.ipMappings + name: Remapped IPs + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: IP is the Schema for the IP API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: IPSpec defines a local IP. + properties: + ip: + description: IP is the local IP. + type: string + required: + - ip + type: object + status: + description: IPStatus defines remapped IPs. + properties: + ipMappings: + additionalProperties: + type: string + description: IPMappings contains the mapping of the local IP for each + remote cluster. + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deployments/liqo/crds/ipam.liqo.io_networks.yaml b/deployments/liqo/crds/ipam.liqo.io_networks.yaml new file mode 100644 index 0000000000..8e4882c4be --- /dev/null +++ b/deployments/liqo/crds/ipam.liqo.io_networks.yaml @@ -0,0 +1,67 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: networks.ipam.liqo.io +spec: + group: ipam.liqo.io + names: + kind: Network + listKind: NetworkList + plural: networks + singular: network + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.cidr + name: Desired CIDR + type: string + - jsonPath: .status.cidr + name: Remapped CIDR + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Network is the Schema for the Network API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: NetworkSpec defines the desired state of Network. + properties: + cidr: + description: CIDR is the desired CIDR for the remote cluster. + type: string + required: + - cidr + type: object + status: + description: NetworkStatus defines the observed state of Network. + properties: + cidr: + description: CIDR is the remapped CIDR for the remote cluster. + type: string + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml b/deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml index b6b4fa0787..4d01a1b812 100644 --- a/deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml +++ b/deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml @@ -256,6 +256,78 @@ rules: - deletecollection - list - watch +- apiGroups: + - ipam.liqo.io + resources: + - ips + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ipam.liqo.io + resources: + - ips/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ipam.liqo.io + resources: + - ips/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ipam.liqo.io + resources: + - networks + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ipam.liqo.io + resources: + - networks/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ipam.liqo.io + resources: + - networks/status + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - metrics.liqo.io resources: diff --git a/deployments/liqo/templates/liqo-controller-manager-deployment.yaml b/deployments/liqo/templates/liqo-controller-manager-deployment.yaml index 830438df8c..b125d25d9b 100644 --- a/deployments/liqo/templates/liqo-controller-manager-deployment.yaml +++ b/deployments/liqo/templates/liqo-controller-manager-deployment.yaml @@ -107,12 +107,12 @@ spec: {{- else }} {{- end }} {{- if .Values.networkManager.externalIPAM.enabled }} - - --kubelet-ipam-server={{ .Values.networkManager.externalIPAM.url }} + - --ipam-server={{ .Values.networkManager.externalIPAM.url }} {{- else if not .Values.networking.internal }} - - --kubelet-ipam-server= + - --ipam-server= - --disable-internal-network {{- else }} - - --kubelet-ipam-server={{ include "liqo.prefixedName" $netManagerConfig }}.{{ .Release.Namespace }}:6000 + - --ipam-server={{ include "liqo.prefixedName" $netManagerConfig }}.{{ .Release.Namespace }}:6000 {{- end }} - --auto-join-discovered-clusters={{ .Values.discovery.config.autojoin }} - --enable-storage={{ .Values.storage.enable }} diff --git a/deployments/liqo/templates/webhooks/liqo-validating-webhook.yaml b/deployments/liqo/templates/webhooks/liqo-validating-webhook.yaml index 7e9c8ff711..346c4b6224 100644 --- a/deployments/liqo/templates/webhooks/liqo-validating-webhook.yaml +++ b/deployments/liqo/templates/webhooks/liqo-validating-webhook.yaml @@ -59,3 +59,37 @@ webhooks: resources: ["shadowpods"] sideEffects: None failurePolicy: {{ .Values.webhook.failurePolicy }} + - name: network.validate.liqo.io + admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: {{ include "liqo.prefixedName" $ctrlManagerConfig }} + namespace: {{ .Release.Namespace }} + path: "/validate/networks" + port: {{ .Values.webhook.port }} + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["ipam.liqo.io"] + apiVersions: ["v1alpha1"] + resources: ["networks"] + sideEffects: None + failurePolicy: {{ .Values.webhook.failurePolicy }} + - name: ip.validate.liqo.io + admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: {{ include "liqo.prefixedName" $ctrlManagerConfig }} + namespace: {{ .Release.Namespace }} + path: "/validate/ips" + port: {{ .Values.webhook.port }} + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["ipam.liqo.io"] + apiVersions: ["v1alpha1"] + resources: ["ips"] + sideEffects: None + failurePolicy: {{ .Values.webhook.failurePolicy }} \ No newline at end of file diff --git a/pkg/liqo-controller-manager/ip-controller/doc.go b/pkg/liqo-controller-manager/ip-controller/doc.go new file mode 100644 index 0000000000..9e53da1b47 --- /dev/null +++ b/pkg/liqo-controller-manager/ip-controller/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 ipctrl contains the logic to manage IP addresses to interact with the remote cluster. +package ipctrl diff --git a/pkg/liqo-controller-manager/ip-controller/ip_controller.go b/pkg/liqo-controller-manager/ip-controller/ip_controller.go new file mode 100644 index 0000000000..9dae9dc1ec --- /dev/null +++ b/pkg/liqo-controller-manager/ip-controller/ip_controller.go @@ -0,0 +1,245 @@ +// 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 ipctrl + +import ( + "context" + "slices" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/klog/v2" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" + "github.com/liqotech/liqo/apis/virtualkubelet/v1alpha1" + "github.com/liqotech/liqo/pkg/liqonet/ipam" + "github.com/liqotech/liqo/pkg/utils/getters" +) + +const ( + ipamIPFinalizer = "ip.ipam.liqo.io" +) + +// IPReconciler reconciles a IP object. +type IPReconciler struct { + client.Client + Scheme *runtime.Scheme + IpamClient ipam.IpamClient +} + +// +kubebuilder:rbac:groups=ipam.liqo.io,resources=ips,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=ipam.liqo.io,resources=ips/status,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=ipam.liqo.io,resources=ips/finalizers,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=virtualkubelet.liqo.io,resources=virtualnodes,verbs=get;list;watch + +// Reconcile Ip objects. +func (r *IPReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + klog.Infof("Reconcilg IP %q", req.NamespacedName) // TODO:: delete + var ip ipamv1alpha1.IP + var desiredIP string + + // Fetch the IP instance + if err := r.Get(ctx, req.NamespacedName, &ip); err != nil { + if apierrors.IsNotFound(err) { + klog.V(4).Infof(" %q not found", req.NamespacedName) + return ctrl.Result{}, nil + } + klog.Errorf("an error occurred while getting IP %q: %v", req.NamespacedName, err) + return ctrl.Result{}, err + } + + desiredIP = ip.Spec.IP + + // Get the clusterIDs of all remote clusters + virtualNodes, err := getters.ListVirtualNodesByLabels(ctx, r.Client, labels.Everything()) + if err != nil { + klog.Errorf("error while listing virtual nodes: %v", err) + return ctrl.Result{}, err + } + clusterIDs := getters.RetrieveClusterIDsFromVirtualNodes(virtualNodes) + + if ip.GetDeletionTimestamp().IsZero() { + if !controllerutil.ContainsFinalizer(&ip, ipamIPFinalizer) { + // Add finalizer to prevent deletion without unmapping the IP. + controllerutil.AddFinalizer(&ip, ipamIPFinalizer) + + // Update the IP object + if err := r.Update(ctx, &ip); err != nil { + klog.Errorf("error while adding finalizer to IP %q: %v", req.NamespacedName, err) + return ctrl.Result{}, err + } + klog.Infof("finalizer %q correctly added to IP %q", ipamIPFinalizer, req.NamespacedName) + + // We return immediately and wait for the next reconcile to eventually update the status. + return ctrl.Result{}, nil + } + + needUpdate, err := r.forgeIPMappings(ctx, clusterIDs, desiredIP, &ip) + if err != nil { + return ctrl.Result{}, err + } + + // Update resource status if needed + if needUpdate { + if err := r.Client.Status().Update(ctx, &ip); err != nil { + klog.Errorf("error while updating IP %q status: %v", req.NamespacedName, err) + return ctrl.Result{}, err + } + klog.Infof("updated IP %q status", req.NamespacedName) + } + } else if controllerutil.ContainsFinalizer(&ip, ipamIPFinalizer) { + // the resource is being deleted, but the finalizer is present: + // - unmap the remapped IPs + // - remove finalizer from the resource. + if err := r.handleDelete(ctx, clusterIDs, desiredIP, &ip); err != nil { + return ctrl.Result{}, err + } + + // Update the IP object + if err := r.Update(ctx, &ip); err != nil { + klog.Errorf("error while removing finalizer from IP %q: %v", req.NamespacedName, err) + return ctrl.Result{}, err + } + klog.Infof("finalizer %q correctly removed from IP %q", ipamIPFinalizer, req.NamespacedName) + } + + return ctrl.Result{}, nil +} + +// SetupWithManager monitors IP resources. +func (r *IPReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, workers int) error { + // List all IP resources and enqueue them. + enqueuer := func(_ context.Context, obj client.Object) []reconcile.Request { + var ipList ipamv1alpha1.IPList + if err := r.List(ctx, &ipList); err != nil { + klog.Errorf("error while listing IPs: %v", err) + return nil + } + var requests []reconcile.Request + for i := range ipList.Items { + requests = append(requests, reconcile.Request{NamespacedName: types.NamespacedName{ + Namespace: ipList.Items[i].Namespace, Name: ipList.Items[i].Name}}) + } + return requests + } + + return ctrl.NewControllerManagedBy(mgr). + For(&ipamv1alpha1.IP{}). + Watches(&v1alpha1.VirtualNode{}, handler.EnqueueRequestsFromMapFunc(enqueuer)). + WithOptions(controller.Options{MaxConcurrentReconciles: workers}). + Complete(r) +} + +// forgeIPMappings forge the IP mappings for each remote cluster. Return true if the status must be updated, false otherwise. +func (r *IPReconciler) forgeIPMappings(ctx context.Context, clusterIDs []string, desiredIP string, ip *ipamv1alpha1.IP) (bool, error) { + // Update IP status for each remote cluster + needUpdate := false + + if ip.Status.IPMappings == nil { + ip.Status.IPMappings = make(map[string]string) + } + + for i := range clusterIDs { + remoteClusterID := &clusterIDs[i] + // Update IP status if it is not set yet + // The IPAM function that maps IPs is not idempotent, so we avoid to call it + // 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) + if err != nil { + return false, err + } + ip.Status.IPMappings[*remoteClusterID] = remappedIP + needUpdate = true + } + } + + // Check if the IPMappings has entries associated to clusters that have been deleted (i.e., the virtualNode is missing) + for entry := range ip.Status.IPMappings { + 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) + delete(ip.Status.IPMappings, entry) + needUpdate = true + } + } + + return needUpdate, nil +} + +// handleDelete handles the deletion of the IP resource. It call the IPAM to unmap the IPs of each remote cluster. +func (r *IPReconciler) handleDelete(ctx context.Context, clusterIDs []string, desiredIP string, ip *ipamv1alpha1.IP) error { + for i := range clusterIDs { + remoteClusterID := &clusterIDs[i] + if err := deleteRemappedIP(ctx, r.IpamClient, *remoteClusterID, desiredIP); err != nil { + return err + } + delete(ip.Status.IPMappings, *remoteClusterID) + } + + // Remove status and finalizer, and update the object. + ip.Status.IPMappings = nil + controllerutil.RemoveFinalizer(ip, ipamIPFinalizer) + + return nil +} + +// getRemappedIP returns the remapped IP for the given IP and remote clusterID. +func getRemappedIP(ctx context.Context, ipamClient ipam.IpamClient, remoteClusterID, desiredIP string) (string, error) { + switch ipamClient.(type) { + case nil: + // IPAM is not enabled, use original IP from spec + return desiredIP, nil + default: + // interact with the IPAM to retrieve the correct mapping. + response, err := ipamClient.MapEndpointIP(ctx, &ipam.MapRequest{ + ClusterID: remoteClusterID, Ip: desiredIP}) + if err != nil { + klog.Errorf("IPAM: error while mapping IP %s for remote cluster %q: %v", desiredIP, remoteClusterID, err) + return "", err + } + klog.Infof("IPAM: mapped IP %s to %s for remote cluster %q", desiredIP, response.Ip, remoteClusterID) + return response.Ip, nil + } +} + +// deleteRemappedIP unmaps the IP for the given remote clusterID. +func deleteRemappedIP(ctx context.Context, ipamClient ipam.IpamClient, remoteClusterID, desiredIP string) error { + switch ipamClient.(type) { + case nil: + // If the IPAM is not enabled we do not need to release the translation. + return nil + default: + // Interact with the IPAM to release the translation. + _, err := ipamClient.UnmapEndpointIP(ctx, &ipam.UnmapRequest{ + ClusterID: remoteClusterID, Ip: desiredIP}) + if err != nil { + klog.Errorf("IPAM: error while unmapping IP %s for remote cluster %q: %v", desiredIP, remoteClusterID, err) + return err + } + klog.Infof("IPAM: unmapped IP %s for remote cluster %q", desiredIP, remoteClusterID) + return nil + } +} diff --git a/pkg/liqo-controller-manager/network-controller/doc.go b/pkg/liqo-controller-manager/network-controller/doc.go new file mode 100644 index 0000000000..e101f8af2b --- /dev/null +++ b/pkg/liqo-controller-manager/network-controller/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 networkctrl contains the logic to manage Networks to interact with the remote cluster. +package networkctrl diff --git a/pkg/liqo-controller-manager/network-controller/network_controller.go b/pkg/liqo-controller-manager/network-controller/network_controller.go new file mode 100644 index 0000000000..18ccd9ab7d --- /dev/null +++ b/pkg/liqo-controller-manager/network-controller/network_controller.go @@ -0,0 +1,185 @@ +// 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 networkctrl + +import ( + "context" + "fmt" + "net" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" + "github.com/liqotech/liqo/pkg/consts" + "github.com/liqotech/liqo/pkg/liqonet/ipam" + foreignclusterutils "github.com/liqotech/liqo/pkg/utils/foreignCluster" +) + +const ( + ipamNetworkFinalizer = "network.ipam.liqo.io" +) + +// NetworkReconciler reconciles a Network object. +type NetworkReconciler struct { + client.Client + Scheme *runtime.Scheme + IpamClient ipam.IpamClient +} + +// +kubebuilder:rbac:groups=ipam.liqo.io,resources=networks,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=ipam.liqo.io,resources=networks/status,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=ipam.liqo.io,resources=networks/finalizers,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=discovery.liqo.io,resources=foreignclusters,verbs=get;list;watch + +// Reconcile Network objects. +func (r *NetworkReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + klog.Infof("Reconcilg Network %q", req.NamespacedName) // TODO:: delete + var nw ipamv1alpha1.Network + var desiredCIDR, remappedCIDR string + + // Fetch the Network instance + if err := r.Get(ctx, req.NamespacedName, &nw); err != nil { + if apierrors.IsNotFound(err) { + klog.V(4).Infof("Network %q not found", req.NamespacedName) + return ctrl.Result{}, nil + } + klog.Errorf("an error occurred while getting Network %q: %v", req.NamespacedName, err) + return ctrl.Result{}, err + } + + // Retrieve the remote cluster ID from the labels. + remoteclusterID, found := nw.Labels[consts.RemoteClusterID] // it should always be present thanks to validating webhook + if !found { + err := fmt.Errorf("missing label %q on Network %q (webhook disabled or misconfigured)", consts.RemoteClusterID, req.NamespacedName) + klog.Error(err) + return ctrl.Result{}, err + } + + _, err := foreignclusterutils.CheckForeignClusterExistence(ctx, r.Client, remoteclusterID) + if err != nil { + return ctrl.Result{}, err + } + + desiredCIDR = nw.Spec.CIDR + + if nw.GetDeletionTimestamp().IsZero() { + if !controllerutil.ContainsFinalizer(&nw, ipamNetworkFinalizer) { + // Add finalizer to prevent deletion without unmapping the Network. + 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 + } + klog.Infof("finalizer %q correctly added to Network %q", ipamNetworkFinalizer, req.NamespacedName) + + // We return immediately and wait for the next reconcile to eventually update the status. + return ctrl.Result{}, 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 == "" { + remappedCIDR, err = getRemappedCIDR(ctx, r.IpamClient, desiredCIDR) + if err != nil { + return ctrl.Result{}, 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 + } + klog.Infof("updated Network %q status (spec: %s -> status: %s)", req.NamespacedName, desiredCIDR, remappedCIDR) + } + } 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 + + if _, _, err := net.ParseCIDR(remappedCIDR); err != nil { + klog.Errorf("Unable to unmap CIDR %s of Network %q (inavlid format): %v", remappedCIDR, req.NamespacedName, err) + return ctrl.Result{}, err + } + + if err := deleteRemappedCIDR(ctx, r.IpamClient, remappedCIDR); err != nil { + return ctrl.Result{}, err + } + + // Remove status and finalizer, and update the object. + nw.Status.CIDR = "" + 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 + } + klog.Infof("finalizer correctly removed from Network %q", req.NamespacedName) + } + + 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) +} + +// getRemappedCIDR returns the remapped CIDR for the given CIDR and remote clusterID. +func getRemappedCIDR(ctx context.Context, ipamClient ipam.IpamClient, desiredCIDR string) (string, 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.MapNetworkCIDR(ctx, &ipam.MapCIDRRequest{Cidr: desiredCIDR}) + if err != nil { + klog.Errorf("IPAM: error while mapping network CIDR %s: %v", desiredCIDR, err) + return "", err + } + klog.Infof("IPAM: mapped network CIDR %s to %s", desiredCIDR, response.Cidr) + return response.Cidr, nil + } +} + +// deleteRemappedCIDR unmaps the CIDR for the given remote clusterID. +func deleteRemappedCIDR(ctx context.Context, ipamClient ipam.IpamClient, remappedCIDR string) error { + switch ipamClient.(type) { + case nil: + // If the IPAM is not enabled we do not need to free the network CIDR. + return nil + default: + // Interact with the IPAM to free the network CIDR. + _, err := ipamClient.UnmapNetworkCIDR(ctx, &ipam.UnmapCIDRRequest{Cidr: remappedCIDR}) + if err != nil { + klog.Errorf("IPAM: error while unmapping CIDR %s: %v", remappedCIDR, err) + return err + } + klog.Infof("IPAM: unmapped CIDR %s", remappedCIDR) + return nil + } +} diff --git a/pkg/liqo-controller-manager/resource-request-controller/resource-monitors/resource-reader.pb.go b/pkg/liqo-controller-manager/resource-request-controller/resource-monitors/resource-reader.pb.go index 5085c5a672..b9e499e2eb 100644 --- a/pkg/liqo-controller-manager/resource-request-controller/resource-monitors/resource-reader.pb.go +++ b/pkg/liqo-controller-manager/resource-request-controller/resource-monitors/resource-reader.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.15.5 // source: resource-reader.proto diff --git a/pkg/liqo-controller-manager/webhooks/ip/doc.go b/pkg/liqo-controller-manager/webhooks/ip/doc.go new file mode 100644 index 0000000000..56487125c1 --- /dev/null +++ b/pkg/liqo-controller-manager/webhooks/ip/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 ipwh contains the logic of the IP webhook. +package ipwh diff --git a/pkg/liqo-controller-manager/webhooks/ip/ip.go b/pkg/liqo-controller-manager/webhooks/ip/ip.go new file mode 100644 index 0000000000..45b712c31a --- /dev/null +++ b/pkg/liqo-controller-manager/webhooks/ip/ip.go @@ -0,0 +1,112 @@ +// 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 ipwh + +import ( + "context" + "fmt" + "net" + "net/http" + + admissionv1 "k8s.io/api/admission/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" +) + +type ipwh struct { + decoder *admission.Decoder +} + +type ipwhv struct { + ipwh +} + +// NewValidator returns a new IP validating webhook. +func NewValidator() *webhook.Admission { + return &webhook.Admission{Handler: &ipwhv{ + ipwh: ipwh{ + decoder: admission.NewDecoder(runtime.NewScheme()), + }, + }} +} + +// DecodeIP decodes the IP from the incoming request. +func (w *ipwh) DecodeIP(obj runtime.RawExtension) (*ipamv1alpha1.IP, error) { + var ip ipamv1alpha1.IP + err := w.decoder.DecodeRaw(obj, &ip) + return &ip, err +} + +// Handle implements the IP validating webhook logic. +// +//nolint:gocritic // The signature of this method is imposed by controller runtime. +func (w *ipwhv) Handle(_ context.Context, req admission.Request) admission.Response { + klog.V(4).Infof("Operation: %s", req.Operation) + + switch req.Operation { + case admissionv1.Create: + return w.HandleCreate(&req) + case admissionv1.Update: + return w.HandleUpdate(&req) + default: + return admission.Errored(http.StatusBadRequest, fmt.Errorf("unsupported operation %s", req.Operation)) + } +} + +func (w *ipwhv) HandleCreate(req *admission.Request) admission.Response { + ip, err := w.DecodeIP(req.Object) + if err != nil { + klog.Errorf("Failed decoding IP object: %v", err) + return admission.Errored(http.StatusBadRequest, err) + } + + // Check existence of the IP + if ip.Spec.IP == "" { + return admission.Denied("Missing IP") + } + + // Check if the IP provided is a valid IP + if ip := net.ParseIP(ip.Spec.IP); ip == nil { + return admission.Denied(fmt.Sprintf("Invalid IP: %v", err)) + } + + return admission.Allowed("") +} + +// HandleUpdate is the function in charge of handling Update requests. +func (w *ipwhv) HandleUpdate(req *admission.Request) admission.Response { + ipnew, err := w.DecodeIP(req.Object) + if err != nil { + klog.Errorf("Failed decoding new IP object: %v", err) + return admission.Errored(http.StatusBadRequest, err) + } + + ipold, err := w.DecodeIP(req.OldObject) + if err != nil { + klog.Errorf("Failed decoding old IP object: %v", err) + return admission.Errored(http.StatusBadRequest, err) + } + + // Check if the IP is modified + if ipold.Spec.IP != ipnew.Spec.IP { + return admission.Denied("The IP cannot be modified after creation") + } + + return admission.Allowed("") +} diff --git a/pkg/liqo-controller-manager/webhooks/network/doc.go b/pkg/liqo-controller-manager/webhooks/network/doc.go new file mode 100644 index 0000000000..2c8698e62a --- /dev/null +++ b/pkg/liqo-controller-manager/webhooks/network/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 nwwh contains the logic of the Network webhook. +package nwwh diff --git a/pkg/liqo-controller-manager/webhooks/network/nw.go b/pkg/liqo-controller-manager/webhooks/network/nw.go new file mode 100644 index 0000000000..21452e471e --- /dev/null +++ b/pkg/liqo-controller-manager/webhooks/network/nw.go @@ -0,0 +1,126 @@ +// 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 nwwh + +import ( + "context" + "fmt" + "net" + "net/http" + + admissionv1 "k8s.io/api/admission/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" + "github.com/liqotech/liqo/pkg/consts" +) + +type nwwh struct { + decoder *admission.Decoder +} + +type nwwhv struct { + nwwh +} + +// NewValidator returns a new Network validating webhook. +func NewValidator() *webhook.Admission { + return &webhook.Admission{Handler: &nwwhv{ + nwwh: nwwh{ + decoder: admission.NewDecoder(runtime.NewScheme()), + }, + }} +} + +// DecodeNetwork decodes the Network from the incoming request. +func (w *nwwh) DecodeNetwork(obj runtime.RawExtension) (*ipamv1alpha1.Network, error) { + var nw ipamv1alpha1.Network + err := w.decoder.DecodeRaw(obj, &nw) + return &nw, err +} + +// Handle implements the Network validating webhook logic. +// +//nolint:gocritic // The signature of this method is imposed by controller runtime. +func (w *nwwhv) Handle(_ context.Context, req admission.Request) admission.Response { + klog.V(4).Infof("Operation: %s", req.Operation) + + switch req.Operation { + case admissionv1.Create: + return w.HandleCreate(&req) + case admissionv1.Update: + return w.HandleUpdate(&req) + default: + return admission.Errored(http.StatusBadRequest, fmt.Errorf("unsupported operation %s", req.Operation)) + } +} + +func (w *nwwhv) HandleCreate(req *admission.Request) admission.Response { + nw, err := w.DecodeNetwork(req.Object) + if err != nil { + klog.Errorf("Failed decoding Network object: %v", err) + return admission.Errored(http.StatusBadRequest, err) + } + + // Check existence of the remote clusterID label + _, found := nw.Labels[consts.RemoteClusterID] + if !found { + return admission.Denied(fmt.Sprintf("Missing remote clusterID label (%q)", consts.RemoteClusterID)) + } + + // Check existence of the network CIDR + if nw.Spec.CIDR == "" { + return admission.Denied("Missing CIDR") + } + + // Check if the CIDR is a valid network + if _, _, err := net.ParseCIDR(nw.Spec.CIDR); err != nil { + return admission.Denied(fmt.Sprintf("Invalid CIDR: %v", err)) + } + + return admission.Allowed("") +} + +// HandleUpdate is the function in charge of handling Update requests. +func (w *nwwhv) HandleUpdate(req *admission.Request) admission.Response { + nwnew, err := w.DecodeNetwork(req.Object) + if err != nil { + klog.Errorf("Failed decoding new Network object: %v", err) + return admission.Errored(http.StatusBadRequest, err) + } + + nwold, err := w.DecodeNetwork(req.OldObject) + if err != nil { + klog.Errorf("Failed decoding old Network object: %v", err) + return admission.Errored(http.StatusBadRequest, err) + } + + // Check if the remote clusterID label is modified + // We do not check the existence of the label as it should always be present + // thank to the webhook validation of creation requests. + if nwold.Labels[consts.RemoteClusterID] != nwnew.Labels[consts.RemoteClusterID] { + return admission.Denied("The remote clusterID label cannot be modified after creation") + } + + // Check if the CIDR is modified + if nwold.Spec.CIDR != nwnew.Spec.CIDR { + return admission.Denied("The CIDR cannot be modified after creation") + } + + return admission.Allowed("") +} diff --git a/pkg/liqonet/ipam/ipam.go b/pkg/liqonet/ipam/ipam.go index 348ae49139..8632897063 100644 --- a/pkg/liqonet/ipam/ipam.go +++ b/pkg/liqonet/ipam/ipam.go @@ -375,6 +375,26 @@ 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. +func (liqoIPAM *IPAM) MapNetworkCIDR(_ context.Context, mapCIDRRequest *MapCIDRRequest) (*MapCIDRResponse, error) { + mappedCIDR, err := liqoIPAM.getOrRemapNetwork(mapCIDRRequest.GetCidr()) + if err != nil { + return &MapCIDRResponse{}, fmt.Errorf("cannot map network CIDR %s: %w", mapCIDRRequest.GetCidr(), err) + } + return &MapCIDRResponse{Cidr: mappedCIDR}, nil +} + +// UnmapNetworkCIDR set the network CIDR as unused for a specific cluster. +func (liqoIPAM *IPAM) UnmapNetworkCIDR(_ context.Context, unmapCIDRRequest *UnmapCIDRRequest) (*UnmapCIDRResponse, error) { + err := liqoIPAM.FreeReservedSubnet(unmapCIDRRequest.GetCidr()) + if err != nil { + return &UnmapCIDRResponse{}, fmt.Errorf("cannot unmap network CIDR %s: %w", unmapCIDRRequest.GetCidr(), err) + } + return &UnmapCIDRResponse{}, 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) { diff --git a/pkg/liqonet/ipam/ipam.pb.go b/pkg/liqonet/ipam/ipam.pb.go index 05e9e05fe4..241d56e15a 100644 --- a/pkg/liqonet/ipam/ipam.pb.go +++ b/pkg/liqonet/ipam/ipam.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.31.0 // protoc v3.15.5 // source: pkg/liqonet/ipam/ipam.proto @@ -216,6 +216,185 @@ func (*UnmapResponse) Descriptor() ([]byte, []int) { return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{3} } +type MapCIDRRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cidr string `protobuf:"bytes,1,opt,name=cidr,proto3" json:"cidr,omitempty"` +} + +func (x *MapCIDRRequest) Reset() { + *x = MapCIDRRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MapCIDRRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MapCIDRRequest) ProtoMessage() {} + +func (x *MapCIDRRequest) ProtoReflect() protoreflect.Message { + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[4] + 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 MapCIDRRequest.ProtoReflect.Descriptor instead. +func (*MapCIDRRequest) Descriptor() ([]byte, []int) { + return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{4} +} + +func (x *MapCIDRRequest) GetCidr() string { + if x != nil { + return x.Cidr + } + return "" +} + +type MapCIDRResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cidr string `protobuf:"bytes,1,opt,name=cidr,proto3" json:"cidr,omitempty"` +} + +func (x *MapCIDRResponse) Reset() { + *x = MapCIDRResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MapCIDRResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MapCIDRResponse) ProtoMessage() {} + +func (x *MapCIDRResponse) ProtoReflect() protoreflect.Message { + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[5] + 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 MapCIDRResponse.ProtoReflect.Descriptor instead. +func (*MapCIDRResponse) Descriptor() ([]byte, []int) { + return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{5} +} + +func (x *MapCIDRResponse) GetCidr() string { + if x != nil { + return x.Cidr + } + return "" +} + +type UnmapCIDRRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cidr string `protobuf:"bytes,1,opt,name=cidr,proto3" json:"cidr,omitempty"` +} + +func (x *UnmapCIDRRequest) Reset() { + *x = UnmapCIDRRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnmapCIDRRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnmapCIDRRequest) ProtoMessage() {} + +func (x *UnmapCIDRRequest) ProtoReflect() protoreflect.Message { + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[6] + 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 UnmapCIDRRequest.ProtoReflect.Descriptor instead. +func (*UnmapCIDRRequest) Descriptor() ([]byte, []int) { + return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{6} +} + +func (x *UnmapCIDRRequest) GetCidr() string { + if x != nil { + return x.Cidr + } + return "" +} + +type UnmapCIDRResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *UnmapCIDRResponse) Reset() { + *x = UnmapCIDRResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UnmapCIDRResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UnmapCIDRResponse) ProtoMessage() {} + +func (x *UnmapCIDRResponse) ProtoReflect() protoreflect.Message { + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[7] + 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 UnmapCIDRResponse.ProtoReflect.Descriptor instead. +func (*UnmapCIDRResponse) Descriptor() ([]byte, []int) { + return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{7} +} + type GetHomePodIPRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -228,7 +407,7 @@ type GetHomePodIPRequest struct { func (x *GetHomePodIPRequest) Reset() { *x = GetHomePodIPRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[4] + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -241,7 +420,7 @@ func (x *GetHomePodIPRequest) String() string { func (*GetHomePodIPRequest) ProtoMessage() {} func (x *GetHomePodIPRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[4] + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -254,7 +433,7 @@ func (x *GetHomePodIPRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHomePodIPRequest.ProtoReflect.Descriptor instead. func (*GetHomePodIPRequest) Descriptor() ([]byte, []int) { - return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{4} + return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{8} } func (x *GetHomePodIPRequest) GetClusterID() string { @@ -282,7 +461,7 @@ type GetHomePodIPResponse struct { func (x *GetHomePodIPResponse) Reset() { *x = GetHomePodIPResponse{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[5] + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -295,7 +474,7 @@ func (x *GetHomePodIPResponse) String() string { func (*GetHomePodIPResponse) ProtoMessage() {} func (x *GetHomePodIPResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[5] + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -308,7 +487,7 @@ func (x *GetHomePodIPResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetHomePodIPResponse.ProtoReflect.Descriptor instead. func (*GetHomePodIPResponse) Descriptor() ([]byte, []int) { - return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{5} + return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{9} } func (x *GetHomePodIPResponse) GetHomeIP() string { @@ -329,7 +508,7 @@ type BelongsRequest struct { func (x *BelongsRequest) Reset() { *x = BelongsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[6] + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -342,7 +521,7 @@ func (x *BelongsRequest) String() string { func (*BelongsRequest) ProtoMessage() {} func (x *BelongsRequest) ProtoReflect() protoreflect.Message { - mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[6] + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -355,7 +534,7 @@ func (x *BelongsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BelongsRequest.ProtoReflect.Descriptor instead. func (*BelongsRequest) Descriptor() ([]byte, []int) { - return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{6} + return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{10} } func (x *BelongsRequest) GetIp() string { @@ -376,7 +555,7 @@ type BelongsResponse struct { func (x *BelongsResponse) Reset() { *x = BelongsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[7] + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -389,7 +568,7 @@ func (x *BelongsResponse) String() string { func (*BelongsResponse) ProtoMessage() {} func (x *BelongsResponse) ProtoReflect() protoreflect.Message { - mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[7] + mi := &file_pkg_liqonet_ipam_ipam_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -402,7 +581,7 @@ func (x *BelongsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BelongsResponse.ProtoReflect.Descriptor instead. func (*BelongsResponse) Descriptor() ([]byte, []int) { - return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{7} + return file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP(), []int{11} } func (x *BelongsResponse) GetBelongs() bool { @@ -427,34 +606,50 @@ var file_pkg_liqonet_ipam_ipam_proto_rawDesc = []byte{ 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x0f, 0x0a, 0x0d, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x43, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x48, 0x6f, - 0x6d, 0x65, 0x50, 0x6f, 0x64, 0x49, 0x50, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, - 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x2e, 0x0a, 0x14, - 0x47, 0x65, 0x74, 0x48, 0x6f, 0x6d, 0x65, 0x50, 0x6f, 0x64, 0x49, 0x50, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x6f, 0x6d, 0x65, 0x49, 0x50, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x6f, 0x6d, 0x65, 0x49, 0x50, 0x22, 0x20, 0x0a, 0x0e, - 0x42, 0x65, 0x6c, 0x6f, 0x6e, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 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, 0xd8, 0x01, 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, 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, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x24, 0x0a, 0x0e, 0x4d, 0x61, 0x70, 0x43, 0x49, + 0x44, 0x52, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x22, 0x25, 0x0a, + 0x0f, 0x4d, 0x61, 0x70, 0x43, 0x49, 0x44, 0x52, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x63, 0x69, 0x64, 0x72, 0x22, 0x26, 0x0a, 0x10, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x43, 0x49, 0x44, + 0x52, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x69, 0x64, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x69, 0x64, 0x72, 0x22, 0x13, 0x0a, 0x11, + 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x43, 0x49, 0x44, 0x52, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x43, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x6d, 0x65, 0x50, 0x6f, 0x64, 0x49, + 0x50, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x49, 0x44, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x22, 0x2e, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x6d, + 0x65, 0x50, 0x6f, 0x64, 0x49, 0x50, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x68, 0x6f, 0x6d, 0x65, 0x49, 0x50, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x68, 0x6f, 0x6d, 0x65, 0x49, 0x50, 0x22, 0x20, 0x0a, 0x0e, 0x42, 0x65, 0x6c, 0x6f, 0x6e, 0x67, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 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, } var ( @@ -469,31 +664,39 @@ func file_pkg_liqonet_ipam_ipam_proto_rawDescGZIP() []byte { return file_pkg_liqonet_ipam_ipam_proto_rawDescData } -var file_pkg_liqonet_ipam_ipam_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_pkg_liqonet_ipam_ipam_proto_msgTypes = make([]protoimpl.MessageInfo, 12) var file_pkg_liqonet_ipam_ipam_proto_goTypes = []interface{}{ (*MapRequest)(nil), // 0: MapRequest (*MapResponse)(nil), // 1: MapResponse (*UnmapRequest)(nil), // 2: UnmapRequest (*UnmapResponse)(nil), // 3: UnmapResponse - (*GetHomePodIPRequest)(nil), // 4: GetHomePodIPRequest - (*GetHomePodIPResponse)(nil), // 5: GetHomePodIPResponse - (*BelongsRequest)(nil), // 6: BelongsRequest - (*BelongsResponse)(nil), // 7: BelongsResponse + (*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 } var file_pkg_liqonet_ipam_ipam_proto_depIdxs = []int32{ - 0, // 0: ipam.MapEndpointIP:input_type -> MapRequest - 2, // 1: ipam.UnmapEndpointIP:input_type -> UnmapRequest - 4, // 2: ipam.GetHomePodIP:input_type -> GetHomePodIPRequest - 6, // 3: ipam.BelongsToPodCIDR:input_type -> BelongsRequest - 1, // 4: ipam.MapEndpointIP:output_type -> MapResponse - 3, // 5: ipam.UnmapEndpointIP:output_type -> UnmapResponse - 5, // 6: ipam.GetHomePodIP:output_type -> GetHomePodIPResponse - 7, // 7: ipam.BelongsToPodCIDR:output_type -> BelongsResponse - 4, // [4:8] is the sub-list for method output_type - 0, // [0:4] 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 + 0, // 0: ipam.MapEndpointIP:input_type -> MapRequest + 2, // 1: ipam.UnmapEndpointIP:input_type -> UnmapRequest + 4, // 2: ipam.MapNetworkCIDR:input_type -> MapCIDRRequest + 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 + 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 } func init() { file_pkg_liqonet_ipam_ipam_proto_init() } @@ -551,7 +754,7 @@ func file_pkg_liqonet_ipam_ipam_proto_init() { } } file_pkg_liqonet_ipam_ipam_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHomePodIPRequest); i { + switch v := v.(*MapCIDRRequest); i { case 0: return &v.state case 1: @@ -563,7 +766,7 @@ func file_pkg_liqonet_ipam_ipam_proto_init() { } } file_pkg_liqonet_ipam_ipam_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetHomePodIPResponse); i { + switch v := v.(*MapCIDRResponse); i { case 0: return &v.state case 1: @@ -575,7 +778,7 @@ func file_pkg_liqonet_ipam_ipam_proto_init() { } } file_pkg_liqonet_ipam_ipam_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BelongsRequest); i { + switch v := v.(*UnmapCIDRRequest); i { case 0: return &v.state case 1: @@ -587,6 +790,54 @@ func file_pkg_liqonet_ipam_ipam_proto_init() { } } file_pkg_liqonet_ipam_ipam_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UnmapCIDRResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_liqonet_ipam_ipam_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetHomePodIPRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_liqonet_ipam_ipam_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetHomePodIPResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_liqonet_ipam_ipam_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BelongsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_liqonet_ipam_ipam_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BelongsResponse); i { case 0: return &v.state @@ -605,7 +856,7 @@ func file_pkg_liqonet_ipam_ipam_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_pkg_liqonet_ipam_ipam_proto_rawDesc, NumEnums: 0, - NumMessages: 8, + NumMessages: 12, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/liqonet/ipam/ipam.proto b/pkg/liqonet/ipam/ipam.proto index 19d0b127af..924e97f5d5 100644 --- a/pkg/liqonet/ipam/ipam.proto +++ b/pkg/liqonet/ipam/ipam.proto @@ -4,6 +4,8 @@ option go_package = "./ipam"; service ipam { rpc MapEndpointIP (MapRequest) returns (MapResponse); rpc UnmapEndpointIP (UnmapRequest) returns (UnmapResponse); + rpc MapNetworkCIDR (MapCIDRRequest) returns (MapCIDRResponse); + rpc UnmapNetworkCIDR (UnmapCIDRRequest) returns (UnmapCIDRResponse); rpc GetHomePodIP (GetHomePodIPRequest) returns (GetHomePodIPResponse); rpc BelongsToPodCIDR (BelongsRequest) returns (BelongsResponse); } @@ -24,6 +26,20 @@ message UnmapRequest { message UnmapResponse {} +message MapCIDRRequest { + string cidr = 1; +} + +message MapCIDRResponse { + string cidr = 1; +} + +message UnmapCIDRRequest { + string cidr = 1; +} + +message UnmapCIDRResponse {} + message GetHomePodIPRequest { string clusterID = 1; string ip = 2; diff --git a/pkg/liqonet/ipam/ipam_grpc.pb.go b/pkg/liqonet/ipam/ipam_grpc.pb.go index 43c24b3726..8211f2bab5 100644 --- a/pkg/liqonet/ipam/ipam_grpc.pb.go +++ b/pkg/liqonet/ipam/ipam_grpc.pb.go @@ -22,6 +22,8 @@ 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" ) @@ -32,6 +34,8 @@ const ( type IpamClient interface { MapEndpointIP(ctx context.Context, in *MapRequest, opts ...grpc.CallOption) (*MapResponse, error) UnmapEndpointIP(ctx context.Context, in *UnmapRequest, opts ...grpc.CallOption) (*UnmapResponse, error) + MapNetworkCIDR(ctx context.Context, in *MapCIDRRequest, opts ...grpc.CallOption) (*MapCIDRResponse, error) + 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) } @@ -62,6 +66,24 @@ func (c *ipamClient) UnmapEndpointIP(ctx context.Context, in *UnmapRequest, opts return out, nil } +func (c *ipamClient) MapNetworkCIDR(ctx context.Context, in *MapCIDRRequest, opts ...grpc.CallOption) (*MapCIDRResponse, error) { + out := new(MapCIDRResponse) + err := c.cc.Invoke(ctx, Ipam_MapNetworkCIDR_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *ipamClient) UnmapNetworkCIDR(ctx context.Context, in *UnmapCIDRRequest, opts ...grpc.CallOption) (*UnmapCIDRResponse, error) { + out := new(UnmapCIDRResponse) + err := c.cc.Invoke(ctx, Ipam_UnmapNetworkCIDR_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *ipamClient) GetHomePodIP(ctx context.Context, in *GetHomePodIPRequest, opts ...grpc.CallOption) (*GetHomePodIPResponse, error) { out := new(GetHomePodIPResponse) err := c.cc.Invoke(ctx, Ipam_GetHomePodIP_FullMethodName, in, out, opts...) @@ -86,6 +108,8 @@ func (c *ipamClient) BelongsToPodCIDR(ctx context.Context, in *BelongsRequest, o type IpamServer interface { MapEndpointIP(context.Context, *MapRequest) (*MapResponse, error) UnmapEndpointIP(context.Context, *UnmapRequest) (*UnmapResponse, error) + MapNetworkCIDR(context.Context, *MapCIDRRequest) (*MapCIDRResponse, error) + UnmapNetworkCIDR(context.Context, *UnmapCIDRRequest) (*UnmapCIDRResponse, error) GetHomePodIP(context.Context, *GetHomePodIPRequest) (*GetHomePodIPResponse, error) BelongsToPodCIDR(context.Context, *BelongsRequest) (*BelongsResponse, error) mustEmbedUnimplementedIpamServer() @@ -101,6 +125,12 @@ func (UnimplementedIpamServer) MapEndpointIP(context.Context, *MapRequest) (*Map func (UnimplementedIpamServer) UnmapEndpointIP(context.Context, *UnmapRequest) (*UnmapResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UnmapEndpointIP not implemented") } +func (UnimplementedIpamServer) MapNetworkCIDR(context.Context, *MapCIDRRequest) (*MapCIDRResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method MapNetworkCIDR not implemented") +} +func (UnimplementedIpamServer) UnmapNetworkCIDR(context.Context, *UnmapCIDRRequest) (*UnmapCIDRResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UnmapNetworkCIDR not implemented") +} func (UnimplementedIpamServer) GetHomePodIP(context.Context, *GetHomePodIPRequest) (*GetHomePodIPResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetHomePodIP not implemented") } @@ -156,6 +186,42 @@ func _Ipam_UnmapEndpointIP_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } +func _Ipam_MapNetworkCIDR_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MapCIDRRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IpamServer).MapNetworkCIDR(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Ipam_MapNetworkCIDR_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IpamServer).MapNetworkCIDR(ctx, req.(*MapCIDRRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Ipam_UnmapNetworkCIDR_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UnmapCIDRRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IpamServer).UnmapNetworkCIDR(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Ipam_UnmapNetworkCIDR_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IpamServer).UnmapNetworkCIDR(ctx, req.(*UnmapCIDRRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Ipam_GetHomePodIP_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetHomePodIPRequest) if err := dec(in); err != nil { @@ -207,6 +273,14 @@ var Ipam_ServiceDesc = grpc.ServiceDesc{ MethodName: "UnmapEndpointIP", Handler: _Ipam_UnmapEndpointIP_Handler, }, + { + MethodName: "MapNetworkCIDR", + Handler: _Ipam_MapNetworkCIDR_Handler, + }, + { + MethodName: "UnmapNetworkCIDR", + Handler: _Ipam_UnmapNetworkCIDR_Handler, + }, { MethodName: "GetHomePodIP", Handler: _Ipam_GetHomePodIP_Handler, diff --git a/pkg/utils/foreignCluster/getForeignCluster.go b/pkg/utils/foreignCluster/getForeignCluster.go index 93f507e40a..ee616d7ba2 100644 --- a/pkg/utils/foreignCluster/getForeignCluster.go +++ b/pkg/utils/foreignCluster/getForeignCluster.go @@ -37,6 +37,19 @@ import ( "github.com/liqotech/liqo/pkg/discovery" ) +// CheckForeignClusterExistence checks if a ForeignCluster with the given clusterID exists. +func CheckForeignClusterExistence(ctx context.Context, cl client.Client, clusterID string) (bool, error) { + _, err := GetForeignClusterByID(ctx, cl, clusterID) + if kerrors.IsNotFound(err) { + klog.Errorf("no ForeignCluster with clusterID %q found: %v", clusterID, err) + return false, err + } else if err != nil { + klog.Errorf("an error occurred when trying to retrieve ForeignClusters: %v", err) + return false, err + } + return true, nil +} + // GetForeignClusterByID returns a ForeignCluster CR retrieving it by its clusterID. func GetForeignClusterByID(ctx context.Context, cl client.Client, clusterID string) (*discoveryv1alpha1.ForeignCluster, error) { lSelector := labels.SelectorFromSet(labels.Set{ diff --git a/pkg/utils/mapper/mapper.go b/pkg/utils/mapper/mapper.go index 8a71e1a653..dfd2010b79 100644 --- a/pkg/utils/mapper/mapper.go +++ b/pkg/utils/mapper/mapper.go @@ -30,6 +30,7 @@ import ( "k8s.io/klog/v2" discoveryv1alpha1 "github.com/liqotech/liqo/apis/discovery/v1alpha1" + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" netv1alpha1 "github.com/liqotech/liqo/apis/net/v1alpha1" offv1alpha1 "github.com/liqotech/liqo/apis/offloading/v1alpha1" sharingv1alpha1 "github.com/liqotech/liqo/apis/sharing/v1alpha1" @@ -85,6 +86,9 @@ func addDefaults(dClient *discovery.DiscoveryClient, mapper *meta.DefaultRESTMap if err = addGroup(dClient, offv1alpha1.GroupVersion, mapper); err != nil { return err } + if err = addGroup(dClient, ipamv1alpha1.GroupVersion, mapper); err != nil { + return err + } // Kubernetes groups if err = addGroup(dClient, corev1.SchemeGroupVersion, mapper); err != nil {