Repository: openyurtio/openyurt (Go)

Issue:
[BUG] yurtadm join with kube-apisvr addr only override localhost:6443
<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks!-->


**What happened**:
by installing yurthub by doc: https://openyurt.io/zh/docs/installation/manually-setup#32-%E5%AE%89%E8%A3%85-yurthub-%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE

`helm upgrade --install yurt-hub -n kube-system --set kubernetesServerAddr=https://1.2.3.4:6443 openyurt/yurthub`

kube-apisvr addr in configmap `yurt-static-set-yurt-hub` will be set to https://1.2.3.4:6443, then if we join edge node with `yurtadm join {{https://external_ip:6443}}`, will not change kube-apisvr-addr from 1.2.3.4:6443 to external_ip:6443

according to the func `useRealServerAddr`, only https://127.0.0.1:6443(constants.DefaultServerAddr) will be overwrite by yurtadm join command, if we set it before(by helm install), nothing will changed
```
// useRealServerAddr check if the server-addr from yurthubTemplate is default value: 127.0.0.1:6443
// if yes, we should use the real server addr
func useRealServerAddr(yurthubTemplate string, kubernetesServerAddrs string) (string, error) {
	scanner := bufio.NewScanner(bytes.NewReader([]byte(yurthubTemplate)))
	var buffer bytes.Buffer
	target := fmt.Sprintf("%v=%v", constants.ServerAddr, constants.DefaultServerAddr)

	for scanner.Scan() {
		line := scanner.Text()
		if strings.Contains(line, target) {
			line = strings.Replace(line, constants.DefaultServerAddr, kubernetesServerAddrs, -1)
		}
		buffer.WriteString(line + "\n")
	}
```

**What you expected to happen**:

in my POV, we install yurthub in cloud node first(usually by internal ip like 172.0.0.11), then we join cloud node by `yurtadm join {internal_ip}`, last we join edge node by `yurtadm join {external_ip}`, so ip should always be overwritten since it will not be `127.0.0.1` by helm install by `172.0.0.11`

here is my solution:

```
func useRealServerAddr(yurthubTemplate string, kubernetesServerAddrs string) (string, error) {
	scanner := bufio.NewScanner(bytes.NewReader([]byte(yurthubTemplate)))
	var buffer bytes.Buffer
	// compile ipv4 regex
	ipRegex := regexp.MustCompile(`https?://(?:[0-9]{1,3}\.){3}[0-9]{1,3}:\d+`)

	// scan template and replace setAddr
	for scanner.Scan() {
		line := scanner.Text()
		if strings.Contains(line, fmt.Sprintf("- --%s=", constants.ServerAddr)) {
			// replace kubernetesServerAddrs by new addr
			line = ipRegex.ReplaceAllString(line, kubernetesServerAddrs)
		}
		buffer.WriteString(line + "\n")
	}
```

**How to reproduce it (as minimally and precisely as possible)**:

**Anything else we need to know?**:

**Environment**:
- OpenYurt version: 1.5.0
- Kubernetes version (use `kubectl version`): 1.31
- OS (e.g: `cat /etc/os-release`): debian12
- Kernel (e.g. `uname -a`): 6.1.119-1 (2024-11-22)
- Install tools: 
- Others:

**others**

/kind bug



Discussion:
@rayne-Li It's a good idea to replace the part of server address(https://xxx.xxx.xxx.xxx:port). Very appreciated.



Patch:
diff --git a/pkg/yurtadm/util/yurthub/yurthub.go b/pkg/yurtadm/util/yurthub/yurthub.go
index 064a22a56aa..e00110a61be 100644
--- a/pkg/yurtadm/util/yurthub/yurthub.go
+++ b/pkg/yurtadm/util/yurthub/yurthub.go
@@ -25,6 +25,7 @@ import (
 	"net/http"
 	"os"
 	"path/filepath"
+	"regexp"
 	"strings"
 	"time"
 
@@ -188,12 +189,15 @@ func CleanHubBootstrapConfig() error {
 func useRealServerAddr(yurthubTemplate string, kubernetesServerAddrs string) (string, error) {
 	scanner := bufio.NewScanner(bytes.NewReader([]byte(yurthubTemplate)))
 	var buffer bytes.Buffer
-	target := fmt.Sprintf("%v=%v", constants.ServerAddr, constants.DefaultServerAddr)
+	// compile ipv4 regex
+	ipRegex := regexp.MustCompile(`https?://(?:[0-9]{1,3}\.){3}[0-9]{1,3}:\d+`)
 
