Skip to content

Commit

Permalink
Ensure Kubernetes version is always parsed as string (#9187)
Browse files Browse the repository at this point in the history
Co-authored-by: Abhay Krishna Arunachalam <arnchlm@amazon.com>
  • Loading branch information
eks-distro-pr-bot and abhay-krishna authored Jan 21, 2025
1 parent 0e8d1ff commit f7af331
Show file tree
Hide file tree
Showing 23 changed files with 65 additions and 99 deletions.
15 changes: 14 additions & 1 deletion pkg/api/v1alpha1/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ type kindObject struct {
// ParseClusterConfigFromContent unmarshalls an API object implementing the KindAccessor interface
// from a multiobject yaml content. It doesn't set defaults nor validates the object.
func ParseClusterConfigFromContent(content []byte, clusterConfig KindAccessor) error {
r := yamlutil.NewYAMLReader(bufio.NewReader(bytes.NewReader(content)))
normalizedConfig := NormalizeKubernetesVersion(string(content))

r := yamlutil.NewYAMLReader(bufio.NewReader(bytes.NewReader([]byte(normalizedConfig))))
for {
d, err := r.Read()
if err == io.EOF {
Expand Down Expand Up @@ -410,6 +412,17 @@ func ValidateClusterNameLength(clusterName string) error {
return nil
}

// NormalizeKubernetesVersion searches the YAML content for the specific string
// `kubernetesVersion: <>` and adds double quotes around the version so that it
// is always interpreted as a string instead of a float64 value.
// Ref: https://github.com/aws/eks-anywhere/issues/9184
func NormalizeKubernetesVersion(yamlContent string) string {
kubernetesVersionRegex := `(?m)(.*kubernetesVersion:\s*)['"]?(1\.[0-9]{2,})['"]?(.*)$`
quotedKubernetesVersionReplacement := `${1}"${2}"${3}`
compiledKubernetesVersionRegex := regexp.MustCompile(kubernetesVersionRegex)
return compiledKubernetesVersionRegex.ReplaceAllString(yamlContent, quotedKubernetesVersionReplacement)
}

func validateClusterConfigName(clusterConfig *Cluster) error {
err := ValidateClusterName(clusterConfig.ObjectMeta.Name)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/v1alpha1/testdata/cluster_1_20.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ spec:
machineGroupRef:
name: eksa-unit-test
kind: VSphereMachineConfig
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
workerNodeGroupConfigurations:
- count: 3
machineGroupRef:
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/v1alpha1/testdata/cluster_1_20_cloudstack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ spec:
datacenterRef:
kind: CloudStackDatacenterConfig
name: eksa-unit-test
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
workerNodeGroupConfigurations:
- count: 3
machineGroupRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ spec:
machineGroupRef:
name: eksa-unit-test
kind: VSphereMachineConfig
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
workerNodeGroupConfigurations:
- count: 3
machineGroupRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ spec:
machineGroupRef:
name: eksa-unit-test
kind: VSphereMachineConfig
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
workerNodeGroupConfigurations:
- count: 3
machineGroupRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ spec:
machineGroupRef:
name: eksa-unit-test
kind: VSphereMachineConfig
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
workerNodeGroupConfigurations:
- count: 3
machineGroupRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ spec:
machineGroupRef:
name: eksa-unit-test
kind: VSphereMachineConfig
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
workerNodeGroupConfigurations:
- count: 3
machineGroupRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ spec:
machineGroupRef:
name: eksa-unit-test
kind: VSphereMachineConfig
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
workerNodeGroupConfigurations:
- count: 0
machineGroupRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ spec:
machineGroupRef:
name: eksa-unit-test
kind: VSphereMachineConfig
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
workerNodeGroupConfigurations:
- count: 3
machineGroupRef:
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/v1alpha1/testdata/incorrect_indentation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ spec:
machineGroupRef:
name: eksa-unit-test
kind: VSphereMachineConfig
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
workerNodeGroupConfigurations:
- count: 3
machineGroupRef:
Expand Down
6 changes: 3 additions & 3 deletions pkg/cluster/config_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ func (c *ConfigManager) unmarshal(yamlManifest []byte) (*parsed, error) {
yamlObjs := separatorRegex.Split(string(yamlManifest), -1)

for _, yamlObj := range yamlObjs {
trimmedYamlObj := strings.TrimSuffix(yamlObj, "\n")
normalizedYamlObj := anywherev1.NormalizeKubernetesVersion(strings.TrimSuffix(yamlObj, "\n"))
k := &basicAPIObject{}
err := yaml.Unmarshal([]byte(trimmedYamlObj), k)
err := yaml.Unmarshal([]byte(normalizedYamlObj), k)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -154,7 +154,7 @@ func (c *ConfigManager) unmarshal(yamlManifest []byte) (*parsed, error) {
continue
}

if err := yaml.Unmarshal([]byte(trimmedYamlObj), obj); err != nil {
if err := yaml.Unmarshal([]byte(normalizedYamlObj), obj); err != nil {
return nil, err
}
parsed.objects.add(obj)
Expand Down
2 changes: 1 addition & 1 deletion pkg/cluster/testdata/cluster_1_19.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ spec:
kind: VSphereMachineConfig
name: eksa-unit-test
- name: workers-2
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
count: 1
machineGroupRef:
kind: VSphereMachineConfig
Expand Down
2 changes: 1 addition & 1 deletion pkg/cluster/testdata/cluster_1_20_cloudstack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ spec:
datacenterRef:
kind: CloudStackDatacenterConfig
name: eksa-unit-test
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
workerNodeGroupConfigurations:
- count: 3
machineGroupRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ spec:
datacenterRef:
kind: CloudStackDatacenterConfig
name: eksa-unit-test
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
workerNodeGroupConfigurations:
- count: 3
machineGroupRef:
Expand Down
2 changes: 1 addition & 1 deletion pkg/cluster/testdata/docker_cluster_oidc_awsiam_flux.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ spec:
name: m-docker
workerNodeGroupConfigurations:
- name: workers-1
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
count: 1
identityProviderRefs:
- kind: OIDCConfig
Expand Down
2 changes: 1 addition & 1 deletion pkg/dependencies/testdata/cluster_tinkerbell.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ spec:
datacenterRef:
kind: TinkerbellDatacenterConfig
name: eksa-unit-test
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
managementCluster:
name: eksa-unit-test
workerNodeGroupConfigurations:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ spec:
workerNodeGroupConfigurations:
- count: 3
name: md-0
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
machineGroupRef:
kind: CloudStackMachineConfig
name: test-md-0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ metadata:
name: eksa-unit-test
namespace: default
spec:
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
controlPlaneConfiguration:
name: eksa-unit-test-cp
count: 3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ spec:
name: test
workerNodeGroupConfigurations:
- count: 1
kubernetesVersion: "1.20"
kubernetesVersion: 1.20
name: md-0
machineGroupRef:
name: test-md
Expand Down
23 changes: 0 additions & 23 deletions pkg/utils/yaml/yaml.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package yaml

import (
"bufio"
"bytes"
"fmt"
"io"

apiyaml "k8s.io/apimachinery/pkg/util/yaml"
"sigs.k8s.io/yaml"
)

Expand All @@ -28,23 +25,3 @@ func Serialize[T any](objs ...T) ([][]byte, error) {
}
return r, nil
}

// SplitDocuments function splits content into individual document parts represented as byte slices.
func SplitDocuments(r io.Reader) ([][]byte, error) {
resources := make([][]byte, 0)

yr := apiyaml.NewYAMLReader(bufio.NewReader(r))
for {
d, err := yr.Read()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}

resources = append(resources, d)
}

return resources, nil
}
79 changes: 25 additions & 54 deletions pkg/utils/yaml/yaml_test.go
Original file line number Diff line number Diff line change
@@ -1,99 +1,70 @@
package yaml_test

import (
"bufio"
"errors"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

yamlutil "github.com/aws/eks-anywhere/pkg/utils/yaml"
)

func TestSplitDocuments(t *testing.T) {
func TestJoin(t *testing.T) {
tests := []struct {
name string
input string
expectedDocs [][]byte
expectedErr error
name string
input [][]byte
output []byte
}{
{
name: "Empty input",
input: "",
expectedDocs: [][]byte{},
expectedErr: nil,
name: "Empty input",
input: [][]byte{},
output: []byte{},
},
{
name: "Single document",
input: `apiVersion: v1
input: [][]byte{
[]byte(`apiVersion: v1
kind: Pod
metadata:
name: pod-1
`,
expectedDocs: [][]byte{
[]byte(`apiVersion: v1
`),
},
output: []byte(`apiVersion: v1
kind: Pod
metadata:
name: pod-1
`),
},
expectedErr: nil,
},
{
name: "Multiple documents",
input: `apiVersion: v1
input: [][]byte{
[]byte(`apiVersion: v1
kind: Pod
metadata:
name: pod-1
---
apiVersion: v1
`),
[]byte(`apiVersion: v1
kind: Service
metadata:
name: service-1
`,
expectedDocs: [][]byte{
[]byte(`apiVersion: v1
`),
},
output: []byte(`apiVersion: v1
kind: Pod
metadata:
name: pod-1
`),
[]byte(`apiVersion: v1
---
apiVersion: v1
kind: Service
metadata:
name: service-1
`),
},
expectedErr: nil,
},
{
name: "Error reading input 2",
input: `---\nkey: value\ninvalid_separator\n`,
expectedDocs: nil,
expectedErr: errors.New("invalid Yaml document separator: \\nkey: value\\ninvalid_separator\\n"),
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
r := strings.NewReader(test.input)

docs, err := yamlutil.SplitDocuments(bufio.NewReader(r))
if test.expectedErr != nil {
assert.Equal(t, test.expectedErr.Error(), err.Error())
assert.Equal(t, len(test.expectedDocs), len(docs))
} else {
require.NoError(t, err)
if len(docs) != len(test.expectedDocs) {
t.Errorf("Expected %d documents, but got %d", len(test.expectedDocs), len(docs))
}

for i, doc := range docs {
if string(doc) != string(test.expectedDocs[i]) {
t.Errorf("Document %d mismatch.\nExpected:\n%s\nGot:\n%s", i+1, string(test.expectedDocs[i]), string(doc))
}
}
joinedDoc := yamlutil.Join(test.input)
if string(joinedDoc) != string(test.output) {
t.Errorf("Document mismatch.\nExpected:\n%s\nGot:\n%s", string(test.output), string(joinedDoc))
}
})
}
Expand Down
5 changes: 4 additions & 1 deletion pkg/yamlutil/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
apiyaml "k8s.io/apimachinery/pkg/util/yaml"
"sigs.k8s.io/yaml"

"github.com/aws/eks-anywhere/pkg/api/v1alpha1"
)

type (
Expand Down Expand Up @@ -95,7 +97,8 @@ type Builder interface {
// Parse reads yaml manifest content with the registered mappings and passes
// the result to the Builder for further processing.
func (p *Parser) Parse(yamlManifest []byte, b Builder) error {
return p.Read(bytes.NewReader(yamlManifest), b)
normalizedYamlManifest := v1alpha1.NormalizeKubernetesVersion(string(yamlManifest))
return p.Read(bytes.NewReader([]byte(normalizedYamlManifest)), b)
}

// Read reads yaml manifest content with the registered mappings and passes
Expand Down
2 changes: 2 additions & 0 deletions pkg/yamlutil/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func TestParserParse(t *testing.T) {
apiVersion: v1
data:
Corefile: "d"
kubernetesVersion: 1.30
kind: ConfigMap
metadata:
name: aws-iam-authenticator
Expand Down Expand Up @@ -77,6 +78,7 @@ data:
g.Expect(parser.Parse([]byte(yaml), holder)).To(Succeed())
g.Expect(holder).NotTo(BeNil())
g.Expect(holder.configMap.Data).To(HaveKeyWithValue("Corefile", "d"))
g.Expect(holder.configMap.Data).To(HaveKeyWithValue("kubernetesVersion", "1.30"))
g.Expect(holder.secret.Data["username"]).To(Equal([]byte("admin")))
}

Expand Down

0 comments on commit f7af331

Please sign in to comment.