@@ -42,7 +42,7 @@ import (
42
42
const defaultNodeLabel = "k8s.aliyun.com=true"
43
43
44
44
type Provider interface {
45
- GetNodeRegisterScript (context.Context , string , * karpv1.NodeClaim , * v1alpha1.KubeletConfiguration ) (string , error )
45
+ GetNodeRegisterScript (context.Context , string , * karpv1.NodeClaim , * v1alpha1.KubeletConfiguration , * string ) (string , error )
46
46
GetClusterCNI (context.Context ) (string , error )
47
47
LivenessProbe (* http.Request ) error
48
48
}
@@ -154,10 +154,11 @@ func (p *DefaultProvider) getTargetNodePoolID(ctx context.Context) (*string, err
154
154
func (p * DefaultProvider ) GetNodeRegisterScript (ctx context.Context ,
155
155
capacityType string ,
156
156
nodeClaim * karpv1.NodeClaim ,
157
- kubeletCfg * v1alpha1.KubeletConfiguration ) (string , error ) {
157
+ kubeletCfg * v1alpha1.KubeletConfiguration ,
158
+ userData * string ) (string , error ) {
158
159
labels := lo .Assign (nodeClaim .Labels , map [string ]string {karpv1 .CapacityTypeLabelKey : capacityType })
159
160
if cachedScript , ok := p .cache .Get (p .clusterID ); ok {
160
- return p .resolveUserData (cachedScript .(string ), labels , nodeClaim , kubeletCfg ), nil
161
+ return p .resolveUserData (cachedScript .(string ), labels , nodeClaim , kubeletCfg , userData ), nil
161
162
}
162
163
163
164
nodepoolID , err := p .getTargetNodePoolID (ctx )
@@ -187,13 +188,24 @@ func (p *DefaultProvider) GetNodeRegisterScript(ctx context.Context,
187
188
}
188
189
189
190
p .cache .SetDefault (p .clusterID , s )
190
- return p .resolveUserData (s , labels , nodeClaim , kubeletCfg ), nil
191
+ return p .resolveUserData (s , labels , nodeClaim , kubeletCfg , userData ), nil
191
192
}
192
193
193
- func (p * DefaultProvider ) resolveUserData (respStr string , labels map [string ]string , nodeClaim * karpv1.NodeClaim , kubeletCfg * v1alpha1.KubeletConfiguration ) string {
194
+ func (p * DefaultProvider ) resolveUserData (respStr string , labels map [string ]string , nodeClaim * karpv1.NodeClaim ,
195
+ kubeletCfg * v1alpha1.KubeletConfiguration , userData * string ) string {
196
+ preUserData , postUserData := parseCustomUserData (userData )
197
+
194
198
var script bytes.Buffer
195
199
// Add bash script header
196
200
script .WriteString ("#!/bin/bash\n \n " )
201
+
202
+ // Insert preUserData if available
203
+ if preUserData != "" {
204
+ // Pre-userData: scripts to be executed before node registration
205
+ script .WriteString ("echo \" Executing preUserData...\" \n " )
206
+ script .WriteString (preUserData + "\n \n " )
207
+ }
208
+
197
209
// Clean up the input string
198
210
cleanupStr := strings .ReplaceAll (respStr , "\r \n " , "" )
199
211
script .WriteString (cleanupStr + " " )
@@ -203,7 +215,15 @@ func (p *DefaultProvider) resolveUserData(respStr string, labels map[string]stri
203
215
cfg := convertNodeClassKubeletConfigToACKNodeConfig (kubeletCfg )
204
216
script .WriteString (fmt .Sprintf ("--node-config %s " , cfg ))
205
217
// Add taints
206
- script .WriteString (fmt .Sprintf ("--taints %s" , p .formatTaints (nodeClaim )))
218
+ script .WriteString (fmt .Sprintf ("--taints %s\n \n " , p .formatTaints (nodeClaim )))
219
+
220
+ // Insert postUserData if available
221
+ if postUserData != "" {
222
+ // Post-userData: scripts to be executed after node registration
223
+ script .WriteString ("echo \" Executing postUserData...\" \n " )
224
+ script .WriteString (postUserData + "\n " )
225
+ }
226
+
207
227
// Encode to base64
208
228
return base64 .StdEncoding .EncodeToString (script .Bytes ())
209
229
}
@@ -252,3 +272,16 @@ func convertNodeClassKubeletConfigToACKNodeConfig(kubeletCfg *v1alpha1.KubeletCo
252
272
}
253
273
return base64 .StdEncoding .EncodeToString (data )
254
274
}
275
+
276
+ const userDataSeparator = "#===USERDATA_SEPARATOR==="
277
+
278
+ // By default, the UserData is executed after the node registration is completed.
279
+ // If a user requires tasks to be executed both before and after node registration,
280
+ // they must split the userdata into preUserData and postUserData using a SEPARATOR.
281
+ func parseCustomUserData (userData * string ) (string , string ) {
282
+ parts := strings .Split (tea .StringValue (userData ), userDataSeparator )
283
+ if len (parts ) == 2 {
284
+ return strings .TrimSpace (parts [0 ]), strings .TrimSpace (parts [1 ])
285
+ }
286
+ return "" , tea .StringValue (userData )
287
+ }
0 commit comments