+	// scan template and replace setAddr
 	for scanner.Scan() {
 		line := scanner.Text()
-		if strings.Contains(line, target) {
-			line = strings.Replace(line, constants.DefaultServerAddr, kubernetesServerAddrs, -1)
+		if strings.Contains(line, fmt.Sprintf("- --%s=", constants.ServerAddr)) {
+			// replace kubernetesServerAddrs by new addr
+			line = ipRegex.ReplaceAllString(line, kubernetesServerAddrs)
 		}
 		buffer.WriteString(line + "\n")
 	}


Test patch:
diff --git a/pkg/yurtadm/util/yurthub/yurthub_test.go b/pkg/yurtadm/util/yurthub/yurthub_test.go
index 755fc456ce1..659fcbd77bf 100644
--- a/pkg/yurtadm/util/yurthub/yurthub_test.go
+++ b/pkg/yurtadm/util/yurthub/yurthub_test.go
@@ -184,6 +184,84 @@ spec:
         type: Directory
       name: kubernetes
 status: {}
+`
+	setAddr2 = `apiVersion: v1
+kind: Pod
+metadata:
+  annotations:
+    openyurt.io/static-pod-hash: 76f4f955b6
+  creationTimestamp: null
+  labels:
+    k8s-app: yurt-hub
+  name: yurt-hub
+  namespace: kube-system
+spec:
+  containers:
+    - command:
+      - yurthub
+      - --v=2
+      - --bind-address=127.0.0.1
+      - --server-addr=https://192.0.0.2:6443
+      - --node-name=$(NODE_NAME)
+      - --bootstrap-file=/var/lib/yurthub/bootstrap-hub.conf
+      - --working-mode=edge
+      - --namespace=kube-system
+      env:
+        - name: NODE_NAME
+          valueFrom:
+            fieldRef:
+              apiVersion: v1
+              fieldPath: spec.nodeName
+      image: openyurt/yurthub:v1.3.0
+      imagePullPolicy: IfNotPresent
+      livenessProbe:
+        failureThreshold: 3
+        httpGet:
+          host: 127.0.0.1
+          path: /v1/healthz
+          port: 10267
+          scheme: HTTP
+        initialDelaySeconds: 300
+        periodSeconds: 5
+        successThreshold: 1
+        timeoutSeconds: 1
+      name: yurt-hub
+      resources:
+        limits:
+          memory: 300Mi
+        requests:
+          cpu: 150m
+          memory: 150Mi
+      securityContext:
+        capabilities:
+          add:
+            - NET_ADMIN
+            - NET_RAW
+      terminationMessagePath: /dev/termination-log
+      terminationMessagePolicy: File
+      volumeMounts:
+        - mountPath: /var/lib/yurthub
+          name: hub-dir
+        - mountPath: /etc/kubernetes
+          name: kubernetes
+  dnsPolicy: ClusterFirst
+  hostNetwork: true
+  priority: 2000001000
+  priorityClassName: system-node-critical
+  restartPolicy: Always
+  schedulerName: default-scheduler
+  securityContext: {}
+  terminationGracePeriodSeconds: 30
+  volumes:
+    - hostPath:
+        path: /var/lib/yurthub
+        type: DirectoryOrCreate
+      name: hub-dir
+    - hostPath:
+        path: /etc/kubernetes
+        type: Directory
+      name: kubernetes
+status: {}
 `
 
 	serverAddrsA = "https://192.0.0.1:6443"
@@ -214,7 +292,7 @@ func Test_useRealServerAddr(t *testing.T) {
 				yurthubTemplate:       setAddr,
 				kubernetesServerAddrs: serverAddrsB,
 			},
-			want: setAddr,
+			want: setAddr2,
 		},
 	}