Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add extended kubernetes version support validations for create and upgrade CLI operations #9225

Merged
merged 1 commit into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/eksctl-anywhere/cmd/createcluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@
CliConfig: cliConfig,
SkippedValidations: skippedValidations,
KubeClient: deps.UnAuthKubeClient.KubeconfigClient(mgmt.KubeconfigFile),
ManifestReader: deps.ManifestReader,

Check warning on line 226 in cmd/eksctl-anywhere/cmd/createcluster.go

View check run for this annotation

Codecov / codecov/patch

cmd/eksctl-anywhere/cmd/createcluster.go#L226

Added line #L226 was not covered by tests
}
createValidations := createvalidations.New(validationOpts)

Expand Down
1 change: 1 addition & 0 deletions cmd/eksctl-anywhere/cmd/upgradecluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@
CliConfig: cliConfig,
SkippedValidations: skippedValidations,
KubeClient: deps.UnAuthKubeClient.KubeconfigClient(managementCluster.KubeconfigFile),
ManifestReader: deps.ManifestReader,

Check warning on line 202 in cmd/eksctl-anywhere/cmd/upgradecluster.go

View check run for this annotation

Codecov / codecov/patch

cmd/eksctl-anywhere/cmd/upgradecluster.go#L202

Added line #L202 was not covered by tests
}

upgradeValidations := upgradevalidations.New(validationOpts)
Expand Down
3 changes: 2 additions & 1 deletion cmd/eksctl-anywhere/cmd/validatecreatecluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
WithGitOpsFlux(clusterSpec.Cluster, clusterSpec.FluxConfig, cliConfig).
WithUnAuthKubeClient().
WithValidatorClients().
WithManifestReader().

Check warning on line 91 in cmd/eksctl-anywhere/cmd/validatecreatecluster.go

View check run for this annotation

Codecov / codecov/patch

cmd/eksctl-anywhere/cmd/validatecreatecluster.go#L91

Added line #L91 was not covered by tests
Build(ctx)
if err != nil {
cleanupDirectory(tmpPath)
Expand All @@ -105,8 +106,8 @@
ManagementCluster: getManagementCluster(clusterSpec),
Provider: deps.Provider,
CliConfig: cliConfig,
ManifestReader: deps.ManifestReader,

Check warning on line 109 in cmd/eksctl-anywhere/cmd/validatecreatecluster.go

View check run for this annotation

Codecov / codecov/patch

cmd/eksctl-anywhere/cmd/validatecreatecluster.go#L109

Added line #L109 was not covered by tests
}

createValidations := createvalidations.New(validationOpts)

commandVal := createcluster.NewValidations(clusterSpec, deps.Provider, deps.GitOpsFlux, createValidations, deps.DockerClient)
Expand Down
2 changes: 1 addition & 1 deletion pkg/providers/tinkerbell/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@
// for any operation other than k8s version change, hookImageURL is immutable
if currentClstr.Spec.KubernetesVersion == desiredClstrSpec.Cluster.Spec.KubernetesVersion {
if desiredDCCfgSpec.HookImagesURLPath != currentDCCfg.Spec.HookImagesURLPath {
return fmt.Errorf("spec.hookImagesURLPath is immutable. previoius = %s, new = %s",
return fmt.Errorf("spec.hookImagesURLPath is immutable. previous = %s, new = %s",

Check warning on line 344 in pkg/providers/tinkerbell/upgrade.go

View check run for this annotation

Codecov / codecov/patch

pkg/providers/tinkerbell/upgrade.go#L344

Added line #L344 was not covered by tests
currentDCCfg.Spec.HookImagesURLPath, desiredDCCfgSpec.HookImagesURLPath)
}
}
Expand Down
15 changes: 15 additions & 0 deletions pkg/validations/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/aws/eks-anywhere/pkg/constants"
"github.com/aws/eks-anywhere/pkg/features"
"github.com/aws/eks-anywhere/pkg/logger"
"github.com/aws/eks-anywhere/pkg/manifests"
"github.com/aws/eks-anywhere/pkg/providers"
"github.com/aws/eks-anywhere/pkg/providers/common"
"github.com/aws/eks-anywhere/pkg/semver"
Expand Down Expand Up @@ -297,3 +298,17 @@ func ValidateK8s132Support(clusterSpec *cluster.Spec) error {
}
return nil
}

