Skip to content

Commit

Permalink
Ensure Kubernetes version is always parsed as string
Browse files Browse the repository at this point in the history
  • Loading branch information
abhay-krishna committed Jan 17, 2025
1 parent 79b3a53 commit f3ebb5e
Show file tree
Hide file tree
Showing 11 changed files with 56 additions and 87 deletions.
5 changes: 4 additions & 1 deletion pkg/api/v1alpha1/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,10 @@ 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)))
kubeVersionRegex := regexp.MustCompile(constants.KubernetesVersionRegex)
sanitizedContent := kubeVersionRegex.ReplaceAllString(string(content), constants.QuotedKubernetesVersionRegexReplacement)

r := yamlutil.NewYAMLReader(bufio.NewReader(bytes.NewReader([]byte(sanitizedContent))))
for {
d, err := r.Read()
if err == io.EOF {
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
12 changes: 8 additions & 4 deletions pkg/cluster/config_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"sigs.k8s.io/yaml"

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

Expand Down Expand Up @@ -113,7 +114,10 @@ type parsed struct {
cluster *anywherev1.Cluster
}

var separatorRegex = regexp.MustCompile(`(?m)^---$`)
var (
separatorRegex = regexp.MustCompile(`(?m)^---$`)
kubeVersionRegex = regexp.MustCompile(constants.KubernetesVersionRegex)
)

func (c *ConfigManager) unmarshal(yamlManifest []byte) (*parsed, error) {
parsed := &parsed{
Expand All @@ -122,9 +126,9 @@ func (c *ConfigManager) unmarshal(yamlManifest []byte) (*parsed, error) {
yamlObjs := separatorRegex.Split(string(yamlManifest), -1)

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

if err := yaml.Unmarshal([]byte(trimmedYamlObj), obj); err != nil {
if err := yaml.Unmarshal([]byte(sanitizedYamlObj), obj); err != nil {
return nil, err
}
parsed.objects.add(obj)
Expand Down
7 changes: 7 additions & 0 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ const (
// DefaultcuratedPackagesRegistry is a containerd compatible registry format that matches all AWS regions.
DefaultCuratedPackagesRegistry = "783794618700.dkr.ecr.*.amazonaws.com"

// KubernetesVersionRegex matches the Kubernetes version field in the cluster config.
KubernetesVersionRegex = `(?m)(.*kubernetesVersion:\s*)['"]?(1\.[0-9]{2,})['"]?(.*)$`

// QuoteRegexReplacement is the target replacement pattern which will add quotes around the Kubernetes version
// in the cluster config.
QuotedKubernetesVersionRegexReplacement = `${1}"${2}"${3}`

// Provider specific env vars.
VSphereUsernameKey = "VSPHERE_USERNAME"
VSpherePasswordKey = "VSPHERE_PASSWORD"
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 TestJoinDocuments(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
7 changes: 6 additions & 1 deletion pkg/yamlutil/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import (
"bufio"
"bytes"
"io"
"regexp"

"github.com/go-logr/logr"
"github.com/pkg/errors"
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/constants"
)

type (
Expand Down Expand Up @@ -95,7 +98,9 @@ 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)
kubeVersionRegex := regexp.MustCompile(constants.KubernetesVersionRegex)
sanitizedYamlManifest := kubeVersionRegex.ReplaceAllString(string(yamlManifest), constants.QuotedKubernetesVersionRegexReplacement)
return p.Read(bytes.NewReader([]byte(sanitizedYamlManifest)), 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
2 changes: 1 addition & 1 deletion release/cli/pkg/assets/archives/archives.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ package archives
import (
"fmt"
"path/filepath"
"slices"

"github.com/pkg/errors"
"slices"

assettypes "github.com/aws/eks-anywhere/release/cli/pkg/assets/types"
"github.com/aws/eks-anywhere/release/cli/pkg/filereader"
Expand Down
2 changes: 1 addition & 1 deletion release/cli/pkg/assets/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ import (
"context"
"fmt"
"path/filepath"
"slices"
"strconv"

"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
"slices"

"github.com/aws/eks-anywhere/release/cli/pkg/assets/archives"
assetconfig "github.com/aws/eks-anywhere/release/cli/pkg/assets/config"
Expand Down
2 changes: 1 addition & 1 deletion release/cli/pkg/bundles/bundles.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ package bundles

import (
"fmt"
"slices"
"strconv"
"strings"

"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"slices"

anywherev1alpha1 "github.com/aws/eks-anywhere/release/api/v1alpha1"
"github.com/aws/eks-anywhere/release/cli/pkg/constants"
Expand Down

0 comments on commit f3ebb5e

Please sign in to comment.