Skip to content

Commit 203c377

Browse files
authored
Merge pull request #45170 from sasidhar-aws/f_lambda_tenancy
Support of tenancy for lambda function creation and invocation
2 parents 1b70869 + 971c8a8 commit 203c377

16 files changed

+436
-0
lines changed

.changelog/45170.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
```release-note:enhancement
2+
resource/aws_lambda_function: Add `tenancy_config` argument
3+
```
4+
5+
```release-note:enhancement
6+
data-source/aws_lambda_function: Add `tenancy_config` attribute
7+
```
8+
9+
```release-note:enhancement
10+
resource/aws_lambda_invocation: Add `tenant_id` argument
11+
```
12+
13+
```release-note:enhancement
14+
data-source/aws_lambda_invocation: Add `tenant_id` argument
15+
```
16+
17+
```release-note:enhancement
18+
action/aws_lambda_invoke: Add `tenant_id` argument
19+
```

internal/service/lambda/function.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,21 @@ func resourceFunction() *schema.Resource {
398398
},
399399
names.AttrTags: tftags.TagsSchema(),
400400
names.AttrTagsAll: tftags.TagsSchemaComputed(),
401+
"tenancy_config": {
402+
Type: schema.TypeList,
403+
MaxItems: 1,
404+
Optional: true,
405+
ForceNew: true,
406+
Elem: &schema.Resource{
407+
Schema: map[string]*schema.Schema{
408+
"tenant_isolation_mode": {
409+
Type: schema.TypeString,
410+
Required: true,
411+
ValidateDiagFunc: enum.Validate[awstypes.TenantIsolationMode](),
412+
},
413+
},
414+
},
415+
},
401416
names.AttrTimeout: {
402417
Type: schema.TypeInt,
403418
Optional: true,
@@ -585,6 +600,12 @@ func resourceFunctionCreate(ctx context.Context, d *schema.ResourceData, meta an
585600
input.Code.SourceKMSKeyArn = aws.String(v.(string))
586601
}
587602

603+
if v, ok := d.GetOk("tenancy_config"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil {
604+
input.TenancyConfig = &awstypes.TenancyConfig{
605+
TenantIsolationMode: awstypes.TenantIsolationMode(v.([]any)[0].(map[string]any)["tenant_isolation_mode"].(string)),
606+
}
607+
}
608+
588609
if v, ok := d.GetOk("tracing_config"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil {
589610
input.TracingConfig = &awstypes.TracingConfig{
590611
Mode: awstypes.TracingMode(v.([]any)[0].(map[string]any)[names.AttrMode].(string)),
@@ -752,6 +773,15 @@ func resourceFunctionRead(ctx context.Context, d *schema.ResourceData, meta any)
752773
}); err != nil {
753774
return sdkdiag.AppendErrorf(diags, "setting tracing_config: %s", err)
754775
}
776+
if function.TenancyConfig != nil {
777+
if err := d.Set("tenancy_config", []any{
778+
map[string]any{
779+
"tenant_isolation_mode": string(function.TenancyConfig.TenantIsolationMode),
780+
},
781+
}); err != nil {
782+
return sdkdiag.AppendErrorf(diags, "setting tenancy_config: %s", err)
783+
}
784+
}
755785
if err := d.Set(names.AttrVPCConfig, flattenVPCConfigResponse(function.VpcConfig)); err != nil {
756786
return sdkdiag.AppendErrorf(diags, "setting vpc_config: %s", err)
757787
}

internal/service/lambda/function_data_source.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,18 @@ func dataSourceFunction() *schema.Resource {
209209
Type: schema.TypeInt,
210210
Computed: true,
211211
},
212+
"tenancy_config": {
213+
Type: schema.TypeList,
214+
Computed: true,
215+
Elem: &schema.Resource{
216+
Schema: map[string]*schema.Schema{
217+
"tenant_isolation_mode": {
218+
Type: schema.TypeString,
219+
Computed: true,
220+
},
221+
},
222+
},
223+
},
212224
"tracing_config": {
213225
Type: schema.TypeList,
214226
Computed: true,
@@ -365,6 +377,15 @@ func dataSourceFunctionRead(ctx context.Context, d *schema.ResourceData, meta an
365377
d.Set("source_code_size", function.CodeSize)
366378
d.Set("source_kms_key_arn", functionCode.SourceKMSKeyArn)
367379
d.Set(names.AttrTimeout, function.Timeout)
380+
if function.TenancyConfig != nil {
381+
if err := d.Set("tenancy_config", []any{
382+
map[string]any{
383+
"tenant_isolation_mode": string(function.TenancyConfig.TenantIsolationMode),
384+
},
385+
}); err != nil {
386+
return sdkdiag.AppendErrorf(diags, "setting tenancy_config: %s", err)
387+
}
388+
}
368389
tracingConfigMode := awstypes.TracingModePassThrough
369390
if function.TracingConfig != nil {
370391
tracingConfigMode = function.TracingConfig.Mode

internal/service/lambda/function_data_source_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,29 @@ func TestAccLambdaFunctionDataSource_loggingConfig(t *testing.T) {
398398
})
399399
}
400400

401+
func TestAccLambdaFunctionDataSource_tenancyConfig(t *testing.T) {
402+
ctx := acctest.Context(t)
403+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
404+
dataSourceName := "data.aws_lambda_function.test"
405+
resourceName := "aws_lambda_function.test"
406+
407+
resource.ParallelTest(t, resource.TestCase{
408+
PreCheck: func() { acctest.PreCheck(ctx, t) },
409+
ErrorCheck: acctest.ErrorCheck(t, names.LambdaServiceID),
410+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
411+
Steps: []resource.TestStep{
412+
{
413+
Config: testAccFunctionDataSourceConfig_tenancyConfig(rName),
414+
Check: resource.ComposeAggregateTestCheckFunc(
415+
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrARN, resourceName, names.AttrARN),
416+
resource.TestCheckResourceAttrPair(dataSourceName, "tenancy_config.#", resourceName, "tenancy_config.#"),
417+
resource.TestCheckResourceAttrPair(dataSourceName, "tenancy_config.0.tenant_isolation_mode", resourceName, "tenancy_config.0.tenant_isolation_mode"),
418+
),
419+
},
420+
},
421+
})
422+
}
423+
401424
func testAccImageLatestPreCheck(t *testing.T) {
402425
if os.Getenv("AWS_LAMBDA_IMAGE_LATEST_ID") == "" {
403426
t.Skip("AWS_LAMBDA_IMAGE_LATEST_ID env var must be set for Lambda Function Data Source Image Support acceptance tests.")
@@ -850,3 +873,23 @@ data "aws_lambda_function" "test" {
850873
}
851874
`, rName, rName+"_custom"))
852875
}
876+
877+
func testAccFunctionDataSourceConfig_tenancyConfig(rName string) string {
878+
return acctest.ConfigCompose(testAccFunctionDataSourceConfig_base(rName), fmt.Sprintf(`
879+
resource "aws_lambda_function" "test" {
880+
filename = "test-fixtures/lambdatest.zip"
881+
function_name = %[1]q
882+
role = aws_iam_role.lambda.arn
883+
handler = "exports.example"
884+
runtime = "nodejs20.x"
885+
886+
tenancy_config {
887+
tenant_isolation_mode = "PER_TENANT"
888+
}
889+
}
890+
891+
data "aws_lambda_function" "test" {
892+
function_name = aws_lambda_function.test.function_name
893+
}
894+
`, rName))
895+
}

internal/service/lambda/function_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,6 +2410,72 @@ func TestAccLambdaFunction_sourceKMSKeyARN(t *testing.T) {
24102410
})
24112411
}
24122412

2413+
func TestAccLambdaFunction_tenancyConfig(t *testing.T) {
2414+
ctx := acctest.Context(t)
2415+
var conf lambda.GetFunctionOutput
2416+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
2417+
resourceName := "aws_lambda_function.test"
2418+
2419+
resource.ParallelTest(t, resource.TestCase{
2420+
PreCheck: func() { acctest.PreCheck(ctx, t) },
2421+
ErrorCheck: acctest.ErrorCheck(t, names.LambdaServiceID),
2422+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
2423+
CheckDestroy: testAccCheckFunctionDestroy(ctx),
2424+
Steps: []resource.TestStep{
2425+
{
2426+
Config: testAccFunctionConfig_tenancyConfig(rName),
2427+
Check: resource.ComposeAggregateTestCheckFunc(
2428+
testAccCheckFunctionExists(ctx, resourceName, &conf),
2429+
resource.TestCheckResourceAttr(resourceName, "tenancy_config.#", "1"),
2430+
resource.TestCheckResourceAttr(resourceName, "tenancy_config.0.tenant_isolation_mode", "PER_TENANT"),
2431+
),
2432+
},
2433+
{
2434+
ResourceName: resourceName,
2435+
ImportState: true,
2436+
ImportStateVerify: true,
2437+
ImportStateVerifyIgnore: []string{"filename", "publish"},
2438+
},
2439+
},
2440+
})
2441+
}
2442+
2443+
func TestAccLambdaFunction_tenancyConfigForceNew(t *testing.T) {
2444+
ctx := acctest.Context(t)
2445+
var conf lambda.GetFunctionOutput
2446+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
2447+
resourceName := "aws_lambda_function.test"
2448+
2449+
resource.ParallelTest(t, resource.TestCase{
2450+
PreCheck: func() { acctest.PreCheck(ctx, t) },
2451+
ErrorCheck: acctest.ErrorCheck(t, names.LambdaServiceID),
2452+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
2453+
CheckDestroy: testAccCheckFunctionDestroy(ctx),
2454+
Steps: []resource.TestStep{
2455+
{
2456+
Config: testAccFunctionConfig_basic(rName, rName, rName, rName),
2457+
Check: resource.ComposeTestCheckFunc(
2458+
testAccCheckFunctionExists(ctx, resourceName, &conf),
2459+
resource.TestCheckResourceAttr(resourceName, "tenancy_config.#", "0"),
2460+
),
2461+
},
2462+
{
2463+
Config: testAccFunctionConfig_tenancyConfig(rName),
2464+
ConfigPlanChecks: resource.ConfigPlanChecks{
2465+
PreApply: []plancheck.PlanCheck{
2466+
plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionReplace),
2467+
},
2468+
},
2469+
Check: resource.ComposeAggregateTestCheckFunc(
2470+
testAccCheckFunctionExists(ctx, resourceName, &conf),
2471+
resource.TestCheckResourceAttr(resourceName, "tenancy_config.#", "1"),
2472+
resource.TestCheckResourceAttr(resourceName, "tenancy_config.0.tenant_isolation_mode", "PER_TENANT"),
2473+
),
2474+
},
2475+
},
2476+
})
2477+
}
2478+
24132479
func TestAccLambdaFunction_resetNonRefreshableAttributesAfterUpdateFailure(t *testing.T) {
24142480
ctx := acctest.Context(t)
24152481
var conf lambda.GetFunctionOutput
@@ -4364,6 +4430,24 @@ resource "aws_lambda_function" "test" {
43644430
`, rName, kmsIdentifier))
43654431
}
43664432

4433+
func testAccFunctionConfig_tenancyConfig(rName string) string {
4434+
return acctest.ConfigCompose(
4435+
acctest.ConfigLambdaBase(rName, rName, rName),
4436+
fmt.Sprintf(`
4437+
resource "aws_lambda_function" "test" {
4438+
filename = "test-fixtures/lambdatest.zip"
4439+
function_name = %[1]q
4440+
role = aws_iam_role.iam_for_lambda.arn
4441+
handler = "exports.example"
4442+
runtime = "nodejs20.x"
4443+
4444+
tenancy_config {
4445+
tenant_isolation_mode = "PER_TENANT"
4446+
}
4447+
}
4448+
`, rName))
4449+
}
4450+
43674451
func testAccFunctionConfig_skipDestroy(rName string) string {
43684452
return acctest.ConfigCompose(acctest.ConfigLambdaBase(rName, rName, rName), fmt.Sprintf(`
43694453
resource "aws_lambda_function" "test" {

internal/service/lambda/invocation.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ func resourceInvocation() *schema.Resource {
8888
Type: schema.TypeString,
8989
Computed: true,
9090
},
91+
"tenant_id": {
92+
Type: schema.TypeString,
93+
Optional: true,
94+
},
9195
"terraform_key": {
9296
Type: schema.TypeString,
9397
Optional: true,
@@ -213,6 +217,9 @@ func invoke(ctx context.Context, conn *lambda.Client, d *schema.ResourceData, ac
213217
Payload: payload,
214218
Qualifier: aws.String(qualifier),
215219
}
220+
if v, ok := d.GetOk("tenant_id"); ok {
221+
input.TenantId = aws.String(v.(string))
222+
}
216223

217224
output, err := conn.Invoke(ctx, input)
218225

internal/service/lambda/invocation_data_source.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ func dataSourceInvocation() *schema.Resource {
4242
Type: schema.TypeString,
4343
Computed: true,
4444
},
45+
"tenant_id": {
46+
Type: schema.TypeString,
47+
Optional: true,
48+
},
4549
},
4650
}
4751
}
@@ -61,6 +65,10 @@ func dataSourceInvocationRead(ctx context.Context, d *schema.ResourceData, meta
6165
Qualifier: aws.String(qualifier),
6266
}
6367

68+
if v, ok := d.GetOk("tenant_id"); ok {
69+
input.TenantId = aws.String(v.(string))
70+
}
71+
6472
output, err := conn.Invoke(ctx, input)
6573

6674
if err != nil {

internal/service/lambda/invocation_data_source_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,26 @@ func TestAccLambdaInvocationDataSource_complex(t *testing.T) {
100100
})
101101
}
102102

103+
func TestAccLambdaInvocationDataSource_tenantId(t *testing.T) {
104+
ctx := acctest.Context(t)
105+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
106+
testData := "value3"
107+
108+
resource.ParallelTest(t, resource.TestCase{
109+
PreCheck: func() { acctest.PreCheck(ctx, t) },
110+
ErrorCheck: acctest.ErrorCheck(t, names.LambdaServiceID),
111+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
112+
Steps: []resource.TestStep{
113+
{
114+
Config: testAccInvocationDataSourceConfig_tenantId(rName, testData),
115+
Check: resource.ComposeTestCheckFunc(
116+
testAccCheckInvocationResult("data.aws_lambda_invocation.invocation_test", `{"key1":"value1","key2":"value2","key3":"`+testData+`"}`),
117+
),
118+
},
119+
},
120+
})
121+
}
122+
103123
func testAccInvocationDataSource_base_config(roleName string) string {
104124
return fmt.Sprintf(`
105125
data "aws_iam_policy_document" "lambda_assume_role_policy" {
@@ -230,3 +250,37 @@ JSON
230250
}
231251
`, rName, testData)
232252
}
253+
254+
func testAccInvocationDataSourceConfig_tenantId(rName, testData string) string {
255+
return fmt.Sprintf(testAccInvocationDataSource_base_config(rName)+`
256+
resource "aws_lambda_function" "lambda" {
257+
depends_on = [aws_iam_role_policy_attachment.lambda_role_policy]
258+
259+
filename = "test-fixtures/lambda_invocation.zip"
260+
function_name = "%s"
261+
role = aws_iam_role.lambda_role.arn
262+
handler = "lambda_invocation.handler"
263+
runtime = "nodejs20.x"
264+
tenancy_config {
265+
tenant_isolation_mode = "PER_TENANT"
266+
}
267+
268+
environment {
269+
variables = {
270+
TEST_DATA = "%s"
271+
}
272+
}
273+
}
274+
275+
data "aws_lambda_invocation" "invocation_test" {
276+
function_name = aws_lambda_function.lambda.function_name
277+
tenant_id = "tenant-1"
278+
input = <<JSON
279+
{
280+
"key1": "value1",
281+
"key2": "value2"
282+
}
283+
JSON
284+
}
285+
`, rName, testData)
286+
}

0 commit comments

Comments
 (0)