From d51cc7c80eb79b0b507eaef2c14ac3fb3dcb4994 Mon Sep 17 00:00:00 2001 From: Soumik Majumder Date: Mon, 5 Aug 2024 15:00:49 +0530 Subject: [PATCH] Add filter for apps for which ownership can be overriden Signed-off-by: Soumik Majumder --- pkg/kapp/cmd/app/deploy.go | 12 ++++++++++ pkg/kapp/cmd/app/deploy_flags.go | 3 +++ pkg/kapp/resources/labeled_resources.go | 30 +++++++++++++++++++++++-- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/pkg/kapp/cmd/app/deploy.go b/pkg/kapp/cmd/app/deploy.go index f4b95915b..2cd46a824 100644 --- a/pkg/kapp/cmd/app/deploy.go +++ b/pkg/kapp/cmd/app/deploy.go @@ -382,15 +382,27 @@ func (o *DeployOptions) existingResources(newResources []ctlres.Resource, return "" } + labelValAppMapResolver := func() map[string]string { + items, _ := apps.List(nil) + appLabelMap := map[string]string{} + for _, item := range items { + meta, _ := item.Meta() + appLabelMap[meta.LabelValue] = item.Name() + } + return appLabelMap + } + matchingOpts := ctlres.AllAndMatchingOpts{ ExistingNonLabeledResourcesCheck: o.DeployFlags.ExistingNonLabeledResourcesCheck, ExistingNonLabeledResourcesCheckConcurrency: o.DeployFlags.ExistingNonLabeledResourcesCheckConcurrency, SkipResourceOwnershipCheck: o.DeployFlags.OverrideOwnershipOfExistingResources, + SkipOwnershipCheckAllowedApps: o.DeployFlags.OwnershipOverrideAllowedApps, IsNewApp: isNewApp, // Prevent accidently overriding kapp state records DisallowedResourcesByLabelKeys: []string{ctlapp.KappIsAppLabelKey}, LabelErrorResolutionFunc: labelErrorResolutionFunc, + LabelValAppMapResolverFunc: labelValAppMapResolver, //Scope resource searching to UsedGKs IdentifiedResourcesListOpts: ctlres.IdentifiedResourcesListOpts{ diff --git a/pkg/kapp/cmd/app/deploy_flags.go b/pkg/kapp/cmd/app/deploy_flags.go index ec483305b..939050553 100644 --- a/pkg/kapp/cmd/app/deploy_flags.go +++ b/pkg/kapp/cmd/app/deploy_flags.go @@ -18,6 +18,7 @@ type DeployFlags struct { ExistingNonLabeledResourcesCheck bool ExistingNonLabeledResourcesCheckConcurrency int OverrideOwnershipOfExistingResources bool + OwnershipOverrideAllowedApps []string AppChangesMaxToKeep int @@ -48,6 +49,8 @@ func (s *DeployFlags) Set(cmd *cobra.Command) { 100, "Concurrency to check for existing non-labeled resources") cmd.Flags().BoolVar(&s.OverrideOwnershipOfExistingResources, "dangerous-override-ownership-of-existing-resources", false, "Steal existing resources from another app") + cmd.Flags().StringSliceVar(&s.OwnershipOverrideAllowedApps, "ownership-override-allowed-apps", nil, + "Specify existing apps in the same namespace that existing resources can be stolen from if --dangerous-override-ownership-of-existing-resources is set") cmd.Flags().BoolVar(&s.DefaultLabelScopingRules, "default-label-scoping-rules", true, "Use default label scoping rules") diff --git a/pkg/kapp/resources/labeled_resources.go b/pkg/kapp/resources/labeled_resources.go index 026335198..b334bf44c 100644 --- a/pkg/kapp/resources/labeled_resources.go +++ b/pkg/kapp/resources/labeled_resources.go @@ -5,6 +5,7 @@ package resources import ( "fmt" + "slices" "strings" "sync" @@ -93,10 +94,12 @@ type AllAndMatchingOpts struct { ExistingNonLabeledResourcesCheck bool ExistingNonLabeledResourcesCheckConcurrency int SkipResourceOwnershipCheck bool + SkipOwnershipCheckAllowedApps []string IsNewApp bool DisallowedResourcesByLabelKeys []string LabelErrorResolutionFunc func(string, string) string + LabelValAppMapResolverFunc func() map[string]string IdentifiedResourcesListOpts IdentifiedResourcesListOpts } @@ -131,7 +134,8 @@ func (a *LabeledResources) AllAndMatching(newResources []Resource, opts AllAndMa } } - if !opts.SkipResourceOwnershipCheck && len(nonLabeledResources) > 0 { + if len(nonLabeledResources) > 0 && (!opts.SkipResourceOwnershipCheck || + (opts.SkipResourceOwnershipCheck && len(opts.SkipOwnershipCheckAllowedApps) > 0)) { resourcesForCheck := a.resourcesForOwnershipCheck(newResources, nonLabeledResources) if len(resourcesForCheck) > 0 { err := a.checkResourceOwnership(resourcesForCheck, opts) @@ -180,10 +184,19 @@ func (a *LabeledResources) checkResourceOwnership(resources []Resource, opts All } var errs []error + labelValAppMap := map[string]string{} + if len(opts.SkipOwnershipCheckAllowedApps) > 0 && opts.SkipResourceOwnershipCheck { + labelValAppMap = opts.LabelValAppMapResolverFunc() + } for _, res := range resources { if val, found := res.Labels()[expectedLabelKey]; found { - if val != expectedLabelVal { + ownershipOverrideAllowed := false + if opts.SkipResourceOwnershipCheck { + ownershipOverrideAllowed = a.ownershipOverrideAllowed(labelValAppMap, res, + expectedLabelKey, opts.SkipOwnershipCheckAllowedApps) + } + if val != expectedLabelVal && !ownershipOverrideAllowed { ownerMsg := fmt.Sprintf("different label '%s=%s'", expectedLabelKey, val) if opts.LabelErrorResolutionFunc != nil { ownerMsgSuggested := opts.LabelErrorResolutionFunc(expectedLabelKey, val) @@ -208,6 +221,19 @@ func (a *LabeledResources) checkResourceOwnership(resources []Resource, opts All return nil } +func (a *LabeledResources) ownershipOverrideAllowed(labelValAppMap map[string]string, res Resource, + expectedLabelKey string, overrideAllowedApps []string) bool { + labelVal, found := res.Labels()[expectedLabelKey] + if !found { + return true + } + appName, found := labelValAppMap[labelVal] + if !found { + return false + } + return slices.Contains(overrideAllowedApps, appName) +} + func (a *LabeledResources) checkDisallowedLabels(resources []Resource, disallowedLblKeys []string) error { var errs []error