// ValidateExtendedKubernetesSupport validates the extended kubernetes version support for create and upgrade operations.
func ValidateExtendedKubernetesSupport(ctx context.Context, clusterSpec v1alpha1.Cluster, reader *manifests.Reader, k kubernetes.Client) error {
eksaVersion := clusterSpec.Spec.EksaVersion
if eksaVersion == nil {
return nil
}

bundles, err := reader.ReadBundlesForVersion(string(*eksaVersion))
if err != nil {
return fmt.Errorf("getting bundle for existing cluster : %w", err)
}
return ValidateExtendedK8sVersionSupport(ctx, clusterSpec, bundles, k)
}
97 changes: 97 additions & 0 deletions pkg/validations/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/aws/eks-anywhere/internal/test"
internalmocks "github.com/aws/eks-anywhere/internal/test/mocks"
"github.com/aws/eks-anywhere/pkg/api/v1alpha1"
anywherev1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1"
"github.com/aws/eks-anywhere/pkg/cluster"
"github.com/aws/eks-anywhere/pkg/features"
"github.com/aws/eks-anywhere/pkg/manifests"
"github.com/aws/eks-anywhere/pkg/manifests/releases"
"github.com/aws/eks-anywhere/pkg/providers"
providermocks "github.com/aws/eks-anywhere/pkg/providers/mocks"
"github.com/aws/eks-anywhere/pkg/types"
Expand Down Expand Up @@ -853,3 +857,96 @@ func TestValidateK8s132SupportActive(t *testing.T) {
os.Setenv(features.K8s132SupportEnvVar, "true")
tt.Expect(validations.ValidateK8s132Support(tt.clusterSpec)).To(Succeed())
}

func TestValidateExtendedKubernetesVersionSupportCLINoError(t *testing.T) {
ctx := context.Background()

cluster := &v1alpha1.Cluster{
Spec: v1alpha1.ClusterSpec{
EksaVersion: nil,
},
}
objs := []client.Object{}
objs = append(objs, cluster)
fakeClient := test.NewFakeKubeClient(objs...)

ctrl := gomock.NewController(t)
reader := internalmocks.NewMockReader(ctrl)

err := validations.ValidateExtendedKubernetesSupport(ctx, *cluster, manifests.NewReader(reader), fakeClient)
if err != nil {
t.Errorf("got = %v, \nwant nil", err)
}
}

func TestValidateExtendedKubernetesVersionSupportCLIError(t *testing.T) {
ctx := context.Background()
version := test.DevEksaVersion()
cluster := &v1alpha1.Cluster{
Spec: v1alpha1.ClusterSpec{
EksaVersion: &version,
},
}

objs := []client.Object{}
objs = append(objs, cluster)
fakeClient := test.NewFakeKubeClient(objs...)

ctrl := gomock.NewController(t)
reader := internalmocks.NewMockReader(ctrl)
releasesURL := releases.ManifestURL()
reader.EXPECT().ReadFile(releasesURL)

err := validations.ValidateExtendedKubernetesSupport(ctx, *cluster, manifests.NewReader(reader), fakeClient)
if err == nil {
t.Errorf("got = nil, \nwant error: getting bundle for existing cluster")
}
}

