@@ -104,21 +104,23 @@ func (p *DefaultProvider) GetClusterCNI(_ context.Context) (string, error) {
104104 return p .clusterCNI , nil
105105}
106106
107- // Get the ID of the target nodepool id when DescribeClusterAttachScriptsRequest.
108- // If there is no default nodepool, select the nodepool with the most HealthyNodes.
107+ // We need to manually retrieve the runtime configuration of the nodepool, with the default node pool prioritized.
108+ // If there is no default node pool, we will choose the runtime configuration of the node pool with the most HealthyNodes.
109+ // In some cases, the DescribeClusterAttachScripts interface may return the Docker runtime in clusters running version 1.24,
110+ // even though Docker runtime only supports clusters of version 1.22 and below.
109111//
110112//nolint:gocyclo
111- func (p * DefaultProvider ) getTargetNodePoolID (ctx context.Context ) (* string , error ) {
113+ func (p * DefaultProvider ) getClusterAttachRuntimeConfiguration (ctx context.Context ) (string , string , error ) {
112114 resp , err := p .ackClient .DescribeClusterNodePools (tea .String (p .clusterID ), & ackclient.DescribeClusterNodePoolsRequest {})
113115 if err != nil {
114116 log .FromContext (ctx ).Error (err , "Failed to describe cluster nodepools" )
115- return nil , err
117+ return "" , "" , err
116118 }
117119 if resp == nil || resp .Body == nil || resp .Body .Nodepools == nil {
118- return nil , fmt .Errorf ("empty describe cluster nodepools response" )
120+ return "" , "" , fmt .Errorf ("empty describe cluster nodepools response" )
119121 }
120122 if len (resp .Body .Nodepools ) == 0 {
121- return nil , fmt .Errorf ("no nodepool found" )
123+ return "" , "" , fmt .Errorf ("no nodepool found" )
122124 }
123125
124126 nodepools := resp .Body .Nodepools
@@ -143,32 +145,23 @@ func (p *DefaultProvider) getTargetNodePoolID(ctx context.Context) (*string, err
143145 })
144146
145147 targetNodepool := nodepools [0 ]
146- if targetNodepool .NodepoolInfo == nil {
147- return nil , fmt .Errorf ("target describe cluster nodepool is empty" )
148+ if targetNodepool .KubernetesConfig == nil || targetNodepool .KubernetesConfig .Runtime == nil ||
149+ targetNodepool .KubernetesConfig .RuntimeVersion == nil {
150+ return "" , "" , fmt .Errorf ("target describe cluster nodepool is empty" )
148151 }
149- return targetNodepool .NodepoolInfo .NodepoolId , nil
152+ return tea .StringValue (targetNodepool .KubernetesConfig .Runtime ),
153+ tea .StringValue (targetNodepool .KubernetesConfig .RuntimeVersion ), nil
150154}
151155
152156func (p * DefaultProvider ) GetNodeRegisterScript (ctx context.Context ,
153157 labels map [string ]string ,
154158 kubeletCfg * v1alpha1.KubeletConfiguration ) (string , error ) {
155159 if cachedScript , ok := p .cache .Get (p .clusterID ); ok {
156- return p .resolveUserData (cachedScript .(string ), labels , kubeletCfg ), nil
160+ return p .resolveUserData (ctx , cachedScript .(string ), labels , kubeletCfg ), nil
157161 }
158162
159- nodepoolID , err := p .getTargetNodePoolID (ctx )
160- if err != nil {
161- // Don't return here, we can process when there is no default cluster id.
162- // We need to try to obtain a usable nodepool ID in order to get the cluster attach scripts.
163- // One known scenario is on an ACK cluster with version 1.24, where the user deleted the default nodepool and
164- // created a nodepool with a containerd runtime. The DescribeClusterAttachScriptsRequest api will use the
165- // CRI configuration of the deleted default nodepool, which might be using the Docker runtime.
166- // This could result in nodes failing to register to the new cluster.
167- log .FromContext (ctx ).Error (err , "Failed to get default nodepool id" )
168- }
169163 reqPara := & ackclient.DescribeClusterAttachScriptsRequest {
170164 KeepInstanceName : tea .Bool (true ),
171- NodepoolId : nodepoolID ,
172165 }
173166 resp , err := p .ackClient .DescribeClusterAttachScripts (tea .String (p .clusterID ), reqPara )
174167 if err != nil {
@@ -183,10 +176,11 @@ func (p *DefaultProvider) GetNodeRegisterScript(ctx context.Context,
183176 }
184177
185178 p .cache .SetDefault (p .clusterID , s )
186- return p .resolveUserData (s , labels , kubeletCfg ), nil
179+ return p .resolveUserData (ctx , s , labels , kubeletCfg ), nil
187180}
188181
189- func (p * DefaultProvider ) resolveUserData (respStr string ,
182+ func (p * DefaultProvider ) resolveUserData (ctx context.Context ,
183+ respStr string ,
190184 labels map [string ]string ,
191185 kubeletCfg * v1alpha1.KubeletConfiguration ) string {
192186 cleanupStr := strings .ReplaceAll (respStr , "\r \n " , "" )
@@ -208,6 +202,16 @@ func (p *DefaultProvider) resolveUserData(respStr string,
208202 taint := karpv1 .UnregisteredNoExecuteTaint
209203 updatedCommand = fmt .Sprintf ("%s --taints %s" , updatedCommand , taint .ToString ())
210204
205+ runtime , runtimeVersion , err := p .getClusterAttachRuntimeConfiguration (ctx )
206+ if err != nil {
207+ // If error happen, we do nothing here
208+ log .FromContext (ctx ).Error (err , "Failed to get cluster attach runtime configuration" )
209+ } else {
210+ // Replace the runtime and runtime-version parameter
211+ updatedCommand = regexp .MustCompile (`\s+--runtime\s+\S+\s+--runtime-version\s+\S+` ).ReplaceAllString (updatedCommand , "" )
212+ updatedCommand = fmt .Sprintf ("%s --runtime %s --runtime-version %s" , updatedCommand , runtime , runtimeVersion )
213+ }
214+
211215 // Add bash script header
212216 finalScript := fmt .Sprintf ("#!/bin/bash\n \n %s" , updatedCommand )
213217
0 commit comments