From c2868c7e62ee260b57b7f4134a363a7e3146750d Mon Sep 17 00:00:00 2001 From: Jim Crossley Date: Wed, 11 Mar 2020 09:18:32 -0400 Subject: [PATCH 1/2] Bump to manifestival 0.4.0 Fixes a pretty gnarly bug where transformers using Scheme.Convert don't work. --- Gopkg.lock | 6 +- Gopkg.toml | 2 +- .../knativeserving_controller.go | 2 +- test/resources/verify.go | 7 +- .../manifestival/manifestival/client.go | 8 +- .../manifestival/manifestival/dry.go | 91 +++++++++++++ .../manifestival/manifestival/filter.go | 66 ++++++--- .../manifestival/manifestival/manifestival.go | 105 +++++++++------ .../manifestival/manifestival/patch/patch.go | 125 ++++++------------ .../manifestival/manifestival/transform.go | 5 +- 10 files changed, 260 insertions(+), 157 deletions(-) create mode 100644 vendor/github.com/manifestival/manifestival/dry.go diff --git a/Gopkg.lock b/Gopkg.lock index 9b2d725f..a9224673 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -390,7 +390,7 @@ version = "v0.2.0" [[projects]] - digest = "1:a0cb66a2605af422373e94b7ce8f9904cf22616e16b74e8601cc529808ffc5a1" + digest = "1:f0a1e0d10140e36b250ba2c897d0729512ddb2407117c322569728092a67115f" name = "github.com/manifestival/manifestival" packages = [ ".", @@ -398,8 +398,8 @@ "sources", ] pruneopts = "NUT" - revision = "062c519a505b425bf0990e7f78e06568b2756b89" - version = "v0.2.0" + revision = "e9d39ec5979318ff82b1047fedafee339575c1b2" + version = "v0.4.0" [[projects]] digest = "1:5985ef4caf91ece5d54817c11ea25f182697534f8ae6521eadcd628c142ac4b6" diff --git a/Gopkg.toml b/Gopkg.toml index f0ead62b..27c0a9ed 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -50,7 +50,7 @@ required = [ [[constraint]] name = "github.com/manifestival/manifestival" - version = "0.2.0" + version = "0.4.0" [[override]] name = "knative.dev/pkg" diff --git a/pkg/reconciler/knativeserving/knativeserving_controller.go b/pkg/reconciler/knativeserving/knativeserving_controller.go index 09eb4517..9ee53438 100644 --- a/pkg/reconciler/knativeserving/knativeserving_controller.go +++ b/pkg/reconciler/knativeserving/knativeserving_controller.go @@ -247,7 +247,7 @@ func (r *Reconciler) delete(instance *servingv1alpha1.KnativeServing) error { return nil } if len(r.servings) == 0 { - if err := r.config.Filter(mf.NotCRDs).Delete(); err != nil { + if err := r.config.Filter(mf.NoCRDs).Delete(); err != nil { return err } } diff --git a/test/resources/verify.go b/test/resources/verify.go index eb0afc49..08895e63 100644 --- a/test/resources/verify.go +++ b/test/resources/verify.go @@ -210,17 +210,14 @@ func KSOperatorCRDelete(t *testing.T, clients *test.Clients, names test.Resource t.Fatal(err) } - // TODO: pred := mf.Any(mf.CRDs, mf.ByKind("Namespace")) - // Loop through both pred and mf.None(pred) - // verify all but the CRD's and the Namespace are gone - for _, u := range m.Filter(mf.NotCRDs, mf.Complement(mf.ByKind("Namespace"))).Resources() { + for _, u := range m.Filter(mf.NoCRDs, mf.None(mf.ByKind("Namespace"))).Resources() { if _, err := m.Client.Get(&u); !apierrs.IsNotFound(err) { t.Fatalf("The %s %s failed to be deleted: %v", u.GetKind(), u.GetName(), err) } } // verify all the CRD's remain - for _, u := range m.Filter(mf.JustCRDs).Resources() { + for _, u := range m.Filter(mf.CRDs).Resources() { if _, err := m.Client.Get(&u); apierrs.IsNotFound(err) { t.Fatalf("The %s CRD was deleted", u.GetName()) } diff --git a/vendor/github.com/manifestival/manifestival/client.go b/vendor/github.com/manifestival/manifestival/client.go index 8535e1ad..f030c9df 100644 --- a/vendor/github.com/manifestival/manifestival/client.go +++ b/vendor/github.com/manifestival/manifestival/client.go @@ -45,25 +45,31 @@ type DeleteOption interface { type ApplyOptions struct { ForCreate *metav1.CreateOptions ForUpdate *metav1.UpdateOptions + Replace bool } type DeleteOptions struct { ForDelete *metav1.DeleteOptions - IgnoreNotFound bool // default to true in OptionsForDelete() + IgnoreNotFound bool // default to true in DeleteWith() } var DryRunAll = dryRunAll{} +var ForceReplace = Replace(true) type FieldManager string type GracePeriodSeconds int64 type Preconditions metav1.Preconditions type PropagationPolicy metav1.DeletionPropagation type IgnoreNotFound bool +type Replace bool type dryRunAll struct{} // for both apply and delete func (dryRunAll) ApplyWith(opts *ApplyOptions) { opts.ForCreate.DryRun = []string{metav1.DryRunAll} opts.ForUpdate.DryRun = []string{metav1.DryRunAll} } +func (i Replace) ApplyWith(opts *ApplyOptions) { + opts.Replace = bool(i) +} func (f FieldManager) ApplyWith(opts *ApplyOptions) { // TODO: The FM was introduced in k8s 1.14, but not ready to // abandon pre-1.14 users yet. Uncomment when ready. diff --git a/vendor/github.com/manifestival/manifestival/dry.go b/vendor/github.com/manifestival/manifestival/dry.go new file mode 100644 index 00000000..05ceac35 --- /dev/null +++ b/vendor/github.com/manifestival/manifestival/dry.go @@ -0,0 +1,91 @@ +package manifestival + +import ( + "encoding/json" + + jsonpatch "github.com/evanphx/json-patch" + "github.com/manifestival/manifestival/patch" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/strategicpatch" + "k8s.io/client-go/kubernetes/scheme" +) + +type MergePatch map[string]interface{} + +// DryRun returns a list of merge patches, either strategic or +// RFC-7386 for unregistered types, that show the effects of applying +// the manifest. +func (m Manifest) DryRun() ([]MergePatch, error) { + diffs, err := m.diff() + if err != nil { + return nil, err + } + result := make([]MergePatch, len(diffs)) + for i, bytes := range diffs { + if err := json.Unmarshal(bytes, &result[i]); err != nil { + return nil, err + } + } + return result, nil +} + +// diff loads the resources in the manifest and computes their difference +func (m Manifest) diff() ([][]byte, error) { + result := make([][]byte, 0, len(m.resources)) + for _, spec := range m.resources { + original, err := m.Client.Get(&spec) + if err != nil { + if errors.IsNotFound(err) { + // this resource will be created when applied + jmp, _ := spec.MarshalJSON() + result = append(result, jmp) + continue + } + return nil, err + } + diff, err := patch.New(original, &spec) + if err != nil { + return nil, err + } + if diff == nil { + // ignore things that won't change + continue + } + modified := original.DeepCopy() + if err := diff.Merge(modified); err != nil { + return nil, err + } + // Remove these fields so they'll be included in the patch + original.SetAPIVersion("") + original.SetKind("") + original.SetName("") + jmp, err := mergePatch(original, modified) + if err != nil { + return nil, err + } + result = append(result, jmp) + } + return result, nil +} + +// mergePatch returns a 2-way merge patch +func mergePatch(orig, mod *unstructured.Unstructured) (_ []byte, err error) { + var original, modified []byte + if original, err = orig.MarshalJSON(); err != nil { + return + } + if modified, err = mod.MarshalJSON(); err != nil { + return + } + obj, err := scheme.Scheme.New(mod.GroupVersionKind()) + switch { + case runtime.IsNotRegisteredError(err): + return jsonpatch.CreateMergePatch(original, modified) + case err != nil: + return nil, err + default: + return strategicpatch.CreateTwoWayMergePatch(original, modified, obj) + } +} diff --git a/vendor/github.com/manifestival/manifestival/filter.go b/vendor/github.com/manifestival/manifestival/filter.go index 5c39711a..eca61224 100644 --- a/vendor/github.com/manifestival/manifestival/filter.go +++ b/vendor/github.com/manifestival/manifestival/filter.go @@ -12,28 +12,53 @@ type Predicate func(u *unstructured.Unstructured) bool // *all* Predicates return true. Any changes callers make to the // resources passed to their Predicate[s] will only be reflected in // the returned Manifest. -func (m Manifest) Filter(fns ...Predicate) Manifest { +func (m Manifest) Filter(preds ...Predicate) Manifest { result := m result.resources = []unstructured.Unstructured{} -NEXT_RESOURCE: + pred := All(preds...) for _, spec := range m.Resources() { - for _, pred := range fns { - if pred != nil { - if !pred(&spec) { - continue NEXT_RESOURCE - } - } + if !pred(&spec) { + continue } result.resources = append(result.resources, spec) } return result } -// JustCRDs returns only CustomResourceDefinitions -var JustCRDs = ByKind("CustomResourceDefinition") +func All(preds ...Predicate) Predicate { + return func(u *unstructured.Unstructured) bool { + for _, p := range preds { + if !p(u) { + return false + } + } + return true + } +} -// NotCRDs returns no CustomResourceDefinitions -var NotCRDs = Complement(JustCRDs) +func Any(preds ...Predicate) Predicate { + return func(u *unstructured.Unstructured) bool { + for _, p := range preds { + if p(u) { + return true + } + } + return false + } +} + +// None returns a Predicate's complement +func None(p Predicate) Predicate { + return func(u *unstructured.Unstructured) bool { + return !p(u) + } +} + +// CRDs returns only CustomResourceDefinitions +var CRDs = ByKind("CustomResourceDefinition") + +// NoCRDs returns no CustomResourceDefinitions +var NoCRDs = None(CRDs) // ByName returns resources with a specifc name func ByName(name string) Predicate { @@ -61,16 +86,21 @@ func ByLabel(label, value string) Predicate { } } -// ByGVK returns resources of a particular GroupVersionKind -func ByGVK(gvk schema.GroupVersionKind) Predicate { +// ByLabels returns true when the resource contains any of the labels. +func ByLabels(labels map[string]string) Predicate { return func(u *unstructured.Unstructured) bool { - return u.GroupVersionKind() == gvk + for key, value := range labels { + if v := u.GetLabels()[key]; v == value { + return true + } + } + return false } } -// Complement returns what another Predicate wouldn't -func Complement(p Predicate) Predicate { +// ByGVK returns resources of a particular GroupVersionKind +func ByGVK(gvk schema.GroupVersionKind) Predicate { return func(u *unstructured.Unstructured) bool { - return !p(u) + return u.GroupVersionKind() == gvk } } diff --git a/vendor/github.com/manifestival/manifestival/manifestival.go b/vendor/github.com/manifestival/manifestival/manifestival.go index eb51f3a2..3a37ec27 100644 --- a/vendor/github.com/manifestival/manifestival/manifestival.go +++ b/vendor/github.com/manifestival/manifestival/manifestival.go @@ -11,9 +11,8 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) -// Manifestival allows group application of a set of Kubernetes resources -// (typically, a set of YAML files, aka a manifest) against a Kubernetes -// apiserver. +// Manifestival defines the operations allowed on a set of Kubernetes +// resources (typically, a set of YAML files, aka a manifest) type Manifestival interface { // Either updates or creates all resources in the manifest Apply(opts ...ApplyOption) error @@ -23,10 +22,12 @@ type Manifestival interface { Transform(fns ...Transformer) (Manifest, error) // Filters resources in a Manifest; Predicates are AND'd Filter(fns ...Predicate) Manifest + // Show how applying the manifest would change the cluster + DryRun() ([]MergePatch, error) } // Manifest tracks a set of concrete resources which should be managed as a -// group using a Kubernetes client provided by `NewManifest`. +// group using a Kubernetes client type Manifest struct { resources []unstructured.Unstructured Client Client @@ -36,13 +37,12 @@ type Manifest struct { var _ Manifestival = &Manifest{} // NewManifest creates a Manifest from a comma-separated set of yaml -// files, directories, or URLs. The Manifest's client and logger may -// be optionally provided. +// files, directories, or URLs func NewManifest(pathname string, opts ...Option) (Manifest, error) { return ManifestFrom(Path(pathname), opts...) } -// ManifestFrom creates a Manifest from any Source +// ManifestFrom creates a Manifest from any Source implementation func ManifestFrom(src Source, opts ...Option) (m Manifest, err error) { m = Manifest{log: testing.NullLogger{}} for _, opt := range opts { @@ -53,7 +53,7 @@ func ManifestFrom(src Source, opts ...Option) (m Manifest, err error) { return } -// Resources returns a deep copy of the manifest resources +// Resources returns a deep copy of the Manifest resources func (m Manifest) Resources() []unstructured.Unstructured { result := make([]unstructured.Unstructured, len(m.resources)) for i, v := range m.resources { @@ -72,8 +72,25 @@ func (m Manifest) Apply(opts ...ApplyOption) error { return nil } -// apply updates or creates a particular resource, which does not need to be -// part of `Resources`, and will not be tracked. +// Delete removes all resources in the Manifest +func (m Manifest) Delete(opts ...DeleteOption) error { + a := make([]unstructured.Unstructured, len(m.resources)) + copy(a, m.resources) // shallow copy is fine + // we want to delete in reverse order + for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 { + a[left], a[right] = a[right], a[left] + } + for _, spec := range a { + if okToDelete(&spec) { + if err := m.delete(&spec, opts...); err != nil { + return err + } + } + } + return nil +} + +// apply updates or creates a particular resource func (m Manifest) apply(spec *unstructured.Unstructured, opts ...ApplyOption) error { current, err := m.get(spec) if err != nil { @@ -81,50 +98,37 @@ func (m Manifest) apply(spec *unstructured.Unstructured, opts ...ApplyOption) er } if current == nil { m.logResource("Creating", spec) - annotate(spec, v1.LastAppliedConfigAnnotation, patch.MakeLastAppliedConfig(spec)) - annotate(spec, "manifestival", resourceCreated) - if err = m.Client.Create(spec.DeepCopy(), opts...); err != nil { - return err - } + current = spec.DeepCopy() + annotate(current, v1.LastAppliedConfigAnnotation, lastApplied(current)) + annotate(current, "manifestival", resourceCreated) + return m.Client.Create(current, opts...) } else { - patch, err := patch.NewPatch(spec, current) + if ApplyWith(opts).Replace { + return m.update(spec.DeepCopy(), lastApplied(spec), opts...) + } + diff, err := patch.New(current, spec) if err != nil { return err } - if patch.IsRequired() { - m.log.Info("Merging", "diff", patch) - if err := patch.Merge(current); err != nil { - return err - } - m.logResource("Updating", current) - if err = m.Client.Update(current, opts...); err != nil { + if diff != nil { + m.log.Info("Merging", "diff", diff) + if err := diff.Merge(current); err != nil { return err } + return m.update(current, lastApplied(spec), opts...) } } return nil } -// Delete removes all tracked `Resources` in the Manifest. -func (m Manifest) Delete(opts ...DeleteOption) error { - a := make([]unstructured.Unstructured, len(m.resources)) - copy(a, m.resources) // shallow copy is fine - // we want to delete in reverse order - for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 { - a[left], a[right] = a[right], a[left] - } - for _, spec := range a { - if okToDelete(&spec) { - if err := m.delete(&spec, opts...); err != nil { - m.log.Error(err, "Delete failed") - } - } - } - return nil +// update a single resource +func (m Manifest) update(obj *unstructured.Unstructured, config string, opts ...ApplyOption) error { + m.logResource("Updating", obj) + annotate(obj, v1.LastAppliedConfigAnnotation, config) + return m.Client.Update(obj, opts...) } -// delete removes the specified objects, which do not need to be registered as -// `Resources` in the Manifest. +// delete removes the specified object func (m Manifest) delete(spec *unstructured.Unstructured, opts ...DeleteOption) error { current, err := m.get(spec) if current == nil && err == nil { @@ -134,8 +138,8 @@ func (m Manifest) delete(spec *unstructured.Unstructured, opts ...DeleteOption) return m.Client.Delete(spec, opts...) } -// get collects a full resource body (or `nil`) from a partial resource -// supplied in `spec`. +// get collects a full resource body (or `nil`) from a partial +// resource supplied in `spec` func (m Manifest) get(spec *unstructured.Unstructured) (*unstructured.Unstructured, error) { result, err := m.Client.Get(spec) if err != nil { @@ -147,11 +151,13 @@ func (m Manifest) get(spec *unstructured.Unstructured) (*unstructured.Unstructur return result, err } +// logResource logs a consistent formatted message func (m Manifest) logResource(msg string, spec *unstructured.Unstructured) { name := fmt.Sprintf("%s/%s", spec.GetNamespace(), spec.GetName()) m.log.Info(msg, "name", name, "type", spec.GroupVersionKind()) } +// annotate sets an annotation in the resource func annotate(spec *unstructured.Unstructured, key string, value string) { annotations := spec.GetAnnotations() if annotations == nil { @@ -161,6 +167,19 @@ func annotate(spec *unstructured.Unstructured, key string, value string) { spec.SetAnnotations(annotations) } +// lastApplied returns a JSON string denoting the resource's state +func lastApplied(obj *unstructured.Unstructured) string { + ann := obj.GetAnnotations() + if len(ann) > 0 { + delete(ann, v1.LastAppliedConfigAnnotation) + obj.SetAnnotations(ann) + } + bytes, _ := obj.MarshalJSON() + return string(bytes) +} + +// okToDelete checks for an annotation indicating that the resources +// was originally created by this library func okToDelete(spec *unstructured.Unstructured) bool { switch spec.GetKind() { case "Namespace": diff --git a/vendor/github.com/manifestival/manifestival/patch/patch.go b/vendor/github.com/manifestival/manifestival/patch/patch.go index 93fa900c..05fe9c3b 100644 --- a/vendor/github.com/manifestival/manifestival/patch/patch.go +++ b/vendor/github.com/manifestival/manifestival/patch/patch.go @@ -12,120 +12,79 @@ import ( "k8s.io/client-go/kubernetes/scheme" ) -type Patch interface { - IsRequired() bool - Merge(*unstructured.Unstructured) error -} - -type jsonPatch struct { +type Patch struct { patch []byte - config string -} - -type strategicPatch struct { - jsonPatch schema strategicpatch.LookupPatchMeta } -func NewPatch(src, tgt *unstructured.Unstructured) (Patch, error) { +// Attempts to create a 3-way strategic JSON merge patch. Falls back +// to RFC-7386 if object's type isn't registered +func New(curr, mod *unstructured.Unstructured) (_ *Patch, err error) { var original, modified, current []byte - var err error - original = getLastAppliedConfig(tgt) - config := MakeLastAppliedConfig(src) - if modified, err = src.MarshalJSON(); err != nil { - return nil, err + original = getLastAppliedConfig(curr) + if modified, err = mod.MarshalJSON(); err != nil { + return } - if current, err = tgt.MarshalJSON(); err != nil { - return nil, err + if current, err = curr.MarshalJSON(); err != nil { + return } - obj, err := scheme.Scheme.New(src.GroupVersionKind()) + obj, err := scheme.Scheme.New(mod.GroupVersionKind()) switch { - case src.GetKind() == "ConfigMap": - fallthrough // force "overwrite" merge case runtime.IsNotRegisteredError(err): - return createJsonPatch(original, modified, current, config) + return createJsonMergePatch(original, modified, current) case err != nil: - return nil, err + return default: - return createStrategicPatch(original, modified, current, obj, config) + return createStrategicMergePatch(original, modified, current, obj) } } -func createJsonPatch(original, modified, current []byte, config string) (*jsonPatch, error) { - patch, err := jsonmergepatch.CreateThreeWayJSONMergePatch(original, modified, current) - return &jsonPatch{patch, config}, err -} - -func createStrategicPatch(original, modified, current []byte, obj runtime.Object, config string) (*strategicPatch, error) { - schema, err := strategicpatch.NewPatchMetaFromStruct(obj) +// Apply the patch to the resource +func (p *Patch) Merge(obj *unstructured.Unstructured) (err error) { + var current, result []byte + if current, err = obj.MarshalJSON(); err != nil { + return + } + if p.schema == nil { + result, err = jsonpatch.MergePatch(current, p.patch) + } else { + result, err = strategicpatch.StrategicMergePatchUsingLookupPatchMeta(current, p.patch, p.schema) + } if err != nil { - return nil, err + return } - patch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, schema, true) - return &strategicPatch{jsonPatch{patch, config}, schema}, err + return obj.UnmarshalJSON(result) } -func (p *jsonPatch) String() string { +func (p *Patch) String() string { return string(p.patch) } -func (p *jsonPatch) IsRequired() bool { - return !bytes.Equal(p.patch, []byte("{}")) +func createJsonMergePatch(original, modified, current []byte) (*Patch, error) { + patch, err := jsonmergepatch.CreateThreeWayJSONMergePatch(original, modified, current) + return create(patch, nil), err } -func (p *jsonPatch) Merge(spec *unstructured.Unstructured) (err error) { - var current, result []byte - if current, err = spec.MarshalJSON(); err != nil { - return - } - if result, err = jsonpatch.MergePatch(current, p.patch); err != nil { - return - } - err = spec.UnmarshalJSON(result) - if err == nil { - setLastAppliedConfig(spec, p.config) +func createStrategicMergePatch(original, modified, current []byte, obj runtime.Object) (*Patch, error) { + schema, err := strategicpatch.NewPatchMetaFromStruct(obj) + if err != nil { + return nil, err } - return + patch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, schema, true) + return create(patch, schema), err } -func (p *strategicPatch) Merge(spec *unstructured.Unstructured) (err error) { - var current, result []byte - if current, err = spec.MarshalJSON(); err != nil { - return - } - if result, err = strategicpatch.StrategicMergePatchUsingLookupPatchMeta(current, p.jsonPatch.patch, p.schema); err != nil { - return - } - err = spec.UnmarshalJSON(result) - if err == nil { - setLastAppliedConfig(spec, p.config) +func create(patch []byte, schema strategicpatch.LookupPatchMeta) *Patch { + if bytes.Equal(patch, []byte("{}")) { + return nil } - return + return &Patch{patch, schema} } -func getLastAppliedConfig(spec *unstructured.Unstructured) []byte { - annotations := spec.GetAnnotations() +func getLastAppliedConfig(obj *unstructured.Unstructured) []byte { + annotations := obj.GetAnnotations() if annotations == nil { return nil } return []byte(annotations[v1.LastAppliedConfigAnnotation]) } - -func setLastAppliedConfig(spec *unstructured.Unstructured, config string) { - annotations := spec.GetAnnotations() - if annotations == nil { - annotations = map[string]string{} - } - annotations[v1.LastAppliedConfigAnnotation] = config - spec.SetAnnotations(annotations) -} - -func MakeLastAppliedConfig(spec *unstructured.Unstructured) string { - ann := spec.GetAnnotations() - if len(ann) > 0 { - delete(ann, v1.LastAppliedConfigAnnotation) - spec.SetAnnotations(ann) - } - bytes, _ := spec.MarshalJSON() - return string(bytes) -} diff --git a/vendor/github.com/manifestival/manifestival/transform.go b/vendor/github.com/manifestival/manifestival/transform.go index 844c204d..d37e03bc 100644 --- a/vendor/github.com/manifestival/manifestival/transform.go +++ b/vendor/github.com/manifestival/manifestival/transform.go @@ -24,10 +24,11 @@ type Owner interface { func (m Manifest) Transform(fns ...Transformer) (Manifest, error) { result := m result.resources = m.Resources() // deep copies - for _, spec := range result.resources { + for i := range result.resources { + spec := &result.resources[i] for _, transform := range fns { if transform != nil { - err := transform(&spec) + err := transform(spec) if err != nil { return Manifest{}, err } From ed56e5574b1cf7e8a89a0765354013ffc849cc88 Mon Sep 17 00:00:00 2001 From: Jim Crossley Date: Wed, 11 Mar 2020 10:39:41 -0400 Subject: [PATCH 2/2] Hack around webhook secret race condition We delete the deployments first, hopefully preventing the webhook controller from recreating the secret after it's deleted. --- pkg/reconciler/knativeserving/knativeserving_controller.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/reconciler/knativeserving/knativeserving_controller.go b/pkg/reconciler/knativeserving/knativeserving_controller.go index 9ee53438..969fd2b5 100644 --- a/pkg/reconciler/knativeserving/knativeserving_controller.go +++ b/pkg/reconciler/knativeserving/knativeserving_controller.go @@ -247,6 +247,9 @@ func (r *Reconciler) delete(instance *servingv1alpha1.KnativeServing) error { return nil } if len(r.servings) == 0 { + if err := r.config.Filter(mf.ByKind("Deployment")).Delete(); err != nil { + return err + } if err := r.config.Filter(mf.NoCRDs).Delete(); err != nil { return err }