Repository: clusternet/clusternet
Pull request #405 (2022-07-06 06:57:12)

fix leader election npe
Signed-off-by: Di Xu <stephenhsu90@gmail.com>

<!--  Thanks for sending a pull request!

-->

#### What type of PR is this?
kind/bug

#### What this PR does / why we need it:
introduced by #378 
#### Which issue(s) this PR fixes:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->
Fixes #

#### Special notes for your reviewer:



Patch:
diff --git a/pkg/hub/hub.go b/pkg/hub/hub.go
index 2dd9d3d..dcaf222 100644
--- a/pkg/hub/hub.go
+++ b/pkg/hub/hub.go
@@ -113,11 +113,7 @@ func NewHub(opts *options.HubServerOptions) (*Hub, error) {
 	}
 	kubeClient := kubernetes.NewForConfigOrDie(rootClientBuilder.ConfigOrDie("clusternet-hub-kube-client"))
 	clusternetClient := clusternet.NewForConfigOrDie(rootClientBuilder.ConfigOrDie("clusternet-hub-client"))
-
-	var electionClient *kubernetes.Clientset
-	if opts.LeaderElection.LeaderElect {
-		electionClient = kubernetes.NewForConfigOrDie(rootClientBuilder.ConfigOrDie("clusternet-hub-election-client"))
-	}
+	electionClient := kubernetes.NewForConfigOrDie(rootClientBuilder.ConfigOrDie("clusternet-hub-election-client"))
 
 	//deployer.broadcaster.StartStructuredLogging(5)
 	broadcaster := record.NewBroadcaster()
@@ -234,7 +230,6 @@ func (hub *Hub) Run(ctx context.Context) error {
 	}
 
 	// create lease for peer
