diff --git a/pkg/clusterlink/agent-manager/agent_controller.go b/pkg/clusterlink/agent-manager/agent_controller.go index 835bcf0c1..0362ffcdd 100644 --- a/pkg/clusterlink/agent-manager/agent_controller.go +++ b/pkg/clusterlink/agent-manager/agent_controller.go @@ -2,6 +2,7 @@ package agent import ( "context" + "fmt" "time" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -21,6 +22,7 @@ import ( "github.com/kosmos.io/kosmos/pkg/clusterlink/controllers/node" "github.com/kosmos.io/kosmos/pkg/clusterlink/network" kosmosv1alpha1lister "github.com/kosmos.io/kosmos/pkg/generated/listers/kosmos/v1alpha1" + "github.com/kosmos.io/kosmos/pkg/utils" ) const ( @@ -93,6 +95,20 @@ func (r *Reconciler) logResult(nodeConfigSyncStatus networkmanager.NodeConfigSyn } } +func formatNodeConfig(nodeConfig *kosmosv1alpha1.NodeConfig) (*kosmosv1alpha1.NodeConfig, error) { + nodeConfigCopy := nodeConfig.DeepCopy() + + for i, route := range nodeConfigCopy.Spec.Routes { + ipNetStr, err := utils.FormatCIDR(route.CIDR) + if err != nil { + return nil, fmt.Errorf("failed to format nodeconfig route cidr, err: %s", err.Error()) + } + nodeConfigCopy.Spec.Routes[i].CIDR = ipNetStr + } + + return nodeConfigCopy, nil +} + func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { klog.Infof("============ agent starts to reconcile %s ============", request.NamespacedName) @@ -109,6 +125,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) ( return reconcile.Result{RequeueAfter: RequeueTime}, nil } + reconcileNodeCopy, err := formatNodeConfig(&reconcileNode) + if err != nil { + klog.Errorf("format nodeconfig %s error: %v", request.NamespacedName, err) + return reconcile.Result{RequeueAfter: RequeueTime}, nil + } + localCluster, err := r.ClusterLister.Get(r.ClusterName) if err != nil { klog.Errorf("could not get local cluster, clusterNode: %s, err: %v", r.NodeName, err) @@ -118,7 +140,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) ( r.NetworkManager.UpdateConfig(localCluster) r.DebounceFunc(func() { - nodeConfigSyncStatus := r.NetworkManager.UpdateFromCRD(&reconcileNode) + nodeConfigSyncStatus := r.NetworkManager.UpdateFromCRD(reconcileNodeCopy) r.logResult(nodeConfigSyncStatus) }) diff --git a/pkg/clusterlink/agent-manager/agent_controller_test.go b/pkg/clusterlink/agent-manager/agent_controller_test.go new file mode 100644 index 000000000..ee38489d5 --- /dev/null +++ b/pkg/clusterlink/agent-manager/agent_controller_test.go @@ -0,0 +1,104 @@ +package agent + +import ( + "testing" + + kosmosv1alpha1 "github.com/kosmos.io/kosmos/pkg/apis/kosmos/v1alpha1" +) + +func TestFormatNodeConfig(t *testing.T) { + tests := []struct { + name string + input *kosmosv1alpha1.NodeConfig + want *kosmosv1alpha1.NodeConfig + }{ + { + name: "test ipv4 and ipv6", + input: &kosmosv1alpha1.NodeConfig{ + Spec: kosmosv1alpha1.NodeConfigSpec{ + Routes: []kosmosv1alpha1.Route{ + { + CIDR: "2409:8c2f:3800:0011::0a18:0000/114", + }, + { + CIDR: "10.237.6.0/18", + }, + }, + }, + }, + want: &kosmosv1alpha1.NodeConfig{ + Spec: kosmosv1alpha1.NodeConfigSpec{ + Routes: []kosmosv1alpha1.Route{ + { + CIDR: "2409:8c2f:3800:11::a18:0/114", + }, + { + CIDR: "10.237.0.0/18", + }, + }, + }, + }, + }, + { + name: "test ipv6", + input: &kosmosv1alpha1.NodeConfig{ + Spec: kosmosv1alpha1.NodeConfigSpec{ + Routes: []kosmosv1alpha1.Route{ + { + CIDR: "2409:8c2f:3800:0011::0a18:0000/114", + }, + }, + }, + }, + want: &kosmosv1alpha1.NodeConfig{ + Spec: kosmosv1alpha1.NodeConfigSpec{ + Routes: []kosmosv1alpha1.Route{ + { + CIDR: "2409:8c2f:3800:11::a18:0/114", + }, + }, + }, + }, + }, + { + name: "test ipv4", + input: &kosmosv1alpha1.NodeConfig{ + Spec: kosmosv1alpha1.NodeConfigSpec{ + Routes: []kosmosv1alpha1.Route{ + { + CIDR: "10.237.6.0/18", + }, + }, + }, + }, + want: &kosmosv1alpha1.NodeConfig{ + Spec: kosmosv1alpha1.NodeConfigSpec{ + Routes: []kosmosv1alpha1.Route{ + { + CIDR: "10.237.0.0/18", + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + nodeconfig, err := formatNodeConfig(tt.input) + + if err != nil { + t.Errorf("formatNodeConfig() error = %v", err) + } + + if len(nodeconfig.Spec.Routes) != len(tt.want.Spec.Routes) { + t.Errorf("formatNodeConfig() = %v, want %v", nodeconfig.Spec.Routes, tt.want.Spec.Routes) + } + + for i := range nodeconfig.Spec.Routes { + if nodeconfig.Spec.Routes[i].CIDR != tt.want.Spec.Routes[i].CIDR { + t.Errorf("formatNodeConfig() = %v, want %v", nodeconfig.Spec.Routes[i].CIDR, tt.want.Spec.Routes[i].CIDR) + } + } + }) + } +} diff --git a/pkg/clusterlink/controllers/cluster/helper.go b/pkg/clusterlink/controllers/cluster/helper.go index 42c395225..7ffd19da0 100644 --- a/pkg/clusterlink/controllers/cluster/helper.go +++ b/pkg/clusterlink/controllers/cluster/helper.go @@ -128,5 +128,14 @@ func ResolveServiceCIDRs(pod *corev1.Pod) ([]string, error) { } } } + + for i, cidr := range serviceCIDRS { + ipNetStr, err := utils.FormatCIDR(cidr) + if err != nil { + return nil, fmt.Errorf("failed to format service cidr %s, pod name is %s, err: %s", cidr, pod.Name, err.Error()) + } + serviceCIDRS[i] = ipNetStr + } + return serviceCIDRS, nil } diff --git a/pkg/clusterlink/controllers/cluster/helper_test.go b/pkg/clusterlink/controllers/cluster/helper_test.go new file mode 100644 index 000000000..490e9d540 --- /dev/null +++ b/pkg/clusterlink/controllers/cluster/helper_test.go @@ -0,0 +1,79 @@ +package cluster + +import ( + "fmt" + "strings" + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func prepareData(crds string) *corev1.Pod { + return &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod", + Namespace: "test-namespace", + Labels: map[string]string{ + "app": "test-app", + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "test-container", + Image: "test-image", + Command: []string{ + "kube-apiserver", + fmt.Sprintf("--service-cluster-ip-range=%s", crds), + "--profiling=false", + }, + }, + }, + }, + } +} + +func TestResolveServiceCIDRs(t *testing.T) { + tests := []struct { + name string + input *corev1.Pod + want []string + }{ + { + name: "test ipv4 and ipv6", + input: prepareData("2409:8c2f:3800:0011::0a18:0000/114,10.237.6.0/18"), + want: []string{ + "2409:8c2f:3800:11::a18:0/114", + "10.237.0.0/18", + }, + }, + { + name: "test ipv4", + input: prepareData("10.237.6.0/18"), + want: []string{ + "10.237.0.0/18", + }, + }, + { + name: "test ipv6", + input: prepareData("2409:8c2f:3800:0011::0a18:0000/114"), + want: []string{ + "2409:8c2f:3800:11::a18:0/114", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ret, err := ResolveServiceCIDRs(tt.input) + if err != nil { + t.Fatalf("ResolveServiceCIDRs err: %s", err.Error()) + } + + if strings.Join(ret, ",") != strings.Join(tt.want, ",") { + t.Fatalf("value is incorretc!") + } + }) + } +} diff --git a/pkg/kubenest/controller/virtualcluster_init_controller.go b/pkg/kubenest/controller/virtualcluster_init_controller.go index aa3abde63..e61361645 100644 --- a/pkg/kubenest/controller/virtualcluster_init_controller.go +++ b/pkg/kubenest/controller/virtualcluster_init_controller.go @@ -128,7 +128,7 @@ func (c *VirtualClusterInitController) Reconcile(ctx context.Context, request re } switch originalCluster.Status.Phase { - case "", v1alpha1.Pending: + case "": //create request updatedCluster.Status.Phase = v1alpha1.Preparing err := c.Update(updatedCluster) diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 08db3f2c1..a0d91409b 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -2,6 +2,7 @@ package utils import ( "fmt" + "net" "os" "strings" @@ -57,3 +58,11 @@ func IPFamilyGenerator(apiServerServiceSubnet string) []corev1.IPFamily { } return ipFamilies } + +func FormatCIDR(cidr string) (string, error) { + _, ipNet, err := net.ParseCIDR(cidr) + if err != nil { + return "", fmt.Errorf("failed to parse cidr %s, err: %s", cidr, err.Error()) + } + return ipNet.String(), nil +}