Skip to content

Commit

Permalink
Suppress undefined to default diffs on aws.autoscaling.Group (#4510)
Browse files Browse the repository at this point in the history
Fix a regression in the import experience on aws.autoscaling.Group.
Specifically the conflict between undefined and default values that
`pulumi import` used to detect is no longer a conflict by automatically
injecting DiffSuppressFunc for the relevant properties.

Fixes #4457
  • Loading branch information
t0yv0 committed Sep 24, 2024
1 parent e45ca74 commit 3379551
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 0 deletions.
34 changes: 34 additions & 0 deletions provider/provider_python_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
package provider

import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
"time"

"github.com/pulumi/pulumi/pkg/v3/testing/integration"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optpreview"
"github.com/stretchr/testify/require"
)

func TestRegress3196(t *testing.T) {
Expand Down Expand Up @@ -70,6 +74,36 @@ func TestRegress2534(t *testing.T) {
execPulumi(t, ptest, workdir, "state", "unprotect", strings.ReplaceAll(targetGroupUrn, "::test", "::newtg"), "--yes")
}

func TestRegress4457(t *testing.T) {
ptest := pulumiTest(t, filepath.Join("test-programs", "regress-4457"))
upResult := ptest.Up()
autoGroupArn := upResult.Outputs["autoGroupArn"].Value.(string)
autoGroupUrn := upResult.Outputs["autoGroupUrn"].Value.(string)
autoGroupName := upResult.Outputs["autoGroupName"].Value.(string)
workspace := ptest.CurrentStack().Workspace()

t.Logf("Provisioned autoscaling group with arn=%s and urn=%s and name=%s", autoGroupArn, autoGroupUrn, autoGroupName)
workdir := workspace.WorkDir()
t.Logf("workdir = %s", workdir)

importResult := ptest.Import("aws:autoscaling/group:Group", "newag", autoGroupName, "" /* providerUrn */)

t.Logf("Editing the program to add the code recommended by import")
i := strings.Index(importResult.Stdout, "import pulumi")
extraCode := importResult.Stdout[i:]
mainPy := filepath.Join(ptest.Source(), "__main__.py")
pyBytes, err := os.ReadFile(mainPy)
require.NoError(t, err)
updatedPyBytes := bytes.ReplaceAll(pyBytes, []byte("# EXTRA CODE HERE"), []byte(extraCode))
err = os.WriteFile(mainPy, updatedPyBytes, 0600)
require.NoError(t, err)

t.Logf("Previewing the edited program")
previewResult := ptest.Preview(optpreview.ExpectNoChanges())
t.Logf("%s", previewResult.StdOut)
t.Logf("%s", previewResult.StdErr)
}

func getPythonBaseOptions(t *testing.T) integration.ProgramTestOptions {
t.Helper()
envRegion := getEnvRegion(t)
Expand Down
39 changes: 39 additions & 0 deletions provider/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,45 @@ compatibility shim in favor of the new "name" field.`)
Name: "tags",
},
},
TransformOutputs: (func() func(ctx context.Context, pm resource.PropertyMap) (resource.PropertyMap, error) {
r, ok := p.ResourcesMap().GetOk("aws_autoscaling_group")
contract.Assertf(ok, "Expected aws_autoscaling_resource to be defined")
defaultValue := func(rawPropName string) resource.PropertyValue {
prop, ok := r.Schema().GetOk(rawPropName)
contract.Assertf(ok, "Expected property %q to be defined", prop)
def := prop.Default()
contract.Assertf(def != nil, "Expected property %q Default() to be defined", prop)
switch prop.Type() {
case shim.TypeString:
defs, ok := def.(string)
contract.Assertf(ok, "Expected property %q Default() to be a string", prop)
return resource.NewStringProperty(defs)
case shim.TypeBool:
defb, ok := def.(bool)
contract.Assertf(ok, "Expected property %q Default() to be a bool", prop)
return resource.NewBoolProperty(defb)
default:
contract.Failf("Types other than string and bool are not supported yet")
return resource.NewNullProperty()
}
}
defaults := map[string]resource.PropertyValue{
"forceDelete": defaultValue("force_delete"),
"forceDeleteWarmPool": defaultValue("force_delete_warm_pool"),
"ignoreFailedScailingActivities": defaultValue("ignore_failed_scaling_activities"),
"waitForCapacityTimeout": defaultValue("wait_for_capacity_timeout"),
}
return func(ctx context.Context, pm resource.PropertyMap) (resource.PropertyMap, error) {
r := pm.Copy()
for k, v := range defaults {
if value, defined := pm[resource.PropertyKey(k)]; defined && !value.IsNull() {
continue
}
r[resource.PropertyKey(k)] = v
}
return r, nil
}
})(),
},
"aws_autoscaling_lifecycle_hook": {
Tok: awsResource(autoscalingMod, "LifecycleHook"),
Expand Down
10 changes: 10 additions & 0 deletions provider/test-programs/regress-4457/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: regress-4457
runtime:
name: python
options:
virtualenv: venv
description: Provision a simple aws.autoscaling.Group to test importing it back
config:
pulumi:tags:
value:
pulumi:template: aws-python
31 changes: 31 additions & 0 deletions provider/test-programs/regress-4457/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import pulumi
import pulumi_aws as aws

ami = aws.ec2.get_ami(
filters=[{"name": "name", "values": ["amzn2-ami-hvm-*"]}],
owners=["amazon"],
most_recent=True)

lt1 = aws.ec2.LaunchTemplate(
"lt1",
name_prefix="lt1",
image_id=ami.id,
instance_type="t2.micro")

ag = aws.autoscaling.Group(
"ag",
availability_zones=["us-west-2a"],
desired_capacity=1,
max_size=1,
min_size=1,
launch_template={
"id": lt1.id,
"version": "$Latest",
})

# EXTRA CODE HERE

pulumi.export('ami', ami.id)
pulumi.export('autoGroupArn', ag.arn)
pulumi.export('autoGroupUrn', ag.urn)
pulumi.export('autoGroupName', ag.name)
2 changes: 2 additions & 0 deletions provider/test-programs/regress-4457/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pulumi>=3.0.0,<4.0.0
pulumi-aws>=6.0.2,<7.0.0

0 comments on commit 3379551

Please sign in to comment.