From 9df0c13604203456fd15aa83721bc814fc05c087 Mon Sep 17 00:00:00 2001 From: Francesco Cheinasso Date: Tue, 19 Sep 2023 16:33:26 +0200 Subject: [PATCH] Configuration controller --- Makefile | 2 +- apis/ipam/v1alpha1/network_types.go | 6 +- apis/networking/v1alpha1/common_types.go | 37 ++++++ .../v1alpha1/configuration_types.go | 11 +- .../v1alpha1/gatewayserver_types.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 20 +-- cmd/liqonet/main.go | 4 + cmd/liqonet/network-manager.go | 8 ++ .../liqo-crds/crds/ipam.liqo.io_networks.yaml | 2 + .../networking.liqo.io_configurations.yaml | 12 +- .../crds/networking.liqo.io_connections.yaml | 2 + .../networking.liqo.io_gatewayservers.yaml | 2 + .../networking.liqo.io_wggatewayservers.yaml | 2 + .../liqo-network-manager-ClusterRole.yaml | 9 ++ .../network-controller/network_controller.go | 15 +-- .../webhooks/network/nw.go | 2 +- .../configuration-controller.go | 118 ++++++++++++++++++ pkg/liqonet/configuration-controller/doc.go | 16 +++ pkg/liqonet/configuration-controller/label.go | 42 +++++++ .../configuration-controller/network.go | 68 ++++++++++ pkg/utils/getters/k8sGetters.go | 11 ++ samples/configuration1.yaml | 16 +++ 22 files changed, 379 insertions(+), 28 deletions(-) create mode 100644 apis/networking/v1alpha1/common_types.go create mode 100644 pkg/liqonet/configuration-controller/configuration-controller.go create mode 100644 pkg/liqonet/configuration-controller/doc.go create mode 100644 pkg/liqonet/configuration-controller/label.go create mode 100644 pkg/liqonet/configuration-controller/network.go create mode 100644 samples/configuration1.yaml diff --git a/Makefile b/Makefile index 9a7a4cca73..7688d2c546 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ rbacs: controller-gen rm -f deployments/liqo/files/* $(CONTROLLER_GEN) paths="./internal/liqonet/route-operator" rbac:roleName=liqo-route output:rbac:stdout | awk -v RS="---\n" 'NR>1{f="./deployments/liqo/files/liqo-route-" $$4 ".yaml";printf "%s",$$0 > f; close(f)}' && sed -i -n '/rules/,$$p' deployments/liqo/files/liqo-route-ClusterRole.yaml deployments/liqo/files/liqo-route-Role.yaml $(CONTROLLER_GEN) paths="./internal/liqonet/tunnel-operator" rbac:roleName=liqo-gateway output:rbac:stdout | awk -v RS="---\n" 'NR>1{f="./deployments/liqo/files/liqo-gateway-" $$4 ".yaml";printf "%s",$$0 > f; close(f)}' && sed -i -n '/rules/,$$p' deployments/liqo/files/liqo-gateway-ClusterRole.yaml deployments/liqo/files/liqo-gateway-Role.yaml - $(CONTROLLER_GEN) paths="./internal/liqonet/network-manager/..." rbac:roleName=liqo-network-manager output:rbac:stdout | awk -v RS="---\n" 'NR>1{f="./deployments/liqo/files/liqo-network-manager-" $$4 ".yaml";printf "%s",$$0 > f; close(f)}' && sed -i -n '/rules/,$$p' deployments/liqo/files/liqo-network-manager-ClusterRole.yaml deployments/liqo/files/liqo-network-manager-Role.yaml + $(CONTROLLER_GEN) paths="{./internal/liqonet/network-manager/...,./pkg/liqonet/...}" rbac:roleName=liqo-network-manager output:rbac:stdout | awk -v RS="---\n" 'NR>1{f="./deployments/liqo/files/liqo-network-manager-" $$4 ".yaml";printf "%s",$$0 > f; close(f)}' && sed -i -n '/rules/,$$p' deployments/liqo/files/liqo-network-manager-ClusterRole.yaml deployments/liqo/files/liqo-network-manager-Role.yaml $(CONTROLLER_GEN) paths="./internal/crdReplicator" rbac:roleName=liqo-crd-replicator output:rbac:stdout | awk -v RS="---\n" 'NR>1{f="./deployments/liqo/files/liqo-crd-replicator-" $$4 ".yaml";printf "%s",$$0 > f; close(f)}' && sed -i -n '/rules/,$$p' deployments/liqo/files/liqo-crd-replicator-ClusterRole.yaml deployments/liqo/files/liqo-crd-replicator-Role.yaml $(CONTROLLER_GEN) paths="./pkg/discoverymanager" rbac:roleName=liqo-discovery output:rbac:stdout | awk -v RS="---\n" 'NR>1{f="./deployments/liqo/files/liqo-discovery-" $$4 ".yaml";printf "%s",$$0 > f; close(f)}' && sed -i -n '/rules/,$$p' deployments/liqo/files/liqo-discovery-ClusterRole.yaml deployments/liqo/files/liqo-discovery-Role.yaml $(CONTROLLER_GEN) paths="./internal/auth-service" rbac:roleName=liqo-auth-service output:rbac:stdout | awk -v RS="---\n" 'NR>1{f="./deployments/liqo/files/liqo-auth-" $$4 ".yaml";printf "%s",$$0 > f; close(f)}' && sed -i -n '/rules/,$$p' deployments/liqo/files/liqo-auth-ClusterRole.yaml deployments/liqo/files/liqo-auth-Role.yaml diff --git a/apis/ipam/v1alpha1/network_types.go b/apis/ipam/v1alpha1/network_types.go index 07d16ce748..62c0aa9750 100644 --- a/apis/ipam/v1alpha1/network_types.go +++ b/apis/ipam/v1alpha1/network_types.go @@ -17,6 +17,8 @@ package v1alpha1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + + v1alpha1networking "github.com/liqotech/liqo/apis/networking/v1alpha1" ) var ( @@ -36,13 +38,13 @@ var ( // NetworkSpec defines the desired state of Network. type NetworkSpec struct { // CIDR is the desired CIDR for the remote cluster. - CIDR string `json:"cidr"` + CIDR v1alpha1networking.CIDR `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"` + CIDR v1alpha1networking.CIDR `json:"cidr,omitempty"` } // +kubebuilder:object:root=true diff --git a/apis/networking/v1alpha1/common_types.go b/apis/networking/v1alpha1/common_types.go new file mode 100644 index 0000000000..eb2ae4a013 --- /dev/null +++ b/apis/networking/v1alpha1/common_types.go @@ -0,0 +1,37 @@ +// 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 networking v1alpha1 API group. +// +//nolint:lll // ignore long lines given by Kubebuilder marker annotations. +package v1alpha1 + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// CIDR defines a syntax validated CIDR. +// +kubebuilder:validation:Pattern=`^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\/([0-9]|[1-2][0-9]|3[0-2])$` +type CIDR string + +func (c CIDR) String() string { + return string(c) +} + +// IP defines a syntax validated IP. +// +kubebuilder:validation:Pattern=`^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])$` +type IP string + +func (i IP) String() string { + return string(i) +} diff --git a/apis/networking/v1alpha1/configuration_types.go b/apis/networking/v1alpha1/configuration_types.go index f30df97cae..acbfbc502d 100644 --- a/apis/networking/v1alpha1/configuration_types.go +++ b/apis/networking/v1alpha1/configuration_types.go @@ -34,18 +34,18 @@ var ConfigurationGroupResource = schema.GroupResource{Group: GroupVersion.Group, // ConfigurationGroupVersionResource is groupResourceVersion used to register these objects. var ConfigurationGroupVersionResource = GroupVersion.WithResource(ConfigurationResource) -// CIDR defines the CIDR of the cluster. -type CIDR struct { +// ClusterConfigCIDR defines the CIDR of the cluster. +type ClusterConfigCIDR struct { // Pod CIDR of the cluster. - Pod string `json:"pod,omitempty"` + Pod CIDR `json:"pod,omitempty"` // External CIDR of the cluster. - External string `json:"external,omitempty"` + External CIDR `json:"external,omitempty"` } // ClusterConfig defines the configuration of a cluster. type ClusterConfig struct { // CIDR of the cluster. - CIDR CIDR `json:"cidr,omitempty"` + CIDR ClusterConfigCIDR `json:"cidr,omitempty"` } // ConfigurationSpec defines the desired state of Configuration. @@ -65,6 +65,7 @@ type ConfigurationStatus struct { // +kubebuilder:object:root=true // +kubebuilder:resource:categories=liqo // +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Alias",type=string,JSONPath=`.spec.alias` // Configuration contains the network configuration of a pair of clusters, // including the local and the remote pod and external CIDRs and how the where remapped. diff --git a/apis/networking/v1alpha1/gatewayserver_types.go b/apis/networking/v1alpha1/gatewayserver_types.go index cd88bf6686..e008d34a50 100644 --- a/apis/networking/v1alpha1/gatewayserver_types.go +++ b/apis/networking/v1alpha1/gatewayserver_types.go @@ -58,7 +58,7 @@ type GatewayServerSpec struct { // EndpointStatus defines the observed state of the endpoint. type EndpointStatus struct { // Addresses specifies the addresses of the endpoint. - Addresses []string `json:"addresses,omitempty"` + Addresses []IP `json:"addresses,omitempty"` // Port specifies the port of the endpoint. Port int32 `json:"port,omitempty"` // Protocol specifies the protocol of the endpoint. diff --git a/apis/networking/v1alpha1/zz_generated.deepcopy.go b/apis/networking/v1alpha1/zz_generated.deepcopy.go index 1512f97544..914f96b6db 100644 --- a/apis/networking/v1alpha1/zz_generated.deepcopy.go +++ b/apis/networking/v1alpha1/zz_generated.deepcopy.go @@ -49,32 +49,32 @@ func (in *AddRemove) DeepCopy() *AddRemove { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CIDR) DeepCopyInto(out *CIDR) { +func (in *ClusterConfig) DeepCopyInto(out *ClusterConfig) { *out = *in + out.CIDR = in.CIDR } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CIDR. -func (in *CIDR) DeepCopy() *CIDR { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterConfig. +func (in *ClusterConfig) DeepCopy() *ClusterConfig { if in == nil { return nil } - out := new(CIDR) + out := new(ClusterConfig) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ClusterConfig) DeepCopyInto(out *ClusterConfig) { +func (in *ClusterConfigCIDR) DeepCopyInto(out *ClusterConfigCIDR) { *out = *in - out.CIDR = in.CIDR } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterConfig. -func (in *ClusterConfig) DeepCopy() *ClusterConfig { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterConfigCIDR. +func (in *ClusterConfigCIDR) DeepCopy() *ClusterConfigCIDR { if in == nil { return nil } - out := new(ClusterConfig) + out := new(ClusterConfigCIDR) in.DeepCopyInto(out) return out } @@ -326,7 +326,7 @@ func (in *EndpointStatus) DeepCopyInto(out *EndpointStatus) { *out = *in if in.Addresses != nil { in, out := &in.Addresses, &out.Addresses - *out = make([]string, len(*in)) + *out = make([]IP, len(*in)) copy(*out, *in) } if in.Protocol != nil { diff --git a/cmd/liqonet/main.go b/cmd/liqonet/main.go index efe03837cd..872dfa9b7b 100644 --- a/cmd/liqonet/main.go +++ b/cmd/liqonet/main.go @@ -16,6 +16,7 @@ package main import ( "flag" + "fmt" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -26,6 +27,7 @@ import ( discoveryv1alpha1 "github.com/liqotech/liqo/apis/discovery/v1alpha1" netv1alpha1 "github.com/liqotech/liqo/apis/net/v1alpha1" + networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" liqoconst "github.com/liqotech/liqo/pkg/consts" "github.com/liqotech/liqo/pkg/utils/restcfg" ) @@ -47,6 +49,8 @@ func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(discoveryv1alpha1.AddToScheme(scheme)) utilruntime.Must(netv1alpha1.AddToScheme(scheme)) + utilruntime.Must(networkingv1alpha1.AddToScheme(scheme)) + fmt.Print(scheme) } func main() { diff --git a/cmd/liqonet/network-manager.go b/cmd/liqonet/network-manager.go index 2883152346..9841da876c 100644 --- a/cmd/liqonet/network-manager.go +++ b/cmd/liqonet/network-manager.go @@ -30,6 +30,7 @@ import ( "github.com/liqotech/liqo/internal/liqonet/network-manager/netcfgcreator" "github.com/liqotech/liqo/internal/liqonet/network-manager/tunnelendpointcreator" liqoconst "github.com/liqotech/liqo/pkg/consts" + configurationcontroller "github.com/liqotech/liqo/pkg/liqonet/configuration-controller" liqonetIpam "github.com/liqotech/liqo/pkg/liqonet/ipam" liqonetutils "github.com/liqotech/liqo/pkg/liqonet/utils" "github.com/liqotech/liqo/pkg/utils/args" @@ -109,6 +110,8 @@ func runNetworkManager(commonFlags *liqonetCommonFlags, managerFlags *networkMan ExternalCIDR: externalCIDR, } + cfgr := configurationcontroller.NewConfigurationReconciler(mgr.GetClient(), mgr.GetScheme(), mgr.GetEventRecorderFor("configuration-controller")) + if err = tec.SetupWithManager(mgr); err != nil { klog.Errorf("unable to create controller TunnelEndpointCreator: %s", err) os.Exit(1) @@ -119,6 +122,11 @@ func runNetworkManager(commonFlags *liqonetCommonFlags, managerFlags *networkMan os.Exit(1) } + if err = cfgr.SetupWithManager(mgr); err != nil { + klog.Errorf("unable to create controller ConfigurationReconciler: %s", err) + os.Exit(1) + } + klog.Info("starting manager as liqo-network-manager") if err := mgr.Start(tec.SetupSignalHandlerForTunEndCreator()); err != nil { klog.Errorf("an error occurred while starting manager: %s", err) diff --git a/deployments/liqo/charts/liqo-crds/crds/ipam.liqo.io_networks.yaml b/deployments/liqo/charts/liqo-crds/crds/ipam.liqo.io_networks.yaml index d9b5dcdc8b..ff93fcb180 100644 --- a/deployments/liqo/charts/liqo-crds/crds/ipam.liqo.io_networks.yaml +++ b/deployments/liqo/charts/liqo-crds/crds/ipam.liqo.io_networks.yaml @@ -48,6 +48,7 @@ spec: properties: cidr: description: CIDR is the desired CIDR for the remote cluster. + pattern: ^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\/([0-9]|[1-2][0-9]|3[0-2])$ type: string required: - cidr @@ -57,6 +58,7 @@ spec: properties: cidr: description: CIDR is the remapped CIDR for the remote cluster. + pattern: ^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\/([0-9]|[1-2][0-9]|3[0-2])$ type: string type: object required: diff --git a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_configurations.yaml b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_configurations.yaml index 00c7801758..da5af033c3 100644 --- a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_configurations.yaml +++ b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_configurations.yaml @@ -16,7 +16,11 @@ spec: singular: configuration scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .spec.alias + name: Alias + type: string + name: v1alpha1 schema: openAPIV3Schema: description: Configuration contains the network configuration of a pair of @@ -47,9 +51,11 @@ spec: properties: external: description: External CIDR of the cluster. + pattern: ^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\/([0-9]|[1-2][0-9]|3[0-2])$ type: string pod: description: Pod CIDR of the cluster. + pattern: ^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\/([0-9]|[1-2][0-9]|3[0-2])$ type: string type: object type: object @@ -61,9 +67,11 @@ spec: properties: external: description: External CIDR of the cluster. + pattern: ^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\/([0-9]|[1-2][0-9]|3[0-2])$ type: string pod: description: Pod CIDR of the cluster. + pattern: ^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\/([0-9]|[1-2][0-9]|3[0-2])$ type: string type: object type: object @@ -80,9 +88,11 @@ spec: properties: external: description: External CIDR of the cluster. + pattern: ^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\/([0-9]|[1-2][0-9]|3[0-2])$ type: string pod: description: Pod CIDR of the cluster. + pattern: ^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\/([0-9]|[1-2][0-9]|3[0-2])$ type: string type: object type: object diff --git a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_connections.yaml b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_connections.yaml index 48c7509a63..342794d185 100644 --- a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_connections.yaml +++ b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_connections.yaml @@ -88,6 +88,8 @@ spec: addresses: description: Addresses specifies the addresses of the endpoint. items: + description: IP defines a syntax validated IP. + pattern: ^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])$ type: string type: array port: diff --git a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_gatewayservers.yaml b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_gatewayservers.yaml index 0b73a9b025..9cfbeca582 100644 --- a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_gatewayservers.yaml +++ b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_gatewayservers.yaml @@ -105,6 +105,8 @@ spec: addresses: description: Addresses specifies the addresses of the endpoint. items: + description: IP defines a syntax validated IP. + pattern: ^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])$ type: string type: array port: diff --git a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_wggatewayservers.yaml b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_wggatewayservers.yaml index 77d8105c15..aaa49bc315 100644 --- a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_wggatewayservers.yaml +++ b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_wggatewayservers.yaml @@ -8966,6 +8966,8 @@ spec: addresses: description: Addresses specifies the addresses of the endpoint. items: + description: IP defines a syntax validated IP. + pattern: ^(([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]{0,1}[0-9]{0,2}|2[0-4][0-9]|25[0-5])$ type: string type: array port: diff --git a/deployments/liqo/files/liqo-network-manager-ClusterRole.yaml b/deployments/liqo/files/liqo-network-manager-ClusterRole.yaml index 8fb45b2f1e..174008704f 100644 --- a/deployments/liqo/files/liqo-network-manager-ClusterRole.yaml +++ b/deployments/liqo/files/liqo-network-manager-ClusterRole.yaml @@ -84,3 +84,12 @@ rules: - patch - update - watch +- apiGroups: + - networking.liqo.io + resources: + - configuration + verbs: + - get + - list + - update + - watch diff --git a/pkg/liqo-controller-manager/network-controller/network_controller.go b/pkg/liqo-controller-manager/network-controller/network_controller.go index c04febfed8..6927d900b2 100644 --- a/pkg/liqo-controller-manager/network-controller/network_controller.go +++ b/pkg/liqo-controller-manager/network-controller/network_controller.go @@ -28,6 +28,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" + networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" "github.com/liqotech/liqo/pkg/consts" "github.com/liqotech/liqo/pkg/liqonet/ipam" foreignclusterutils "github.com/liqotech/liqo/pkg/utils/foreignCluster" @@ -52,7 +53,7 @@ type NetworkReconciler struct { // Reconcile Network objects. func (r *NetworkReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { var nw ipamv1alpha1.Network - var desiredCIDR, remappedCIDR string + var desiredCIDR, remappedCIDR networkingv1alpha1.CIDR // Fetch the Network instance if err := r.Get(ctx, req.NamespacedName, &nw); err != nil { @@ -116,7 +117,7 @@ func (r *NetworkReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct // 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 { + if _, _, err := net.ParseCIDR(remappedCIDR.String()); err != nil { klog.Errorf("Unable to unmap CIDR %s of Network %q (inavlid format): %v", remappedCIDR, req.NamespacedName, err) return ctrl.Result{}, err } @@ -148,32 +149,32 @@ func (r *NetworkReconciler) SetupWithManager(mgr ctrl.Manager, workers int) erro } // getRemappedCIDR returns the remapped CIDR for the given CIDR and remote clusterID. -func getRemappedCIDR(ctx context.Context, ipamClient ipam.IpamClient, desiredCIDR string) (string, error) { +func getRemappedCIDR(ctx context.Context, ipamClient ipam.IpamClient, desiredCIDR networkingv1alpha1.CIDR) (networkingv1alpha1.CIDR, error) { switch ipamClient.(type) { case nil: // IPAM is not enabled, use original CIDR from spec return desiredCIDR, nil default: // interact with the IPAM to retrieve the correct mapping. - response, err := ipamClient.MapNetworkCIDR(ctx, &ipam.MapCIDRRequest{Cidr: desiredCIDR}) + response, err := ipamClient.MapNetworkCIDR(ctx, &ipam.MapCIDRRequest{Cidr: desiredCIDR.String()}) 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 + return networkingv1alpha1.CIDR(response.Cidr), nil } } // deleteRemappedCIDR unmaps the CIDR for the given remote clusterID. -func deleteRemappedCIDR(ctx context.Context, ipamClient ipam.IpamClient, remappedCIDR string) error { +func deleteRemappedCIDR(ctx context.Context, ipamClient ipam.IpamClient, remappedCIDR networkingv1alpha1.CIDR) 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}) + _, err := ipamClient.UnmapNetworkCIDR(ctx, &ipam.UnmapCIDRRequest{Cidr: remappedCIDR.String()}) if err != nil { klog.Errorf("IPAM: error while unmapping CIDR %s: %v", remappedCIDR, err) return err diff --git a/pkg/liqo-controller-manager/webhooks/network/nw.go b/pkg/liqo-controller-manager/webhooks/network/nw.go index 21452e471e..8c803232fa 100644 --- a/pkg/liqo-controller-manager/webhooks/network/nw.go +++ b/pkg/liqo-controller-manager/webhooks/network/nw.go @@ -89,7 +89,7 @@ func (w *nwwhv) HandleCreate(req *admission.Request) admission.Response { } // Check if the CIDR is a valid network - if _, _, err := net.ParseCIDR(nw.Spec.CIDR); err != nil { + if _, _, err := net.ParseCIDR(nw.Spec.CIDR.String()); err != nil { return admission.Denied(fmt.Sprintf("Invalid CIDR: %v", err)) } diff --git a/pkg/liqonet/configuration-controller/configuration-controller.go b/pkg/liqonet/configuration-controller/configuration-controller.go new file mode 100644 index 0000000000..09ba54edc6 --- /dev/null +++ b/pkg/liqonet/configuration-controller/configuration-controller.go @@ -0,0 +1,118 @@ +// 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 configurationcontroller + +import ( + "context" + "fmt" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/record" + "k8s.io/klog/v2" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" + networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" +) + +// ConfigurationReconciler manage Configuration lifecycle. +type ConfigurationReconciler struct { + client.Client + Scheme *runtime.Scheme + EventsRecorder record.EventRecorder +} + +// NewConfigurationReconciler returns a new ConfigurationReconciler. +func NewConfigurationReconciler(cl client.Client, s *runtime.Scheme, er record.EventRecorder) *ConfigurationReconciler { + return &ConfigurationReconciler{ + Client: cl, + Scheme: s, + EventsRecorder: er, + } +} + +// cluster-role +// +kubebuilder:rbac:groups=networking.liqo.io,resources=configuration,verbs=get;list;watch;update + +// Reconcile manage NamespaceMaps associated with the virtual-node. +func (r *ConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + configuration := &networkingv1alpha1.Configuration{} + if err := r.Get(ctx, req.NamespacedName, configuration); err != nil { + if apierrors.IsNotFound(err) { + klog.Infof("There is no a configuration called '%s' in '%s'", req.Name, req.Namespace) + return ctrl.Result{}, nil + } + return ctrl.Result{}, fmt.Errorf(" %w --> Unable to get the configuration '%s'", err, req.Name) + } + + requeue, err := r.RemapConfiguration(ctx, configuration) + if requeue || err != nil { + return ctrl.Result{}, err + } + + return ctrl.Result{}, r.UpdateConfigurationStatus(ctx, configuration) +} + +// RemapConfiguration remap the configuration using ipamv1alpha1.Network. +func (r *ConfigurationReconciler) RemapConfiguration(ctx context.Context, cfg *networkingv1alpha1.Configuration) (requeue bool, err error) { + var cidrRemapped networkingv1alpha1.CIDR + for _, cidrType := range LabelCIDRTypeValues { + switch cidrType { + case LabelCIDRTypePod: + cidrRemapped = cfg.Status.Remote.CIDR.Pod + case LabelCIDRTypeExternal: + cidrRemapped = cfg.Status.Remote.CIDR.External + } + if cidrRemapped != "" { + continue + } + network, err := CreateOrGetNetwork(ctx, r.Client, r.Scheme, cfg, cidrType) + if err != nil { + return true, fmt.Errorf(" %w --> Unable to create or get the network '%s'", err, network.Name) + } + if network.Status.CIDR == "" { + return true, nil + } + var cidrNew, cidrOld networkingv1alpha1.CIDR + cidrNew = network.Status.CIDR + switch cidrType { + case LabelCIDRTypePod: + cidrOld = cfg.Status.Remote.CIDR.Pod + cfg.Status.Remote.CIDR.Pod = network.Status.CIDR + case LabelCIDRTypeExternal: + cidrOld = cfg.Status.Remote.CIDR.External + cfg.Status.Remote.CIDR.External = network.Status.CIDR + } + klog.Infof("Configuration %s/%s %s CIDR: %s -> %s", cfg.Name, cfg.Namespace, cidrType, cidrOld, cidrNew) + } + return false, nil +} + +// UpdateConfigurationStatus update the status of the configuration. +func (r *ConfigurationReconciler) UpdateConfigurationStatus(ctx context.Context, cfg *networkingv1alpha1.Configuration) error { + if err := r.Status().Update(ctx, cfg); err != nil { + return fmt.Errorf(" %w --> Unable to update the configuration '%s'", err, cfg.Name) + } + return nil +} + +// SetupWithManager register the ConfigurationReconciler to the manager. +func (r *ConfigurationReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&networkingv1alpha1.Configuration{}).Owns(&ipamv1alpha1.Network{}). + Complete(r) +} diff --git a/pkg/liqonet/configuration-controller/doc.go b/pkg/liqonet/configuration-controller/doc.go new file mode 100644 index 0000000000..69b28a4b20 --- /dev/null +++ b/pkg/liqonet/configuration-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 configurationcontroller contains the logic to manage the Configuration resource. +package configurationcontroller diff --git a/pkg/liqonet/configuration-controller/label.go b/pkg/liqonet/configuration-controller/label.go new file mode 100644 index 0000000000..0499c8cd34 --- /dev/null +++ b/pkg/liqonet/configuration-controller/label.go @@ -0,0 +1,42 @@ +// 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 configurationcontroller + +import "k8s.io/apimachinery/pkg/labels" + +// LabelCIDRType is the label used to target a ipamv1alpha1.Network resource that manages a PodCIDR or an ExternalCIDR. +const LabelCIDRType = "configuration.liqo.io/cidr-type" + +// LabelCIDRTypeValue is the value of the LabelCIDRType label. +type LabelCIDRTypeValue string + +const ( + // LabelCIDRTypePod is used to target a ipamv1alpha1.Network resource that manages a PodCIDR. + LabelCIDRTypePod LabelCIDRTypeValue = "pod" + // LabelCIDRTypeExternal is used to target a ipamv1alpha1.Network resource that manages an ExternalCIDR. + LabelCIDRTypeExternal LabelCIDRTypeValue = "external" +) + +var LabelCIDRTypeValues = []LabelCIDRTypeValue{LabelCIDRTypePod, LabelCIDRTypeExternal} + +func ForgeLabel(cidrType LabelCIDRTypeValue) map[string]string { + return map[string]string{ + LabelCIDRType: string(cidrType), + } +} + +func ForgeLabelSelector(cidrType LabelCIDRTypeValue) labels.Selector { + return labels.SelectorFromSet(ForgeLabel(cidrType)) +} diff --git a/pkg/liqonet/configuration-controller/network.go b/pkg/liqonet/configuration-controller/network.go new file mode 100644 index 0000000000..30eb3800a9 --- /dev/null +++ b/pkg/liqonet/configuration-controller/network.go @@ -0,0 +1,68 @@ +// 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 configurationcontroller + +import ( + "context" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + ctrlutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + ipamv1alpha1 "github.com/liqotech/liqo/apis/ipam/v1alpha1" + networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" + "github.com/liqotech/liqo/pkg/utils/getters" +) + +// ForgeNetwork creates a ipamv1alpha1.Network resource. +func ForgeNetwork(cfg networkingv1alpha1.Configuration, cidrType LabelCIDRTypeValue, scheme *runtime.Scheme) *ipamv1alpha1.Network { + network := &ipamv1alpha1.Network{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s", cfg.Name, cidrType), + Namespace: cfg.Namespace, + Labels: ForgeLabel(cidrType), + }, + Spec: ipamv1alpha1.NetworkSpec{ + CIDR: cfg.Spec.Remote.CIDR.Pod, + }, + } + ctrlutil.SetOwnerReference(&cfg, network, scheme) + return network +} + +// CreateOrGetNetwork creates or gets a ipamv1alpha1.Network resource. +func CreateOrGetNetwork(ctx context.Context, cl client.Client, scheme *runtime.Scheme, + cfg *networkingv1alpha1.Configuration, cidrType LabelCIDRTypeValue) (*ipamv1alpha1.Network, error) { + ls := ForgeLabelSelector(cidrType) + ns := cfg.Namespace + list, err := getters.ListNetworkByLabel(ctx, cl, ns, ls) + if err != nil { + return nil, err + } + if len(list.Items) == 1 { + return &list.Items[0], nil + } + if len(list.Items) > 1 { + return nil, fmt.Errorf("multiple networks found with label selector '%s'", ls) + } + network := ForgeNetwork(*cfg, cidrType, scheme) + + if err := cl.Create(ctx, network); err != nil { + return nil, err + } + return network, nil +} diff --git a/pkg/utils/getters/k8sGetters.go b/pkg/utils/getters/k8sGetters.go index 236e1e07b8..e444395285 100644 --- a/pkg/utils/getters/k8sGetters.go +++ b/pkg/utils/getters/k8sGetters.go @@ -27,6 +27,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" 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" @@ -325,3 +326,13 @@ func ListVirtualKubeletPodsFromVirtualNode(ctx context.Context, cl client.Client } return list, nil } + +// ListNetworkByLabel returns the Network resource with the given labels. +func ListNetworkByLabel(ctx context.Context, cl client.Client, ns string, lSelector labels.Selector) (*ipamv1alpha1.NetworkList, error) { + list := &ipamv1alpha1.NetworkList{} + err := cl.List(ctx, list, &client.ListOptions{LabelSelector: lSelector}, client.InNamespace(ns)) + if err != nil { + return nil, err + } + return list, err +} diff --git a/samples/configuration1.yaml b/samples/configuration1.yaml new file mode 100644 index 0000000000..8489186dd3 --- /dev/null +++ b/samples/configuration1.yaml @@ -0,0 +1,16 @@ +apiVersion: networking.liqo.io/v1alpha1 +kind: Configuration +metadata: + name: configuration-sample +spec: + local: + cidr: + external: 0.0.225.0/3 + pod: 10.3.3.3/4 + remote: + cidr: + external: 6.6.6.6/3 + pod: 255.255.255.255/10 + + +