From f40fd3d48448dae66ef92f9363e3ca560a9550c6 Mon Sep 17 00:00:00 2001 From: Simon Bein Date: Tue, 16 May 2023 22:09:43 +0200 Subject: [PATCH] Add KRM func suppport for PackageVariants (#3925) * add deepcopy for kptfile funcs and selectors * add KRM func suppport for PackageVariants * add handling for removed mutators/validators * remove comment * allow for mutator/validator name to be empty * switch to getFileKubeObject utility func * edit validators/mutators in single loop * document functionality of ensureKRMFunctions * fix formatting after rebase * add deleting existin pv mutators/validators and pruning of pipeline field * Fix failing PVS unit test --------- Co-authored-by: John Belamaric --- docs/design-docs/08-package-variant.md | 2 +- pkg/api/kptfile/v1/types.go | 4 + pkg/api/kptfile/v1/zz_generated.deepcopy.go | 87 ++++ .../api/v1alpha1/packagevariant_types.go | 2 + .../packagevariant_controller.go | 129 +++++ .../packagevariant_controller_test.go | 443 ++++++++++++++++++ .../packagevariantset_controller_test.go | 2 +- 7 files changed, 667 insertions(+), 2 deletions(-) create mode 100644 pkg/api/kptfile/v1/zz_generated.deepcopy.go diff --git a/docs/design-docs/08-package-variant.md b/docs/design-docs/08-package-variant.md index 4027db2710..684b7a4dce 100644 --- a/docs/design-docs/08-package-variant.md +++ b/docs/design-docs/08-package-variant.md @@ -514,7 +514,7 @@ Then the resulting Kptfile will have these two entries prepended to its - image: gcr.io/kpt-fn/set-labels:v0.1 configMap: app: foo - name: PackageVariant.my-pv.1 + name: PackageVariant.my-pv..1 ``` During subsequent reconciliations, this allows the controller to identify the diff --git a/pkg/api/kptfile/v1/types.go b/pkg/api/kptfile/v1/types.go index 3c8c711650..3b60bd0b88 100644 --- a/pkg/api/kptfile/v1/types.go +++ b/pkg/api/kptfile/v1/types.go @@ -24,6 +24,8 @@ import ( "sigs.k8s.io/kustomize/kyaml/yaml" ) +//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0 object object:headerFile="../../../../porch/scripts/boilerplate.go.txt" + const ( KptFileName = "Kptfile" @@ -280,6 +282,7 @@ func (p *Pipeline) IsEmpty() bool { } // Function specifies a KRM function. +// +kubebuilder:object:generate=true type Function struct { // `Image` specifies the function container image. // It can either be fully qualified, e.g.: @@ -325,6 +328,7 @@ type Function struct { // Selector specifies the selection criteria // please update IsEmpty method if more properties are added +// +kubebuilder:object:generate=true type Selector struct { // APIVersion of the target resources APIVersion string `yaml:"apiVersion,omitempty" json:"apiVersion,omitempty"` diff --git a/pkg/api/kptfile/v1/zz_generated.deepcopy.go b/pkg/api/kptfile/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..3c8b0a8e44 --- /dev/null +++ b/pkg/api/kptfile/v1/zz_generated.deepcopy.go @@ -0,0 +1,87 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Copyright 2023 The kpt Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by controller-gen. DO NOT EDIT. + +package v1 + +import () + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Function) DeepCopyInto(out *Function) { + *out = *in + if in.ConfigMap != nil { + in, out := &in.ConfigMap, &out.ConfigMap + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Selectors != nil { + in, out := &in.Selectors, &out.Selectors + *out = make([]Selector, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Exclusions != nil { + in, out := &in.Exclusions, &out.Exclusions + *out = make([]Selector, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Function. +func (in *Function) DeepCopy() *Function { + if in == nil { + return nil + } + out := new(Function) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Selector) DeepCopyInto(out *Selector) { + *out = *in + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Selector. +func (in *Selector) DeepCopy() *Selector { + if in == nil { + return nil + } + out := new(Selector) + in.DeepCopyInto(out) + return out +} diff --git a/porch/controllers/packagevariants/api/v1alpha1/packagevariant_types.go b/porch/controllers/packagevariants/api/v1alpha1/packagevariant_types.go index a4e1f9754a..89d4027134 100644 --- a/porch/controllers/packagevariants/api/v1alpha1/packagevariant_types.go +++ b/porch/controllers/packagevariants/api/v1alpha1/packagevariant_types.go @@ -15,6 +15,7 @@ package v1alpha1 import ( + kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -64,6 +65,7 @@ type PackageVariantSpec struct { Annotations map[string]string `json:"annotations,omitempty"` PackageContext *PackageContext `json:"packageContext,omitempty"` + Pipeline *kptfilev1.Pipeline `json:"pipeline,omitempty"` Injectors []InjectionSelector `json:"injectors,omitempty"` } diff --git a/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller.go b/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller.go index 9946dbf4c0..841f5053e6 100644 --- a/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller.go +++ b/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller.go @@ -28,6 +28,7 @@ import ( api "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" + kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1" "golang.org/x/mod/semver" "k8s.io/apimachinery/pkg/api/meta" @@ -773,6 +774,10 @@ func (r *PackageVariantReconciler) calculateDraftResources(ctx context.Context, return nil, false, err } + if err := ensureKRMFunctions(pv, &prr); err != nil { + return nil, false, err + } + if err := ensureConfigInjection(ctx, r.Client, pv, &prr); err != nil { return nil, false, err } @@ -852,6 +857,130 @@ func getFileKubeObject(prr *porchapi.PackageRevisionResources, file, kind, name return ko, nil } +// ensureKRMFunctions adds mutators and validators specified in the PackageVariant to the kptfile inside the PackageRevisionResources. +// It generates a unique name that identifies the func (see func generatePVFuncname) and moves it to the top of the mutator sequence. +// It does not preserve yaml indent-style. +func ensureKRMFunctions(pv *api.PackageVariant, + prr *porchapi.PackageRevisionResources) error { + + // parse kptfile + kptfile, err := getFileKubeObject(prr, kptfilev1.KptFileName, "", "") + if err != nil { + return err + } + pipeline := kptfile.UpsertMap("pipeline") + + fieldlist := map[string][]kptfilev1.Function{ + "validators": nil, + "mutators": nil, + } + // retrieve fields if pipeline is not nil, to avoid nilpointer exception + if pv.Spec.Pipeline != nil { + fieldlist["validators"] = pv.Spec.Pipeline.Validators + fieldlist["mutators"] = pv.Spec.Pipeline.Mutators + } + + for fieldname, field := range fieldlist { + var newFieldVal = fn.SliceSubObjects{} + + existingFields, ok, err := pipeline.NestedSlice(fieldname) + if err != nil { + return err + } + if !ok || existingFields == nil { + existingFields = fn.SliceSubObjects{} + } + + for _, existingField := range existingFields { + ok, err := isPackageVariantFunc(existingField, pv.ObjectMeta.Name) + if err != nil { + return err + } + if !ok { + newFieldVal = append(newFieldVal, existingField) + } + } + + var newPVFieldVal = fn.SliceSubObjects{} + for i, newFields := range field { + newFieldVal := newFields.DeepCopy() + newFieldVal.Name = generatePVFuncName(newFields.Name, pv.ObjectMeta.Name, i) + f, err := fn.NewFromTypedObject(newFieldVal) + if err != nil { + return err + } + newPVFieldVal = append(newPVFieldVal, &f.SubObject) + } + + newFieldVal = append(newPVFieldVal, newFieldVal...) + + // if there are new mutators/validators, set them. Otherwise delete the field. This avoids ugly dangling `mutators: []` fields in the final kptfile + if len(newFieldVal) > 0 { + if err := pipeline.SetSlice(newFieldVal, fieldname); err != nil { + return err + } + } else { + if _, err := pipeline.RemoveNestedField(fieldname); err != nil { + return err + } + } + } + + // if there are no mutators and no validators, remove the dangling pipeline field + if pipeline.GetMap("mutators") == nil && pipeline.GetMap("validators") == nil { + if _, err := kptfile.RemoveNestedField("pipeline"); err != nil { + return err + } + } + + // update kptfile + prr.Spec.Resources[kptfilev1.KptFileName] = kptfile.String() + + return nil +} + +const PackageVariantFuncPrefix = "PackageVariant" + +// isPackageVariantFunc returns true if a function has been created via a PackageVariant. +// It uses the name of the func to determine its origin and compares it with the supplied pvName. +func isPackageVariantFunc(fn *fn.SubObject, pvName string) (bool, error) { + origname, ok, err := fn.NestedString("name") + if err != nil { + return false, fmt.Errorf("could not retrieve field name: %w", err) + } + if !ok { + return false, fmt.Errorf("could not find field name in supplied func") + } + + name := strings.Split(origname, ".") + + // if more or less than 3 dots have been used, return false + if len(name) != 4 { + return false, nil + } + + // if PackageVariantFuncPrefix has not been used, return false + if name[0] != PackageVariantFuncPrefix { + return false, nil + } + + // if pv-names don't match, return false + if name[1] != pvName { + return false, nil + } + + // if the last segment is not an integer, return false + if _, err := strconv.Atoi(name[3]); err != nil { + return false, nil + } + + return true, nil +} + +func generatePVFuncName(funcName, pvName string, pos int) string { + return fmt.Sprintf("%s.%s.%s.%d", PackageVariantFuncPrefix, pvName, funcName, pos) +} + func hashFromPackageRevisionResources(prr *porchapi.PackageRevisionResources) (string, error) { b, err := yaml.Marshal(prr.Spec.Resources) if err != nil { diff --git a/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller_test.go b/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller_test.go index b515890abb..c77ad340f3 100644 --- a/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller_test.go +++ b/porch/controllers/packagevariants/pkg/controllers/packagevariant/packagevariant_controller_test.go @@ -19,6 +19,7 @@ import ( "fmt" "testing" + "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" porchapi "github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1" api "github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/api/v1alpha1" "github.com/stretchr/testify/require" @@ -1134,3 +1135,445 @@ spec: }) } } + +func TestEnsureKRMFunctions(t *testing.T) { + pvBase := ` +apiVersion: config.porch.kpt.dev +kind: PackageVariant +metadata: + name: my-pv + uid: pv-uid +spec: + upstream: + repo: blueprints + package: foo + revision: v1 + downstream: + repo: deployments + package: bar + pipeline: +`[1:] + + prrBase := ` +apiVersion: porch.kpt.dev/v1alpha1 +kind: PackageRevisionResources +metadata: + name: prr + namespace: default +spec: + packageName: nephio-system + repository: nephio-packages + resources: + Kptfile: | + apiVersion: kpt.dev/v1 + kind: Kptfile + metadata: + name: prr + annotations: + config.kubernetes.io/local-config: "true" + info: + description: Example +`[1:] + + testCases := map[string]struct { + initialPipeline string + pvPipeline string + expectedErr string + expectedPrr string + }{ + "add one mutator with existing mutators": { + initialPipeline: ` + mutators: + - image: gcr.io/kpt-fn/set-labels:v0.1 + name: set-labels + configMap: + app: foo + - image: gcr.io/kpt-fn/set-annotations:v0.1 + name: set-annotations`[1:], + pvPipeline: ` + mutators: + - image: gcr.io/kpt-fn/set-namespace:v0.1 + name: set-namespace + configMap: + namespace: my-ns`[1:], + expectedErr: "", + expectedPrr: prrBase + ` + pipeline: + mutators: + - name: PackageVariant.my-pv.set-namespace.0 + image: gcr.io/kpt-fn/set-namespace:v0.1 + configMap: + namespace: my-ns + - image: gcr.io/kpt-fn/set-labels:v0.1 + name: set-labels + configMap: + app: foo + - image: gcr.io/kpt-fn/set-annotations:v0.1 + name: set-annotations +`[1:], + }, + "add two mutators with existing": { + initialPipeline: ` + mutators: + - image: gcr.io/kpt-fn/set-labels:v0.1 + name: set-labels + configMap: + app: foo + - image: gcr.io/kpt-fn/set-annotations:v0.1 + name: set-annotations`[1:], + pvPipeline: ` + mutators: + - image: gcr.io/kpt-fn/set-namespace:v0.1 + name: set-namespace + configMap: + namespace: my-ns + - image: gcr.io/kpt-fn/format:unstable + name: format`[1:], + expectedErr: "", + expectedPrr: prrBase + ` + pipeline: + mutators: + - name: PackageVariant.my-pv.set-namespace.0 + image: gcr.io/kpt-fn/set-namespace:v0.1 + configMap: + namespace: my-ns + - name: PackageVariant.my-pv.format.1 + image: gcr.io/kpt-fn/format:unstable + - image: gcr.io/kpt-fn/set-labels:v0.1 + name: set-labels + configMap: + app: foo + - image: gcr.io/kpt-fn/set-annotations:v0.1 + name: set-annotations +`[1:], + }, + "add one mutator with none existing": { + initialPipeline: "", + pvPipeline: ` + mutators: + - image: gcr.io/kpt-fn/set-namespace:v0.1 + name: set-namespace + configMap: + namespace: my-ns`[1:], + expectedErr: "", + expectedPrr: prrBase + ` + pipeline: + mutators: + - name: PackageVariant.my-pv.set-namespace.0 + image: gcr.io/kpt-fn/set-namespace:v0.1 + configMap: + namespace: my-ns +`[1:], + }, + "add none with existing mutators": { + initialPipeline: ` + mutators: + - image: gcr.io/kpt-fn/set-labels:v0.1 + name: set-labels + configMap: + app: foo + - image: gcr.io/kpt-fn/set-annotations:v0.1 + name: set-annotations`[1:], + pvPipeline: "", + expectedErr: "", + expectedPrr: prrBase + ` + pipeline: + mutators: + - image: gcr.io/kpt-fn/set-labels:v0.1 + name: set-labels + configMap: + app: foo + - image: gcr.io/kpt-fn/set-annotations:v0.1 + name: set-annotations +`[1:], + }, + "add one mutator with existing with comments": { + initialPipeline: ` + mutators: + - image: gcr.io/kpt-fn/set-labels:v0.1 + # this is a comment + name: set-labels + configMap: + app: foo + - image: gcr.io/kpt-fn/set-annotations:v0.1 + name: set-annotations`[1:], + pvPipeline: ` + mutators: + - image: gcr.io/kpt-fn/set-namespace:v0.1 + name: set-namespace + configMap: + namespace: my-ns`[1:], + expectedErr: "", + expectedPrr: prrBase + ` + pipeline: + mutators: + - name: PackageVariant.my-pv.set-namespace.0 + image: gcr.io/kpt-fn/set-namespace:v0.1 + configMap: + namespace: my-ns + - image: gcr.io/kpt-fn/set-labels:v0.1 + # this is a comment + name: set-labels + configMap: + app: foo + - image: gcr.io/kpt-fn/set-annotations:v0.1 + name: set-annotations +`[1:], + }, + "add one validator with existing validators": { + initialPipeline: ` + validators: + - image: gcr.io/kpt-fn/gatekeeper-validate:v0.1 + name: gatekeeper-validate`[1:], + pvPipeline: ` + validators: + - image: gcr.io/kpt-fn/validate-name:undefined + name: validate-name `[1:], + expectedErr: "", + expectedPrr: prrBase + ` + pipeline: + validators: + - name: PackageVariant.my-pv.validate-name.0 + image: gcr.io/kpt-fn/validate-name:undefined + - image: gcr.io/kpt-fn/gatekeeper-validate:v0.1 + name: gatekeeper-validate +`[1:], + }, + "add two validators with existing validators": { + initialPipeline: ` + validators: + - image: gcr.io/kpt-fn/gatekeeper-validate:v0.1 + name: gatekeeper-validate`[1:], + pvPipeline: ` + validators: + - image: gcr.io/kpt-fn/validate-name:undefined + name: validate-name `[1:], + expectedErr: "", + expectedPrr: prrBase + ` + pipeline: + validators: + - name: PackageVariant.my-pv.validate-name.0 + image: gcr.io/kpt-fn/validate-name:undefined + - image: gcr.io/kpt-fn/gatekeeper-validate:v0.1 + name: gatekeeper-validate +`[1:], + }, + "add none with existing validator": { + initialPipeline: ` + validators: + - image: gcr.io/kpt-fn/gatekeeper-validate:v0.1 + name: gatekeeper-validate`[1:], + pvPipeline: "", + expectedErr: "", + expectedPrr: prrBase + ` + pipeline: + validators: + - image: gcr.io/kpt-fn/gatekeeper-validate:v0.1 + name: gatekeeper-validate +`[1:], + }, + "add validator and mutator with existing": { + initialPipeline: ` + validators: + - image: gcr.io/val1 + name: val1 + - image: gcr.io/val2 + name: val2 + mutators: + - image: gcr.io/mut1 + name: mut1 + - image: gcr.io/mut2 + name: mut2`[1:], + pvPipeline: ` + validators: + - image: gcr.io/val3 + name: val3 + - image: gcr.io/val4 + name: val4 + mutators: + - image: gcr.io/mut3 + name: mut3 + - image: gcr.io/mut4 + name: mut4 +`[1:], + expectedErr: "", + expectedPrr: prrBase + ` + pipeline: + validators: + - name: PackageVariant.my-pv.val3.0 + image: gcr.io/val3 + - name: PackageVariant.my-pv.val4.1 + image: gcr.io/val4 + - image: gcr.io/val1 + name: val1 + - image: gcr.io/val2 + name: val2 + mutators: + - name: PackageVariant.my-pv.mut3.0 + image: gcr.io/mut3 + - name: PackageVariant.my-pv.mut4.1 + image: gcr.io/mut4 + - image: gcr.io/mut1 + name: mut1 + - image: gcr.io/mut2 + name: mut2 +`[1:], + }, + "remove pv mutator": { + initialPipeline: ` + mutators: + - image: gcr.io/mut:v1 + name: PackageVariant.my-pv.mut.0`[1:], + pvPipeline: "", + expectedErr: "", + expectedPrr: prrBase + "\n", + }, + "remove pv validator": { + initialPipeline: ` + validators: + - image: gcr.io/val:v1 + name: PackageVariant.my-pv.val.0`[1:], + pvPipeline: "", + expectedErr: "", + expectedPrr: prrBase + "\n", + }, + "remove pv validator, keep prr one": { + initialPipeline: ` + validators: + - image: gcr.io/val:v1 + name: PackageVariant.my-pv.val.0 + - image: gcr.io/val:v1 + name: non-pv-val`[1:], + pvPipeline: "", + expectedErr: "", + expectedPrr: prrBase + ` + pipeline: + validators: + - image: gcr.io/val:v1 + name: non-pv-val +`[1:], + }, + } + + for tn, tc := range testCases { + t.Run(tn, func(t *testing.T) { + locPrrBase := prrBase + if tc.initialPipeline != "" { + locPrrBase += " pipeline:\n" + } + var prr porchapi.PackageRevisionResources + require.NoError(t, yaml.Unmarshal([]byte(locPrrBase+tc.initialPipeline), &prr)) + var pv api.PackageVariant + require.NoError(t, yaml.Unmarshal([]byte(pvBase+tc.pvPipeline), &pv)) + + actualErr := ensureKRMFunctions(&pv, &prr) + if tc.expectedErr == "" { + require.NoError(t, actualErr) + } else { + require.EqualError(t, actualErr, tc.expectedErr) + } + var expectedPRR porchapi.PackageRevisionResources + require.NoError(t, yaml.Unmarshal([]byte(tc.expectedPrr), &expectedPRR)) + + require.Equal(t, expectedPRR, prr) + + // test idempotence + idemErr := ensureKRMFunctions(&pv, &prr) + if tc.expectedErr == "" { + require.NoError(t, idemErr) + } else { + require.EqualError(t, idemErr, tc.expectedErr) + } + require.Equal(t, expectedPRR, prr) // check that prr still matches expected + }) + } +} + +func TestGeneratePVFuncName(t *testing.T) { + tt := map[string]struct { + funcName string + pvName string + pos int + expectedName string + }{ + "regular func": { + funcName: "my-func", + pvName: "my-pv", + pos: 3, + expectedName: "PackageVariant.my-pv.my-func.3", + }, + "empty func name": { + funcName: "", + pvName: "my-pv", + pos: 0, + expectedName: "PackageVariant.my-pv..0", + }, + } + + for name, tc := range tt { + t.Run(name, func(t *testing.T) { + res := generatePVFuncName(tc.funcName, tc.pvName, tc.pos) + + require.Equal(t, tc.expectedName, res) + }) + } +} + +func TestIsPackageVariantFunc(t *testing.T) { + tt := map[string]struct { + funcyaml string + pvName string + expectedRes bool + }{ + "valid func name": { + funcyaml: "name: PackageVariant.my-pv.my-func.0", + pvName: "my-pv", + expectedRes: true, + }, + "field name is missing": { + funcyaml: "otherkey: PackageVariant.my-pv.my-func.0", + pvName: "my-pv", + expectedRes: false, + }, + "additional dots": { + funcyaml: "name: PackageVariant.too.many.dots.0", + pvName: "too", + expectedRes: false, + }, + "not enough dots": { + funcyaml: "name: PackageVariant.not-enough.dots", + pvName: "not-enough", + expectedRes: false, + }, + "no PackageVariantPrefix": { + funcyaml: "name: noprefix.my-pv.my-func.0", + pvName: "my-pv", + expectedRes: false, + }, + "pv-name mismatch": { + funcyaml: "name: PackageVariant.my-pv.my-func.0", + pvName: "actually-a-different-pv", + expectedRes: false, + }, + "empty func name": { + funcyaml: "name: PackageVariant.my-pv..0", + pvName: "my-pv", + expectedRes: true, + }, + "positional location is not an int": { + funcyaml: "name: PackageVariant.my-pv.my-func.str", + pvName: "my-pv", + expectedRes: false, + }, + } + + for name, tc := range tt { + t.Run(name, func(t *testing.T) { + o, err := fn.ParseKubeObject([]byte(tc.funcyaml)) + require.NoError(t, err) + res, _ := isPackageVariantFunc(&o.SubObject, tc.pvName) + + require.Equal(t, tc.expectedRes, res) + }) + } +} diff --git a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/packagevariantset_controller_test.go b/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/packagevariantset_controller_test.go index 7e65f641a2..6954f6fd07 100644 --- a/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/packagevariantset_controller_test.go +++ b/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset/packagevariantset_controller_test.go @@ -86,5 +86,5 @@ func TestEnsurePackageVariants(t *testing.T) { downstreams)) require.Equal(t, 2, len(fc.objects)) require.Equal(t, "my-pv-1", fc.objects[0].GetName()) - require.Equal(t, "my-pvs-3048996f91b83df6bb62e497c3839acc367a2e79", fc.objects[1].GetName()) + require.Equal(t, "my-pvs-9c07e0818b755a2067903d10aecf91e19dcb9a82", fc.objects[1].GetName()) }