Alternative: annotation-only solution

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

@ -249,6 +249,11 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release.
return nil, errors.Wrap(err, "unable to build kubernetes objects from release manifest")
}
err = resources.Visit(setMetadataVisitor(rel.Name, rel.Namespace))
if err != nil {
return nil, err
}
// Install requires an extra validation step of checking that resources
// don't already exist before we actually create resources. If we continue
// forward and create the release object with resources that already exist,
@ -256,7 +261,7 @@ 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 {
toBeUpdated, err := existingResourceConflict(resources, rel.Name)
toBeUpdated, err := existingResourceConflict(resources, rel.Name, rel.Namespace)
if err != nil {
return nil, errors.Wrap(err, "rendered manifests contain a resource that already exists. Unable to continue with install")
}

@ -203,6 +203,11 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
return upgradedRelease, errors.Wrap(err, "unable to build kubernetes objects from new release manifest")
}
err = target.Visit(setMetadataVisitor(upgradedRelease.Name, upgradedRelease.Namespace))
if err != nil {
return upgradedRelease, err
}
// Do a basic diff using gvk + name to figure out what new resources are being created so we can validate they don't already exist
existingResources := make(map[string]bool)
for _, r := range current {
@ -216,7 +221,7 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea
}
}
toBeUpdated, err := existingResourceConflict(toBeCreated, upgradedRelease.Name)
toBeUpdated, err := existingResourceConflict(toBeCreated, upgradedRelease.Name, upgradedRelease.Namespace)
if err != nil {
return nil, errors.Wrap(err, "rendered manifests contain a resource that already exists. Unable to continue with update")
}

@ -22,36 +22,22 @@ 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"
)
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))
}
var accessor = meta.NewAccessor()
func existingResourceConflict(resources kube.ResourceList, release string) (kube.ResourceList, error) {
sel, err := newReleaseSelector(release)
if err != nil {
return nil, err
}
const (
helmReleaseNameAnnotation = "meta.helm.sh/release-name"
helmReleaseNamespaceAnnotation = "meta.helm.sh/release-namespace"
)
func existingResourceConflict(resources kube.ResourceList, releaseName, releaseNamespace string) (kube.ResourceList, error) {
requireUpdate := kube.ResourceList{}
err = resources.Visit(func(info *resource.Info, err error) error {
err := resources.Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
}
@ -67,14 +53,11 @@ func existingResourceConflict(resources kube.ResourceList, release string) (kube
}
// 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) {
anno, err := accessor.Annotations(existing)
if err == nil && anno != nil && anno[helmReleaseNameAnnotation] == releaseName && anno[helmReleaseNamespaceAnnotation] == releaseNamespace {
requireUpdate = append(requireUpdate, info)
return nil
}
}
return fmt.Errorf(
"existing resource conflict: namespace: %s, name: %s, existing_kind: %s, new_kind: %s",
@ -83,3 +66,21 @@ func existingResourceConflict(resources kube.ResourceList, release string) (kube
return requireUpdate, err
}
func setMetadataVisitor(releaseName, releaseNamespace string) resource.VisitorFunc {
return func(info *resource.Info, err error) error {
if err != nil {
return err
}
anno, err := accessor.Annotations(info.Object)
if err != nil {
return err
}
if anno == nil {
anno = make(map[string]string)
}
anno[helmReleaseNameAnnotation] = releaseName
anno[helmReleaseNamespaceAnnotation] = releaseNamespace
return accessor.SetAnnotations(info.Object, anno)
}
}

Loading…
Cancel
Save