Skip to content

Commit

Permalink
Patch lambda to allow imports (#3420)
Browse files Browse the repository at this point in the history
Should address #2392

We regressed in our handling of imported lambdas in 5.28, when we picked
up upstream
https://github.com/hashicorp/terraform-provider-aws/releases/tag/v4.51.0
with
https://github.com/hashicorp/terraform-provider-aws/pull/28963/files,
which introduces the `ExactlyOneOf` constraints in the lambda resource.

This PR reverts the upstream `ExactlyOneOf` constraints and replaces
them with the previously applied `ConflictsWith`. This in turn allows
imports of lambdas via `pulumi import` and the `import` resource option
to work properly.

I've added a GRPC test for a lambda imported via `pulumi import` as well
as an integration test for a lambda imported via the `import` resource
option and a test which checks that we still fail to create lambdas
without any code-related properties (which should be the only case that
now passes the validation step which previously didn't).

Note that this slightly worsens the behaviour in the case when none of
the code-related properties are specified. Previously that'd tirgger a
failure during `Check` and print a sensible error message but now we
will fail during `Create` with the following much less legible error:

```
  aws:lambda:Function (testLambda):
    error: 1 error occurred:
        * creating Lambda Function (testLambda-e9e5e22): operation error Lambda: CreateFunction, https response error StatusCode: 400, RequestID: 88b5f9d7-42d6-4a3b-becc-96cdf954f596, api error ValidationException: 2 validation errors detected: Value '' at 'code.s3Key' failed to satisfy constraint: Member must have length greater than or equal to 1; Value '' at 'code.s3Bucket' failed to satisfy constraint: Member must have length greater than or equal to 3
```

I don't see a sensible way around it though and I think the change is
still worthwhile.


Summary of effects:
| | <5.28 | 5.28-6.22 | This PR |
| :-------------  | :-------: | :----:| :-------:|
| pulumi import  | works? | doesn't work | works|
| import option   | works |doesn't work | works|
| no code lambda| errors during update?| errors during validation |
errors during update |
| other lambdas| works| works  | works |
  • Loading branch information
VenelinMartinov authored Feb 15, 2024
1 parent 32a25bf commit d80e951
Show file tree
Hide file tree
Showing 12 changed files with 338 additions and 0 deletions.
34 changes: 34 additions & 0 deletions examples/examples_nodejs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/lambda"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/pulumi/providertest/pulumitest"
"github.com/pulumi/providertest/pulumitest/opttest"
"github.com/pulumi/pulumi/pkg/v3/testing/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -577,3 +579,35 @@ func getAwsSession(t *testing.T) *session.Session {
require.NoError(t, err)
return sess
}

func TestUpdateImportedLambda(t *testing.T) {
test := pulumitest.NewPulumiTest(t, "lambda-import-ts",
opttest.LocalProviderPath("aws", filepath.Join(getCwd(t), "..", "bin")),
)

test.SetConfig("runtime", "nodejs18.x")
res := test.Up()
lambdaName := res.Outputs["lambda_name"]
lambdaRole := res.Outputs["lambda_role"]

secondStack := test.InstallStack("new_stack")

// Check that we can reimport the lambda.
secondStack.SetConfig("lambda_name", lambdaName.Value.(string))
secondStack.SetConfig("runtime", "nodejs18.x")
secondStack.SetConfig("lambda_role", lambdaRole.Value.(string))
secondStack.Up()

// Check that we can change a property on the lambda
secondStack.SetConfig("runtime", "nodejs16.x")
secondStack.Up()
}

func TestNoCodeLambda(t *testing.T) {
test := pulumitest.NewPulumiTest(t, "no-code-lambda",
opttest.LocalProviderPath("aws", filepath.Join(getCwd(t), "..", "bin")),
)
_, err := test.CurrentStack().Up(test.Context())
require.Error(t, err)
require.Contains(t, err.Error(), "ValidationException")
}
130 changes: 130 additions & 0 deletions examples/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,136 @@ func TestWrongStateMaxItemOneDiffProduced(t *testing.T) {
replay(t, repro)
}

func TestSourceCodeHashImportedLambdaChecksCleanly(t *testing.T) {
replay(t, `
[{
"method": "/pulumirpc.ResourceProvider/Check",
"request": {
"urn": "urn:pulumi:imported::repro_lambda::aws:lambda/function:Function::mylambda",
"olds": {
"__defaults": [],
"architectures": [
"x86_64"
],
"environment": {
"__defaults": [],
"variables": {
"__defaults": [],
"foo": "bar"
}
},
"ephemeralStorage": {
"__defaults": [],
"size": 512
},
"handler": "index.test",
"loggingConfig": {
"__defaults": [],
"logFormat": "Text",
"logGroup": "/aws/lambda/testLambda-83906f2"
},
"name": "testLambda-83906f2",
"packageType": "Zip",
"role": "arn:aws:iam::616138583583:role/iamForLambda-d5757fe",
"runtime": "nodejs18.x",
"sourceCodeHash": "WUsPYQdwiMj+sDZzl3tNaSzS42vqVfng2CZtgcy+TRs=",
"tracingConfig": {
"__defaults": [],
"mode": "PassThrough"
}
},
"news": {
"__defaults": [],
"architectures": [
"x86_64"
],
"environment": {
"__defaults": [],
"variables": {
"__defaults": [],
"foo": "bar"
}
},
"ephemeralStorage": {
"__defaults": [],
"size": 512
},
"handler": "index.test",
"loggingConfig": {
"__defaults": [],
"logFormat": "Text",
"logGroup": "/aws/lambda/testLambda-83906f2"
},
"name": "testLambda-83906f2",
"packageType": "Zip",
"role": "arn:aws:iam::616138583583:role/iamForLambda-d5757fe",
"runtime": "nodejs18.x",
"sourceCodeHash": "WUsPYQdwiMj+sDZzl3tNaSzS42vqVfng2CZtgcy+TRs=",
"tracingConfig": {
"__defaults": [],
"mode": "PassThrough"
}
},
"randomSeed": "MpcMRlpQV7R8mD8Nmx9KpLPPIyFTHsB8HA4kxXdWTfo="
},
"response": {
"inputs": {
"__defaults": [
"memorySize",
"publish",
"reservedConcurrentExecutions",
"skipDestroy",
"timeout"
],
"architectures": [
"x86_64"
],
"environment": {
"__defaults": [],
"variables": {
"__defaults": [],
"foo": "bar"
}
},
"ephemeralStorage": {
"__defaults": [],
"size": 512
},
"handler": "index.test",
"loggingConfig": {
"__defaults": [
"applicationLogLevel",
"systemLogLevel"
],
"applicationLogLevel": "",
"logFormat": "Text",
"logGroup": "/aws/lambda/testLambda-83906f2",
"systemLogLevel": ""
},
"memorySize": 128,
"name": "testLambda-83906f2",
"packageType": "Zip",
"publish": false,
"reservedConcurrentExecutions": -1,
"role": "arn:aws:iam::616138583583:role/iamForLambda-d5757fe",
"runtime": "nodejs18.x",
"skipDestroy": false,
"sourceCodeHash": "WUsPYQdwiMj+sDZzl3tNaSzS42vqVfng2CZtgcy+TRs=",
"timeout": 3,
"tracingConfig": {
"__defaults": [],
"mode": "PassThrough"
}
}
},
"metadata": {
"kind": "resource",
"mode": "client",
"name": "aws"
}
}]`)
}

// A lot of tests do not currently refresh cleanly. The work to root cause each tests has not been
// done yet but the common causes are listed here:
//
Expand Down
4 changes: 4 additions & 0 deletions examples/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.21.0

require (
github.com/aws/aws-sdk-go v1.50.13
github.com/pulumi/providertest v0.0.10
github.com/pulumi/pulumi-aws/provider/v6 v6.0.0-00010101000000-000000000000
github.com/pulumi/pulumi-terraform-bridge/pf v0.27.0
github.com/pulumi/pulumi-terraform-bridge/testing v0.0.2-0.20230927165309-e3fd9503f2d3
Expand Down Expand Up @@ -207,6 +208,7 @@ require (
github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect
github.com/gertd/go-pluralize v0.2.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
Expand Down Expand Up @@ -299,6 +301,7 @@ require (
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/natefinch/atomic v1.0.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/opentracing/basictracer-go v1.1.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
Expand Down Expand Up @@ -368,6 +371,7 @@ require (
google.golang.org/grpc v1.61.0 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
14 changes: 14 additions & 0 deletions examples/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1478,6 +1478,12 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
github.com/gkampitakis/ciinfo v0.3.0 h1:gWZlOC2+RYYttL0hBqcoQhM7h1qNkVqvRCV1fOvpAv8=
github.com/gkampitakis/ciinfo v0.3.0/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
github.com/gkampitakis/go-snaps v0.4.9 h1:x6+GEQeYWC+cnLNsHK5uXXgEQADmlH/1EqMrjfXjzk8=
github.com/gkampitakis/go-snaps v0.4.9/go.mod h1:8HW4KX3JKV8M0GSw69CvT+Jqhd1AlBPMPpBfjBI3bdY=
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
Expand Down Expand Up @@ -2630,7 +2636,15 @@ github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ
github.com/tedsuo/ifrit v0.0.0-20180802180643-bea94bb476cc/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0=
github.com/texttheater/golang-levenshtein v1.0.1 h1:+cRNoVrfiwufQPhoMzB6N0Yf/Mqajr6t1lOv8GyGE2U=
github.com/texttheater/golang-levenshtein v1.0.1/go.mod h1:PYAKrbF5sAiq9wd+H82hs7gNaen0CplQ9uvm6+enD/8=
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
Expand Down
2 changes: 2 additions & 0 deletions examples/lambda-import-ts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/bin/
/node_modules/
7 changes: 7 additions & 0 deletions examples/lambda-import-ts/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name: lambda-import-ts
runtime: nodejs
description: A minimal AWS TypeScript Pulumi program
config:
pulumi:tags:
value:
pulumi:template: aws-typescript
44 changes: 44 additions & 0 deletions examples/lambda-import-ts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as pulumi from "@pulumi/pulumi";
import * as archive from "@pulumi/archive";
import * as aws from "@pulumi/aws";

const config = new pulumi.Config();
const imported_lambda_name = config.get("lambda_name");
const imported_lambda_role = config.get("lambda_role");

const runtime = config.get("runtime");

const assumeRole = aws.iam.getPolicyDocument({
statements: [{
effect: "Allow",
principals: [{
type: "Service",
identifiers: ["lambda.amazonaws.com"],
}],
actions: ["sts:AssumeRole"],
}],
});
const iamForLambda = new aws.iam.Role("iamForLambda", {assumeRolePolicy: assumeRole.then(assumeRole => assumeRole.json)});
const lambda = archive.getFile({
type: "zip",
sourceFile: "lambda.js",
outputPath: "lambda_function_payload.zip",
});

const testLambda = new aws.lambda.Function("testLambda", {
name: imported_lambda_name,
code: imported_lambda_name ? undefined : new pulumi.asset.FileArchive("lambda_function_payload.zip"),
role: imported_lambda_role || iamForLambda.arn,
handler: "index.test",
runtime: runtime || "nodejs18.x",
environment: {
variables: {
foo: "bar",
},
},
}, imported_lambda_name ? {
import: imported_lambda_name, ignoreChanges: ["code", "filename", "s3_bucket", "source_code_hash", "image_uri"]
} : undefined);

export const lambda_name = testLambda.name;
export const lambda_role = testLambda.role;
1 change: 1 addition & 0 deletions examples/lambda-import-ts/lambda.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log("hi")
13 changes: 13 additions & 0 deletions examples/lambda-import-ts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "lambda-import-ts",
"main": "index.ts",
"devDependencies": {
"@types/node": "^18"
},
"dependencies": {
"@pulumi/pulumi": "^3.0.0",
"@pulumi/aws": "5.28.0",
"@pulumi/awsx": "^2.0.2",
"@pulumi/archive": "^0.0.4"
}
}
18 changes: 18 additions & 0 deletions examples/lambda-import-ts/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"strict": true,
"outDir": "bin",
"target": "es2016",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"experimentalDecorators": true,
"pretty": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.ts"
]
}
34 changes: 34 additions & 0 deletions examples/no-code-lambda/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: no-code-lambda
runtime: yaml
description: A minimal AWS Pulumi YAML program
config:
pulumi:tags:
value:
pulumi:template: aws-yaml
resources:
iamForLambda:
type: aws:iam:Role
properties:
assumeRolePolicy: ${assumeRole.json}
testLambda:
type: aws:lambda:Function
properties:
role: ${iamForLambda.arn}
handler: index.test
runtime: nodejs18.x
environment:
variables:
foo: bar
variables:
assumeRole:
fn::invoke:
Function: aws:iam:getPolicyDocument
Arguments:
statements:
- effect: Allow
principals:
- type: Service
identifiers:
- lambda.amazonaws.com
actions:
- sts:AssumeRole
Loading

0 comments on commit d80e951

Please sign in to comment.