diff --git a/pkg/kapp/cmd/app/deploy.go b/pkg/kapp/cmd/app/deploy.go index 53376e855..1822915fb 100644 --- a/pkg/kapp/cmd/app/deploy.go +++ b/pkg/kapp/cmd/app/deploy.go @@ -411,13 +411,15 @@ func (o *DeployOptions) calculateAndPresentChanges(existingResources, changeFactory := ctldiff.NewChangeFactory(conf.RebaseMods(), conf.DiffAgainstLastAppliedFieldExclusionMods()) changeSetFactory := ctldiff.NewChangeSetFactory(o.DiffFlags.ChangeSetOpts, changeFactory) - err := ctldiff.NewRenewableResources(existingResources, newResources).Prepare() + diffRs := ctldiff.NewDiffResources(existingResources, newResources, conf.TemplateRules()) + + err := ctldiff.NewRenewableResources(diffRs).Prepare() if err != nil { return clusterChangeSet, nil, false, "", err } changes, err := ctldiff.NewChangeSetWithVersionedRs( - existingResources, newResources, conf.TemplateRules(), + diffRs, o.DiffFlags.ChangeSetOpts, changeFactory).Calculate() if err != nil { return clusterChangeSet, nil, false, "", err diff --git a/pkg/kapp/config/default_test.go b/pkg/kapp/config/default_test.go index 976aad555..9468ef5a8 100644 --- a/pkg/kapp/config/default_test.go +++ b/pkg/kapp/config/default_test.go @@ -293,7 +293,7 @@ spec: } // Calculate changes with default template rules - changes, err := ctldiff.NewChangeSetWithVersionedRs([]ctlres.Resource{}, newResources, defaultConfig.TemplateRules(), ctldiff.ChangeSetOpts{}, changeFactory).Calculate() + changes, err := ctldiff.NewChangeSetWithVersionedRs(ctldiff.NewDiffResources([]ctlres.Resource{}, newResources, defaultConfig.TemplateRules()), ctldiff.ChangeSetOpts{}, changeFactory).Calculate() require.NoError(t, err) // Compare against expected diff diff --git a/pkg/kapp/diff/change_set_with_versioned_rs.go b/pkg/kapp/diff/change_set_with_versioned_rs.go index c6587d0ba..d91ba6028 100644 --- a/pkg/kapp/diff/change_set_with_versioned_rs.go +++ b/pkg/kapp/diff/change_set_with_versioned_rs.go @@ -5,10 +5,8 @@ package diff import ( "fmt" - "sort" "strconv" - ctlconf "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/config" ctlres "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/resources" ) @@ -19,23 +17,21 @@ const ( ) type ChangeSetWithVersionedRs struct { - existingRs, newRs []ctlres.Resource - rules []ctlconf.TemplateRule - opts ChangeSetOpts - changeFactory ChangeFactory + diffRs DiffResources + opts ChangeSetOpts + changeFactory ChangeFactory } -func NewChangeSetWithVersionedRs(existingRs, newRs []ctlres.Resource, - rules []ctlconf.TemplateRule, opts ChangeSetOpts, changeFactory ChangeFactory) *ChangeSetWithVersionedRs { +func NewChangeSetWithVersionedRs(diffRs DiffResources, opts ChangeSetOpts, changeFactory ChangeFactory) *ChangeSetWithVersionedRs { - return &ChangeSetWithVersionedRs{existingRs, newRs, rules, opts, changeFactory} + return &ChangeSetWithVersionedRs{diffRs, opts, changeFactory} } func (d ChangeSetWithVersionedRs) Calculate() ([]Change, error) { - existingRs := existingVersionedResources(d.existingRs) - existingRsGrouped := newGroupedVersionedResources(existingRs.Versioned) + existingRs := d.diffRs.ExistingResources + existingRsGrouped := d.diffRs.ExistingResourcesGrouped - newRs := newVersionedResources(d.newRs) + newRs := d.diffRs.NewResources allChanges := []Change{} d.assignNewNames(newRs, existingRsGrouped) @@ -133,7 +129,7 @@ func (d ChangeSetWithVersionedRs) addAndKeepChanges( } // Update both versioned and non-versioned - verRes := VersionedResource{usedRes, d.rules} + verRes := VersionedResource{usedRes, d.diffRs.rules} err := verRes.UpdateAffected(newRs.NonVersioned) if err != nil { @@ -232,83 +228,3 @@ func (d ChangeSetWithVersionedRs) newChange(existingRes, newRes ctlres.Resource) } return changeFactoryFunc(existingRes, newRes) } - -type versionedResources struct { - Versioned []ctlres.Resource - NonVersioned []ctlres.Resource -} - -func newVersionedResources(rs []ctlres.Resource) versionedResources { - var result versionedResources - for _, res := range rs { - _, hasVersionedAnn := res.Annotations()[versionedResAnnKey] - _, hasVersionedOrigAnn := res.Annotations()[versionedResOrigAnnKey] - - if hasVersionedAnn { - result.Versioned = append(result.Versioned, res) - if hasVersionedOrigAnn { - result.NonVersioned = append(result.NonVersioned, res.DeepCopy()) - } - } else { - result.NonVersioned = append(result.NonVersioned, res) - } - } - return result -} - -func existingVersionedResources(rs []ctlres.Resource) versionedResources { - var result versionedResources - for _, res := range rs { - // Expect that versioned resources should not be transient - // (Annotations may have been copied from versioned resources - // onto transient resources for non-versioning related purposes). - _, hasVersionedAnn := res.Annotations()[versionedResAnnKey] - - versionedRs := VersionedResource{res: res} - _, version := versionedRs.BaseNameAndVersion() - - if hasVersionedAnn && !res.Transient() && version != "" { - result.Versioned = append(result.Versioned, res) - } else { - result.NonVersioned = append(result.NonVersioned, res) - } - } - return result -} - -func newGroupedVersionedResources(rs []ctlres.Resource) map[string][]ctlres.Resource { - result := map[string][]ctlres.Resource{} - - groupByFunc := func(res ctlres.Resource) string { - _, found := res.Annotations()[versionedResAnnKey] - if found { - return VersionedResource{res, nil}.UniqVersionedKey().String() - } - panic("Expected to find versioned annotation on resource") - } - - for resKey, subRs := range (GroupResources{rs, groupByFunc}).Resources() { - sort.Slice(subRs, func(i, j int) bool { - return VersionedResource{subRs[i], nil}.Version() < VersionedResource{subRs[j], nil}.Version() - }) - result[resKey] = subRs - } - return result -} - -func existingResourcesMap(res []ctlres.Resource) map[string]ctlres.Resource { - result := map[string]ctlres.Resource{} - - existingRs := existingVersionedResources(res) - existingVersionRsGrouped := newGroupedVersionedResources(existingRs.Versioned) - - for _, res := range existingRs.NonVersioned { - resKey := ctlres.NewUniqueResourceKey(res).String() - result[resKey] = res - } - - for resKey, res := range existingVersionRsGrouped { - result[resKey] = res[len(res)-1] - } - return result -} diff --git a/pkg/kapp/diff/change_set_with_versioned_rs_test.go b/pkg/kapp/diff/change_set_with_versioned_rs_test.go index 66db1d906..291485db9 100644 --- a/pkg/kapp/diff/change_set_with_versioned_rs_test.go +++ b/pkg/kapp/diff/change_set_with_versioned_rs_test.go @@ -27,7 +27,7 @@ metadata: kapp.k14s.io/versioned: "" `)) - changeSetWithVerRes := NewChangeSetWithVersionedRs([]ctlres.Resource{existingRes}, []ctlres.Resource{newRs}, nil, + changeSetWithVerRes := NewChangeSetWithVersionedRs(NewDiffResources([]ctlres.Resource{existingRes}, []ctlres.Resource{newRs}, nil), ChangeSetOpts{}, ChangeFactory{}) changes, err := changeSetWithVerRes.Calculate() @@ -75,7 +75,7 @@ metadata: name: secret `)) - changeSetWithVerRes := NewChangeSetWithVersionedRs([]ctlres.Resource{existingRes}, []ctlres.Resource{newRs}, nil, + changeSetWithVerRes := NewChangeSetWithVersionedRs(NewDiffResources([]ctlres.Resource{existingRes}, []ctlres.Resource{newRs}, nil), ChangeSetOpts{}, ChangeFactory{}) changes, err := changeSetWithVerRes.Calculate() @@ -124,7 +124,7 @@ metadata: name: secret `)) - changeSetWithVerRes := NewChangeSetWithVersionedRs([]ctlres.Resource{existingRes}, []ctlres.Resource{newRs}, nil, + changeSetWithVerRes := NewChangeSetWithVersionedRs(NewDiffResources([]ctlres.Resource{existingRes}, []ctlres.Resource{newRs}, nil), ChangeSetOpts{}, ChangeFactory{}) changes, err := changeSetWithVerRes.Calculate() diff --git a/pkg/kapp/diff/diff_resources.go b/pkg/kapp/diff/diff_resources.go new file mode 100644 index 000000000..b8c8a5059 --- /dev/null +++ b/pkg/kapp/diff/diff_resources.go @@ -0,0 +1,105 @@ +// Copyright 2020 VMware, Inc. +// SPDX-License-Identifier: Apache-2.0 + +package diff + +import ( + "sort" + + ctlconf "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/config" + ctlres "github.com/vmware-tanzu/carvel-kapp/pkg/kapp/resources" +) + +type DiffResources struct { + ExistingResources, NewResources versionedResources + ExistingResourcesGrouped map[string][]ctlres.Resource + + newRs []ctlres.Resource + rules []ctlconf.TemplateRule +} + +func NewDiffResources(existingRs, newRs []ctlres.Resource, rules []ctlconf.TemplateRule) DiffResources { + existingVRs := existingVersionedResources(existingRs) + newVRs := newVersionedResources(newRs) + + existingRsGrouped := newGroupedVersionedResources(existingVRs.Versioned) + + return DiffResources{existingVRs, newVRs, existingRsGrouped, newRs, rules} +} + +type versionedResources struct { + Versioned []ctlres.Resource + NonVersioned []ctlres.Resource +} + +func newVersionedResources(rs []ctlres.Resource) versionedResources { + var result versionedResources + for _, res := range rs { + _, hasVersionedAnn := res.Annotations()[versionedResAnnKey] + _, hasVersionedOrigAnn := res.Annotations()[versionedResOrigAnnKey] + + if hasVersionedAnn { + result.Versioned = append(result.Versioned, res) + if hasVersionedOrigAnn { + result.NonVersioned = append(result.NonVersioned, res.DeepCopy()) + } + } else { + result.NonVersioned = append(result.NonVersioned, res) + } + } + return result +} + +func existingVersionedResources(rs []ctlres.Resource) versionedResources { + var result versionedResources + for _, res := range rs { + // Expect that versioned resources should not be transient + // (Annotations may have been copied from versioned resources + // onto transient resources for non-versioning related purposes). + _, hasVersionedAnn := res.Annotations()[versionedResAnnKey] + + versionedRs := VersionedResource{res: res} + _, version := versionedRs.BaseNameAndVersion() + + if hasVersionedAnn && !res.Transient() && version != "" { + result.Versioned = append(result.Versioned, res) + } else { + result.NonVersioned = append(result.NonVersioned, res) + } + } + return result +} + +func newGroupedVersionedResources(rs []ctlres.Resource) map[string][]ctlres.Resource { + result := map[string][]ctlres.Resource{} + + groupByFunc := func(res ctlres.Resource) string { + _, found := res.Annotations()[versionedResAnnKey] + if found { + return VersionedResource{res, nil}.UniqVersionedKey().String() + } + panic("Expected to find versioned annotation on resource") + } + + for resKey, subRs := range (GroupResources{rs, groupByFunc}).Resources() { + sort.Slice(subRs, func(i, j int) bool { + return VersionedResource{subRs[i], nil}.Version() < VersionedResource{subRs[j], nil}.Version() + }) + result[resKey] = subRs + } + return result +} + +func (d DiffResources) existingResourcesMap() map[string]ctlres.Resource { + result := map[string]ctlres.Resource{} + + for _, res := range d.ExistingResources.NonVersioned { + resKey := ctlres.NewUniqueResourceKey(res).String() + result[resKey] = res + } + + for resKey, res := range d.ExistingResourcesGrouped { + result[resKey] = res[len(res)-1] + } + return result +} diff --git a/pkg/kapp/diff/renewable_resources.go b/pkg/kapp/diff/renewable_resources.go index cf0744d7c..539bfaa67 100644 --- a/pkg/kapp/diff/renewable_resources.go +++ b/pkg/kapp/diff/renewable_resources.go @@ -16,17 +16,17 @@ const ( ) type RenewableResources struct { - existingRs, newRs []ctlres.Resource + diffRs DiffResources } -func NewRenewableResources(existingRs, newRs []ctlres.Resource) *RenewableResources { - return &RenewableResources{existingRs: existingRs, newRs: newRs} +func NewRenewableResources(diffRs DiffResources) *RenewableResources { + return &RenewableResources{diffRs} } func (d RenewableResources) Prepare() error { - exResourcesMap := existingResourcesMap(d.existingRs) + exResourcesMap := d.diffRs.existingResourcesMap() - for _, res := range d.newRs { + for _, res := range d.diffRs.newRs { val, found := res.Annotations()[renewDurationAnnKey] if found { duration, err := time.ParseDuration(val)