Este é o Guia do Desenvolvedor do AWS CDK v2. O CDK v1 antigo entrou em manutenção em 1º de junho de 2022 e encerrou o suporte em 1º de junho de 2023.
Tokens e o AWS CDK
No AWS Cloud Development Kit (AWS CDK), os tokens são espaços reservados para valores que não são conhecidos ao definir constructos ou sintetizar pilhas. Esses valores serão totalmente resolvidos na implantação, quando sua infraestrutura real for criada. Ao desenvolver aplicativos AWS CDK, você trabalhará com tokens para gerenciar esses valores em todo o seu aplicativo.
Exemplo de token
A seguir temos um exemplo de uma pilha CDK que define uma constructo para um bucket do Amazon Simple Storage Service (Amazon S3). Como o nome do nosso bucket ainda não é conhecido, o valor de bucketName
é armazenado como um token:
- TypeScript
-
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
export class CdkDemoAppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Define an S3 bucket
const myBucket = new s3.Bucket(this, 'myBucket');
// Store value of the S3 bucket name
const myBucketName = myBucket.bucketName;
// Print the current value for the S3 bucket name at synthesis
console.log("myBucketName: " + bucketName);
}
}
- JavaScript
-
const { Stack, Duration } = require('aws-cdk-lib');
const s3 = require('aws-cdk-lib/aws-s3');
class CdkDemoAppStack extends Stack {
constructor(scope, id, props) {
super(scope, id, props);
// Define an S3 bucket
const myBucket = new s3.Bucket(this, 'myBucket');
// Store value of the S3 bucket name
const myBucketName = myBucket.bucketName;
// Print the current value for the S3 bucket name at synthesis
console.log("myBucketName: " + myBucketName);
}
}
module.exports = { CdkDemoAppStack }
- Python
-
from aws_cdk import (
Stack
)
from constructs import Construct
from aws_cdk import aws_s3 as s3
class CdkDemoAppStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Define an S3 bucket
my_bucket = s3.Bucket(self, "myBucket")
# Store the value of the S3 bucket name
my_bucket_name = my_bucket.bucket_name
# Print the current value for the S3 bucket name at synthesis
print(f"myBucketName: {my_bucket_name}")
- Java
-
package com.myorg;
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.s3.Bucket;
import java.util.Map;
public class CdkDemoAppStack extends Stack {
public CdkDemoAppStack(final Construct scope, final String id) {
this(scope, id, null);
}
public CdkDemoAppStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
// Define an S3 bucket
Bucket myBucket = Bucket.Builder.create(this, "myBucket")
.build();
// Store the token for the bucket name
String myBucketName = myBucket.getBucketName();
// Print the token at synthesis
System.out.println("myBucketName: " + myBucketName);
}
}
- C#
-
using Amazon.CDK;
using Constructs;
using Amazon.CDK.AWS.S3;
namespace CdkDemoApp
{
public class CdkDemoAppStack : Stack
{
internal CdkDemoAppStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
{
// Define an S3 bucket
var myBucket = new Bucket(this, "myBucket");
// Store the token for the bucket name
var myBucketName = myBucket.BucketName;
// Print the token at synthesis
System.Console.WriteLine($"myBucketName: {myBucketName}");
}
}
}
- Go
-
package main
import (
"fmt"
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/aws-cdk-go/awscdk/v2/awss3"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
type CdkDemoAppStackProps struct {
awscdk.StackProps
}
func NewCdkDemoAppStack(scope constructs.Construct, id string, props *CdkDemoAppStackProps) awscdk.Stack {
var sprops awscdk.StackProps
if props != nil {
sprops = props.StackProps
}
stack := awscdk.NewStack(scope, &id, &sprops)
// Define an S3 bucket
myBucket := awss3.NewBucket(stack, jsii.String("myBucket"), &awss3.BucketProps{})
// Store the token for the bucket name
myBucketName := myBucket.BucketName()
// Print the token at synthesis
fmt.Println("myBucketName: ", *myBucketName)
return stack
}
// ...
Quando executamos cdk synth
para sintetizar nossa pilha, o valor de myBucketName
será exibido no formato de token ${Token[TOKEN.1234
]}
. Esse formato de token é resultado de como o AWS CDK codifica os tokens. Neste exemplo, o token é codificado como uma string:
$
cdk synth --quiet
myBucketName: ${Token[TOKEN.21
]}
Como o valor do nome do nosso bucket não é conhecido na síntese, o token é renderizado como myBucket<unique-hash>
. Nosso modelo AWS CloudFormation usa a função intrínseca Ref
para referenciar seu valor, que será conhecido na implantação:
Resources:
myBucket5AF9C99B
:
# ...
Outputs:
bucketNameOutput:
Description: The name of the S3 bucket
Value:
Ref: myBucket5AF9C99B
Para obter mais informações sobre como o hash exclusivo é gerado, consulte IDs lógicos gerados em seu modelo do AWS CloudFormation.
Passando tokens
Os tokens podem ser passados como se fossem o valor real que representam. Veja a seguir um exemplo que passa o token do nome do nosso bucket para um constructo de uma função AWS Lambda:
- TypeScript
-
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as lambda from 'aws-cdk-lib/aws-lambda';
export class CdkDemoAppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Define an S3 bucket
const myBucket = new s3.Bucket(this, 'myBucket');
// ...
// Define a Lambda function
const myFunction = new lambda.Function(this, "myFunction", {
runtime: lambda.Runtime.NODEJS_20_X,
handler: "index.handler",
code: lambda.Code.fromInline(`
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`),
functionName: myBucketName + "Function", // Pass token for the S3 bucket name
environment: {
BUCKET_NAME: myBucketName, // Pass token for the S3 bucket name
}
});
}
}
- JavaScript
-
const { Stack, Duration } = require('aws-cdk-lib');
const s3 = require('aws-cdk-lib/aws-s3');
const lambda = require('aws-cdk-lib/aws-lambda');
class CdkDemoAppStack extends Stack {
constructor(scope, id, props) {
super(scope, id, props);
// Define an S3 bucket
const myBucket = new s3.Bucket(this, 'myBucket');
// ...
// Define a Lambda function
const myFunction = new lambda.Function(this, 'myFunction', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromInline(`
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`),
functionName: myBucketName + 'Function', // Pass token for the S3 bucket name
environment: {
BUCKET_NAME: myBucketName, // Pass token for the S3 bucket name
}
});
}
}
module.exports = { CdkDemoAppStack }
- Python
-
from aws_cdk import (
Stack
)
from constructs import Construct
from aws_cdk import aws_s3 as s3
from aws_cdk import aws_lambda as _lambda
class CdkDemoAppStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Define an S3 bucket
my_bucket = s3.Bucket(self, "myBucket")
# ...
# Define a Lambda function
my_function = _lambda.Function(self, "myFunction",
runtime=_lambda.Runtime.NODEJS_20_X,
handler="index.handler",
code=_lambda.Code.from_inline("""
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
"""),
function_name=f"{my_bucket_name}Function", # Pass token for the S3 bucket name
environment={
"BUCKET_NAME": my_bucket_name # Pass token for the S3 bucket name
}
)
- Java
-
package com.myorg;
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.s3.Bucket;
import software.amazon.awscdk.services.lambda.Code;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;
import java.util.Map;
public class CdkDemoAppStack extends Stack {
public CdkDemoAppStack(final Construct scope, final String id) {
this(scope, id, null);
}
public CdkDemoAppStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
// Define an S3 bucket
Bucket myBucket = Bucket.Builder.create(this, "myBucket")
.build();
// ...
// Define a Lambda function
Function myFunction = Function.Builder.create(this, "myFunction")
.runtime(Runtime.NODEJS_20_X)
.handler("index.handler")
.code(Code.fromInline(
"exports.handler = async function(event) {" +
"return {" +
"statusCode: 200," +
"body: JSON.stringify('Hello World!')," +
"};" +
"};"
))
.functionName(myBucketName + "Function") // Pass the token for the s3 bucket to the function construct
.environment(Map.of("BUCKET_NAME", myBucketName)) // Pass the bucket name as environment variable
.build();
}
}
- C#
-
using Amazon.CDK;
using Constructs;
using Amazon.CDK.AWS.S3;
using Amazon.CDK.AWS.Lambda;
using System;
using System.Collections.Generic;
namespace CdkDemoApp
{
public class CdkDemoAppStack : Stack
{
internal CdkDemoAppStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
{
// Define an S3 bucket
var myBucket = new Bucket(this, "myBucket");
// ...
// Define a Lambda function
var myFunction = new Function(this, "myFunction", new FunctionProps
{
Runtime = Runtime.NODEJS_20_X,
Handler = "index.handler",
Code = Code.FromInline(@"
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
"),
// Pass the token for the S3 bucket name
Environment = new Dictionary<string, string>
{
{ "BUCKET_NAME", myBucketName }
},
FunctionName = $"{myBucketName}Function" // Pass the token for the s3 bucket to the function construct
});
}
}
}
- Go
-
package main
import (
"fmt"
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/aws-cdk-go/awscdk/v2/awslambda"
"github.com/aws/aws-cdk-go/awscdk/v2/awss3"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
type CdkDemoAppStackProps struct {
awscdk.StackProps
}
func NewCdkDemoAppStack(scope constructs.Construct, id string, props *CdkDemoAppStackProps) awscdk.Stack {
var sprops awscdk.StackProps
if props != nil {
sprops = props.StackProps
}
stack := awscdk.NewStack(scope, &id, &sprops)
// Define an S3 bucket
myBucket := awss3.NewBucket(stack, jsii.String("myBucket"), &awss3.BucketProps{})
// ...
// Define a Lambda function
myFunction := awslambda.NewFunction(stack, jsii.String("myFunction"), &awslambda.FunctionProps{
Runtime: awslambda.Runtime_NODEJS_20_X(),
Handler: jsii.String("index.handler"),
Code: awslambda.Code_FromInline(jsii.String(`
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`)),
FunctionName: jsii.String(fmt.Sprintf("%sFunction", *myBucketName)), // Pass the token for the S3 bucket to the function name
Environment: &map[string]*string{
"BUCKET_NAME": myBucketName,
},
})
return stack
}
// ...
Quando sintetizamos nosso modelo, as funções intrínsecas Ref
e as funções intrínsecas Fn::Join
são usadas para especificar os valores, que serão conhecidos na implantação:
Resources:
myBucket5AF9C99B
:
Type: AWS::S3::Bucket
# ...
myFunction884E1557
:
Type: AWS::Lambda::Function
Properties:
# ...
Environment:
Variables:
BUCKET_NAME:
Ref: myBucket5AF9C99B
FunctionName:
Fn::Join:
- ""
- - Ref: myBucket5AF9C99B
- Function
# ...
Como funciona a codificação de token
Tokens são objetos que implementam a interface IResolvable
, que contém um único método resolve
. Durante a síntese, o AWS CDK chama esse método para produzir o valor final dos tokens em seu modelo do CloudFormation.
Você raramente trabalhará diretamente com a interface IResolvable
. Provavelmente, você verá apenas versões codificadas por string dos tokens.
Tipos de codificação de token
Os tokens participam do processo de síntese para produzir valores arbitrários de qualquer tipo. Outras funções normalmente aceitam apenas argumentos de tipos básicos, como string
ou number
. Para usar tokens nesses casos, você pode codificá-los em um dos três tipos usando métodos estáticos na classe cdk.Token
.
Eles pegam um valor arbitrário, que pode ser um IResolvable
, e os codificam em um valor primitivo do tipo indicado.
Como qualquer um dos tipos anteriores pode ser potencialmente um token codificado, tenha cuidado ao analisar ou tentar ler seu conteúdo. Por exemplo, se você tentar analisar uma string para extrair um valor dela, e a string for um token codificado, sua análise falhará. Da mesma forma, se você tentar consultar o comprimento de uma matriz ou realizar operações matemáticas com um número, primeiro verifique se eles não são tokens codificados.
Como verificar se há tokens em seu aplicativo
Para verificar se um valor tem um token não resolvido, chame o método Token.isUnresolved
(Python: is_unresolved
). Veja a seguir um exemplo que verifica se o valor do nome do nosso bucket do Amazon S3 é um token. Se não for um token, então validamos o tamanho do nome do bucket:
- TypeScript
-
// ...
export class CdkDemoAppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Define an S3 bucket
const myBucket = new s3.Bucket(this, 'myBucket');
// ...
// Check if bucket name is a token. If not, check if length is less than 10 characters
if (cdk.Token.isUnresolved(myBucketName)) {
console.log("Token identified.");
} else if (!cdk.Token.isUnresolved(myBucketName) && myBucketName.length > 10) {
throw new Error('Maximum length for name is 10 characters.');
};
// ...
- JavaScript
-
const { Stack, Duration, Token, CfnOutput } = require('aws-cdk-lib');
// ...
class CdkDemoAppStack extends Stack {
constructor(scope, id, props) {
super(scope, id, props);
// Define an S3 bucket
const myBucket = new s3.Bucket(this, 'myBucket');
// ...
// Check if bucket name is a token. If not, check if length is less than 10 characters
if (Token.isUnresolved(myBucketName)) {
console.log("Token identified.");
} else if (!Token.isUnresolved(myBucketName) && myBucketName.length > 10) {
throw new Error('Maximum length for name is 10 characters.');
};
// ...
- Python
-
from aws_cdk import (
Stack,
Token
)
# ...
class CdkDemoAppStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Define an S3 bucket
my_bucket = s3.Bucket(self, "myBucket")
# ...
# Check if bucket name is a token. If not, check if length is less than 10 characters
if Token.is_unresolved(my_bucket_name):
print("Token identified.")
elif not Token.is_unresolved(my_bucket_name) and len(my_bucket_name) < 10:
raise ValueError("Maximum length for name is 10 characters.")
# ...
- Java
-
// ...
import software.amazon.awscdk.Token;
// ...
public class CdkDemoAppStack extends Stack {
public CdkDemoAppStack(final Construct scope, final String id) {
this(scope, id, null);
}
public CdkDemoAppStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
// Define an S3 bucket
Bucket myBucket = Bucket.Builder.create(this, "myBucket")
.build();
// ...
// Check if the bucket name is a token. If not, check if length is less than 10 characters
if (Token.isUnresolved(myBucketName)) {
System.out.println("Token identified.");
} else if (!Token.isUnresolved(myBucketName) && myBucketName.length() > 10) {
throw new IllegalArgumentException("Maximum length for name is 10 characters.");
}
// ...
}
}
- C#
-
using Amazon.CDK;
using Constructs;
using Amazon.CDK.AWS.S3;
using Amazon.CDK.AWS.Lambda;
using System;
using System.Collections.Generic;
namespace CdkDemoApp
{
public class CdkDemoAppStack : Stack
{
internal CdkDemoAppStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
{
// Define an S3 bucket
var myBucket = new Bucket(this, "myBucket");
// ...
// Check if bucket name is a token. If not, check if length is less than 10 characters
if (Token.IsUnresolved(myBucketName))
{
System.Console.WriteLine("Token identified.");
}
else if (!Token.IsUnresolved(myBucketName) && myBucketName.Length > 10)
{
throw new System.Exception("Maximum length for name is 10 characters.");
}
// ...
- Go
-
// ...
func NewCdkDemoAppStack(scope constructs.Construct, id string, props *CdkDemoAppStackProps) awscdk.Stack {
var sprops awscdk.StackProps
if props != nil {
sprops = props.StackProps
}
stack := awscdk.NewStack(scope, &id, &sprops)
// Define an S3 bucket
myBucket := awss3.NewBucket(stack, jsii.String("myBucket"), &awss3.BucketProps{})
// ...
// Check if the bucket name is unresolved (a token)
if tokenUnresolved := awscdk.Token_IsUnresolved(myBucketName); tokenUnresolved != nil && *tokenUnresolved {
fmt.Println("Token identified.")
} else if tokenUnresolved != nil && !*tokenUnresolved && len(*myBucketName) > 10 {
panic("Maximum length for name is 10 characters.")
}
// ...
Quando executamos cdk synth
, myBucketName
é identificado como um token:
$
cdk synth --quiet
Token identified.
Você pode usar codificações de token para escapar do sistema de tipos. Por exemplo, você pode codificar em string um token que produz um valor numérico no momento da síntese. Se você usar essas funções, é sua responsabilidade garantir que seu modelo seja resolvido em um estado utilizável após a síntese.
Trabalhando com tokens codificados por string
Os tokens codificados por string são semelhantes aos seguintes:
${TOKEN[Bucket.Name.1234]}
Eles podem ser transmitidos como strings regulares e podem ser concatenados, conforme mostrado no exemplo a seguir.
- TypeScript
-
const functionName = bucket.bucketName + 'Function';
- JavaScript
-
const functionName = bucket.bucketName + 'Function';
- Python
-
function_name = bucket.bucket_name + "Function"
- Java
-
String functionName = bucket.getBucketName().concat("Function");
- C#
-
string functionName = bucket.BucketName + "Function";
- Go
-
functionName := *bucket.BucketName() + "Function"
Você também pode usar interpolação de strings, se seu idioma for compatível, conforme mostrado no exemplo a seguir.
- TypeScript
-
const functionName = `${bucket.bucketName}Function`;
- JavaScript
-
const functionName = `${bucket.bucketName}Function`;
- Python
-
function_name = f"{bucket.bucket_name}Function"
- Java
-
String functionName = String.format("%sFunction". bucket.getBucketName());
- C#
-
string functionName = $"${bucket.bucketName}Function";
- Go
-
Use fmt.Sprintf
para uma funcionalidade semelhante:
functionName := fmt.Sprintf("%sFunction", *bucket.BucketName())
Evite manipular a string de outras formas. Por exemplo, pegar uma substring de uma string provavelmente quebrará o token da string.
Trabalhando com tokens codificados em lista
Os tokens codificados em lista são semelhantes aos seguintes:
["#{TOKEN[Stack.NotificationArns.1234]}"]
A única coisa segura a fazer com essas listas é passá-las diretamente para outros constructos. Os tokens no formato de lista de strings não podem ser concatenados, nem um elemento pode ser retirado do token. A única maneira segura de manipulá-los é usando funções intrínsecas AWS CloudFormation como Fn.Select.
Trabalhando com tokens codificados por números
Os tokens codificados por números são um conjunto de pequenos números negativos de ponto flutuante que se parecem com os seguintes.
-1.8881545897087626e+289
Assim como acontece com os tokens da lista, você não pode modificar o valor do número, pois isso provavelmente quebrará o token numérico.
A seguir temos um exemplo de um constructo que contém um token codificado como um número:
- TypeScript
-
import { Stack, Duration, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
export class CdkDemoAppStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// Define a new VPC
const vpc = new ec2.Vpc(this, 'MyVpc', {
maxAzs: 3, // Maximum number of availability zones to use
});
// Define an RDS database cluster
const dbCluster = new rds.DatabaseCluster(this, 'MyRDSCluster', {
engine: rds.DatabaseClusterEngine.AURORA,
instanceProps: {
vpc,
},
});
// Get the port token (this is a token encoded as a number)
const portToken = dbCluster.clusterEndpoint.port;
// Print the value for our token at synthesis
console.log("portToken: " + portToken);
}
}
- JavaScript
-
const { Stack, Duration } = require('aws-cdk-lib');
const lambda = require('aws-cdk-lib/aws-lambda');
const rds = require('aws-cdk-lib/aws-rds');
const ec2 = require('aws-cdk-lib/aws-ec2');
class CdkDemoAppStack extends Stack {
constructor(scope, id, props) {
super(scope, id, props);
// Define a new VPC
const vpc = new ec2.Vpc(this, 'MyVpc', {
maxAzs: 3, // Maximum number of availability zones to use
});
// Define an RDS database cluster
const dbCluster = new rds.DatabaseCluster(this, 'MyRDSCluster', {
engine: rds.DatabaseClusterEngine.AURORA,
instanceProps: {
vpc,
},
});
// Get the port token (this is a token encoded as a number)
const portToken = dbCluster.clusterEndpoint.port;
// Print the value for our token at synthesis
console.log("portToken: " + portToken);
}
}
module.exports = { CdkDemoAppStack }
- Python
-
from aws_cdk import (
Duration,
Stack,
)
from aws_cdk import aws_rds as rds
from aws_cdk import aws_ec2 as ec2
from constructs import Construct
class CdkDemoAppStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Define a new VPC
vpc = ec2.Vpc(self, 'MyVpc',
max_azs=3 # Maximum number of availability zones to use
)
# Define an RDS database cluster
db_cluster = rds.DatabaseCluster(self, 'MyRDSCluster',
engine=rds.DatabaseClusterEngine.AURORA,
instance_props=rds.InstanceProps(
vpc=vpc
)
)
# Get the port token (this is a token encoded as a number)
port_token = db_cluster.cluster_endpoint.port
# Print the value for our token at synthesis
print(f"portToken: {port_token}")
- Java
-
package com.myorg;
import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.ec2.Vpc;
import software.amazon.awscdk.services.rds.DatabaseCluster;
import software.amazon.awscdk.services.rds.DatabaseClusterEngine;
import software.amazon.awscdk.services.rds.InstanceProps;
public class CdkDemoAppStack extends Stack {
public CdkDemoAppStack(final Construct scope, final String id) {
this(scope, id, null);
}
public CdkDemoAppStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
// Define a new VPC
Vpc vpc = Vpc.Builder.create(this, "MyVpc")
.maxAzs(3) // Maximum number of availability zones to use
.build();
// Define an RDS database cluster
DatabaseCluster dbCluster = DatabaseCluster.Builder.create(this, "MyRDSCluster")
.engine(DatabaseClusterEngine.AURORA)
.instanceProps(InstanceProps.builder()
.vpc(vpc)
.build())
.build();
// Get the port token (this is a token encoded as a number)
Number portToken = dbCluster.getClusterEndpoint().getPort();
// Print the value for our token at synthesis
System.out.println("portToken: " + portToken);
}
}
- C#
-
using Amazon.CDK;
using Constructs;
using Amazon.CDK.AWS.EC2;
using Amazon.CDK.AWS.RDS;
using System;
using System.Collections.Generic;
namespace CdkDemoApp
{
public class CdkDemoAppStack : Stack
{
internal CdkDemoAppStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
{
// Define a new VPC
var vpc = new Vpc(this, "MyVpc", new VpcProps
{
MaxAzs = 3 // Maximum number of availability zones to use
});
// Define an RDS database cluster
var dbCluster = new DatabaseCluster(this, "MyRDSCluster", new DatabaseClusterProps
{
Engine = DatabaseClusterEngine.AURORA, // Remove parentheses
InstanceProps = new Amazon.CDK.AWS.RDS.InstanceProps // Specify RDS InstanceProps
{
Vpc = vpc
}
});
// Get the port token (this is a token encoded as a number)
var portToken = dbCluster.ClusterEndpoint.Port;
// Print the value for our token at synthesis
System.Console.WriteLine($"portToken: {portToken}");
}
}
}
- Go
-
package main
import (
"fmt"
"github.com/aws/aws-cdk-go/awscdk/v2"
"github.com/aws/aws-cdk-go/awscdk/v2/awsec2"
"github.com/aws/aws-cdk-go/awscdk/v2/awsrds"
"github.com/aws/constructs-go/constructs/v10"
"github.com/aws/jsii-runtime-go"
)
type CdkDemoAppStackProps struct {
awscdk.StackProps
}
func NewCdkDemoAppStack(scope constructs.Construct, id string, props *CdkDemoAppStackProps) awscdk.Stack {
var sprops awscdk.StackProps
if props != nil {
sprops = props.StackProps
}
stack := awscdk.NewStack(scope, &id, &sprops)
// Define a new VPC
vpc := awsec2.NewVpc(stack, jsii.String("MyVpc"), &awsec2.VpcProps{
MaxAzs: jsii.Number(3), // Maximum number of availability zones to use
})
// Define an RDS database cluster
dbCluster := awsrds.NewDatabaseCluster(stack, jsii.String("MyRDSCluster"), &awsrds.DatabaseClusterProps{
Engine: awsrds.DatabaseClusterEngine_AURORA(),
InstanceProps: &awsrds.InstanceProps{
Vpc: vpc,
},
})
// Get the port token (this is a token encoded as a number)
portToken := dbCluster.ClusterEndpoint().Port()
// Print the value for our token at synthesis
fmt.Println("portToken: ", portToken)
return stack
}
// ...
Quando executamos cdk synth
, o valor de portToken
é exibido como um token codificado por número:
$
cdk synth --quiet
portToken: -1.8881545897087968e+289
Passar tokens codificados por números
Quando você passa tokens codificados em números para outros constructos, pode fazer sentido convertê-los em strings primeiro. Por exemplo, se você quiser usar o valor de uma string codificada por número como parte de uma string concatenada, convertê-la ajuda na legibilidade.
No exemplo a seguir, portToken
é um token codificado em números que queremos passar para nossa função do Lambda como parte de connectionString
:
- TypeScript
-
import { Stack, Duration, CfnOutput, StackProps } from 'aws-cdk-lib';
// ...
import * as lambda from 'aws-cdk-lib/aws-lambda';
export class CdkDemoAppStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// Define a new VPC
// ...
// Define an RDS database cluster
// ...
// Get the port token (this is a token encoded as a number)
const portToken = dbCluster.clusterEndpoint.port;
// ...
// Example connection string with the port token as a number
const connectionString = `jdbc:mysql://mydb.cluster.amazonaws.com:${portToken}/mydatabase`;
// Use the connection string as an environment variable in a Lambda function
const myFunction = new lambda.Function(this, 'MyLambdaFunction', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromInline(`
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`),
environment: {
DATABASE_CONNECTION_STRING: connectionString, // Using the port token as part of the string
},
});
// Output the value of our connection string at synthesis
console.log("connectionString: " + connectionString);
// Output the connection string
new CfnOutput(this, 'ConnectionString', {
value: connectionString,
});
}
}
- JavaScript
-
const { Stack, Duration, CfnOutput } = require('aws-cdk-lib');
// ...
const lambda = require('aws-cdk-lib/aws-lambda');
class CdkDemoAppStack extends Stack {
constructor(scope, id, props) {
super(scope, id, props);
// Define a new VPC
// ...
// Define an RDS database cluster
// ...
// Get the port token (this is a token encoded as a number)
const portToken = dbCluster.clusterEndpoint.port;
// ...
// Example connection string with the port token as a number
const connectionString = `jdbc:mysql://mydb.cluster.amazonaws.com:${portToken}/mydatabase`;
// Use the connection string as an environment variable in a Lambda function
const myFunction = new lambda.Function(this, 'MyLambdaFunction', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromInline(`
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`),
environment: {
DATABASE_CONNECTION_STRING: connectionString, // Using the port token as part of the string
},
});
// Output the value of our connection string at synthesis
console.log("connectionString: " + connectionString);
// Output the connection string
new CfnOutput(this, 'ConnectionString', {
value: connectionString,
});
}
}
module.exports = { CdkDemoAppStack }
- Python
-
from aws_cdk import (
Duration,
Stack,
CfnOutput,
)
from aws_cdk import aws_lambda as _lambda
# ...
class CdkDemoAppStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Define a new VPC
# ...
# Define an RDS database cluster
# ...
# Get the port token (this is a token encoded as a number)
port_token = db_cluster.cluster_endpoint.port
# ...
# Example connection string with the port token as a number
connection_string = f"jdbc:mysql://mydb.cluster.amazonaws.com:{port_token}/mydatabase"
# Use the connection string as an environment variable in a Lambda function
my_function = _lambda.Function(self, 'MyLambdaFunction',
runtime=_lambda.Runtime.NODEJS_20_X,
handler='index.handler',
code=_lambda.Code.from_inline("""
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
"""),
environment={
'DATABASE_CONNECTION_STRING': connection_string # Using the port token as part of the string
}
)
# Output the value of our connection string at synthesis
print(f"connectionString: {connection_string}")
# Output the connection string
CfnOutput(self, 'ConnectionString',
value=connection_string
)
- Java
-
// ...
import software.amazon.awscdk.CfnOutput;
import software.amazon.awscdk.services.lambda.Function;
import software.amazon.awscdk.services.lambda.Runtime;
import software.amazon.awscdk.services.lambda.Code;
import java.util.Map;
public class CdkDemoAppStack extends Stack {
public CdkDemoAppStack(final Construct scope, final String id) {
this(scope, id, null);
}
public CdkDemoAppStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
// Define a new VPC
// ...
// Define an RDS database cluster
// ...
// Get the port token (this is a token encoded as a number)
Number portToken = dbCluster.getClusterEndpoint().getPort();
// ...
// Example connection string with the port token as a number
String connectionString = "jdbc:mysql://mydb.cluster.amazonaws.com:" + portToken + "/mydatabase";
// Use the connection string as an environment variable in a Lambda function
Function myFunction = Function.Builder.create(this, "MyLambdaFunction")
.runtime(Runtime.NODEJS_20_X)
.handler("index.handler")
.code(Code.fromInline(
"exports.handler = async function(event) {\n" +
" return {\n" +
" statusCode: 200,\n" +
" body: JSON.stringify('Hello World!'),\n" +
" };\n" +
"};"))
.environment(Map.of(
"DATABASE_CONNECTION_STRING", connectionString // Using the port token as part of the string
))
.build();
// Output the value of our connection string at synthesis
System.out.println("connectionString: " + connectionString);
// Output the connection string
CfnOutput.Builder.create(this, "ConnectionString")
.value(connectionString)
.build();
}
}
- C#
-
// ...
using Amazon.CDK.AWS.Lambda;
namespace CdkDemoApp
{
public class CdkDemoAppStack : Stack
{
internal CdkDemoAppStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
{
// Define a new VPC
// ...
// Define an RDS database cluster
var dbCluster = new DatabaseCluster(this, "MyRDSCluster", new DatabaseClusterProps
// ...
// Get the port token (this is a token encoded as a number)
var portToken = dbCluster.ClusterEndpoint.Port;
// ...
// Example connection string with the port token as a number
var connectionString = $"jdbc:mysql://mydb.cluster.amazonaws.com:{portToken}/mydatabase";
// Use the connection string as an environment variable in a Lambda function
var myFunction = new Function(this, "MyLambdaFunction", new FunctionProps
{
Runtime = Runtime.NODEJS_20_X,
Handler = "index.handler",
Code = Code.FromInline(@"
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
"),
Environment = new Dictionary<string, string>
{
{ "DATABASE_CONNECTION_STRING", connectionString } // Using the port token as part of the string
}
});
// Output the value of our connection string at synthesis
Console.WriteLine($"connectionString: {connectionString}");
// Output the connection string
new CfnOutput(this, "ConnectionString", new CfnOutputProps
{
Value = connectionString
});
}
}
}
- Go
-
// ...
"github.com/aws/aws-cdk-go/awscdk/v2/awslambda"
)
type CdkDemoAppStackProps struct {
awscdk.StackProps
}
func NewCdkDemoAppStack(scope constructs.Construct, id string, props *CdkDemoAppStackProps) awscdk.Stack {
var sprops awscdk.StackProps
if props != nil {
sprops = props.StackProps
}
stack := awscdk.NewStack(scope, &id, &sprops)
// Define a new VPC
// ...
// Define an RDS database cluster
// ...
// Get the port token (this is a token encoded as a number)
portToken := dbCluster.ClusterEndpoint().Port()
// ...
// Example connection string with the port token as a number
connectionString := fmt.Sprintf("jdbc:mysql://mydb.cluster.amazonaws.com:%s/mydatabase", portToken)
// Use the connection string as an environment variable in a Lambda function
myFunction := awslambda.NewFunction(stack, jsii.String("MyLambdaFunction"), &awslambda.FunctionProps{
Runtime: awslambda.Runtime_NODEJS_20_X(),
Handler: jsii.String("index.handler"),
Code: awslambda.Code_FromInline(jsii.String(`
exports.handler = async function(event) {
return {
statusCode: 200,
body: JSON.stringify('Hello World!'),
};
};
`)),
Environment: &map[string]*string{
"DATABASE_CONNECTION_STRING": jsii.String(connectionString), // Using the port token as part of the string
},
})
// Output the value of our connection string at synthesis
fmt.Println("connectionString: ", connectionString)
// Output the connection string
awscdk.NewCfnOutput(stack, jsii.String("ConnectionString"), &awscdk.CfnOutputProps{
Value: jsii.String(connectionString),
})
return stack
}
// ...
Se passarmos esse valor para connectionString
, o valor de saída quando executamos cdk synth
pode ser confuso devido à string codificada por números:
$
cdk synth --quiet
connectionString: jdbc:mysql://mydb.cluster.amazonaws.com:-1.888154589708796e+289/mydatabase
Para converter um token codificado por número em uma string, use cdk.Tokenization.stringifyNumber(token
)
. No exemplo a seguir, convertemos o token codificado por número em uma string antes de definir nossa string de conexão:
- TypeScript
-
import { Stack, Duration, Tokenization, CfnOutput, StackProps } from 'aws-cdk-lib';
// ...
export class CdkDemoAppStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
// Define a new VPC
// ...
// Define an RDS database cluster
// ...
// Get the port token (this is a token encoded as a number)
const portToken = dbCluster.clusterEndpoint.port;
// ...
// Convert the encoded number to an encoded string for use in the connection string
const portAsString = Tokenization.stringifyNumber(portToken);
// Example connection string with the port token as a string
const connectionString = `jdbc:mysql://mydb.cluster.amazonaws.com:${portAsString}/mydatabase`;
// Use the connection string as an environment variable in a Lambda function
const myFunction = new lambda.Function(this, 'MyLambdaFunction', {
// ...
environment: {
DATABASE_CONNECTION_STRING: connectionString, // Using the port token as part of the string
},
});
// Output the value of our connection string at synthesis
console.log("connectionString: " + connectionString);
// Output the connection string
new CfnOutput(this, 'ConnectionString', {
value: connectionString,
});
}
}
- JavaScript
-
const { Stack, Duration, Tokenization, CfnOutput } = require('aws-cdk-lib');
// ...
class CdkDemoAppStack extends Stack {
constructor(scope, id, props) {
super(scope, id, props);
// Define a new VPC
// ...
// Define an RDS database cluster
// ...
// Get the port token (this is a token encoded as a number)
const portToken = dbCluster.clusterEndpoint.port;
// ...
// Convert the encoded number to an encoded string for use in the connection string
const portAsString = Tokenization.stringifyNumber(portToken);
// Example connection string with the port token as a string
const connectionString = `jdbc:mysql://mydb.cluster.amazonaws.com:${portAsString}/mydatabase`;
// Use the connection string as an environment variable in a Lambda function
const myFunction = new lambda.Function(this, 'MyLambdaFunction', {
// ...
environment: {
DATABASE_CONNECTION_STRING: connectionString, // Using the port token as part of the string
},
});
// Output the value of our connection string at synthesis
console.log("connectionString: " + connectionString);
// Output the connection string
new CfnOutput(this, 'ConnectionString', {
value: connectionString,
});
}
}
module.exports = { CdkDemoAppStack }
- Python
-
from aws_cdk import (
Duration,
Stack,
Tokenization,
CfnOutput,
)
# ...
class CdkDemoAppStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# Define a new VPC
# ...
# Define an RDS database cluster
# ...
# Get the port token (this is a token encoded as a number)
port_token = db_cluster.cluster_endpoint.port
# Convert the encoded number to an encoded string for use in the connection string
port_as_string = Tokenization.stringify_number(port_token)
# Example connection string with the port token as a string
connection_string = f"jdbc:mysql://mydb.cluster.amazonaws.com:{port_as_string}/mydatabase"
# Use the connection string as an environment variable in a Lambda function
my_function = _lambda.Function(self, 'MyLambdaFunction',
# ...
environment={
'DATABASE_CONNECTION_STRING': connection_string # Using the port token as part of the string
}
)
# Output the value of our connection string at synthesis
print(f"connectionString: {connection_string}")
# Output the connection string
CfnOutput(self, 'ConnectionString',
value=connection_string
)
- Java
-
// ...
import software.amazon.awscdk.Tokenization;
public class CdkDemoAppStack extends Stack {
public CdkDemoAppStack(final Construct scope, final String id) {
this(scope, id, null);
}
public CdkDemoAppStack(final Construct scope, final String id, final StackProps props) {
super(scope, id, props);
// Define a new VPC
// ...
// Define an RDS database cluster
// ...
// Get the port token (this is a token encoded as a number)
Number portToken = dbCluster.getClusterEndpoint().getPort();
// ...
// Convert the encoded number to an encoded string for use in the connection string
String portAsString = Tokenization.stringifyNumber(portToken);
// Example connection string with the port token as a string
String connectionString = "jdbc:mysql://mydb.cluster.amazonaws.com:" + portAsString + "/mydatabase";
// Use the connection string as an environment variable in a Lambda function
Function myFunction = Function.Builder.create(this, "MyLambdaFunction")
// ...
.environment(Map.of(
"DATABASE_CONNECTION_STRING", connectionString // Using the port token as part of the string
))
.build();
// Output the value of our connection string at synthesis
System.out.println("connectionString: " + connectionString);
// Output the connection string
CfnOutput.Builder.create(this, "ConnectionString")
.value(connectionString)
.build();
}
}
- C#
-
// ...
namespace CdkDemoApp
{
public class CdkDemoAppStack : Stack
{
internal CdkDemoAppStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
{
// Define a new VPC
// ...
// Define an RDS database cluster
// ...
// Get the port token (this is a token encoded as a number)
var portToken = dbCluster.ClusterEndpoint.Port;
// ...
// Convert the encoded number to an encoded string for use in the connection string
var portAsString = Tokenization.StringifyNumber(portToken);
// Example connection string with the port token as a string
var connectionString = $"jdbc:mysql://mydb.cluster.amazonaws.com:{portAsString}/mydatabase";
// Use the connection string as an environment variable in a Lambda function
var myFunction = new Function(this, "MyLambdaFunction", new FunctionProps
{
// ...
Environment = new Dictionary<string, string>
{
{ "DATABASE_CONNECTION_STRING", connectionString } // Using the port token as part of the string
}
});
// Output the value of our connection string at synthesis
Console.WriteLine($"connectionString: {connectionString}");
// Output the connection string
new CfnOutput(this, "ConnectionString", new CfnOutputProps
{
Value = connectionString
});
}
}
}
- Go
-
// ...
func NewCdkDemoAppStack(scope constructs.Construct, id string, props *CdkDemoAppStackProps) awscdk.Stack {
var sprops awscdk.StackProps
if props != nil {
sprops = props.StackProps
}
stack := awscdk.NewStack(scope, &id, &sprops)
// Define a new VPC
// ...
// Define an RDS database cluster
// ...
// Get the port token (this is a token encoded as a number)
portToken := dbCluster.ClusterEndpoint().Port()
// ...
// Convert the encoded number to an encoded string for use in the connection string
portAsString := awscdk.Tokenization_StringifyNumber(portToken)
// Example connection string with the port token as a string
connectionString := fmt.Sprintf("jdbc:mysql://mydb.cluster.amazonaws.com:%s/mydatabase", portAsString)
// Use the connection string as an environment variable in a Lambda function
myFunction := awslambda.NewFunction(stack, jsii.String("MyLambdaFunction"), &awslambda.FunctionProps{
// ...
Environment: &map[string]*string{
"DATABASE_CONNECTION_STRING": jsii.String(connectionString), // Using the port token as part of the string
},
})
// Output the value of our connection string at synthesis
fmt.Println("connectionString: ", connectionString)
// Output the connection string
awscdk.NewCfnOutput(stack, jsii.String("ConnectionString"), &awscdk.CfnOutputProps{
Value: jsii.String(connectionString),
})
fmt.Println(myFunction)
return stack
}
// ...
Quando executamos o cdk synth
, o valor da nossa string de conexão é representado em um formato mais limpo e claro:
$
cdk synth --quiet
connectionString: jdbc:mysql://mydb.cluster.amazonaws.com:${Token[TOKEN.242]}/mydatabase
Valores lentos
Além de representar valores de tempo de implantação, como parâmetros AWS CloudFormation, os tokens também são comumente usados para representar valores lentos de tempo de síntese. Esses são valores para os quais o valor final será determinado antes da conclusão da síntese, mas não no ponto em que o valor é construído. Use tokens para passar uma string literal ou um valor numérico para outro constructo, enquanto o valor real no momento da síntese pode depender de algum cálculo que ainda não foi feito.
Você pode criar tokens representando valores lentos de tempo de sintetizador usando métodos estáticos na Lazy
classe, como Lazy.string
e Lazy.number
. Esses métodos aceitam um objeto cuja propriedade produce
é uma função que aceita um argumento de contexto e retorna o valor final quando chamada.
O exemplo a seguir cria um grupo do Auto Scaling cuja capacidade é determinada após sua criação.
- TypeScript
-
let actualValue: number;
new AutoScalingGroup(this, 'Group', {
desiredCapacity: Lazy.numberValue({
produce(context) {
return actualValue;
}
})
});
// At some later point
actualValue = 10;
- JavaScript
-
let actualValue;
new AutoScalingGroup(this, 'Group', {
desiredCapacity: Lazy.numberValue({
produce(context) {
return (actualValue);
}
})
});
// At some later point
actualValue = 10;
- Python
-
class Producer:
def __init__(self, func):
self.produce = func
actual_value = None
AutoScalingGroup(self, "Group",
desired_capacity=Lazy.number_value(Producer(lambda context: actual_value))
)
# At some later point
actual_value = 10
- Java
-
double actualValue = 0;
class ProduceActualValue implements INumberProducer {
@Override
public Number produce(IResolveContext context) {
return actualValue;
}
}
AutoScalingGroup.Builder.create(this, "Group")
.desiredCapacity(Lazy.numberValue(new ProduceActualValue())).build();
// At some later point
actualValue = 10;
- C#
-
public class NumberProducer : INumberProducer
{
Func<Double> function;
public NumberProducer(Func<Double> function)
{
this.function = function;
}
public Double Produce(IResolveContext context)
{
return function();
}
}
double actualValue = 0;
new AutoScalingGroup(this, "Group", new AutoScalingGroupProps
{
DesiredCapacity = Lazy.NumberValue(new NumberProducer(() => actualValue))
});
// At some later point
actualValue = 10;
Conversão para JSON
Às vezes, você deseja produzir uma string JSON de dados arbitrários e talvez não saiba se os dados contêm tokens. Para codificar adequadamente qualquer estrutura de dados em JSON, independentemente de ela conter tokens, use o método stack.toJsonString
, conforme mostrado no exemplo a seguir.
- TypeScript
-
const stack = Stack.of(this);
const str = stack.toJsonString({
value: bucket.bucketName
});
- JavaScript
-
const stack = Stack.of(this);
const str = stack.toJsonString({
value: bucket.bucketName
});
- Python
-
stack = Stack.of(self)
string = stack.to_json_string(dict(value=bucket.bucket_name))
- Java
-
Stack stack = Stack.of(this);
String stringVal = stack.toJsonString(java.util.Map.of( // Map.of requires Java 9+
put("value", bucket.getBucketName())));
- C#
-
var stack = Stack.Of(this);
var stringVal = stack.ToJsonString(new Dictionary<string, string>
{
["value"] = bucket.BucketName
});