pulumi / pulumi-kubernetes

A Pulumi resource provider for Kubernetes to manage API resources and workloads in running clusters
https://www.pulumi.com/docs/reference/clouds/kubernetes/
Apache License 2.0
406 stars 117 forks source link

Helm Chart v4: graceful migration from v3 #3110

Open awoimbee opened 3 months ago

awoimbee commented 3 months ago

Hello!

Issue details

I'm trying to migrate from the helm Chart resource v3 to v4, but pulumi wants to redeploy the helm charts, and since it creates new resources before deleting old ones I get name conflicts.

There should be a clean migration path. Personally I would be grateful even of a pulumi stack export [...] && sed [...] && pulumi stack import solution.

Affected area/feature

kubernetes.helm.v4.Chart

EronWright commented 2 months ago

Sorry for the inconvenience, it is an aspect we'd like to improve upon.

A possible workaround is to use a transform function to apply an "alias" option to each child. The alias option lets you "move" a resource by defining its prior parent URN and its prior name.

awoimbee commented 2 months ago

Since I don't want to bloat the "codebase" with aliases everywhere I have resorted to stuff like:

pulumi -s <ENV> stack export | sed -E \
    -e 's|urn:(.*)v3:Chart(.*cert-manager.*)::(.*)|urn:\1v4:Chart\2::cert-manager:\3|g' \
    -e 's|urn:(.*)v3:Chart(.+)::(.*cert-manager.*)|urn:\1v4:Chart\2::cert-manager:\3|g' \
    -e 's|v3:Chart::cert-manager"|v4:Chart::cert-manager"|g' \
    > stack.json
pulumi -s <ENV> stack import --file stack.json

The issue is that Chart v4 adds the release name to all resources compared to Chart v3 so sed can't be used alone as a generic migration script, otherwise this technique works great (as long as you up, refresh, up to avoid drift)

blampe commented 2 months ago

We'd like to add some documentation around how to accomplish this using transforms since it's fairly involved.

mortaelth commented 1 week ago

this helped me to migrate:

in the v4 in the ComponentResourceOptions I am using something like this:

{
  parent: this,
  aliases: [{type: "kubernetes:helm.sh/v3:Chart"],
  transforms: [args => {
    return {
        props: args.props,
        opts: pulumi.mergeOptions(args.opts, {
            aliases: [{ parent: "<urn of the helm v3 resource>"}]
        })
    };
  }],
}

// quite a recent versions of @pulumi/kubernetes and @pulumi/pulumi required as of today

update: I have just noticed the "aliases" is not required, transforms are enough

xSAVIKx commented 1 week ago

Wanted to wonder if there's any guidelines on how to manage outputs better with the v4 Chart?

The v3 chart had getResource typed API which was very helpful.

awoimbee commented 1 day ago

Thanks @mortaelth, here is the generic solution I built from your snippet:

export class HelmChart extends k8s.helm.v4.Chart {
  constructor (
    releaseName: string,
    config: k8s.helm.v4.ChartArgs,
    opts?: pulumi.ComponentResourceOptions
  ) {
    // [...]
    // gracefully migrate from v3
    opts ??= {};
    opts.transforms ??= [];
    opts.transforms.push(({ props, opts: rOpts }) => {
      if (!props.apiVersion) {
        return;
      }
      const namespace = props.metadata?.namespace ? props.metadata.namespace + "/" : "";
      const apiVersion = props.apiVersion === "v1" ? "core/v1" : props.apiVersion;
      const helmV3Urn = `urn:pulumi:${stackName}::{projectName}::kubernetes:helm.sh/v3:Chart$kubernetes:${apiVersion}:${props.kind}::${namespace}${props.metadata?.name}`;
      return {
        props,
        opts: pulumi.mergeOptions(rOpts, {
          aliases: [helmV3Urn],
          provider: opts.provider
        })
      };
    });
    super(releaseName, config, opts);
  }
  // [...]