From 3054c9ac8fc4c4e10347597c3c103a7096de6842 Mon Sep 17 00:00:00 2001
From: kolorful <kewei@indeed.com>
Date: Tue, 3 Sep 2024 16:23:42 +0000
Subject: [PATCH] feat: add k8s topology zone info for nodePort service

---
 .changelog/4301.txt                           |  3 ++
 control-plane/catalog/to-consul/resource.go   | 44 +++++++++++--------
 .../catalog/to-consul/resource_test.go        |  2 +
 3 files changed, 30 insertions(+), 19 deletions(-)
 create mode 100644 .changelog/4301.txt

diff --git a/.changelog/4301.txt b/.changelog/4301.txt
new file mode 100644
index 0000000000..5d952e4a1e
--- /dev/null
+++ b/.changelog/4301.txt
@@ -0,0 +1,3 @@
+```release-note:feature
+control-plane: Add available Zone Kubernetes Topology Metadata for NodePort Service when Syncing Kubernetes Services.
+```
\ No newline at end of file
diff --git a/control-plane/catalog/to-consul/resource.go b/control-plane/catalog/to-consul/resource.go
index 09e7e17200..70eb2a77ee 100644
--- a/control-plane/catalog/to-consul/resource.go
+++ b/control-plane/catalog/to-consul/resource.go
@@ -661,7 +661,7 @@ func (t *ServiceResource) generateRegistrations(key string) {
 							r.Service = &rs
 							r.Service.ID = serviceID(r.Service.Service, endpointAddr)
 							r.Service.Address = address.Address
-
+							r.Service.Meta = updateServiceMeta(baseService.Meta, endpoint)
 							t.consulMap[key] = append(t.consulMap[key], &r)
 							// Only consider the first address that matches. In some cases
 							// there will be multiple addresses like when using AWS CNI.
@@ -682,7 +682,7 @@ func (t *ServiceResource) generateRegistrations(key string) {
 								r.Service = &rs
 								r.Service.ID = serviceID(r.Service.Service, endpointAddr)
 								r.Service.Address = address.Address
-
+								r.Service.Meta = updateServiceMeta(baseService.Meta, endpoint)
 								t.consulMap[key] = append(t.consulMap[key], &r)
 								// Only consider the first address that matches. In some cases
 								// there will be multiple addresses like when using AWS CNI.
@@ -778,23 +778,7 @@ func (t *ServiceResource) registerServiceInstance(
 				r.Service.ID = serviceID(r.Service.Service, addr)
 				r.Service.Address = addr
 				r.Service.Port = epPort
-				r.Service.Meta = make(map[string]string)
-				// Deepcopy baseService.Meta into r.Service.Meta as baseService is shared
-				// between all nodes of a service
-				for k, v := range baseService.Meta {
-					r.Service.Meta[k] = v
-				}
-				if endpoint.TargetRef != nil {
-					r.Service.Meta[ConsulK8SRefValue] = endpoint.TargetRef.Name
-					r.Service.Meta[ConsulK8SRefKind] = endpoint.TargetRef.Kind
-				}
-				if endpoint.NodeName != nil {
-					r.Service.Meta[ConsulK8SNodeName] = *endpoint.NodeName
-				}
-				if endpoint.Zone != nil {
-					r.Service.Meta[ConsulK8STopologyZone] = *endpoint.Zone
-				}
-
+				r.Service.Meta = updateServiceMeta(baseService.Meta, endpoint)
 				r.Check = &consulapi.AgentCheck{
 					CheckID:   consulHealthCheckID(endpointSlice.Namespace, serviceID(r.Service.Service, addr)),
 					Name:      consulKubernetesCheckName,
@@ -1104,3 +1088,25 @@ func getServiceWeight(weight string) (int, error) {
 
 	return weightI, nil
 }
+
+// deepcopy baseService.Meta into r.Service.Meta as baseService is shared between all nodes of a service.
+// update service meta with k8s topology info.
+func updateServiceMeta(baseServiceMeta map[string]string, endpoint discoveryv1.Endpoint) map[string]string {
+
+	serviceMeta := make(map[string]string)
+
+	for k, v := range baseServiceMeta {
+		serviceMeta[k] = v
+	}
+	if endpoint.TargetRef != nil {
+		serviceMeta[ConsulK8SRefValue] = endpoint.TargetRef.Name
+		serviceMeta[ConsulK8SRefKind] = endpoint.TargetRef.Kind
+	}
+	if endpoint.NodeName != nil {
+		serviceMeta[ConsulK8SNodeName] = *endpoint.NodeName
+	}
+	if endpoint.Zone != nil {
+		serviceMeta[ConsulK8STopologyZone] = *endpoint.Zone
+	}
+	return serviceMeta
+}
diff --git a/control-plane/catalog/to-consul/resource_test.go b/control-plane/catalog/to-consul/resource_test.go
index 08b08ced2f..b0b6d76cca 100644
--- a/control-plane/catalog/to-consul/resource_test.go
+++ b/control-plane/catalog/to-consul/resource_test.go
@@ -854,6 +854,8 @@ func TestServiceResource_nodePort(t *testing.T) {
 		require.Equal(r, "2.3.4.5", actual[1].Service.Address)
 		require.Equal(r, 30000, actual[1].Service.Port)
 		require.Equal(r, "k8s-sync", actual[1].Node)
+		require.Equal(r, "us-west-2a", actual[0].Service.Meta[ConsulK8STopologyZone])
+		require.Equal(r, "us-west-2b", actual[1].Service.Meta[ConsulK8STopologyZone])
 		require.NotEqual(r, actual[0].Service.ID, actual[1].Service.ID)
 	})
 }