Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ go 1.24.0
replace github.com/jmespath/go-jmespath => github.com/AndrewKlopper/go-jmespath v0.4.1

require (
github.com/aws/aws-sdk-go-v2 v1.43.2
github.com/aws/aws-sdk-go-v2 v1.43.4
github.com/aws/aws-sdk-go-v2/config v1.32.5
github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.20.29
github.com/aws/aws-sdk-go-v2/service/acm v1.37.18
Expand Down Expand Up @@ -54,13 +54,14 @@ require (
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.41 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.33 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.33 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect
github.com/aws/aws-sdk-go-v2/service/codeartifact v1.30.3 // indirect
github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.32.9 // indirect
github.com/aws/aws-sdk-go-v2/service/ecr v1.36.6 // indirect
github.com/aws/aws-sdk-go-v2/service/elasticache v1.56.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.16 // indirect
Expand All @@ -73,7 +74,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect
github.com/aws/smithy-go v1.27.5 // indirect
github.com/aws/smithy-go v1.27.6 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
Expand Down
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aws/aws-sdk-go-v2 v1.43.2 h1:cl+IXwWb3qazClUcm08tGSsB6OiuV83JVJO9B0jQcPc=
github.com/aws/aws-sdk-go-v2 v1.43.2/go.mod h1:WEzLKBh/mEjXvx1FtQMWgSxMSTVqxQzjkRtk5fa3wkg=
github.com/aws/aws-sdk-go-v2 v1.43.4 h1:b9FTvbRwy+JCsfp2Wp6wV/KbOx3Aj7nkoFb2cRX0IhE=
github.com/aws/aws-sdk-go-v2 v1.43.4/go.mod h1:70vwSy16txshwG+g55WkpgPKDIByzHI8ccBsOteo3bQ=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
github.com/aws/aws-sdk-go-v2/config v1.32.5 h1:pz3duhAfUgnxbtVhIK39PGF/AHYyrzGEyRD9Og0QrE8=
Expand All @@ -28,8 +30,12 @@ github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.41 h1:hqcxMc2g/MwwnRMod9n6
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.41/go.mod h1:d1eH0VrttvPmrCraU68LOyNdu26zFxQFjrVSb5vdhog=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.33 h1:HAp1wLFZzch054uh3FK7rcVYg4v7J2FxVf3h3IGNZas=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.33/go.mod h1:mJk5fmqnF+WUlMdPG37pR2Fh3oh6r8F6ZGUgPKvzu0c=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35 h1:kzVuGlatQtYinwBJEEyLAbggepCoavosiaHHX9+fD+c=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35/go.mod h1:0yLx0yEI+SfqeJMPvOtIEFoZbiQYXMGszBueiutQyaI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.33 h1:0YA0aCKgsJyno6xkFfaIgjE3/wK08+Qxo9nQfe1UrWM=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.33/go.mod h1:UZqj4WIdTH+ga8Y/DgpAuy/8cGjM3h7gDCliJYGg2SE=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35 h1:WK6CjihTuLisCjSKKbildJ79sGZZgbBz3iNa7VsKIhU=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35/go.mod h1:KYleN57luLoe97R7vTnx8PMcVrr9gAcRECtOjl91DNg=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic=
Expand Down Expand Up @@ -62,6 +68,8 @@ github.com/aws/aws-sdk-go-v2/service/ecr v1.36.6 h1:zg+3FGHA0PBs0KM25qE/rOf2o5zs
github.com/aws/aws-sdk-go-v2/service/ecr v1.36.6/go.mod h1:ZSq54Z9SIsOTf1Efwgw1msilSs4XVEfVQiP9nYVnKpM=
github.com/aws/aws-sdk-go-v2/service/ecs v1.52.0 h1:7/vgFWplkusJN/m+3QOa+W9FNRqa8ujMPNmdufRaJpg=
github.com/aws/aws-sdk-go-v2/service/ecs v1.52.0/go.mod h1:dPTOvmjJQ1T7Q+2+Xs2KSPrMvx+p0rpyV+HsQVnUK4o=
github.com/aws/aws-sdk-go-v2/service/elasticache v1.56.4 h1:ApnIXsRMPkYY4ehi+SVuSmarkvWerqIncHtR2jPFthI=
github.com/aws/aws-sdk-go-v2/service/elasticache v1.56.4/go.mod h1:cOZC/yZzWPVLKlsEyvgzaGQUisyPcTAf4dPbRPekl9s=
github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.17 h1:ltbEzdlO5qKYK1FuwTt2LibddWFmH/QY6usxvPOQP08=
github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.17/go.mod h1:KXFNdzl+mZpQlLYm378Ml18wBHybbMpyBwNXuYjbDT4=
github.com/aws/aws-sdk-go-v2/service/iam v1.53.1 h1:xNCUk9XN6Pa9PyzbEfzgRpvEIVlqtth402yjaWvNMu4=
Expand Down Expand Up @@ -110,6 +118,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk=
github.com/aws/smithy-go v1.27.5 h1:d1ro7KpYOYwP6m73YFa+Kc/A130VsAdX68SpsJwARMM=
github.com/aws/smithy-go v1.27.5/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/aws/smithy-go v1.27.6 h1:0zjT8jgK3jbrTT7JJ3EE6JsMhX8JTrZ+f1sEndYDXrA=
github.com/aws/smithy-go v1.27.6/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
Expand Down
4 changes: 4 additions & 0 deletions integ/aws/storage/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ docdb.cluster: ## Test DocDB DatabaseCluster L2 (live DocumentDB cluster + insta
go test -v -count 1 -timeout 45m ./... -run ^TestDocdbCluster$
.PHONY: docdb.cluster

elasticache.serverless-cache: ## Test ElastiCache ServerlessCache L2 (live Valkey 8 + IamUser + UserGroup)
go test -v -count 1 -timeout 30m ./... -run ^TestElasticacheServerlessCache$
.PHONY: elasticache.serverless-cache

bucket-notifications: ## Test S3 Bucket with EventBridge Notifications
go test -v -count 1 -timeout 15m ./... -run ^TestBucketNotifications$
.PHONY: bucket-notifications
95 changes: 95 additions & 0 deletions integ/aws/storage/apps/elasticache.serverless-cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Live test for the storage.elasticache ServerlessCache L2 (alpha port):
// mirrors upstream integ.serverless-cache.ts -- a real Valkey 8 serverless
// cache with an IamUser + UserGroup, KMS key, security group, backup settings
// and cache usage limits. Validates the full aws_elasticache_serverless_cache
// mapping plus user/user-group wiring against live AWS.
// https://github.com/aws/aws-cdk/blob/v2.263.0/packages/@aws-cdk/aws-elasticache-alpha/test/integ.serverless-cache.ts
import { App, LocalBackend, TerraformOutput } from "cdktn";
import { aws, Size } from "../../../../src";

const environmentName = process.env.ENVIRONMENT_NAME ?? "test";
const region = process.env.AWS_REGION ?? "us-east-1";
const outdir = process.env.OUT_DIR ?? "cdktf.out";
const stackName = process.env.STACK_NAME ?? "elasticache.serverless-cache";

const app = new App({
outdir,
});

const stack = new aws.AwsStack(app, stackName, {
gridUUID: "g00000000-0000",
environmentName,
providerConfig: {
region,
},
});
new LocalBackend(stack, {
path: `${stackName}.tfstate`,
});

const vpc = new aws.compute.Vpc(stack, "Vpc", {
maxAzs: 2,
natGateways: 0,
subnetConfiguration: [
{
name: "isolated",
subnetType: aws.compute.SubnetType.PRIVATE_ISOLATED,
cidrMask: 24,
},
],
});

const key = new aws.encryption.Key(stack, "Key", {});
const securityGroup = new aws.compute.SecurityGroup(stack, "SecurityGroup", {
vpc,
});

const user = new aws.storage.elasticache.IamUser(stack, "User", {
userId: "cacheuser",
accessControl: aws.storage.elasticache.AccessControl.fromAccessString(
"on ~* +@all",
),
});
const userGroup = new aws.storage.elasticache.UserGroup(stack, "UserGroup", {
users: [user],
userGroupName: "usergroup",
});

const cache = new aws.storage.elasticache.ServerlessCache(stack, "Cache", {
description: "Serverless cache",
vpc,
engine: aws.storage.elasticache.CacheEngine.VALKEY_8,
serverlessCacheName: "serverlesscache",
kmsKey: key,
vpcSubnets: { subnetType: aws.compute.SubnetType.PRIVATE_ISOLATED },
securityGroups: [securityGroup],
userGroup,
backup: {
backupRetentionLimit: 2,
backupNameBeforeDeletion: "last-snapshot-name",
},
cacheUsageLimits: {
dataStorageMinimumSize: Size.gibibytes(1),
dataStorageMaximumSize: Size.gibibytes(1),
requestRateLimitMinimum: 1_000,
requestRateLimitMaximum: 2_000,
},
});

const clientSG = new aws.compute.SecurityGroup(stack, "ClientSG", { vpc });
clientSG.connections.allowToDefaultPort(cache);

new TerraformOutput(stack, "cache_name", {
value: cache.serverlessCacheName,
staticId: true,
});
new TerraformOutput(stack, "user_id", {
value: user.userId,
staticId: true,
});
new TerraformOutput(stack, "user_group_id", {
value: userGroup.userGroupName,
staticId: true,
});

app.synth();
78 changes: 78 additions & 0 deletions integ/aws/storage/elasticache_serverless_cache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package test

import (
"context"
"testing"

"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/elasticache"
"github.com/gruntwork-io/terratest/modules/terraform"
test_structure "github.com/gruntwork-io/terratest/modules/test-structure"
"github.com/stretchr/testify/require"
)

// Run the apps/elasticache.serverless-cache.ts integration test: a real
// Valkey 8 serverless cache with IamUser + UserGroup through the
// storage.elasticache alpha port. Mirrors upstream's integ assertions
// (describeServerlessCaches engine/version/status) plus user/user-group
// read-backs and the post-apply drift oracle.
func TestElasticacheServerlessCache(t *testing.T) {
runStorageIntegrationTest(t, "elasticache.serverless-cache", "us-east-1", validateElasticacheServerlessCache)
}

func validateElasticacheServerlessCache(t *testing.T, tfWorkingDir string, awsRegion string) {
terraformOptions := test_structure.LoadTerraformOptions(t, tfWorkingDir)
outputs := terraform.OutputAll(t, terraformOptions)

cacheName := outputs["cache_name"].(string)
userID := outputs["user_id"].(string)
userGroupID := outputs["user_group_id"].(string)

ctx := context.Background()
cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(awsRegion))
require.NoError(t, err)
client := elasticache.NewFromConfig(cfg)

// --- 1. Serverless cache read-back (upstream integ asserts the same fields). ---
sc, err := client.DescribeServerlessCaches(ctx, &elasticache.DescribeServerlessCachesInput{
ServerlessCacheName: &cacheName,
})
require.NoError(t, err)
require.Len(t, sc.ServerlessCaches, 1)
c := sc.ServerlessCaches[0]
require.Equal(t, "available", *c.Status)
require.Equal(t, "valkey", *c.Engine)
require.Equal(t, "8", *c.MajorEngineVersion)
require.NotNil(t, c.CacheUsageLimits)
require.Equal(t, int32(1), *c.CacheUsageLimits.DataStorage.Minimum)
require.Equal(t, int32(1), *c.CacheUsageLimits.DataStorage.Maximum)
require.Equal(t, int32(1000), *c.CacheUsageLimits.ECPUPerSecond.Minimum)
require.Equal(t, int32(2000), *c.CacheUsageLimits.ECPUPerSecond.Maximum)
require.NotNil(t, c.Endpoint)
t.Logf("elasticache-serverless: %s available (valkey %s at %s:%d, limits applied)",
cacheName, *c.MajorEngineVersion, *c.Endpoint.Address, *c.Endpoint.Port)

// --- 2. IAM user read-back. ---
du, err := client.DescribeUsers(ctx, &elasticache.DescribeUsersInput{
UserId: &userID,
})
require.NoError(t, err)
require.Len(t, du.Users, 1)
require.Equal(t, "active", *du.Users[0].Status)
require.Equal(t, "iam", string(du.Users[0].Authentication.Type))
t.Logf("elasticache-serverless: user %s active (iam auth)", userID)

// --- 3. User group contains the user and is attached. ---
dg, err := client.DescribeUserGroups(ctx, &elasticache.DescribeUserGroupsInput{
UserGroupId: &userGroupID,
})
require.NoError(t, err)
require.Len(t, dg.UserGroups, 1)
require.Contains(t, dg.UserGroups[0].UserIds, userID)
t.Logf("elasticache-serverless: user group %s contains %s", userGroupID, userID)

// --- Drift oracle: re-planning the already-applied stack must show zero changes. ---
planExitCode := terraform.PlanExitCode(t, terraformOptions)
require.Equal(t, terraform.DefaultSuccessExitCode, planExitCode,
"expected `tofu plan -detailed-exitcode` to report no drift after apply (got exit code %d)", planExitCode)
}
47 changes: 47 additions & 0 deletions src/aws/storage/elasticache/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// https://github.com/aws/aws-cdk/blob/v2.263.0/packages/@aws-cdk/aws-elasticache-alpha/lib/common.ts

/**
* Engine type for ElastiCache users and user groups.
*
* Use the named static members for the engines currently supported by ElastiCache
* user/user-group resources. To target an engine not yet represented by a named
* instance, use `UserEngine.of(engineType)`.
*/
export class UserEngine {
/**
* Valkey engine.
*/
public static readonly VALKEY = UserEngine.of("valkey");

/**
* Redis engine.
*/
public static readonly REDIS = UserEngine.of("redis");

/**
* Create a new `UserEngine` with an arbitrary engine type.
*
* @param engineType the engine type (for example, `'valkey'` or `'redis'`)
*/
public static of(engineType: string): UserEngine {
return new UserEngine(engineType);
}

/**
* The engine type, for example `'valkey'` or `'redis'`.
* Maps directly to the `Engine` property of `AWS::ElastiCache::User` and
* `AWS::ElastiCache::UserGroup`.
*/
public readonly engineType: string;

private constructor(engineType: string) {
this.engineType = engineType;
}

/**
* Returns the engine type as a string (for example, `'valkey'`).
*/
public toString(): string {
return this.engineType;
}
}
Loading
Loading