@@ -20,6 +20,12 @@ export PATH="$PATH:$root_path/usr/local/bin"
2020
2121KUBE_VIP_LOC=" /etc/kubernetes/manifests/kube-vip.yaml"
2222
23+ # Prevents infinite retry loops (original used until loop)
24+ MAX_RETRIES=3
25+ # Time to wait for etcd/static pods to become ready
26+ ETCD_HEALTH_TIMEOUT=60
27+ RETRY_DELAY=30
28+
2329restart_containerd () {
2430 if systemctl cat spectro-containerd > /dev/null 2< & 1; then
2531 systemctl restart spectro-containerd
@@ -30,6 +36,100 @@ restart_containerd() {
3036 fi
3137}
3238
39+ # Function to wait for static pods to be created and running
40+ wait_for_static_pods () {
41+ local timeout=$1
42+ local start_time=$( date +%s)
43+
44+ echo " Waiting for static pods to be created and running..."
45+
46+ # Check if crictl is available
47+ if ! command -v crictl > /dev/null 2>&1 ; then
48+ echo " crictl not available, checking only static pod manifests"
49+ # Fallback: just check if manifests exist and wait
50+ while [ $(( $(date +% s) - start_time)) -lt $timeout ]; do
51+ if [ -f /etc/kubernetes/manifests/etcd.yaml ] && [ -f /etc/kubernetes/manifests/kube-apiserver.yaml ] && [ -f /etc/kubernetes/manifests/kube-controller-manager.yaml ] && [ -f /etc/kubernetes/manifests/kube-scheduler.yaml ]; then
52+ echo " Static pod manifests are ready, waiting additional time for pods to stabilize..."
53+ sleep 15
54+ return 0
55+ fi
56+ sleep 5
57+ done
58+ echo " Timeout waiting for static pod manifests after ${timeout} s"
59+ return 1
60+ fi
61+
62+ while [ $(( $(date +% s) - start_time)) -lt $timeout ]; do
63+ # Check if all required static pod manifests exist
64+ if [ -f /etc/kubernetes/manifests/etcd.yaml ] && [ -f /etc/kubernetes/manifests/kube-apiserver.yaml ] && [ -f /etc/kubernetes/manifests/kube-controller-manager.yaml ] && [ -f /etc/kubernetes/manifests/kube-scheduler.yaml ]; then
65+ # Check if etcd container is running
66+ local etcd_container_id=$( crictl ps --name etcd --quiet 2> /dev/null)
67+ if [ -n " $etcd_container_id " ] && crictl ps --id " $etcd_container_id " --format table | grep -q " Running" ; then
68+ echo " Static pods are running, waiting additional time for etcd to stabilize..."
69+ sleep 10
70+ return 0
71+ fi
72+ fi
73+ sleep 5
74+ done
75+
76+ echo " Timeout waiting for static pods to be ready after ${timeout} s"
77+ return 1
78+ }
79+
80+ # Function to check if etcd is healthy (only if etcdctl and crictl are available)
81+ check_etcd_health_if_available () {
82+ local timeout=$1
83+ local start_time=$( date +%s)
84+
85+ # Check if etcdctl is available
86+ if ! command -v etcdctl > /dev/null 2>&1 ; then
87+ echo " etcdctl not available, skipping etcd health check"
88+ return 0
89+ fi
90+
91+ # Check if crictl is available
92+ if ! command -v crictl > /dev/null 2>&1 ; then
93+ echo " crictl not available, skipping etcd health check"
94+ return 0
95+ fi
96+
97+ echo " Checking etcd health with etcdctl..."
98+
99+ while [ $(( $(date +% s) - start_time)) -lt $timeout ]; do
100+ # Check if etcd container is running
101+ local etcd_container_id=$( crictl ps --name etcd --quiet 2> /dev/null)
102+ if [ -n " $etcd_container_id " ] && crictl ps --id " $etcd_container_id " --format table | grep -q " Running" ; then
103+ # Try to connect to local etcd directly
104+ if timeout 10s etcdctl endpoint health --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key > /dev/null 2>&1 ; then
105+ echo " etcd is healthy"
106+ return 0
107+ fi
108+ fi
109+ sleep 5
110+ done
111+
112+ echo " etcd health check timed out after ${timeout} s"
113+ return 1
114+ }
115+
116+ # Function to clean up cluster state before retry
117+ cleanup_cluster_state () {
118+ local node_name=$( hostname)
119+ echo " Cleaning up cluster state for node: $node_name "
120+
121+ # Try to remove node from cluster if possible
122+ if [ -f /etc/kubernetes/admin.conf ]; then
123+ kubectl delete node $node_name --kubeconfig=/etc/kubernetes/admin.conf --ignore-not-found=true 2> /dev/null || true
124+ fi
125+
126+ # For control plane nodes, try to remove etcd member
127+ if [ " $NODE_ROLE " = " controlplane" ]; then
128+ # This would need to be done from another control plane node
129+ echo " Note: etcd member cleanup should be done from another control plane node"
130+ fi
131+ }
132+
33133do_kubeadm_reset () {
34134 if [ -S /run/spectro/containerd/containerd.sock ]; then
35135 kubeadm reset -f --cri-socket unix:///run/spectro/containerd/containerd.sock --cleanup-tmp-dir
@@ -59,24 +159,68 @@ restore_kube_vip_manifest_after_reset() {
59159 fi
60160}
61161
62- if [ " $PROXY_CONFIGURED " = true ]; then
63- until HTTP_PROXY=$proxy_http http_proxy=$proxy_http HTTPS_PROXY=$proxy_https https_proxy=$proxy_https NO_PROXY=$proxy_no no_proxy=$proxy_no kubeadm join --config " $root_path " /opt/kubeadm/kubeadm.yaml --ignore-preflight-errors=DirAvailable--etc-kubernetes-manifests -v=5 > /dev/null
64- do
162+ # Function to attempt kubeadm join with proper error handling
163+ attempt_kubeadm_join () {
164+ local attempt=$1
165+ local max_retries=$2
166+
167+ echo " Attempting kubeadm join (attempt $attempt /$max_retries )"
168+
169+ if [ " $PROXY_CONFIGURED " = true ]; then
170+ HTTP_PROXY=$proxy_http http_proxy=$proxy_http HTTPS_PROXY=$proxy_https https_proxy=$proxy_https NO_PROXY=$proxy_no no_proxy=$proxy_no kubeadm join --config " $root_path " /opt/kubeadm/kubeadm.yaml --ignore-preflight-errors=DirAvailable--etc-kubernetes-manifests -v=5
171+ else
172+ kubeadm join --config " $root_path " /opt/kubeadm/kubeadm.yaml --ignore-preflight-errors=DirAvailable--etc-kubernetes-manifests -v=5
173+ fi
174+ }
175+
176+ # Main join logic with intelligent retry
177+ retry_count=0
178+ while [ $retry_count -lt $MAX_RETRIES ]; do
179+ retry_count=$(( retry_count + 1 ))
180+
181+ if attempt_kubeadm_join $retry_count $MAX_RETRIES ; then
182+ echo " kubeadm join completed successfully"
183+ break
184+ else
185+ echo " kubeadm join failed on attempt $retry_count "
186+
187+ # Check if this is an etcd health check failure
188+ if grep -q " etcd cluster is not healthy" /var/log/kube-join.log 2> /dev/null; then
189+ echo " Detected etcd health check failure"
190+
191+ # For first attempt, try to wait for static pods to be ready
192+ if [ $retry_count -eq 1 ]; then
193+ echo " Waiting for static pods to be ready before retry..."
194+ if wait_for_static_pods $ETCD_HEALTH_TIMEOUT ; then
195+ echo " Static pods are ready, checking etcd health if available..."
196+ if check_etcd_health_if_available 30; then
197+ echo " etcd is healthy, retrying join without reset"
198+ continue
199+ else
200+ echo " etcd health check failed or etcdctl not available, retrying join without reset"
201+ continue
202+ fi
203+ else
204+ echo " Static pods not ready, proceeding with reset"
205+ fi
206+ fi
207+ fi
208+
209+ # If we've reached max retries, exit with error
210+ if [ $retry_count -eq $MAX_RETRIES ]; then
211+ echo " Maximum retry attempts ($MAX_RETRIES ) reached. Exiting."
212+ exit 1
213+ fi
214+
215+ # Clean up cluster state before reset
216+ cleanup_cluster_state
217+
218+ # Reset and retry
65219 backup_kube_vip_manifest_if_present
66- echo " failed to apply kubeadm join, will retry in 10s " ;
220+ echo " Resetting kubeadm and retrying in ${RETRY_DELAY} s "
67221 do_kubeadm_reset
68- echo " retrying in 10s "
69- sleep 10 ;
222+ echo " Retrying in ${RETRY_DELAY} s "
223+ sleep $RETRY_DELAY
70224 restore_kube_vip_manifest_after_reset
71- done ;
72- else
73- until kubeadm join --config " $root_path " /opt/kubeadm/kubeadm.yaml --ignore-preflight-errors=DirAvailable--etc-kubernetes-manifests -v=5 > /dev/null
74- do
75- backup_kube_vip_manifest_if_present
76- echo " failed to apply kubeadm join, will retry in 10s" ;
77- do_kubeadm_reset
78- echo " retrying in 10s"
79- sleep 10;
80- restore_kube_vip_manifest_after_reset
81- done ;
82- fi
225+ fi
226+ done
0 commit comments