func TestValidateExtendedKubernetesVersionSupportCLICheckExtendedSupport(t *testing.T) {
ctx := context.Background()
version := test.DevEksaVersion()
cluster := &v1alpha1.Cluster{
Spec: v1alpha1.ClusterSpec{
EksaVersion: &version,
KubernetesVersion: anywherev1.Kube130,
},
}

objs := []client.Object{}
objs = append(objs, cluster)
fakeClient := test.NewFakeKubeClient(objs...)

ctrl := gomock.NewController(t)
reader := internalmocks.NewMockReader(ctrl)
releasesURL := releases.ManifestURL()
releasesManifest := fmt.Sprintf(`apiVersion: anywhere.eks.amazonaws.com/v1alpha1
kind: Release
metadata:
name: release-1
spec:
releases:
- bundleManifestUrl: "https://bundles/bundles.yaml"
version: %s`, string(version))
reader.EXPECT().ReadFile(releasesURL).Return([]byte(releasesManifest), nil)

bundlesManifest := `apiVersion: anywhere.eks.amazonaws.com/v1alpha1
apiVersion: anywhere.eks.amazonaws.com/v1alpha1
kind: Bundles
metadata:
annotations:
anywhere.eks.amazonaws.com/signature: MEYCIQDgmE8oY9xUyFO3uOHRkpRWjTxoej8Wf7Ty5HQcbs9ouQIhANV2kylPXjcpLY2xu7vD6ktXqm7yrnLUgiehSdbL8JUJ
name: bundles-1
spec:
number: 1
versionsBundles:
- kubeversion: "1.30"
endOfStandardSupport: "2026-12-31"`

reader.EXPECT().ReadFile("https://bundles/bundles.yaml").Return([]byte(bundlesManifest), nil)

err := validations.ValidateExtendedKubernetesSupport(ctx, *cluster, manifests.NewReader(reader), fakeClient)
if err != nil {
t.Errorf("got = %v, \nwant nil", err)
}
}
7 changes: 7 additions & 0 deletions pkg/validations/createvalidations/preflightvalidations.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ func (v *CreateValidations) PreflightValidations(ctx context.Context) []validati
Silent: true,
}
},
func() *validations.ValidationResult {
return &validations.ValidationResult{
Name: "validate extended kubernetes version support is supported",
Remediation: "ensure you have a valid license for extended Kubernetes version support",
Err: validations.ValidateExtendedKubernetesSupport(ctx, *v.Opts.Spec.Cluster, v.Opts.ManifestReader, v.Opts.KubeClient),
}
},
}