-
 	peerLease, err := createPeerLease(
 		peerInfo{
 			ID:       hub.peerID,
@@ -272,7 +267,8 @@ func (hub *Hub) Run(ctx context.Context) error {
 			// config.GenericConfig.SharedInformerFactory.WaitForCacheSync(postStartHookContext.StopCh)
 
 			if !hub.options.LeaderElection.LeaderElect {
-				hub.runControllers(ctx)
+				wait.UntilWithContext(ctx, hub.runControllers, 0)
+				klog.Warning("finished without leader elect")
 				return nil
 			}
 
diff --git a/pkg/registry/shadow/template/trimmer.go b/pkg/registry/shadow/template/trimmer.go
index 9e65b03..f4eb7a1 100644
--- a/pkg/registry/shadow/template/trimmer.go
+++ b/pkg/registry/shadow/template/trimmer.go
@@ -39,11 +39,18 @@ func trimCoreService(result *unstructured.Unstructured) {
 		return
 	}
 
+	clusterIP, found, _ := unstructured.NestedString(result.Object, "spec", "clusterIP")
+	if found && clusterIP != corev1.ClusterIPNone {
+		// not a headless service
+		unstructured.RemoveNestedField(result.Object, "spec", "clusterIP")
+		unstructured.RemoveNestedField(result.Object, "spec", "clusterIPs")
+	}
+
 	switch corev1.ServiceType(serviceType) {
 	case corev1.ServiceTypeNodePort, corev1.ServiceTypeLoadBalancer:
 		// corev1.Service will init node ports when creating NodePort or LoadBalancer
-		items, found, err := unstructured.NestedSlice(result.Object, "spec", "ports")
-		if !found || err != nil {
+		items, found2, err2 := unstructured.NestedSlice(result.Object, "spec", "ports")
+		if !found2 || err2 != nil {
 			return
 		}
 		for _, item := range items {
@@ -54,9 +61,9 @@ func trimCoreService(result *unstructured.Unstructured) {
 			unstructured.RemoveNestedField(servicePort, "nodePort")
 		}
 
-		err = unstructured.SetNestedSlice(result.Object, items, "spec", "ports")
-		if err != nil {
-			klog.ErrorDepth(2, fmt.Sprintf("failed to trim Service %s/%s: %v", result.GetNamespace(), result.GetName(), err))
+		err2 = unstructured.SetNestedSlice(result.Object, items, "spec", "ports")
+		if err2 != nil {
+			klog.ErrorDepth(2, fmt.Sprintf("failed to trim Service %s/%s: %v", result.GetNamespace(), result.GetName(), err2))
 		}
 	}
 }


Test patch:
diff --git a/pkg/registry/shadow/template/trimmer_test.go b/pkg/registry/shadow/template/trimmer_test.go
index 1a8f32b..de73b28 100644
--- a/pkg/registry/shadow/template/trimmer_test.go
+++ b/pkg/registry/shadow/template/trimmer_test.go
@@ -91,10 +91,6 @@ func TestTrimCoreService(t *testing.T) {
 						"uid":       "28f5ae38-9eea-431c-918b-68ffdf263c24",
 					},
 					"spec": map[string]interface{}{
-						"clusterIP": "10.98.177.115",
-						"clusterIPs": []string{
-							"10.98.177.115",
-						},
 						"externalTrafficPolicy": "Cluster",
 						"ipFamilies": []string{
 							"IPv4",
@@ -121,6 +117,90 @@ func TestTrimCoreService(t *testing.T) {
 				},
 			},
 		},
+		{
+			name: "Headless Service",
+			resultRaw: &unstructured.Unstructured{
+				Object: map[string]interface{}{
+					"apiVersion": "v1",
+					"kind":       "Service",
+					"metadata": map[string]interface{}{
+						"creationTimestamp": "2021-11-01T08:12:43Z",
+						"labels": map[string]string{
+							"clusternet.io/created-by": "clusternet-hub",
+						},
+						"name":            "my-test-nodeport-svc",
+						"namespace":       "nginx-test",
+						"resourceVersion": "4457294",
+						"selfLink":        "test-link",
+						"uid":             "28f5ae38-9eea-431c-918b-68ffdf263c24",
+					},
+					"spec": map[string]interface{}{
+						"clusterIP":             "None",
+						"externalTrafficPolicy": "Cluster",
+						"ipFamilies": []string{
+							"IPv4",
+						},
+						"ipFamilyPolicy": "SingleStack",
+						"ports": []interface{}{
+							map[string]interface{}{
+								"name":       "tcp-80-80",
+								"port":       int64(80),
+								"protocol":   "TCP",
+								"targetPort": int64(80),
+							},
+							map[string]interface{}{
+								"name":       "tcp-443-443",
+								"port":       int64(443),
+								"protocol":   "TCP",
+								"targetPort": int64(443),
+							},
+						},
+						"sessionAffinity": "None",
+						"type":            "ClusterIP",
+					},
+					"status": map[string]interface{}{},
+				},
+			},
+			resultDesired: &unstructured.Unstructured{
+				Object: map[string]interface{}{
+					"apiVersion": "v1",
+					"kind":       "Service",
+					"metadata": map[string]interface{}{
+						"labels": map[string]string{
+							"clusternet.io/created-by": "clusternet-hub",
+						},
+						"name":      "my-test-nodeport-svc",
+						"namespace": "nginx-test",
+						"uid":       "28f5ae38-9eea-431c-918b-68ffdf263c24",
+					},
+					"spec": map[string]interface{}{
+						"clusterIP":             "None",
+						"externalTrafficPolicy": "Cluster",
+						"ipFamilies": []string{
+							"IPv4",
+						},
+						"ipFamilyPolicy": "SingleStack",
+						"ports": []interface{}{
+							map[string]interface{}{
+								"name":       "tcp-80-80",
+								"port":       int64(80),
+								"protocol":   "TCP",
+								"targetPort": int64(80),
+							},
+							map[string]interface{}{
+								"name":       "tcp-443-443",
+								"port":       int64(443),
+								"protocol":   "TCP",
+								"targetPort": int64(443),
+							},
+						},
+						"sessionAffinity": "None",
+						"type":            "ClusterIP",
+					},
+					"status": map[string]interface{}{},
+				},
+			},
+		},
 	}
 
 	for _, tt := range tests {