pulumi / pulumi-azure-native

Azure Native Provider
Apache License 2.0
126 stars 33 forks source link

NodeLabels are mangled when the 'name' includes periods #3431

Closed phillipedwards closed 1 month ago

phillipedwards commented 1 month ago

What happened?

Adding labels w/ names containing periods (my.label.name) to both AKS Clusters (ManagedCluster) and Additional Node Pools (AgentPool) results in the label name being exploded into an object. In addition to exploding the string name into an object, the value of the label is also represented as null.

More concretely, a label such as:

- name: my.label.name
  value: foo

is represented by Pulumi as:

nodeLabels: {
      ~ my: {
          ~ label: {
              + name: <null>
            }
        }
    }

whereas the label should be represented as:

nodeLabels: {
          ~ my.label.name: foo
        }

Example

package main

import (
    svc "github.com/pulumi/pulumi-azure-native-sdk/containerservice/v2"
    "github.com/pulumi/pulumi-azure-native-sdk/resources/v2"
    "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    "github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)

func main() {
    pulumi.Run(func(ctx *pulumi.Context) error {

        cfg := config.New(ctx, "")
        key := cfg.Require("sshPublicKey")

        // Define the resource group
        resourceGroup, err := resources.NewResourceGroup(ctx, "aks-rg", nil)
        if err != nil {
            return err
        }

        cluster, err := svc.NewManagedCluster(ctx, "cluster", &svc.ManagedClusterArgs{
            ResourceGroupName: resourceGroup.Name,
            Location:          resourceGroup.Location,
            DnsPrefix:         pulumi.String("aksdns"),
            AgentPoolProfiles: svc.ManagedClusterAgentPoolProfileArray{
                &svc.ManagedClusterAgentPoolProfileArgs{
                    Name:   pulumi.String("agentpool"),
                    Count:  pulumi.Int(3),
                    VmSize: pulumi.String("Standard_DS2_v2"),
                    OsType: pulumi.String("Linux"),
                    Mode:   pulumi.String("System"),
                    NodeLabels: pulumi.StringMap{
                        "role": pulumi.String("frontend"),
                        "env":  pulumi.String("production"),
                        // this label is exploded into an object
                        "my.label.name": pulumi.String("foo"),
                    },
                },
            },
            LinuxProfile: &svc.ContainerServiceLinuxProfileArgs{
                AdminUsername: pulumi.String("aksadmin"),
                Ssh: svc.ContainerServiceSshConfigurationArgs{
                    PublicKeys: svc.ContainerServiceSshPublicKeyArray{
                        &svc.ContainerServiceSshPublicKeyArgs{
                            KeyData: pulumi.String(key),
                        },
                    },
                },
            },
            Identity: &svc.ManagedClusterIdentityArgs{
                Type: svc.ResourceIdentityTypeSystemAssigned,
            },
            NetworkProfile: &svc.ContainerServiceNetworkProfileArgs{
                NetworkPlugin: pulumi.String("azure"),
                ServiceCidr:   pulumi.String("10.0.0.0/16"),
                DnsServiceIP:  pulumi.String("10.0.0.10"),
            },
        })

        if err != nil {
            return err
        }

        // Define an additional agent pool
        _, err = svc.NewAgentPool(ctx, "pool", &svc.AgentPoolArgs{
            ResourceGroupName: resourceGroup.Name,
            ResourceName:      cluster.Name,
            Count:             pulumi.Int(3),
            Mode:              pulumi.String("User"),
            VmSize:            pulumi.String("Standard_DS2_v2"),
            OsType:            pulumi.String("Linux"),
            MinCount:          pulumi.Int(1),
            MaxCount:          pulumi.Int(5),
            EnableAutoScaling: pulumi.Bool(true),
            NodeLabels: pulumi.StringMap{
                "role": pulumi.String("backend"),
                "env":  pulumi.String("staging"),
                // this label is exploded into an object
                "my.label.name": pulumi.String("foo"),
            },
        })
        if err != nil {
            return err
        }

        return nil
    })
}

Output of pulumi about

github.com/pulumi/pulumi-azure-native-sdk/containerservice/v2 v2.49.1 github.com/pulumi/pulumi-azure-native-sdk/resources/v2 v2.42.1 github.com/pulumi/pulumi-azure-native-sdk/storage/v2 v2.42.1 github.com/pulumi/pulumi/sdk/v3 v3.122.0

CLI - 3.122.0

Additional context

No response

Contributing

Vote on this issue by adding a 👍 reaction. To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).

phillipedwards commented 1 month ago

Only dots (.) seem to provoke the behavior detailed here. Dashes and underscores behave as expected.

thomas11 commented 1 month ago

Hi @phillipedwards, this looks definitely like a bug. Where exactly do you see the wrong output below? On pulumi preview?

nodeLabels: {
      ~ my: {
          ~ label: {
              + name: <null>
            }
        }
    }

What happens when you deploy anyway?

thomas11 commented 1 month ago

As an aside: periods are allowed in labels.

thomas11 commented 1 month ago

Running pulumi preview --diff on your example code, I get

                nodeLabels: {
                    env          : "production"
                    my.label.name: "foo"
                    role         : "frontend"
                }
thomas11 commented 1 month ago

I was now able to reproduce it by first deploying the cluster (which went fine), then changing the NodeLabel key. The next preview shows the wrong diff.

The good news is that the label is actually correct in Azure, both after creation and update. It's only the Pulumi diff that is wrong.

Screenshot 2024-07-16 at 14 45 28

pulumi-bot commented 1 month ago

This issue has been addressed in PR #3439 and shipped in release v2.50.1.