diff --git a/pkg/api/v1alpha1/cluster.go b/pkg/api/v1alpha1/cluster.go index 267c686e8d0d..967c48d458fe 100644 --- a/pkg/api/v1alpha1/cluster.go +++ b/pkg/api/v1alpha1/cluster.go @@ -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 { @@ -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 { diff --git a/pkg/api/v1alpha1/testdata/cluster_1_20.yaml b/pkg/api/v1alpha1/testdata/cluster_1_20.yaml index 3fdf59e4f0dd..9d1cf85d73b8 100644 --- a/pkg/api/v1alpha1/testdata/cluster_1_20.yaml +++ b/pkg/api/v1alpha1/testdata/cluster_1_20.yaml @@ -10,7 +10,7 @@ spec: machineGroupRef: name: eksa-unit-test kind: VSphereMachineConfig - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 workerNodeGroupConfigurations: - count: 3 machineGroupRef: diff --git a/pkg/api/v1alpha1/testdata/cluster_1_20_cloudstack.yaml b/pkg/api/v1alpha1/testdata/cluster_1_20_cloudstack.yaml index 7f041942073a..ae62a7d6445a 100644 --- a/pkg/api/v1alpha1/testdata/cluster_1_20_cloudstack.yaml +++ b/pkg/api/v1alpha1/testdata/cluster_1_20_cloudstack.yaml @@ -21,7 +21,7 @@ spec: datacenterRef: kind: CloudStackDatacenterConfig name: eksa-unit-test - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 workerNodeGroupConfigurations: - count: 3 machineGroupRef: diff --git a/pkg/api/v1alpha1/testdata/cluster_1_20_namespace_mismatch_between_cluster_and_datacenter.yaml b/pkg/api/v1alpha1/testdata/cluster_1_20_namespace_mismatch_between_cluster_and_datacenter.yaml index 03c00edeba81..fd25cb3f7b3b 100644 --- a/pkg/api/v1alpha1/testdata/cluster_1_20_namespace_mismatch_between_cluster_and_datacenter.yaml +++ b/pkg/api/v1alpha1/testdata/cluster_1_20_namespace_mismatch_between_cluster_and_datacenter.yaml @@ -11,7 +11,7 @@ spec: machineGroupRef: name: eksa-unit-test kind: VSphereMachineConfig - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 workerNodeGroupConfigurations: - count: 3 machineGroupRef: diff --git a/pkg/api/v1alpha1/testdata/cluster_1_20_namespace_mismatch_between_cluster_and_machineconfigs.yaml b/pkg/api/v1alpha1/testdata/cluster_1_20_namespace_mismatch_between_cluster_and_machineconfigs.yaml index a35d32efda72..3e73e8bc56c5 100644 --- a/pkg/api/v1alpha1/testdata/cluster_1_20_namespace_mismatch_between_cluster_and_machineconfigs.yaml +++ b/pkg/api/v1alpha1/testdata/cluster_1_20_namespace_mismatch_between_cluster_and_machineconfigs.yaml @@ -11,7 +11,7 @@ spec: machineGroupRef: name: eksa-unit-test kind: VSphereMachineConfig - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 workerNodeGroupConfigurations: - count: 3 machineGroupRef: diff --git a/pkg/api/v1alpha1/testdata/cluster_1_20_with_non_eksa_resources.yaml b/pkg/api/v1alpha1/testdata/cluster_1_20_with_non_eksa_resources.yaml index 0c43624d9093..e8da14871715 100644 --- a/pkg/api/v1alpha1/testdata/cluster_1_20_with_non_eksa_resources.yaml +++ b/pkg/api/v1alpha1/testdata/cluster_1_20_with_non_eksa_resources.yaml @@ -17,7 +17,7 @@ spec: machineGroupRef: name: eksa-unit-test kind: VSphereMachineConfig - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 workerNodeGroupConfigurations: - count: 3 machineGroupRef: diff --git a/pkg/api/v1alpha1/testdata/cluster_invalid_cluster_name.yaml b/pkg/api/v1alpha1/testdata/cluster_invalid_cluster_name.yaml index 3c9639ed6ac3..bf6cfcad0b32 100644 --- a/pkg/api/v1alpha1/testdata/cluster_invalid_cluster_name.yaml +++ b/pkg/api/v1alpha1/testdata/cluster_invalid_cluster_name.yaml @@ -10,7 +10,7 @@ spec: machineGroupRef: name: eksa-unit-test kind: VSphereMachineConfig - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 workerNodeGroupConfigurations: - count: 3 machineGroupRef: diff --git a/pkg/api/v1alpha1/testdata/cluster_invalid_worker_node_count.yaml b/pkg/api/v1alpha1/testdata/cluster_invalid_worker_node_count.yaml index f94650468e03..0ab1c50da65e 100644 --- a/pkg/api/v1alpha1/testdata/cluster_invalid_worker_node_count.yaml +++ b/pkg/api/v1alpha1/testdata/cluster_invalid_worker_node_count.yaml @@ -10,7 +10,7 @@ spec: machineGroupRef: name: eksa-unit-test kind: VSphereMachineConfig - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 workerNodeGroupConfigurations: - count: 0 machineGroupRef: diff --git a/pkg/api/v1alpha1/testdata/cluster_package_configuration.yaml b/pkg/api/v1alpha1/testdata/cluster_package_configuration.yaml index 6cb6a2b1780a..3842b07be160 100644 --- a/pkg/api/v1alpha1/testdata/cluster_package_configuration.yaml +++ b/pkg/api/v1alpha1/testdata/cluster_package_configuration.yaml @@ -10,7 +10,7 @@ spec: machineGroupRef: name: eksa-unit-test kind: VSphereMachineConfig - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 workerNodeGroupConfigurations: - count: 3 machineGroupRef: diff --git a/pkg/api/v1alpha1/testdata/incorrect_indentation.yaml b/pkg/api/v1alpha1/testdata/incorrect_indentation.yaml index ecef3a113263..4f3db75fe27c 100644 --- a/pkg/api/v1alpha1/testdata/incorrect_indentation.yaml +++ b/pkg/api/v1alpha1/testdata/incorrect_indentation.yaml @@ -10,7 +10,7 @@ spec: machineGroupRef: name: eksa-unit-test kind: VSphereMachineConfig - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 workerNodeGroupConfigurations: - count: 3 machineGroupRef: diff --git a/pkg/cluster/config_manager.go b/pkg/cluster/config_manager.go index 38a2bc4b5418..76ae48c07f9b 100644 --- a/pkg/cluster/config_manager.go +++ b/pkg/cluster/config_manager.go @@ -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 } @@ -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) diff --git a/pkg/cluster/testdata/cluster_1_19.yaml b/pkg/cluster/testdata/cluster_1_19.yaml index 5ae212b2d28b..26cf671d2148 100644 --- a/pkg/cluster/testdata/cluster_1_19.yaml +++ b/pkg/cluster/testdata/cluster_1_19.yaml @@ -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 diff --git a/pkg/cluster/testdata/cluster_1_20_cloudstack.yaml b/pkg/cluster/testdata/cluster_1_20_cloudstack.yaml index 722568e31044..6a188a697c1c 100644 --- a/pkg/cluster/testdata/cluster_1_20_cloudstack.yaml +++ b/pkg/cluster/testdata/cluster_1_20_cloudstack.yaml @@ -21,7 +21,7 @@ spec: datacenterRef: kind: CloudStackDatacenterConfig name: eksa-unit-test - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 workerNodeGroupConfigurations: - count: 3 machineGroupRef: diff --git a/pkg/cluster/testdata/cluster_cloudstack_missing_datacenter.yaml b/pkg/cluster/testdata/cluster_cloudstack_missing_datacenter.yaml index 816bf76950fb..b2ee73ba7dd2 100644 --- a/pkg/cluster/testdata/cluster_cloudstack_missing_datacenter.yaml +++ b/pkg/cluster/testdata/cluster_cloudstack_missing_datacenter.yaml @@ -21,7 +21,7 @@ spec: datacenterRef: kind: CloudStackDatacenterConfig name: eksa-unit-test - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 workerNodeGroupConfigurations: - count: 3 machineGroupRef: diff --git a/pkg/cluster/testdata/docker_cluster_oidc_awsiam_flux.yaml b/pkg/cluster/testdata/docker_cluster_oidc_awsiam_flux.yaml index d27d57c06c5c..682e4fdbda5a 100644 --- a/pkg/cluster/testdata/docker_cluster_oidc_awsiam_flux.yaml +++ b/pkg/cluster/testdata/docker_cluster_oidc_awsiam_flux.yaml @@ -21,7 +21,7 @@ spec: name: m-docker workerNodeGroupConfigurations: - name: workers-1 - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 count: 1 identityProviderRefs: - kind: OIDCConfig diff --git a/pkg/dependencies/testdata/cluster_tinkerbell.yaml b/pkg/dependencies/testdata/cluster_tinkerbell.yaml index 986ea1a8f405..e30d63d4d42f 100644 --- a/pkg/dependencies/testdata/cluster_tinkerbell.yaml +++ b/pkg/dependencies/testdata/cluster_tinkerbell.yaml @@ -22,7 +22,7 @@ spec: datacenterRef: kind: TinkerbellDatacenterConfig name: eksa-unit-test - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 managementCluster: name: eksa-unit-test workerNodeGroupConfigurations: diff --git a/pkg/providers/cloudstack/testdata/cluster_main_worker_node_group_kubernetes_version.yaml b/pkg/providers/cloudstack/testdata/cluster_main_worker_node_group_kubernetes_version.yaml index d8e22aa867b5..c0f38c7ea880 100644 --- a/pkg/providers/cloudstack/testdata/cluster_main_worker_node_group_kubernetes_version.yaml +++ b/pkg/providers/cloudstack/testdata/cluster_main_worker_node_group_kubernetes_version.yaml @@ -31,7 +31,7 @@ spec: workerNodeGroupConfigurations: - count: 3 name: md-0 - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 machineGroupRef: kind: CloudStackMachineConfig name: test-md-0 diff --git a/pkg/providers/nutanix/testdata/eksa-cluster-external-etcd-k8s-1-20.yaml b/pkg/providers/nutanix/testdata/eksa-cluster-external-etcd-k8s-1-20.yaml index 1df3211dcae2..e5ee2f1a7d32 100644 --- a/pkg/providers/nutanix/testdata/eksa-cluster-external-etcd-k8s-1-20.yaml +++ b/pkg/providers/nutanix/testdata/eksa-cluster-external-etcd-k8s-1-20.yaml @@ -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 diff --git a/pkg/providers/tinkerbell/testdata/cluster_tinkerbell_worker_version.yaml b/pkg/providers/tinkerbell/testdata/cluster_tinkerbell_worker_version.yaml index 96879ab83b42..e470638bbb35 100644 --- a/pkg/providers/tinkerbell/testdata/cluster_tinkerbell_worker_version.yaml +++ b/pkg/providers/tinkerbell/testdata/cluster_tinkerbell_worker_version.yaml @@ -35,7 +35,7 @@ spec: name: test workerNodeGroupConfigurations: - count: 1 - kubernetesVersion: "1.20" + kubernetesVersion: 1.20 name: md-0 machineGroupRef: name: test-md diff --git a/pkg/utils/yaml/yaml.go b/pkg/utils/yaml/yaml.go index e15d35473b77..c7fc9ef76580 100644 --- a/pkg/utils/yaml/yaml.go +++ b/pkg/utils/yaml/yaml.go @@ -1,12 +1,9 @@ package yaml import ( - "bufio" "bytes" "fmt" - "io" - apiyaml "k8s.io/apimachinery/pkg/util/yaml" "sigs.k8s.io/yaml" ) @@ -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 -} diff --git a/pkg/utils/yaml/yaml_test.go b/pkg/utils/yaml/yaml_test.go index 0c1560337c18..231df7a85ab4 100644 --- a/pkg/utils/yaml/yaml_test.go +++ b/pkg/utils/yaml/yaml_test.go @@ -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)) } }) } diff --git a/pkg/yamlutil/parser.go b/pkg/yamlutil/parser.go index b7587187c349..d0fa787f0146 100644 --- a/pkg/yamlutil/parser.go +++ b/pkg/yamlutil/parser.go @@ -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 ( @@ -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 diff --git a/pkg/yamlutil/parser_test.go b/pkg/yamlutil/parser_test.go index 43a8558b22a1..e8968079b3c3 100644 --- a/pkg/yamlutil/parser_test.go +++ b/pkg/yamlutil/parser_test.go @@ -45,6 +45,7 @@ func TestParserParse(t *testing.T) { apiVersion: v1 data: Corefile: "d" + kubernetesVersion: 1.30 kind: ConfigMap metadata: name: aws-iam-authenticator @@ -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"))) }