pulumi / pulumi-aws

An Amazon Web Services (AWS) Pulumi resource package, providing multi-language access to AWS
Apache License 2.0
466 stars 156 forks source link

`rds.resourceProxy` Panic #3835

Closed zbuchheit closed 7 months ago

zbuchheit commented 7 months ago

Panic in rds.resourceProxy reported by a customer. Will upload full log separately.

Top level error

         [stdout]  2024-04-17 14:09:45 INFO     panic: interface conversion: interface {} is nil, not map[string]interface {} 
         [stdout]  2024-04-17 14:09:45 INFO      
         [stdout]  2024-04-17 14:09:45 INFO     goroutine 270 [running]: 
         [stdout]  2024-04-17 14:09:45 INFO      
         [stdout]  2024-04-17 14:09:45 INFO     github.com/hashicorp/terraform-provider-aws/internal/service/rds.resourceProxy.SimpleSchemaSetFunc.func1({0x0?, 0x0?}) 
corymhall commented 7 months ago

@zbuchheit do you have an example program we can use to reproduce this issue? Thanks!

corymhall commented 7 months ago

Also, if you happen to know what the previous working version and the current working version are that could help us narrow down the issue.

corymhall commented 7 months ago

Ok, here is the repro

import * as aws from "@pulumi/aws";

const proxyRole = new aws.iam.Role(
  "role",
  {
    assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal(
      aws.iam.Principals.RdsPrincipal,
    ),
    managedPolicyArns: [],
  },
  {},
);

const vpc = new aws.ec2.Vpc("vpc", {
  cidrBlock: "10.0.0.0/16",
});

const subnet = new aws.ec2.Subnet("subnet", {
  vpcId: vpc.id,
  cidrBlock: "10.0.1.0/24",
  availabilityZone: "us-east-2a",
});

const anotherSubnet = new aws.ec2.Subnet("another-subnet", {
  vpcId: vpc.id,
  cidrBlock: "10.0.2.0/24",
  availabilityZone: "us-east-2b",
});

const example = new aws.rds.Proxy("example", {
  name: "example",
  debugLogging: false,
  engineFamily: "MYSQL",
  idleClientTimeout: 1800,
  requireTls: true,
  roleArn: proxyRole.arn,
  vpcSubnetIds: [subnet.id, anotherSubnet.id],
  auths: [{}],
  tags: {
    Name: "example",
    Key: "value",
  },
});

The issue is caused by a change in upstream where Proxy.auth was changed from TypeList to TypeSet.

t0yv0 commented 7 months ago

We have filed https://github.com/hashicorp/terraform-provider-aws/issues/36965 as this reproduces upstream. Our first suspicion was an issue in the bridge, but even with the PlanResourceChange the issue reproduces. I poked in the debugger and found this:

In SimpleDiff(c ResourceConfig)

(dlv) print c.Config["auth"]
interface {}([]interface {}) [
        map[string]interface {} [],
]
(dlv) print c.Raw["auth"]
interface {}([]interface {}) [
        map[string]interface {} [],
]
(dlv) print c.CtyValue
github.com/hashicorp/go-cty/cty.Value {
        ty: github.com/hashicorp/go-cty/cty.Type {
                typeImpl: github.com/hashicorp/go-cty/cty.typeImpl nil,},
        v: interface {} nil,}

When we enter diffSet we get this:

*github.com/hashicorp/terraform-plugin-sdk/v2/terraform.InstanceDiff {
        mu: sync.Mutex {state: 0, sema: 0},
        Attributes: map[string]*github.com/hashicorp/terraform-plugin-sdk/v2/terraform.ResourceAttrDiff [],
        Destroy: false,
        DestroyDeposed: false,
        DestroyTainted: false,
        RawConfig: github.com/hashicorp/go-cty/cty.Value {
                ty: (*"github.com/hashicorp/go-cty/cty.Type")(0xc002c8ce50),
                v: interface {} nil,},
        RawState: github.com/hashicorp/go-cty/cty.Value {
                ty: (*"github.com/hashicorp/go-cty/cty.Type")(0xc002c8ce70),
                v: interface {} nil,},
        RawPlan: github.com/hashicorp/go-cty/cty.Value {
                ty: (*"github.com/hashicorp/go-cty/cty.Type")(0xc002c8ce90),
                v: interface {} nil,},
        Meta: map[string]interface {} nil,}

So when passing an empty object to a single-element set, this hash customizer doesn't work very well:

sdkv2.SimpleSchemaSetFunc("auth_scheme", "description", "iam_auth", "secret_arn", "username")

