Skip to content

Commit 1521250

Browse files
committed
Code refactor
1 parent 2c8d41b commit 1521250

File tree

3 files changed

+207
-422
lines changed

3 files changed

+207
-422
lines changed

bootstrap/eks/controllers/eksconfig_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ func (r *EKSConfigReconciler) joinWorker(ctx context.Context, cluster *clusterv1
287287
DiskSetup: config.Spec.DiskSetup,
288288
Mounts: config.Spec.Mounts,
289289
Files: files,
290+
ClusterCIDR: controlPlane.Spec.NetworkSpec.VPC.CidrBlock,
290291
}
291292

292293
if config.Spec.PauseContainer != nil {

bootstrap/eks/internal/userdata/node.go

Lines changed: 100 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import (
2323
"text/template"
2424

2525
"github.com/alessio/shellescape"
26-
26+
"k8s.io/klog/v2"
27+
"k8s.io/utils/ptr"
2728
eksbootstrapv1 "sigs.k8s.io/cluster-api-provider-aws/v2/bootstrap/eks/api/v1beta2"
2829
"sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2"
2930
)
@@ -50,10 +51,32 @@ runcmd:
5051
{{- template "mounts" .Mounts}}
5152
`
5253

53-
// Multipart MIME template for AL2023.
54-
al2023UserDataTemplate = `MIME-Version: 1.0
54+
// Common MIME header and boundary template
55+
mimeHeaderTemplate = `MIME-Version: 1.0
5556
Content-Type: multipart/mixed; boundary="{{.Boundary}}"
5657
58+
`
59+
60+
// Shell script part template for AL2023
61+
shellScriptPartTemplate = `--{{.Boundary}}
62+
Content-Type: text/x-shellscript; charset="us-ascii"
63+
64+
#!/bin/bash
65+
set -o errexit
66+
set -o pipefail
67+
set -o nounset
68+
{{- if or .PreBootstrapCommands .PostBootstrapCommands }}
69+
70+
{{- range .PreBootstrapCommands}}
71+
{{.}}
72+
{{- end}}
73+
{{- range .PostBootstrapCommands}}
74+
{{.}}
75+
{{- end}}
76+
{{- end}}`
77+
78+
// Node config part template for AL2023
79+
nodeConfigPartTemplate = `
5780
--{{.Boundary}}
5881
Content-Type: application/node.eks.aws
5982
@@ -62,26 +85,24 @@ apiVersion: node.eks.aws/v1alpha1
6285
kind: NodeConfig
6386
spec:
6487
cluster:
88+
name: {{.ClusterName}}
6589
apiServerEndpoint: {{.APIServerEndpoint}}
6690
certificateAuthority: {{.CACert}}
67-
cidr: 10.96.0.0/12
68-
name: {{.ClusterName}}
91+
cidr: {{if .ClusterCIDR}}{{.ClusterCIDR}}{{else}}10.96.0.0/12{{end}}
6992
kubelet:
7093
config:
7194
maxPods: {{.MaxPods}}
7295
clusterDNS:
73-
- {{.ClusterDNS}}
96+
- {{.DNSClusterIP}}
7497
flags:
75-
- "--node-labels=eks.amazonaws.com/nodegroup-image={{.AMIImageID}},eks.amazonaws.com/capacityType={{.CapacityType}},eks.amazonaws.com/nodegroup={{.NodeGroupName}}"{{.PreCommands}}{{.PostCommands}}{{template "al2023KubeletExtraArgs" .KubeletExtraArgs}}{{template "al2023ContainerRuntime" .ContainerRuntime}}{{template "al2023DockerConfig" .DockerConfigJSONEscaped}}{{template "al2023APIRetryAttempts" .APIRetryAttempts}}{{template "al2023PauseContainer" .PauseContainerInfo}}{{template "al2023Files" .Files}}{{template "al2023DiskSetup" .DiskSetup}}{{template "al2023Mounts" .Mounts}}{{template "al2023Users" .Users}}{{template "al2023NTP" .NTP}}
98+
- "--node-labels={{if and .KubeletExtraArgs (index .KubeletExtraArgs "node-labels")}}{{index .KubeletExtraArgs "node-labels"}}{{else}}eks.amazonaws.com/nodegroup-image={{if .AMIImageID}}{{.AMIImageID}}{{end}},eks.amazonaws.com/capacityType={{if .CapacityType}}{{.CapacityType}}{{else}}ON_DEMAND{{end}},eks.amazonaws.com/nodegroup={{.NodeGroupName}}{{end}}"
7699
77100
--{{.Boundary}}--`
78101

79102
// AL2023-specific templates.
80103
al2023KubeletExtraArgsTemplate = `{{- define "al2023KubeletExtraArgs" -}}
81-
{{- if . -}}
82-
{{- range $k, $v := . -}}
83-
- "--{{$k}}={{$v}}"
84-
{{- end -}}
104+
{{- if . }}
105+
- "--node-labels={{range $k, $v := .}}{{$k}}={{$v}}{{end}}"
85106
{{- end -}}
86107
{{- end -}}`
87108

@@ -177,7 +198,12 @@ spec:
177198
{{- end -}}`
178199
)
179200

180-
// NodeInput defines the context to generate a node user data.
201+
// NodeUserData is responsible for generating userdata for EKS nodes.
202+
type NodeUserData struct {
203+
input *NodeInput
204+
}
205+
206+
// NodeInput contains all the information required to generate user data for a node.
181207
type NodeInput struct {
182208
ClusterName string
183209
KubeletExtraArgs map[string]string
@@ -210,6 +236,10 @@ type NodeInput struct {
210236
NodeGroupName string
211237
AMIImageID string
212238
CapacityType *v1beta2.ManagedMachinePoolCapacityType
239+
MaxPods *int32
240+
Boundary string
241+
ClusterDNS string
242+
ClusterCIDR string // CIDR range for the cluster
213243
}
214244

215245
// PauseContainerInfo holds pause container information for templates.
@@ -302,129 +332,85 @@ func generateStandardUserData(input *NodeInput) ([]byte, error) {
302332

303333
// generateAL2023UserData generates userdata for Amazon Linux 2023 nodes.
304334
func generateAL2023UserData(input *NodeInput) ([]byte, error) {
305-
// Validate required AL2023 fields
306-
if input.APIServerEndpoint == "" {
307-
return nil, fmt.Errorf("API server endpoint is required for AL2023")
308-
}
309-
if input.CACert == "" {
310-
return nil, fmt.Errorf("CA certificate is required for AL2023")
311-
}
312-
if input.ClusterName == "" {
313-
return nil, fmt.Errorf("cluster name is required for AL2023")
314-
}
315-
if input.NodeGroupName == "" {
316-
return nil, fmt.Errorf("node group name is required for AL2023")
335+
if err := validateAL2023Input(input); err != nil {
336+
return nil, err
317337
}
318338

319-
// Calculate maxPods based on UseMaxPods setting
320-
maxPods := 110 // Default when UseMaxPods is false
321-
if input.UseMaxPods != nil && *input.UseMaxPods {
322-
maxPods = 58 // Default when UseMaxPods is true
323-
}
339+
var buf bytes.Buffer
324340

325-
// Get cluster DNS
326-
clusterDNS := "10.96.0.10" // Default value
327-
if input.DNSClusterIP != nil && *input.DNSClusterIP != "" {
328-
clusterDNS = *input.DNSClusterIP
341+
// Write MIME header
342+
if _, err := buf.WriteString(fmt.Sprintf("MIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=\"%s\"\n\n", input.Boundary)); err != nil {
343+
return nil, fmt.Errorf("failed to write MIME header: %v", err)
329344
}
330345

331-
// Get capacity type as string
332-
capacityType := "ON_DEMAND" // Default value
333-
if input.CapacityType != nil {
334-
switch *input.CapacityType {
335-
case v1beta2.ManagedMachinePoolCapacityTypeSpot:
336-
capacityType = "SPOT"
337-
case v1beta2.ManagedMachinePoolCapacityTypeOnDemand:
338-
capacityType = "ON_DEMAND"
339-
default:
340-
capacityType = strings.ToUpper(string(*input.CapacityType))
346+
// Write shell script part if needed
347+
if len(input.PreBootstrapCommands) > 0 || len(input.PostBootstrapCommands) > 0 {
348+
shellScriptTemplate := template.Must(template.New("shell").Parse(shellScriptPartTemplate))
349+
if err := shellScriptTemplate.Execute(&buf, input); err != nil {
350+
return nil, fmt.Errorf("failed to execute shell script template: %v", err)
351+
}
352+
if _, err := buf.WriteString("\n"); err != nil {
353+
return nil, fmt.Errorf("failed to write newline: %v", err)
341354
}
342355
}
343356

344-
// Get AMI ID - use empty string if not specified
345-
amiID := ""
346-
if input.AMIImageID != "" {
347-
amiID = input.AMIImageID
357+
// Write node config part
358+
nodeConfigTemplate := template.Must(template.New("node").Parse(nodeConfigPartTemplate))
359+
if err := nodeConfigTemplate.Execute(&buf, input); err != nil {
360+
return nil, fmt.Errorf("failed to execute node config template: %v", err)
348361
}
349362

350-
// Debug logging
351-
fmt.Printf("DEBUG: AL2023 Userdata Generation - maxPods: %d, clusterDNS: %s, amiID: %s, capacityType: %s\n",
352-
maxPods, clusterDNS, amiID, capacityType)
363+
return buf.Bytes(), nil
364+
}
353365

354-
// Generate pre/post commands sections
355-
preCommands := ""
356-
if len(input.PreBootstrapCommands) > 0 {
357-
preCommands = "\n preKubeadmCommands:"
358-
for _, cmd := range input.PreBootstrapCommands {
359-
preCommands += fmt.Sprintf("\n - %s", cmd)
360-
}
366+
// getCapacityTypeString returns the string representation of the capacity type
367+
func (ni *NodeInput) getCapacityTypeString() string {
368+
if ni.CapacityType == nil {
369+
return "ON_DEMAND"
361370
}
362-
363-
postCommands := ""
364-
if len(input.PostBootstrapCommands) > 0 {
365-
postCommands = "\n postKubeadmCommands:"
366-
for _, cmd := range input.PostBootstrapCommands {
367-
postCommands += fmt.Sprintf("\n - %s", cmd)
368-
}
371+
switch *ni.CapacityType {
372+
case v1beta2.ManagedMachinePoolCapacityTypeSpot:
373+
return "SPOT"
374+
case v1beta2.ManagedMachinePoolCapacityTypeOnDemand:
375+
return "ON_DEMAND"
376+
default:
377+
return strings.ToUpper(string(*ni.CapacityType))
369378
}
379+
}
370380

371-
// Create template with all AL2023 templates
372-
tm := template.New("AL2023Node").Funcs(defaultTemplateFuncMap)
373-
374-
// Parse all AL2023-specific templates
375-
templates := []string{
376-
al2023KubeletExtraArgsTemplate,
377-
al2023ContainerRuntimeTemplate,
378-
al2023DockerConfigTemplate,
379-
al2023APIRetryAttemptsTemplate,
380-
al2023PauseContainerTemplate,
381-
al2023FilesTemplate,
382-
al2023DiskSetupTemplate,
383-
al2023MountsTemplate,
384-
al2023UsersTemplate,
385-
al2023NTPTemplate,
381+
// validateAL2023Input validates the input for AL2023 user data generation
382+
func validateAL2023Input(input *NodeInput) error {
383+
if input.APIServerEndpoint == "" {
384+
return fmt.Errorf("API server endpoint is required for AL2023")
385+
}
386+
if input.CACert == "" {
387+
return fmt.Errorf("CA certificate is required for AL2023")
388+
}
389+
if input.ClusterName == "" {
390+
return fmt.Errorf("cluster name is required for AL2023")
391+
}
392+
if input.NodeGroupName == "" {
393+
return fmt.Errorf("node group name is required for AL2023")
386394
}
387395

388-
for _, tpl := range templates {
389-
if _, err := tm.Parse(tpl); err != nil {
390-
return nil, fmt.Errorf("failed to parse AL2023 template: %w", err)
396+
if input.MaxPods == nil {
397+
if input.UseMaxPods != nil && *input.UseMaxPods {
398+
input.MaxPods = ptr.To[int32](58)
399+
} else {
400+
input.MaxPods = ptr.To[int32](110)
391401
}
392402
}
393-
394-
// Parse the main AL2023 template
395-
t, err := tm.Parse(al2023UserDataTemplate)
396-
if err != nil {
397-
return nil, fmt.Errorf("failed to parse AL2023 userdata template: %w", err)
403+
if input.DNSClusterIP == nil {
404+
input.DNSClusterIP = ptr.To[string]("10.96.0.10")
398405
}
406+
input.ClusterDNS = *input.DNSClusterIP
399407

400-
// Create template data with all fields
401-
templateData := struct {
402-
*NodeInput
403-
Boundary string
404-
MaxPods int
405-
ClusterDNS string
406-
CapacityType string
407-
AMIImageID string
408-
PreCommands string
409-
PostCommands string
410-
PauseContainerInfo PauseContainerInfo
411-
}{
412-
NodeInput: input,
413-
Boundary: boundary,
414-
MaxPods: maxPods,
415-
ClusterDNS: clusterDNS,
416-
CapacityType: capacityType,
417-
AMIImageID: amiID,
418-
PreCommands: preCommands,
419-
PostCommands: postCommands,
420-
PauseContainerInfo: PauseContainerInfo{AccountNumber: input.PauseContainerAccount, Version: input.PauseContainerVersion},
408+
if input.Boundary == "" {
409+
input.Boundary = boundary
421410
}
422411

423-
// Execute template
424-
var out bytes.Buffer
425-
if err := t.Execute(&out, templateData); err != nil {
426-
return nil, fmt.Errorf("failed to generate AL2023 userdata: %w", err)
427-
}
412+
klog.V(2).Infof("AL2023 Userdata Generation - maxPods: %d, clusterDNS: %s, amiID: %s, capacityType: %s",
413+
*input.MaxPods, *input.DNSClusterIP, input.AMIImageID, input.getCapacityTypeString())
428414

429-
return out.Bytes(), nil
415+
return nil
430416
}

0 commit comments

Comments
 (0)