if len(v.Opts.Spec.VSphereMachineConfigs) != 0 {
Expand Down
60 changes: 55 additions & 5 deletions pkg/validations/createvalidations/preflightvalidations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package createvalidations_test

import (
"context"
"fmt"
"testing"

"github.com/golang/mock/gomock"
Expand All @@ -11,9 +12,12 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/aws/eks-anywhere/internal/test"
internalmocks "github.com/aws/eks-anywhere/internal/test/mocks"
anywherev1 "github.com/aws/eks-anywhere/pkg/api/v1alpha1"
"github.com/aws/eks-anywhere/pkg/cluster"
"github.com/aws/eks-anywhere/pkg/constants"
"github.com/aws/eks-anywhere/pkg/manifests"
"github.com/aws/eks-anywhere/pkg/manifests/releases"
"github.com/aws/eks-anywhere/pkg/types"
"github.com/aws/eks-anywhere/pkg/validations"
"github.com/aws/eks-anywhere/pkg/validations/createvalidations"
Expand All @@ -30,22 +34,32 @@ type preflightValidationsTest struct {
func newPreflightValidationsTest(t *testing.T) *preflightValidationsTest {
ctrl := gomock.NewController(t)
k := mocks.NewMockKubectlClient(ctrl)

version := test.DevEksaVersion()

c := &types.Cluster{
KubeconfigFile: "kubeconfig",
}

clusterSpec := test.NewClusterSpec(func(s *cluster.Spec) {
s.Cluster.Spec.GitOpsRef = &anywherev1.Ref{
Name: "gitops",
s.Cluster = &anywherev1.Cluster{
Spec: anywherev1.ClusterSpec{
KubernetesVersion: "1.30",
GitOpsRef: &anywherev1.Ref{
Name: "gitops",
},
EksaVersion: &version,
},
}
})
version := "v0.19.0-dev+latest"

objects := []client.Object{test.EKSARelease()}
opts := &validations.Opts{
Kubectl: k,
Spec: clusterSpec,
WorkloadCluster: c,
ManagementCluster: c,
CliVersion: version,
CliVersion: string(version),
KubeClient: test.NewFakeKubeClient(objects...),
}
return &preflightValidationsTest{
Expand All @@ -56,8 +70,42 @@ func newPreflightValidationsTest(t *testing.T) *preflightValidationsTest {
}
}

func addManifestReaderMock(t *testing.T, version anywherev1.EksaVersion) *manifests.Reader {
ctrl := gomock.NewController(t)
reader := internalmocks.NewMockReader(ctrl)
releasesURL := releases.ManifestURL()

releasesManifest := fmt.Sprintf(`apiVersion: anywhere.eks.amazonaws.com/v1alpha1
kind: Release
metadata:
name: release-1
spec:
releases:
- bundleManifestUrl: "https://bundles/bundles.yaml"
version: %s`, string(version))
reader.EXPECT().ReadFile(releasesURL).Return([]byte(releasesManifest), nil)

bundlesManifest := `apiVersion: anywhere.eks.amazonaws.com/v1alpha1
apiVersion: anywhere.eks.amazonaws.com/v1alpha1
kind: Bundles
metadata:
annotations:
anywhere.eks.amazonaws.com/signature: MEYCIQDgmE8oY9xUyFO3uOHRkpRWjTxoej8Wf7Ty5HQcbs9ouQIhANV2kylPXjcpLY2xu7vD6ktXqm7yrnLUgiehSdbL8JUJ
name: bundles-1
spec:
number: 1
versionsBundles:
- kubeversion: "1.30"
endOfStandardSupport: "2026-12-31"`

reader.EXPECT().ReadFile("https://bundles/bundles.yaml").Return([]byte(bundlesManifest), nil)

return manifests.NewReader(reader)
}

func TestPreFlightValidationsGitProvider(t *testing.T) {
tt := newPreflightValidationsTest(t)
tt.c.Opts.ManifestReader = addManifestReaderMock(t, anywherev1.EksaVersion(tt.c.Opts.CliVersion))
tt.Expect(validations.ProcessValidationResults(tt.c.PreflightValidations(tt.ctx))).To(Succeed())
}

Expand All @@ -67,13 +115,15 @@ func TestPreFlightValidationsWorkloadCluster(t *testing.T) {
tt.c.Opts.Spec.Cluster.SetManagedBy(mgmtClusterName)
tt.c.Opts.Spec.Cluster.Spec.ManagementCluster.Name = mgmtClusterName
tt.c.Opts.ManagementCluster.Name = mgmtClusterName
version := test.DevEksaVersion()
version := anywherev1.EksaVersion(tt.c.Opts.CliVersion)
tt.c.Opts.ManifestReader = addManifestReaderMock(t, version)

mgmt := &anywherev1.Cluster{
ObjectMeta: v1.ObjectMeta{
Name: "mgmt-cluster",
},
Spec: anywherev1.ClusterSpec{
KubernetesVersion: "1.30",
ManagementCluster: anywherev1.ManagementCluster{
Name: "mgmt-cluster",
},
Expand Down
2 changes: 1 addition & 1 deletion pkg/validations/extendedversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
return err
}
if !valid {
return fmt.Errorf("signature on the bundle is invalid, error: %w", err)
return errors.New("signature on the bundle is invalid")

Check warning on line 53 in pkg/validations/extendedversion.go

View check run for this annotation

Codecov / codecov/patch

pkg/validations/extendedversion.go#L53

Added line #L53 was not covered by tests
}
return nil
}
Expand Down
7 changes: 7 additions & 0 deletions pkg/validations/upgradevalidations/preflightvalidations.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ func (u *UpgradeValidations) PreflightValidations(ctx context.Context) []validat
Silent: true,
}
},
func() *validations.ValidationResult {
return &validations.ValidationResult{
Name: "validate extended kubernetes version support is supported",
Remediation: "ensure you have a valid license for extended Kubernetes version support",
Err: validations.ValidateExtendedKubernetesSupport(ctx, *u.Opts.Spec.Cluster, u.Opts.ManifestReader, u.Opts.KubeClient),
}
},
}

if len(u.Opts.Spec.VSphereMachineConfigs) != 0 {
Expand Down
Loading
Loading