diff --git a/addons/pkg/constants/constants.go b/addons/pkg/constants/constants.go index 407fa9be9e..4c9e8bc46c 100644 --- a/addons/pkg/constants/constants.go +++ b/addons/pkg/constants/constants.go @@ -371,6 +371,9 @@ const ( TKGDevCCPan = "devcc" TKRAnnotationKey = "run.tanzu.vmware.com/tkr-spec" + + // Zshippable postscrip added to mark a component as in development + Zshippable = "-zshippable" ) var ( diff --git a/addons/webhooks/clusterbootstrap_webhook.go b/addons/webhooks/clusterbootstrap_webhook.go index 9064b6f3cf..7f8cab8dc0 100644 --- a/addons/webhooks/clusterbootstrap_webhook.go +++ b/addons/webhooks/clusterbootstrap_webhook.go @@ -6,6 +6,7 @@ package webhooks import ( "context" "fmt" + "strings" "sync" "time" @@ -484,6 +485,10 @@ func (wh *ClusterBootstrap) validateAdditionalPackagesUpdate(ctx context.Context return allErrs } +// ValidateClusterBootstrapPackageUpdate for unit test validateClusterBoostrapPackageUpdate only. Not intended to be called directly from outside the package. +func (wh *ClusterBootstrap) ValidateClusterBootstrapPackageUpdate(ctx context.Context, oldPkg, newPkg *runv1alpha3.ClusterBootstrapPackage, fldPath *field.Path) *field.Error { + return wh.validateClusterBootstrapPackageUpdate(ctx, oldPkg, newPkg, fldPath) +} func (wh *ClusterBootstrap) validateClusterBootstrapPackageUpdate(ctx context.Context, oldPkg, newPkg *runv1alpha3.ClusterBootstrapPackage, fldPath *field.Path) *field.Error { // 1. For cni, cpi, csi, kapp once created // a. we won’t allow packageRef’s to be downgraded or change the package from something like calico to antrea @@ -520,12 +525,13 @@ func (wh *ClusterBootstrap) validateClusterBootstrapPackageUpdate(ctx context.Co } // The package can't be downgraded - newPkgSemver, err := versions.NewRelaxedSemver(newPackageVersion) + // trim zshippable from minor if present to help on development testing + newPkgSemver, err := versions.NewRelaxedSemver(strings.TrimRight(newPackageVersion, constants.Zshippable)) if err != nil { retErr := errors.Wrap(err, "new package version is invalid") return field.Invalid(fldPath.Child("refName"), newPkg.RefName, retErr.Error()) } - oldPkgSemver, err := versions.NewRelaxedSemver(oldPackageVersion) + oldPkgSemver, err := versions.NewRelaxedSemver(strings.TrimRight(oldPackageVersion, constants.Zshippable)) if err != nil { retErr := errors.Wrap(err, "old package version is invalid") return field.Invalid(fldPath.Child("refName"), oldPkg.RefName, retErr.Error()) diff --git a/addons/webhooks/clusterbootstrap_webhook_test.go b/addons/webhooks/clusterbootstrap_webhook_test.go index 74eaccb1f4..fcf72cbfab 100644 --- a/addons/webhooks/clusterbootstrap_webhook_test.go +++ b/addons/webhooks/clusterbootstrap_webhook_test.go @@ -7,6 +7,8 @@ import ( "context" "fmt" + "k8s.io/apimachinery/pkg/util/validation/field" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" @@ -306,6 +308,39 @@ var _ = Describe("ClusterbootstrapWebhook", func() { }) }) + Context("ValidateClusterBootstrapPackageUpdate", func() { + BeforeEach(func() { + err := createVersionedCarvelPackage(ctx, k8sClient, "oldpkg", "pkg", "0.12.1+vmware.2-tkg.2-zshippable") + if err != nil && !apierrors.IsAlreadyExists(err) { + Expect(err).NotTo(HaveOccurred()) + } + err = createVersionedCarvelPackage(ctx, k8sClient, "newpkg", "pkg", "0.12.1+vmware.2-tkg.3") + if err != nil && !apierrors.IsAlreadyExists(err) { + Expect(err).NotTo(HaveOccurred()) + } + }) + Context(" oldPackage is 0.12.1+vmware.2-tkg.2-zshippable", func() { + Context("newPackage is 0.12.1+vmware.2-tkg.3", func() { + It("should return ok", func() { + wh := webhooks.ClusterBootstrap{Client: k8sClient} + wh.SetupWebhookWithManager(ctx, mgr) + wh.SystemNamespace = SystemNamespace + oldPackage := &runv1alpha3.ClusterBootstrapPackage{ + RefName: "oldpkg", + ValuesFrom: nil, + } + newPackage := &runv1alpha3.ClusterBootstrapPackage{ + RefName: "newpkg", + ValuesFrom: nil, + } + fldPath := &field.Path{} + + Expect(wh.ValidateClusterBootstrapPackageUpdate(context.TODO(), oldPackage, newPackage, fldPath)).To(BeNil()) + }) + }) + + }) + }) }) func assertTKRBootstrapPackageNamesContain(tkr *runv1alpha3.TanzuKubernetesRelease, name string) { @@ -373,25 +408,34 @@ func createCarvelPackages(ctx context.Context, client client.Client) { } for _, refName := range packageRefNames { - err := client.Create(ctx, &packagev1alpha1.Package{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s.%s", refName, fakeCarvelPackageVersion), - Namespace: SystemNamespace, - }, - Spec: packagev1alpha1.PackageSpec{ - RefName: refName, - Version: fakeCarvelPackageVersion, - Template: packagev1alpha1.AppTemplateSpec{ - Spec: &kappctrlv1alph1.AppSpec{}, - }, - }, - }) + pkgName := fmt.Sprintf("%s.%s", refName, fakeCarvelPackageVersion) + err := createVersionedCarvelPackage(ctx, client, pkgName, refName, fakeCarvelPackageVersion) if err != nil && !apierrors.IsAlreadyExists(err) { Expect(err).NotTo(HaveOccurred()) } } } +func createVersionedCarvelPackage(ctx context.Context, client client.Client, pkgName, refName, version string) error { + + err := client.Create(ctx, &packagev1alpha1.Package{ + ObjectMeta: metav1.ObjectMeta{ + Name: pkgName, + Namespace: SystemNamespace, + }, + Spec: packagev1alpha1.PackageSpec{ + RefName: refName, + Version: version, + Template: packagev1alpha1.AppTemplateSpec{ + Spec: &kappctrlv1alph1.AppSpec{}, + }, + }, + }) + + return err + +} + func deleteCarvelPackages(ctx context.Context, client client.Client) { packageRefNames := []string{ fakeAntreaCarvelPackageRefName,