Adopt resources into release with correct instance and managed-by labels

Signed-off-by: Jacob LeGrone <git@jacob.work>
pull/7649/head
Jacob LeGrone 6 years ago
parent d6fad6b3c6
commit a29365b3c6
No known key found for this signature in database
GPG Key ID: 5FD0852F235368C1

@ -38,6 +38,7 @@ import (
"helm.sh/helm/v3/pkg/downloader"
"helm.sh/helm/v3/pkg/engine"
"helm.sh/helm/v3/pkg/getter"
"helm.sh/helm/v3/pkg/kube"
kubefake "helm.sh/helm/v3/pkg/kube/fake"
"helm.sh/helm/v3/pkg/postrender"
"helm.sh/helm/v3/pkg/release"
@ -242,6 +243,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
// Mark this release as in-progress
rel.SetStatus(release.StatusPendingInstall, "Initial install underway")
var adoptedResources kube.ResourceList
resources, err := i.cfg.KubeClient.Build(bytes.NewBufferString(rel.Manifest), !i.DisableOpenAPIValidation)
if err != nil {
return nil, errors.Wrap(err, "unable to build kubernetes objects from release manifest")
@ -254,9 +256,11 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
// deleting the release because the manifest will be pointing at that
// resource
if !i.ClientOnly && !isUpgrade {
if err := existingResourceConflict(resources); err != nil {
toBeUpdated, err := existingResourceConflict(resources, rel.Name)
if err != nil {
return nil, errors.Wrap(err, "rendered manifests contain a resource that already exists. Unable to continue with install")
}
adoptedResources = toBeUpdated
}
// Bail out here if it is a dry run
@ -291,7 +295,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
// At this point, we can do the install. Note that before we were detecting whether to
// do an update, but it's not clear whether we WANT to do an update if the re-use is set
// to true, since that is basically an upgrade operation.
if _, err := i.cfg.KubeClient.Create(resources); err != nil {
if _, err := i.cfg.KubeClient.Update(adoptedResources, resources, false); err != nil {
return i.failRelease(rel, err)
}

@ -216,10 +216,19 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
}
}
if err := existingResourceConflict(toBeCreated); err != nil {
return nil, errors.Wrap(err, "rendered manifests contain a new resource that already exists. Unable to continue with update")
toBeUpdated, err := existingResourceConflict(toBeCreated, upgradedRelease.Name)
if err != nil {
return nil, errors.Wrap(err, "rendered manifests contain a resource that already exists. Unable to continue with update")
}
toBeUpdated.Visit(func(r *resource.Info, err error) error {
if err != nil {
return err
}
current.Append(r)
return nil
})
if u.DryRun {
u.cfg.Log("dry run for %s", upgradedRelease.Name)
if len(u.Description) > 0 {

@ -21,13 +21,37 @@ import (
"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/cli-runtime/pkg/resource"
"helm.sh/helm/v3/pkg/kube"
)
func existingResourceConflict(resources kube.ResourceList) error {
err := resources.Visit(func(info *resource.Info, err error) error {
var (
managedByReq, _ = labels.NewRequirement("app.kubernetes.io/managed-by", selection.Equals, []string{"Helm"})
accessor = meta.NewAccessor()
)
func newReleaseSelector(release string) (labels.Selector, error) {
releaseReq, err := labels.NewRequirement("app.kubernetes.io/instance", selection.Equals, []string{release})
if err != nil {
return nil, err
}
return labels.Parse(fmt.Sprintf("%s,%s", releaseReq, managedByReq))
}
func existingResourceConflict(resources kube.ResourceList, release string) (kube.ResourceList, error) {
sel, err := newReleaseSelector(release)
if err != nil {
return nil, err
}
requireUpdate := kube.ResourceList{}
err = resources.Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
}
@ -42,7 +66,20 @@ func existingResourceConflict(resources kube.ResourceList) error {
return errors.Wrap(err, "could not get information about the resource")
}
return fmt.Errorf("existing resource conflict: namespace: %s, name: %s, existing_kind: %s, new_kind: %s", info.Namespace, info.Name, existing.GetObjectKind().GroupVersionKind(), info.Mapping.GroupVersionKind)
// Allow adoption of the resource if it already has app.kubernetes.io/instance and app.kubernetes.io/managed-by labels.
lbls, err := accessor.Labels(existing)
if err == nil {
set := labels.Set(lbls)
if sel.Matches(set) {
requireUpdate = append(requireUpdate, info)
return nil
}
}
return fmt.Errorf(
"existing resource conflict: namespace: %s, name: %s, existing_kind: %s, new_kind: %s",
info.Namespace, info.Name, existing.GetObjectKind().GroupVersionKind(), info.Mapping.GroupVersionKind)
})
return err
return requireUpdate, err
}

Loading…
Cancel
Save