From 5e7546bf11f07924d7b1889bdebc8ed0b440ca0b Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Fri, 9 Oct 2020 15:28:37 +0200 Subject: [PATCH] Rename OperatorVersion CRs from `name-` to `name--` (#1684) * Changed the generated name for OperatorVersion CRDs * NO automatic migration - but the OperatTaskDependency Lookup now iterates over the OVs to find a match * Created a bit more framework for future migrations Co-authored-by: Aleksey Dukhovniy Signed-off-by: Andreas Neumann --- go.sum | 1 + hack/run-operator-tests.sh | 2 +- .../v1beta1/operatorversion_types_helpers.go | 43 +++++++- pkg/controller/instance/resolver_incluster.go | 2 +- pkg/engine/task/task_kudo_operator.go | 3 +- pkg/kudoctl/cmd/verify/verify.go | 1 + pkg/kudoctl/kube/config.go | 7 ++ pkg/kudoctl/kudoinit/migration/migration.go | 12 ++- .../kudoinit/migration/migration_helper.go | 56 ++++++++++ pkg/kudoctl/kudoinit/setup/setup.go | 20 ++-- pkg/kudoctl/packages/convert/resources.go | 8 +- .../packages/resolver/resolver_incluster.go | 68 ++++-------- .../resolver/resolver_incluster_test.go | 2 +- .../testdata/zk-crd-golden1/instance.golden | 2 +- .../zk-crd-golden1/operatorversion.golden | 2 +- .../testdata/zk-crd-golden2/instance.golden | 2 +- .../zk-crd-golden2/operatorversion.golden | 2 +- pkg/kudoctl/packages/types.go | 21 ++++ pkg/kudoctl/resources/dependencies/resolve.go | 12 ++- .../resources/dependencies/resolve_test.go | 79 ++++++++++---- pkg/kudoctl/util/repo/resolver_repo.go | 4 +- pkg/util/kudo/versions.go | 100 ++++++++++++++++++ pkg/util/kudo/versions_test.go | 88 +++++++++++++++ test/e2e/apply-delete-apply/00-assert.yaml | 2 +- test/e2e/plan-trigger/00-assert.yaml | 2 +- test/e2e/plan-trigger/01-assert.yaml | 2 +- test/e2e/terminal-failed-job/00-assert.yaml | 2 +- test/e2e/terminal-failed-job/01-assert.yaml | 2 +- test/e2e/toggle-task/00-assert.yaml | 2 +- test/e2e/toggle-task/01-assert.yaml | 2 +- .../invalid-crd-install/00-assert.yaml | 2 +- .../upgrade/upgrade-to-current/01-assert.yaml | 10 ++ .../upgrade/upgrade-to-current/02-assert.yaml | 23 +++- .../upgrade/upgrade-to-current/03-assert.yaml | 14 ++- .../simple-op-0.1.0/operator.yaml | 1 + .../simple-op-0.2.0/operator.yaml | 1 + 36 files changed, 491 insertions(+), 111 deletions(-) create mode 100644 pkg/kudoctl/kudoinit/migration/migration_helper.go create mode 100644 pkg/util/kudo/versions.go create mode 100644 pkg/util/kudo/versions_test.go diff --git a/go.sum b/go.sum index 88fa2c810..7df6e3ee6 100644 --- a/go.sum +++ b/go.sum @@ -317,6 +317,7 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= diff --git a/hack/run-operator-tests.sh b/hack/run-operator-tests.sh index 12d062cc9..0c80e821b 100755 --- a/hack/run-operator-tests.sh +++ b/hack/run-operator-tests.sh @@ -19,7 +19,7 @@ docker build . \ -t "kudobuilder/controller:$KUDO_VERSION" rm -rf operators -git clone https://github.com/kudobuilder/operators +git clone --branch "an/rename-operatorversions" https://github.com/kudobuilder/operators mkdir operators/bin/ cp ./bin/kubectl-kudo operators/bin/ sed "s/%version%/$KUDO_VERSION/" operators/kudo-test.yaml.tmpl > operators/kudo-test.yaml diff --git a/pkg/apis/kudo/v1beta1/operatorversion_types_helpers.go b/pkg/apis/kudo/v1beta1/operatorversion_types_helpers.go index 24c2d668e..64ca6692c 100644 --- a/pkg/apis/kudo/v1beta1/operatorversion_types_helpers.go +++ b/pkg/apis/kudo/v1beta1/operatorversion_types_helpers.go @@ -6,24 +6,37 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/kudobuilder/kudo/pkg/util/kudo" ) func OperatorInstanceName(operatorName string) string { return fmt.Sprintf("%s-instance", operatorName) } -func OperatorVersionName(operatorName, version string) string { - return fmt.Sprintf("%s-%s", operatorName, version) +func OperatorVersionName(operatorName, appVersion, opVersion string) string { + if appVersion == "" { + return fmt.Sprintf("%s-%s", operatorName, opVersion) + } + return fmt.Sprintf("%s-%s-%s", operatorName, appVersion, opVersion) } func (ov *OperatorVersion) FullyQualifiedName() string { - return fmt.Sprintf("%s-%s", ov.Name, ov.Spec.AppVersion) + return OperatorVersionName(ov.Spec.Operator.Name, ov.Spec.AppVersion, ov.Spec.Version) } func (ov *OperatorVersion) EqualOperatorVersion(other *OperatorVersion) bool { return ov.FullyQualifiedName() == other.FullyQualifiedName() } +func ListOperatorVersions(ns string, c client.Reader) (l *OperatorVersionList, err error) { + l = &OperatorVersionList{} + if err := c.List(context.TODO(), l, client.InNamespace(ns)); err != nil { + return nil, err + } + return l, nil +} + func GetOperatorVersionByName(name, ns string, c client.Reader) (ov *OperatorVersion, err error) { ov = &OperatorVersion{} err = c.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: ns}, ov) @@ -32,3 +45,27 @@ func GetOperatorVersionByName(name, ns string, c client.Reader) (ov *OperatorVer } return ov, nil } + +// Sortable Operator implements functionality to correctly sort OVs by name, appVersion and operatorVersion +var _ kudo.SortableOperator = &OperatorVersion{} + +func (ov *OperatorVersion) OperatorName() string { + return ov.Spec.Operator.Name +} + +func (ov *OperatorVersion) OperatorVersion() string { + return ov.Spec.Version +} + +func (ov *OperatorVersion) AppVersion() string { + return ov.Spec.AppVersion +} + +func ToSortableOperatorList(ovList []OperatorVersion) kudo.SortableOperatorList { + l := kudo.SortableOperatorList{} + for _, ov := range ovList { + ov := ov + l = append(l, &ov) + } + return l +} diff --git a/pkg/controller/instance/resolver_incluster.go b/pkg/controller/instance/resolver_incluster.go index 21abe15fe..66a3e714a 100644 --- a/pkg/controller/instance/resolver_incluster.go +++ b/pkg/controller/instance/resolver_incluster.go @@ -25,7 +25,7 @@ type InClusterResolver struct { } func (r InClusterResolver) Resolve(name string, appVersion string, operatorVersion string) (*packages.Package, error) { - ovn := kudoapi.OperatorVersionName(name, operatorVersion) + ovn := kudoapi.OperatorVersionName(name, appVersion, operatorVersion) ov, err := kudoapi.GetOperatorVersionByName(ovn, r.ns, r.c) if err != nil { diff --git a/pkg/engine/task/task_kudo_operator.go b/pkg/engine/task/task_kudo_operator.go index 157736197..7094b8a35 100644 --- a/pkg/engine/task/task_kudo_operator.go +++ b/pkg/engine/task/task_kudo_operator.go @@ -40,7 +40,8 @@ func (kt KudoOperatorTask) Run(ctx Context) (bool, error) { namespace := ctx.Meta.InstanceNamespace operatorName := kt.OperatorName operatorVersion := kt.OperatorVersion - operatorVersionName := kudoapi.OperatorVersionName(operatorName, operatorVersion) + appVersion := kt.AppVersion + operatorVersionName := kudoapi.OperatorVersionName(operatorName, appVersion, operatorVersion) instanceName := dependencyInstanceName(ctx.Meta.InstanceName, kt.InstanceName, operatorName) // 1. - Expand parameter file if exists - diff --git a/pkg/kudoctl/cmd/verify/verify.go b/pkg/kudoctl/cmd/verify/verify.go index a064b4612..388c11626 100644 --- a/pkg/kudoctl/cmd/verify/verify.go +++ b/pkg/kudoctl/cmd/verify/verify.go @@ -89,6 +89,7 @@ func (VersionVerifier) Verify(pf *packages.Files) verifier.Result { return res } verifySemVer(pf.Operator.OperatorVersion, "operatorVersion", &res, true) + verifySemVer(pf.Operator.AppVersion, "appVersion", &res, false) verifySemVer(pf.Operator.KubernetesVersion, "kubernetesVersion", &res, true) verifySemVer(pf.Operator.KUDOVersion, "kudoVersion", &res, false) return res diff --git a/pkg/kudoctl/kube/config.go b/pkg/kudoctl/kube/config.go index 29afe1359..a2fa38dbd 100644 --- a/pkg/kudoctl/kube/config.go +++ b/pkg/kudoctl/kube/config.go @@ -10,6 +10,7 @@ import ( "k8s.io/client-go/tools/clientcmd" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/kudobuilder/kudo/pkg/client/clientset/versioned" "github.com/kudobuilder/kudo/pkg/kudoctl/clog" ) @@ -19,6 +20,7 @@ type Client struct { ExtClient apiextensionsclient.Interface DynamicClient dynamic.Interface CtrlClient client.Client + KudoClient versioned.Interface } // GetConfig returns a Kubernetes client config for a given kubeconfig. @@ -70,11 +72,16 @@ func GetKubeClientForConfig(config *rest.Config) (*Client, error) { if err != nil { return nil, fmt.Errorf("could not create Controller Runtime client: %s", err) } + kudoClient, err := versioned.NewForConfig(config) + if err != nil { + return nil, fmt.Errorf("could not create KUDO client: %v", err) + } return &Client{ KubeClient: kubeClient, ExtClient: extClient, DynamicClient: dynamicClient, CtrlClient: ctrlClient, + KudoClient: kudoClient, }, nil } diff --git a/pkg/kudoctl/kudoinit/migration/migration.go b/pkg/kudoctl/kudoinit/migration/migration.go index 5f425944f..0a6a671dc 100644 --- a/pkg/kudoctl/kudoinit/migration/migration.go +++ b/pkg/kudoctl/kudoinit/migration/migration.go @@ -1,8 +1,12 @@ package migration -import "github.com/kudobuilder/kudo/pkg/kudoctl/kube" - +// Migrater is the base interface for migrations. type Migrater interface { - CanMigrate(client *kube.Client) error - Migrate(client *kube.Client) error + // CanMigrate checks if there are any conditions that would prevent this migration to run + // This function should only return an error if it is sure that the migration can not be executed + CanMigrate() error + + // Migrate executes the migration. The call must be idempotent and ignore already migrated resources + // It can be called multiple times on the same cluster and encounter migrated and unmigrated resources. + Migrate() error } diff --git a/pkg/kudoctl/kudoinit/migration/migration_helper.go b/pkg/kudoctl/kudoinit/migration/migration_helper.go new file mode 100644 index 000000000..20f3ef860 --- /dev/null +++ b/pkg/kudoctl/kudoinit/migration/migration_helper.go @@ -0,0 +1,56 @@ +// This package contains helper functions that can be reused by all migrations +package migration + +import ( + "context" + "fmt" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + kudoapi "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" + "github.com/kudobuilder/kudo/pkg/kudoctl/kube" +) + +// ForEachNamespace calls the given function for all namespaces in the cluster +func ForEachNamespace(client *kube.Client, f func(ns string) error) error { + l, err := client.KubeClient.CoreV1().Namespaces().List(context.TODO(), v1.ListOptions{}) + if err != nil { + return fmt.Errorf("failed to fetch namespaces: %v", err) + } + for _, ns := range l.Items { + if err := f(ns.Name); err != nil { + return fmt.Errorf("failed to run function for namespace %q: %v", ns.Name, err) + } + } + return nil +} + +// ForEachOperatorVersion calls the given function for all operatorversions in the given namespace +func ForEachOperatorVersion(client *kube.Client, ns string, f func(ov *kudoapi.OperatorVersion) error) error { + l, err := client.KudoClient.KudoV1beta1().OperatorVersions(ns).List(context.TODO(), v1.ListOptions{}) + if err != nil { + return fmt.Errorf("failed to fetch OperatorVersions from namespace %q: %v", ns, err) + } + for _, ov := range l.Items { + ov := ov + if err := f(&ov); err != nil { + return fmt.Errorf("failed to run function for OperatorVersion \"%s/%s\": %v", ov.Namespace, ov.Name, err) + } + } + return nil +} + +// ForEachInstance calls the given function for all instances in the given namespace +func ForEachInstance(client *kube.Client, ns string, f func(ov *kudoapi.Instance) error) error { + l, err := client.KudoClient.KudoV1beta1().Instances(ns).List(context.TODO(), v1.ListOptions{}) + if err != nil { + return fmt.Errorf("failed to fetch Instances from namespace %q: %v", ns, err) + } + for _, i := range l.Items { + i := i + if err := f(&i); err != nil { + return fmt.Errorf("failed to run function for Instance \"%s/%s\": %v", i.Namespace, i.Name, err) + } + } + return nil +} diff --git a/pkg/kudoctl/kudoinit/setup/setup.go b/pkg/kudoctl/kudoinit/setup/setup.go index b1073841b..57547ed33 100644 --- a/pkg/kudoctl/kudoinit/setup/setup.go +++ b/pkg/kudoctl/kudoinit/setup/setup.go @@ -68,12 +68,9 @@ func (i *Installer) VerifyInstallation(client *kube.Client, result *verifier.Res return nil } -func requiredMigrations() []migration.Migrater { - +func requiredMigrations(client *kube.Client, dryRun bool) []migration.Migrater { // Determine which migrations to run - return []migration.Migrater{ - // Implement actual migrations - } + return []migration.Migrater{} } func (i *Installer) PreUpgradeVerify(client *kube.Client, result *verifier.Result) error { @@ -88,13 +85,16 @@ func (i *Installer) PreUpgradeVerify(client *kube.Client, result *verifier.Resul return nil } - // Step 2 - Verify that any migration is possible - migrations := requiredMigrations() + // Step 2 - Verify that all migrations can run (with dryRun) + migrations := requiredMigrations(client, true) clog.V(1).Printf("Verify that %d required migrations can be applied", len(migrations)) for _, m := range migrations { - if err := m.CanMigrate(client); err != nil { + if err := m.CanMigrate(); err != nil { result.AddErrors(fmt.Errorf("migration %s failed install check: %v", m, err).Error()) } + if err := m.Migrate(); err != nil { + result.AddErrors(fmt.Errorf("migration %s failed dry-run: %v", m, err).Error()) + } } // TODO: Verify existing operators and instances? @@ -117,10 +117,10 @@ func (i *Installer) Upgrade(client *kube.Client) error { } // Step 5 - Execute Migrations - migrations := requiredMigrations() + migrations := requiredMigrations(client, false) clog.Printf("Run %d migrations", len(migrations)) for _, m := range migrations { - if err := m.Migrate(client); err != nil { + if err := m.Migrate(); err != nil { return fmt.Errorf("migration %s failed to execute: %v", m, err) } } diff --git a/pkg/kudoctl/packages/convert/resources.go b/pkg/kudoctl/packages/convert/resources.go index 90dabd5ab..456d1a023 100644 --- a/pkg/kudoctl/packages/convert/resources.go +++ b/pkg/kudoctl/packages/convert/resources.go @@ -60,7 +60,7 @@ func FilesToResources(files *packages.Files) (*packages.Resources, error) { APIVersion: packages.APIVersion, }, ObjectMeta: metav1.ObjectMeta{ - Name: kudoapi.OperatorVersionName(files.Operator.Name, files.Operator.OperatorVersion), + Name: kudoapi.OperatorVersionName(files.Operator.Name, files.Operator.AppVersion, files.Operator.OperatorVersion), }, Spec: kudoapi.OperatorVersionSpec{ Operator: corev1.ObjectReference{ @@ -78,7 +78,7 @@ func FilesToResources(files *packages.Files) (*packages.Resources, error) { Status: kudoapi.OperatorVersionStatus{}, } - instance := BuildInstanceResource(files.Operator.Name, files.Operator.OperatorVersion) + instance := BuildInstanceResource(files.Operator.Name, files.Operator.AppVersion, files.Operator.OperatorVersion) return &packages.Resources{ Operator: operator, @@ -87,7 +87,7 @@ func FilesToResources(files *packages.Files) (*packages.Resources, error) { }, nil } -func BuildInstanceResource(operatorName, operatorVersion string) *kudoapi.Instance { +func BuildInstanceResource(operatorName, appVersion, operatorVersion string) *kudoapi.Instance { return &kudoapi.Instance{ TypeMeta: metav1.TypeMeta{ Kind: "Instance", @@ -99,7 +99,7 @@ func BuildInstanceResource(operatorName, operatorVersion string) *kudoapi.Instan }, Spec: kudoapi.InstanceSpec{ OperatorVersion: corev1.ObjectReference{ - Name: kudoapi.OperatorVersionName(operatorName, operatorVersion), + Name: kudoapi.OperatorVersionName(operatorName, appVersion, operatorVersion), }, }, Status: kudoapi.InstanceStatus{}, diff --git a/pkg/kudoctl/packages/resolver/resolver_incluster.go b/pkg/kudoctl/packages/resolver/resolver_incluster.go index d618d773b..304532039 100644 --- a/pkg/kudoctl/packages/resolver/resolver_incluster.go +++ b/pkg/kudoctl/packages/resolver/resolver_incluster.go @@ -2,12 +2,11 @@ package resolver import ( "fmt" - "sort" + kudoapi "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" "github.com/kudobuilder/kudo/pkg/kudoctl/packages" "github.com/kudobuilder/kudo/pkg/kudoctl/packages/convert" "github.com/kudobuilder/kudo/pkg/kudoctl/util/kudo" - "github.com/kudobuilder/kudo/pkg/kudoctl/util/repo" ) // InClusterResolver resolves packages that are already installed in the cluster on the client-side. Note, that unlike @@ -19,68 +18,43 @@ type InClusterResolver struct { } func (r InClusterResolver) Resolve(name string, appVersion string, operatorVersion string) (*packages.Package, error) { - // 1. find all in-cluster operator versions with the passed operator name - versions, err := r.FindInClusterOperatorVersions(name) + // Fetch all OVs + ovList, err := r.c.ListOperatorVersions(r.ns) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to list operator versions in namespace %q: %v", r.ns, err) } - //2. sorting packages in descending order same as the repo does it: pkg/kudoctl/util/repo/index.go::sortPackages - // to preserve the selection rules. See sortPackages method description for more details. - sort.Sort(sort.Reverse(versions)) - - // 3. find first matching operator version - version, err := repo.FindFirstMatchForEntries(versions, name, appVersion, operatorVersion) - if err != nil { - return nil, err + if len(ovList) == 0 { + return nil, fmt.Errorf("failed to find any operator version in namespace %s", r.ns) } - // 4. fetch the existing O/OV and make the instance to install - ovn := version.Name - operatorVersion = version.OperatorVersion + // Put all items into a new list to be sortable + newOvList := kudoapi.ToSortableOperatorList(ovList) - ov, err := r.c.GetOperatorVersion(ovn, r.ns) - if err != nil { - return nil, fmt.Errorf("failed to resolve operator version %s/%s:%s", r.ns, ovn, appVersion) - } + // Only consider OVs for the given name + newOvList = newOvList.FilterByName(name) + // Sort items + newOvList.Sort() + + // Find first matching OV + // The ignored error here is from the cast to OperatorVersion and we can ignore it, as we handle the nil case below + ov, _ := newOvList.FindFirstMatch(name, operatorVersion, appVersion).(*kudoapi.OperatorVersion) // nolint:errcheck + + if ov == nil { + return nil, fmt.Errorf("failed to resolve operator version in namespace %q for name %q, version %q, appVersion %q", r.ns, name, operatorVersion, appVersion) + } o, err := r.c.GetOperator(name, r.ns) if err != nil { return nil, fmt.Errorf("failed to resolve operator %s/%s", r.ns, name) } - i := convert.BuildInstanceResource(name, operatorVersion) - return &packages.Package{ Resources: &packages.Resources{ Operator: o, OperatorVersion: ov, - Instance: i, + Instance: convert.BuildInstanceResource(name, operatorVersion, appVersion), }, Files: nil, }, nil } - -// FindInClusterOperatorVersions method searches for all in-cluster operator versions for the passed operator name -// and returns them as an []*PackageVersion array -func (r InClusterResolver) FindInClusterOperatorVersions(operatorName string) (repo.PackageVersions, error) { - ovs, err := r.c.ListOperatorVersions(r.ns) - if err != nil { - return nil, fmt.Errorf("failed to list in-cluster operator %s versions: %v", operatorName, err) - } - - versions := repo.PackageVersions{} - for _, ov := range ovs { - if ov.Spec.Operator.Name == operatorName { - versions = append(versions, &repo.PackageVersion{ - Metadata: &repo.Metadata{ - Name: ov.Name, - OperatorVersion: ov.Spec.Version, - AppVersion: ov.Spec.AppVersion, - }, - }) - } - } - - return versions, nil -} diff --git a/pkg/kudoctl/packages/resolver/resolver_incluster_test.go b/pkg/kudoctl/packages/resolver/resolver_incluster_test.go index 2f422d84e..34b680969 100644 --- a/pkg/kudoctl/packages/resolver/resolver_incluster_test.go +++ b/pkg/kudoctl/packages/resolver/resolver_incluster_test.go @@ -38,7 +38,7 @@ func TestInClusterResolver_Resolve(t *testing.T) { Kind: "OperatorVersion", }, ObjectMeta: metav1.ObjectMeta{ - Name: kudoapi.OperatorVersionName("foo-operator", operatorVersion), + Name: kudoapi.OperatorVersionName("foo-operator", appVersion, operatorVersion), Namespace: "default", }, Spec: kudoapi.OperatorVersionSpec{ diff --git a/pkg/kudoctl/packages/testdata/zk-crd-golden1/instance.golden b/pkg/kudoctl/packages/testdata/zk-crd-golden1/instance.golden index 84e243888..fd2e61d00 100644 --- a/pkg/kudoctl/packages/testdata/zk-crd-golden1/instance.golden +++ b/pkg/kudoctl/packages/testdata/zk-crd-golden1/instance.golden @@ -6,6 +6,6 @@ metadata: name: zk1 spec: operatorVersion: - name: zookeeper-0.1.0 + name: zookeeper-3.4.10-0.1.0 type: OperatorVersions name: "zookeeper-0.1.0" diff --git a/pkg/kudoctl/packages/testdata/zk-crd-golden1/operatorversion.golden b/pkg/kudoctl/packages/testdata/zk-crd-golden1/operatorversion.golden index 6274ef4c6..e1d1a3986 100644 --- a/pkg/kudoctl/packages/testdata/zk-crd-golden1/operatorversion.golden +++ b/pkg/kudoctl/packages/testdata/zk-crd-golden1/operatorversion.golden @@ -1,7 +1,7 @@ apiVersion: kudo.dev/v1beta1 kind: OperatorVersion metadata: - name: zookeeper-0.1.0 + name: zookeeper-3.4.10-0.1.0 spec: operator: name: zookeeper diff --git a/pkg/kudoctl/packages/testdata/zk-crd-golden2/instance.golden b/pkg/kudoctl/packages/testdata/zk-crd-golden2/instance.golden index 324485c6d..a7bf917c0 100644 --- a/pkg/kudoctl/packages/testdata/zk-crd-golden2/instance.golden +++ b/pkg/kudoctl/packages/testdata/zk-crd-golden2/instance.golden @@ -6,6 +6,6 @@ metadata: name: zk2 spec: operatorVersion: - name: zookeeper-0.1.0 + name: zookeeper-3.4.10-0.1.0 type: OperatorVersions name: "zookeeper-0.1.0" diff --git a/pkg/kudoctl/packages/testdata/zk-crd-golden2/operatorversion.golden b/pkg/kudoctl/packages/testdata/zk-crd-golden2/operatorversion.golden index 6274ef4c6..e1d1a3986 100644 --- a/pkg/kudoctl/packages/testdata/zk-crd-golden2/operatorversion.golden +++ b/pkg/kudoctl/packages/testdata/zk-crd-golden2/operatorversion.golden @@ -1,7 +1,7 @@ apiVersion: kudo.dev/v1beta1 kind: OperatorVersion metadata: - name: zookeeper-0.1.0 + name: zookeeper-3.4.10-0.1.0 spec: operator: name: zookeeper diff --git a/pkg/kudoctl/packages/types.go b/pkg/kudoctl/packages/types.go index 9a38c6ac2..517b39e2e 100644 --- a/pkg/kudoctl/packages/types.go +++ b/pkg/kudoctl/packages/types.go @@ -19,6 +19,27 @@ type Package struct { Files *Files } +func (p Package) OperatorName() string { + if p.Resources == nil || p.Resources.Operator == nil { + return "" + } + return p.Resources.Operator.Name +} + +func (p Package) OperatorVersionString() string { + if p.Resources == nil || p.Resources.OperatorVersion == nil { + return "" + } + return p.Resources.OperatorVersion.Spec.Version +} + +func (p Package) AppVersionString() string { + if p.Resources == nil || p.Resources.OperatorVersion == nil { + return "" + } + return p.Resources.OperatorVersion.Spec.AppVersion +} + // Resources is collection of CRDs that are used when installing operator // during installation, package format is converted to this structure type Resources struct { diff --git a/pkg/kudoctl/resources/dependencies/resolve.go b/pkg/kudoctl/resources/dependencies/resolve.go index 07b51a564..cfdc4d899 100644 --- a/pkg/kudoctl/resources/dependencies/resolve.go +++ b/pkg/kudoctl/resources/dependencies/resolve.go @@ -144,6 +144,16 @@ func indexOf(dependencies *[]Dependency, dependency *Dependency) int { return -1 } +// fullyQualifiedName formats a TaskSpec for human readable consumption. func fullyQualifiedName(kt kudoapi.KudoOperatorTaskSpec) string { - return fmt.Sprintf("%s-%s", kudoapi.OperatorVersionName(kt.Package, kt.OperatorVersion), kt.AppVersion) + operatorVersion := kt.OperatorVersion + if operatorVersion == "" { + operatorVersion = "any" + } + appVersion := kt.AppVersion + if appVersion == "" { + appVersion = "any" + } + + return fmt.Sprintf("Operator: %q, OperatorVersion: %q, AppVersion %q", kt.Package, operatorVersion, appVersion) } diff --git a/pkg/kudoctl/resources/dependencies/resolve_test.go b/pkg/kudoctl/resources/dependencies/resolve_test.go index 270abedb4..a9ff32190 100644 --- a/pkg/kudoctl/resources/dependencies/resolve_test.go +++ b/pkg/kudoctl/resources/dependencies/resolve_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/thoas/go-funk" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kudoapi "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" @@ -22,7 +23,9 @@ func (resolver nameResolver) Resolve( appVersion string, operatorVersion string) (*packages.Package, error) { for _, pkg := range resolver.Pkgs { - if pkg.Resources.Operator.Name == name { + if pkg.OperatorName() == name && + (operatorVersion == "" || pkg.OperatorVersionString() == operatorVersion) && + (appVersion == "" || pkg.AppVersionString() == appVersion) { return &pkg, nil } } @@ -31,6 +34,32 @@ func (resolver nameResolver) Resolve( } func createPackage(name string, dependencies ...string) packages.Package { + opVersion := "0.0.1" + appVersion := "" + + deps := []kudoapi.Task{} + for _, d := range dependencies { + deps = append(deps, createDependency(d, "", "")) + } + + return createPackageWithVersions(name, opVersion, appVersion, deps...) +} + +func createDependency(name, opVersion, appVersion string) kudoapi.Task { + return kudoapi.Task{ + Name: "dependency", + Kind: engtask.KudoOperatorTaskKind, + Spec: kudoapi.TaskSpec{ + KudoOperatorTaskSpec: kudoapi.KudoOperatorTaskSpec{ + Package: name, + OperatorVersion: opVersion, + AppVersion: appVersion, + }, + }, + } +} + +func createPackageWithVersions(name, opVersion, appVersion string, dependencies ...kudoapi.Task) packages.Package { p := packages.Package{ Resources: &packages.Resources{ Operator: &kudoapi.Operator{ @@ -40,25 +69,20 @@ func createPackage(name string, dependencies ...string) packages.Package { }, OperatorVersion: &kudoapi.OperatorVersion{ ObjectMeta: metav1.ObjectMeta{ - Name: kudoapi.OperatorVersionName(name, ""), + Name: kudoapi.OperatorVersionName(name, appVersion, opVersion), + }, + Spec: kudoapi.OperatorVersionSpec{ + Operator: v1.ObjectReference{ + Name: name, + }, + Version: opVersion, + AppVersion: appVersion, }, }, }, } - for _, dependency := range dependencies { - p.Resources.OperatorVersion.Spec.Tasks = append( - p.Resources.OperatorVersion.Spec.Tasks, - kudoapi.Task{ - Name: "dependency", - Kind: engtask.KudoOperatorTaskKind, - Spec: kudoapi.TaskSpec{ - KudoOperatorTaskSpec: kudoapi.KudoOperatorTaskSpec{ - Package: dependency, - }, - }, - }) - } + p.Resources.OperatorVersion.Spec.Tasks = append(p.Resources.OperatorVersion.Spec.Tasks, dependencies...) return p } @@ -78,7 +102,7 @@ func TestResolve(t *testing.T) { createPackage("A", "A"), }, want: []string{}, - wantErr: "cyclic package dependency found when adding package A-- -> A--", + wantErr: "cyclic package dependency found when adding package A-0.0.1 -> A-0.0.1", }, { // A @@ -90,7 +114,7 @@ func TestResolve(t *testing.T) { createPackage("B", "B"), }, want: []string{}, - wantErr: "cyclic package dependency found when adding package B-- -> B--", + wantErr: "cyclic package dependency found when adding package B-0.0.1 -> B-0.0.1", }, { // A @@ -102,7 +126,7 @@ func TestResolve(t *testing.T) { createPackage("B", "A"), }, want: []string{}, - wantErr: "cyclic package dependency found when adding package B-- -> A--", + wantErr: "cyclic package dependency found when adding package B-0.0.1 -> A-0.0.1", }, { // A @@ -116,7 +140,7 @@ func TestResolve(t *testing.T) { createPackage("C", "B"), }, want: []string{}, - wantErr: "cyclic package dependency found when adding package C-- -> B--", + wantErr: "cyclic package dependency found when adding package C-0.0.1 -> B-0.0.1", }, { // A @@ -126,7 +150,7 @@ func TestResolve(t *testing.T) { createPackage("A", "B"), }, want: []string{}, - wantErr: "failed to resolve package B--, dependency of package A--: package not found", + wantErr: "failed to resolve package Operator: \"B\", OperatorVersion: \"any\", AppVersion \"any\", dependency of package A-0.0.1: package not found", }, { // A @@ -180,7 +204,18 @@ func TestResolve(t *testing.T) { createPackage("F"), }, want: []string{}, - wantErr: "cyclic package dependency found when adding package C-- -> A--", + wantErr: "cyclic package dependency found when adding package C-0.0.1 -> A-0.0.1", + }, + { + // A + // └── B + name: "versioned dependency", + pkgs: []packages.Package{ + createPackageWithVersions("A", "0.0.1", "1.2.3", createDependency("B", "0.0.2", "")), + createPackageWithVersions("B", "0.0.1", ""), + }, + want: []string{}, + wantErr: "failed to resolve package Operator: \"B\", OperatorVersion: \"0.0.2\", AppVersion \"any\", dependency of package A-1.2.3-0.0.1: package not found", }, } @@ -201,7 +236,7 @@ func TestResolve(t *testing.T) { assert.NotNil(t, funk.Find(got, func(dep Dependency) bool { return dep.Operator.Name == operatorName - }), tt.name) + }), fmt.Sprintf("failed to find wanted dependency %s", operatorName)) } }) } diff --git a/pkg/kudoctl/util/repo/resolver_repo.go b/pkg/kudoctl/util/repo/resolver_repo.go index 14e353175..6adf144ca 100644 --- a/pkg/kudoctl/util/repo/resolver_repo.go +++ b/pkg/kudoctl/util/repo/resolver_repo.go @@ -126,10 +126,10 @@ func (i IndexFile) FindFirstMatch(name string, appVersion string, operatorVersio if !ok || len(vs) == 0 { return nil, fmt.Errorf("no operator found for: %s", name) } - return FindFirstMatchForEntries(vs, name, appVersion, operatorVersion) + return findFirstMatchForEntries(vs, name, appVersion, operatorVersion) } -func FindFirstMatchForEntries(versions PackageVersions, name, appVersion, operatorVersion string) (*PackageVersion, error) { +func findFirstMatchForEntries(versions PackageVersions, name, appVersion, operatorVersion string) (*PackageVersion, error) { for _, ver := range versions { if (ver.AppVersion == appVersion || appVersion == "") && (ver.OperatorVersion == operatorVersion || operatorVersion == "") { diff --git a/pkg/util/kudo/versions.go b/pkg/util/kudo/versions.go new file mode 100644 index 000000000..9eb9009f2 --- /dev/null +++ b/pkg/util/kudo/versions.go @@ -0,0 +1,100 @@ +package kudo + +import ( + "sort" + + "github.com/Masterminds/semver/v3" + "github.com/thoas/go-funk" +) + +type SortableOperator interface { + OperatorName() string + OperatorVersion() string + AppVersion() string +} + +type SortableOperatorList []SortableOperator + +func (b SortableOperatorList) FilterByName(name string) SortableOperatorList { + // nolint:errcheck + return funk.Filter(b, func(o SortableOperator) bool { return o.OperatorName() == name }).([]SortableOperator) +} + +func (b SortableOperatorList) Sort() { + // We want to pick the newest (highest) versions first, that's why we reverse the order + sort.Sort(sort.Reverse(b)) +} + +func (b SortableOperatorList) FindFirstMatch(name, operatorVersion, appVersion string) SortableOperator { + for _, o := range b { + o := o + if name == o.OperatorName() && + (operatorVersion == "" || operatorVersion == o.OperatorVersion()) && + (appVersion == "" || appVersion == o.AppVersion()) { + return o + } + } + return nil +} + +// Len returns the number of entries +// This is needed to allow sorting. +func (b SortableOperatorList) Len() int { return len(b) } + +// Swap swaps the position of two items in the slice. +// This is needed to allow sorting. +func (b SortableOperatorList) Swap(i, j int) { b[i], b[j] = b[j], b[i] } + +// Less returns true if the version of entry a is less than the version of entry b. +// This is needed to allow sorting. +func (b SortableOperatorList) Less(x, y int) bool { + // First compare Operator name + if b[x].OperatorName() != b[y].OperatorName() { + // We compare in the other direction here - this way we get the operator names sorted alphabetically, + // and the version from high to low + return b[x].OperatorName() > b[y].OperatorName() + } + + avCompare := compareVersion(b[x].AppVersion(), b[y].AppVersion()) + if avCompare != 0 { + return avCompare < 0 + } + + ovCompare := compareVersion(b[x].OperatorVersion(), b[y].OperatorVersion()) + return ovCompare < 0 +} + +// Compares two versions - tries to use semantic versioning first, falls back to string compare. +// non-semantic versions are always ordered lower than semantic ones +// abc +// cde +// 1.0.0 +// 1.0.1 +// 2.0.0 +// 2.1.0 +// 10.0.0 +func compareVersion(x, y string) int { + if x == y { + return 0 + } + xVersion, _ := semver.NewVersion(x) + yVersion, _ := semver.NewVersion(y) + + if xVersion != nil && yVersion != nil { + return xVersion.Compare(yVersion) + } + + if xVersion == nil && yVersion == nil { + if x < y { + return -1 + } + return 1 + } + if xVersion == nil { + return -1 + } + if yVersion == nil { + return 1 + } + return 1 +} diff --git a/pkg/util/kudo/versions_test.go b/pkg/util/kudo/versions_test.go new file mode 100644 index 000000000..5d925e680 --- /dev/null +++ b/pkg/util/kudo/versions_test.go @@ -0,0 +1,88 @@ +package kudo + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +var _ SortableOperator = &sortableOp{} + +type sortableOp struct { + name string + ovVersion string + appVersion string +} + +func (s sortableOp) OperatorName() string { + return s.name +} + +func (s sortableOp) OperatorVersion() string { + return s.ovVersion +} + +func (s sortableOp) AppVersion() string { + return s.appVersion +} + +func TestVersions(t *testing.T) { + + l := SortableOperatorList{ + sortableOp{name: "abc", appVersion: "aaa", ovVersion: "0.0.1"}, + sortableOp{name: "abc", appVersion: "bbb", ovVersion: "0.1.0"}, + sortableOp{name: "abc", appVersion: "aaa", ovVersion: "0.0.2"}, + sortableOp{name: "abc", appVersion: "bbb", ovVersion: "0.0.1"}, + sortableOp{name: "abc", appVersion: "0.0.1", ovVersion: "1.0.0"}, + sortableOp{name: "abc", appVersion: "bbb", ovVersion: "1.1.0"}, + sortableOp{name: "abc", appVersion: "bbb", ovVersion: "10.1.0"}, + sortableOp{name: "abc", appVersion: "0.0.1", ovVersion: "10.1.0"}, + sortableOp{name: "abc", appVersion: "0.0.9", ovVersion: "1.0.1"}, + sortableOp{name: "abc", appVersion: "0.0.2", ovVersion: "1.0.0"}, + sortableOp{name: "abc", appVersion: "0.0.9", ovVersion: "1.0.0"}, + sortableOp{name: "abc", appVersion: "1.0.0", ovVersion: "1.0.0"}, + sortableOp{name: "abc", appVersion: "0.1.9", ovVersion: "1.0.1"}, + sortableOp{name: "abc", appVersion: "1.0.0", ovVersion: "1.0.2"}, + sortableOp{name: "abc", appVersion: "10.1.0", ovVersion: "0.1.0"}, + sortableOp{name: "abc", appVersion: "1.0.0", ovVersion: "0.0.1"}, + sortableOp{name: "abc", appVersion: "10.0.0", ovVersion: "0.1.1"}, + sortableOp{name: "abc", appVersion: "10.0.0", ovVersion: "0.1.0"}, + sortableOp{name: "cde", appVersion: "1.0.0", ovVersion: "1.0.0"}, + } + + sortedList := SortableOperatorList{ + sortableOp{name: "abc", appVersion: "10.1.0", ovVersion: "0.1.0"}, + sortableOp{name: "abc", appVersion: "10.0.0", ovVersion: "0.1.1"}, + sortableOp{name: "abc", appVersion: "10.0.0", ovVersion: "0.1.0"}, + sortableOp{name: "abc", appVersion: "1.0.0", ovVersion: "1.0.2"}, + sortableOp{name: "abc", appVersion: "1.0.0", ovVersion: "1.0.0"}, + sortableOp{name: "abc", appVersion: "1.0.0", ovVersion: "0.0.1"}, + sortableOp{name: "abc", appVersion: "0.1.9", ovVersion: "1.0.1"}, + sortableOp{name: "abc", appVersion: "0.0.9", ovVersion: "1.0.1"}, + sortableOp{name: "abc", appVersion: "0.0.9", ovVersion: "1.0.0"}, + sortableOp{name: "abc", appVersion: "0.0.2", ovVersion: "1.0.0"}, + sortableOp{name: "abc", appVersion: "0.0.1", ovVersion: "10.1.0"}, + sortableOp{name: "abc", appVersion: "0.0.1", ovVersion: "1.0.0"}, + sortableOp{name: "abc", appVersion: "bbb", ovVersion: "10.1.0"}, + sortableOp{name: "abc", appVersion: "bbb", ovVersion: "1.1.0"}, + sortableOp{name: "abc", appVersion: "bbb", ovVersion: "0.1.0"}, + sortableOp{name: "abc", appVersion: "bbb", ovVersion: "0.0.1"}, + sortableOp{name: "abc", appVersion: "aaa", ovVersion: "0.0.2"}, + sortableOp{name: "abc", appVersion: "aaa", ovVersion: "0.0.1"}, + sortableOp{name: "cde", appVersion: "1.0.0", ovVersion: "1.0.0"}, + } + + filteredList := SortableOperatorList{ + sortableOp{name: "cde", appVersion: "1.0.0", ovVersion: "1.0.0"}, + } + + l.Sort() + //for _, i := range l { + // fmt.Printf("sortableOp{name: %q, appVersion: %q, ovVersion: %q},\n", i.OperatorName(), i.AppVersion(), i.OperatorVersion()) + //} + + assert.Equal(t, l, sortedList) + + filtered := l.FilterByName("cde") + assert.Equal(t, filtered, filteredList) +} diff --git a/test/e2e/apply-delete-apply/00-assert.yaml b/test/e2e/apply-delete-apply/00-assert.yaml index 0352012d3..89db1e637 100644 --- a/test/e2e/apply-delete-apply/00-assert.yaml +++ b/test/e2e/apply-delete-apply/00-assert.yaml @@ -4,7 +4,7 @@ metadata: name: configmap-instance spec: operatorVersion: - name: configmap-operator-0.1.0 + name: configmap-operator-1.7.9-0.1.0 status: planStatus: deploy: diff --git a/test/e2e/plan-trigger/00-assert.yaml b/test/e2e/plan-trigger/00-assert.yaml index 005be823e..769c69b2c 100644 --- a/test/e2e/plan-trigger/00-assert.yaml +++ b/test/e2e/plan-trigger/00-assert.yaml @@ -5,7 +5,7 @@ metadata: kudo.dev/operator: feature-operator spec: operatorVersion: - name: feature-operator-0.1.0 + name: feature-operator-1.7.9-0.1.0 status: planStatus: deploy: diff --git a/test/e2e/plan-trigger/01-assert.yaml b/test/e2e/plan-trigger/01-assert.yaml index d2af35d80..fd871c6ee 100644 --- a/test/e2e/plan-trigger/01-assert.yaml +++ b/test/e2e/plan-trigger/01-assert.yaml @@ -5,7 +5,7 @@ metadata: kudo.dev/operator: feature-operator spec: operatorVersion: - name: feature-operator-0.1.0 + name: feature-operator-1.7.9-0.1.0 status: planStatus: deploy: diff --git a/test/e2e/terminal-failed-job/00-assert.yaml b/test/e2e/terminal-failed-job/00-assert.yaml index eb334bfae..5a6d0e99f 100644 --- a/test/e2e/terminal-failed-job/00-assert.yaml +++ b/test/e2e/terminal-failed-job/00-assert.yaml @@ -5,7 +5,7 @@ metadata: kudo.dev/operator: failjob-operator spec: operatorVersion: - name: failjob-operator-0.1.0 + name: failjob-operator-1.7.9-0.1.0 status: planStatus: deploy: diff --git a/test/e2e/terminal-failed-job/01-assert.yaml b/test/e2e/terminal-failed-job/01-assert.yaml index 3c476df4c..273184231 100644 --- a/test/e2e/terminal-failed-job/01-assert.yaml +++ b/test/e2e/terminal-failed-job/01-assert.yaml @@ -5,7 +5,7 @@ metadata: kudo.dev/operator: job-timeout-operator spec: operatorVersion: - name: job-timeout-operator-0.1.0 + name: job-timeout-operator-1.7.9-0.1.0 status: planStatus: deploy: diff --git a/test/e2e/toggle-task/00-assert.yaml b/test/e2e/toggle-task/00-assert.yaml index e67d70db4..345aacd13 100644 --- a/test/e2e/toggle-task/00-assert.yaml +++ b/test/e2e/toggle-task/00-assert.yaml @@ -5,7 +5,7 @@ metadata: kudo.dev/operator: feature-operator spec: operatorVersion: - name: feature-operator-0.1.0 + name: feature-operator-1.7.9-0.1.0 status: planStatus: deploy: diff --git a/test/e2e/toggle-task/01-assert.yaml b/test/e2e/toggle-task/01-assert.yaml index 005be823e..769c69b2c 100644 --- a/test/e2e/toggle-task/01-assert.yaml +++ b/test/e2e/toggle-task/01-assert.yaml @@ -5,7 +5,7 @@ metadata: kudo.dev/operator: feature-operator spec: operatorVersion: - name: feature-operator-0.1.0 + name: feature-operator-1.7.9-0.1.0 status: planStatus: deploy: diff --git a/test/integration/invalid-crd-install/00-assert.yaml b/test/integration/invalid-crd-install/00-assert.yaml index 0ce332bea..ed665d911 100644 --- a/test/integration/invalid-crd-install/00-assert.yaml +++ b/test/integration/invalid-crd-install/00-assert.yaml @@ -4,7 +4,7 @@ metadata: name: op-with-crd spec: operatorVersion: - name: op-with-crd-0.1.0 + name: op-with-crd-1.7.9-0.1.0 status: planStatus: deploy: diff --git a/test/upgrade/upgrade-to-current/01-assert.yaml b/test/upgrade/upgrade-to-current/01-assert.yaml index 8ea0687be..58be04baa 100644 --- a/test/upgrade/upgrade-to-current/01-assert.yaml +++ b/test/upgrade/upgrade-to-current/01-assert.yaml @@ -10,6 +10,16 @@ status: deploy: status: COMPLETE --- +apiVersion: kudo.dev/v1beta1 +kind: OperatorVersion +metadata: + name: simple-op-0.1.0 +spec: + appVersion: 1.2.3 + version: 0.1.0 + operator: + name: simple-op +--- apiVersion: apps/v1 kind: Deployment metadata: diff --git a/test/upgrade/upgrade-to-current/02-assert.yaml b/test/upgrade/upgrade-to-current/02-assert.yaml index 7c0ed7905..dbf8dbf4f 100644 --- a/test/upgrade/upgrade-to-current/02-assert.yaml +++ b/test/upgrade/upgrade-to-current/02-assert.yaml @@ -10,4 +10,25 @@ spec: template: spec: containers: - - image: kudobuilder/controller:test \ No newline at end of file + - image: kudobuilder/controller:test +--- +# Assert that the operator names are still the same as before +apiVersion: kudo.dev/v1beta1 +kind: OperatorVersion +metadata: + name: simple-op-0.1.0 +spec: + version: 0.1.0 + appVersion: 1.2.3 + operator: + kind: Operator + name: simple-op +--- +# Assert that the operator names are still the same as before +apiVersion: kudo.dev/v1beta1 +kind: Instance +metadata: + name: simple-op +spec: + operatorVersion: + name: simple-op-0.1.0 \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/03-assert.yaml b/test/upgrade/upgrade-to-current/03-assert.yaml index 8a4628714..553202fc3 100644 --- a/test/upgrade/upgrade-to-current/03-assert.yaml +++ b/test/upgrade/upgrade-to-current/03-assert.yaml @@ -1,10 +1,22 @@ +# Assert that the operator names are still the same as before +apiVersion: kudo.dev/v1beta1 +kind: OperatorVersion +metadata: + name: simple-op-1.2.3-0.2.0 +spec: + version: 0.2.0 + appVersion: 1.2.3 + operator: + kind: Operator + name: simple-op +--- apiVersion: kudo.dev/v1beta1 kind: Instance metadata: name: simple-op spec: operatorVersion: - name: simple-op-0.2.0 + name: simple-op-1.2.3-0.2.0 status: planStatus: deploy: diff --git a/test/upgrade/upgrade-to-current/simple-op-0.1.0/operator.yaml b/test/upgrade/upgrade-to-current/simple-op-0.1.0/operator.yaml index a051e02b6..0f80916b9 100644 --- a/test/upgrade/upgrade-to-current/simple-op-0.1.0/operator.yaml +++ b/test/upgrade/upgrade-to-current/simple-op-0.1.0/operator.yaml @@ -1,6 +1,7 @@ apiVersion: kudo.dev/v1beta1 name: "simple-op" operatorVersion: "0.1.0" +appVersion: "1.2.3" kubernetesVersion: 1.13.0 maintainers: - name: Your name diff --git a/test/upgrade/upgrade-to-current/simple-op-0.2.0/operator.yaml b/test/upgrade/upgrade-to-current/simple-op-0.2.0/operator.yaml index 0bbb85956..335970555 100644 --- a/test/upgrade/upgrade-to-current/simple-op-0.2.0/operator.yaml +++ b/test/upgrade/upgrade-to-current/simple-op-0.2.0/operator.yaml @@ -1,6 +1,7 @@ apiVersion: kudo.dev/v1beta1 name: "simple-op" operatorVersion: "0.2.0" +appVersion: "1.2.3" kubernetesVersion: 1.15.0 maintainers: - name: Your name