The various diff reader code in TFSDK is rather difficult for me to follow but I suspect right now that there might be an issue there in the reader code, not necessarily the set customizer itself. Alas.

t0yv0 commented 7 months ago

If we could back out the upstream change via a patch that would be ideal, so customers are not affected until such time as the root cause is fixed.

t0yv0 commented 7 months ago

OK there is another Pulumi-level issue here. Check turns an unknown property into a list of a single-known element.

{
  "method": "/pulumirpc.ResourceProvider/Check",
  "request": {
    "urn": "urn:pulumi:dev::golevel::aws:rds/proxy:Proxy::proxy",
    "olds": {},
    "news": {
      "auths": "04da6b54-80e4-46f7-96ec-b56ff0331ba9",
      "engineFamily": "MYSQL",
      "roleArn": "04da6b54-80e4-46f7-96ec-b56ff0331ba9",
      "vpcSubnetIds": [
        "04da6b54-80e4-46f7-96ec-b56ff0331ba9",
        "04da6b54-80e4-46f7-96ec-b56ff0331ba9"
      ]
    },
    "randomSeed": "J0Aw7NUBOt6y1jrDNci17siIDTE0toDNdhPxKB6L5w8="
  },
  "response": {
    "inputs": {
      "__defaults": [
        "name"
      ],
      "auths": [
        {}
      ],
      "engineFamily": "MYSQL",
      "name": "proxy-e01ed94",
      "roleArn": "04da6b54-80e4-46f7-96ec-b56ff0331ba9",
      "vpcSubnetIds": [
        "04da6b54-80e4-46f7-96ec-b56ff0331ba9",
        "04da6b54-80e4-46f7-96ec-b56ff0331ba9"
      ]
    }
  }
}

Go program:

package main

import (
    "github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2"
    "github.com/pulumi/pulumi-aws/sdk/v6/go/aws/iam"
    "github.com/pulumi/pulumi-aws/sdk/v6/go/aws/rds"
    "github.com/pulumi/pulumi-aws/sdk/v6/go/aws/secretsmanager"
    "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

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

        assumeRolePolicy, _ := iam.GetPolicyDocument(ctx, &iam.GetPolicyDocumentArgs{
            Statements: []iam.GetPolicyDocumentStatement{
                {
                    Actions:    []string{"sts:AssumeRole"},
                    Principals: []iam.GetPolicyDocumentStatementPrincipal{{Type: "Service", Identifiers: []string{"lambda.amazonaws.com"}}},
                },
            },
        })
        role, _ := iam.NewRole(ctx, "myrole", &iam.RoleArgs{
            AssumeRolePolicy: pulumi.String(assumeRolePolicy.Json),
        })

        vpc, _ := ec2.NewVpc(ctx, "Vpc", &ec2.VpcArgs{
            CidrBlock: pulumi.String("10.0.0.0/16"),
        })
        subnet, _ := ec2.NewSubnet(ctx, "subnet", &ec2.SubnetArgs{
            VpcId:            vpc.ID(),
            CidrBlock:        pulumi.String("10.0.2.0/24"),
            AvailabilityZone: pulumi.String("us-east-2a"),
        })
        anotherSubnet, _ := ec2.NewSubnet(ctx, "another-subnet", &ec2.SubnetArgs{
            VpcId:            vpc.ID(),
            CidrBlock:        pulumi.String("10.0.1.0/24"),
            AvailabilityZone: pulumi.String("us-east-1a"),
        })

        secret, err := secretsmanager.NewSecret(ctx, "secret", &secretsmanager.SecretArgs{})
        if err != nil {
            panic(err)
        }

        if 1+2 == 3 {
            rds.NewProxy(ctx, "proxy", &rds.ProxyArgs{
                VpcSubnetIds: pulumi.StringArray{
                    subnet.ID(),
                    anotherSubnet.ID(),
                },
                Auths: secret.Arn.ApplyT(func(arn string) []rds.ProxyAuth {
                    return []rds.ProxyAuth{
                        {
                            AuthScheme: pulumi.StringRef("SECRETS"),
                            IamAuth:    pulumi.StringRef("DISABLED"),
                            SecretArn:  &arn,
                        },
                    }
                }).(rds.ProxyAuthArrayInput),
                RoleArn:      role.Arn,
                EngineFamily: pulumi.String("MYSQL"),
            })
        }
        return nil
    })
}
t0yv0 commented 7 months ago

https://github.com/pulumi/pulumi-terraform-bridge/pull/1881