Personalizar constructos da Biblioteca de Constructos da AWS - AWS Cloud Development Kit (AWS CDK) v2

Este é o Guia do Desenvolvedor AWS CDK v2. A CDK v1 mais antiga entrou em manutenção em 1º de junho de 2022 e encerrou o suporte em 1º de junho de 2023.

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Personalizar constructos da Biblioteca de Constructos da AWS

Personalize os constructos da Biblioteca de Constructos da AWS por meio de hatches de escape, substituições brutas e recursos personalizados.

Usar hatches de escape

A Biblioteca de Constructos da AWS fornece constructos de vários níveis de abstração.

No nível mais alto, seu aplicativo do AWS CDK e as pilhas nele contidas são, em si, abstrações de toda a sua infraestrutura de nuvem ou de partes significativas dela. Eles podem ser parametrizados para serem implantados em diferentes ambientes ou para diferentes necessidades.

As abstrações são ferramentas poderosas para projetar e implementar aplicativos em nuvem. O AWS CDK dá a você o poder não apenas de construir com suas abstrações, mas também de criar novas abstrações. Usando os constructos L2 e L3 de código aberto existentes como orientação, você pode criar seus próprios constructos L2 e L3 para refletir as práticas recomendadas e opiniões de sua própria organização.

Nenhuma abstração é perfeita, e mesmo boas abstrações não podem cobrir todos os casos de uso possíveis. Durante o desenvolvimento, você pode encontrar um constructo que quase atenda às suas necessidades, exigindo uma personalização pequena ou grande.

Por esse motivo, o AWS CDK fornece maneiras de sair do modelo de constructo. Isso inclui mudar para uma abstração de nível inferior ou para um modelo totalmente diferente. Os hatches de escape permitem que você escape do paradigma do AWS CDK e o personalize de forma que atenda às suas necessidades. Em seguida, você pode agrupar suas alterações em um novo constructo para abstrair a complexidade subjacente e fornecer uma API limpa para outros desenvolvedores.

Veja a seguir exemplos de situações em que você pode usar hatches de escape:

  • Um atributo de serviço da AWS está disponível por meio do AWS CloudFormation, mas não há constructos L2 para ele.

  • Um atributo de serviço da AWS está disponível por meio do AWS CloudFormation e há constructos L2 para o serviço, mas elas ainda não expõem o atributo. Como os constructos L2 são selecionados pela equipe do CDK, eles podem não estar imediatamente disponíveis para novos atributos.

  • O atributo ainda não está disponível por meio do AWS CloudFormation no momento.

    Para determinar se um atributo está disponível por meio do AWS CloudFormation, consulte Referência de tipos de recursos e propriedades da AWS.

Desenvolver hatches de escape para constructos L1

Se os constructos L2 não estiverem disponíveis para o serviço, você poderá usar os constructos L1 gerados automaticamente. Esses recursos podem ser reconhecidos pelo nome que começa com Cfn, como CfnBucket ou CfnRole. Você os instancia exatamente da mesma forma que usaria o recurso do AWS CloudFormation equivalente.

Por exemplo, para instanciar um bucket L1 de baixo nível do Amazon S3 com análises ativadas, você escreveria algo como o seguinte.

TypeScript
new s3.CfnBucket(this, 'amzn-s3-demo-bucket', { analyticsConfigurations: [ { id: 'Config', // ... } ] });
JavaScript
new s3.CfnBucket(this, 'amzn-s3-demo-bucket', { analyticsConfigurations: [ { id: 'Config' // ... } ] });
Python
s3.CfnBucket(self, "amzn-s3-demo-bucket", analytics_configurations: [ dict(id="Config", # ... ) ] )
Java
CfnBucket.Builder.create(this, "amzn-s3-demo-bucket") .analyticsConfigurations(Arrays.asList(java.util.Map.of( // Java 9 or later "id", "Config", // ... ))).build();
C#
new CfnBucket(this, 'amzn-s3-demo-bucket', new CfnBucketProps { AnalyticsConfigurations = new Dictionary<string, string> { ["id"] = "Config", // ... } });

Pode haver casos raros em que você queira definir um recurso que não tenha uma classe do CfnXxx correspondente. Esse pode ser um novo tipo de recurso que ainda não foi publicado na especificação do recurso do AWS CloudFormation. Em casos como esse, você pode instanciar o cdk.CfnResource diretamente e especificar o tipo e as propriedades do recurso. Isso é mostrado no exemplo a seguir.

TypeScript
new cdk.CfnResource(this, 'amzn-s3-demo-bucket', { type: 'AWS::S3::Bucket', properties: { // Note the PascalCase here! These are CloudFormation identifiers. AnalyticsConfigurations: [ { Id: 'Config', // ... } ] } });
JavaScript
new cdk.CfnResource(this, 'amzn-s3-demo-bucket', { type: 'AWS::S3::Bucket', properties: { // Note the PascalCase here! These are CloudFormation identifiers. AnalyticsConfigurations: [ { Id: 'Config' // ... } ] } });
Python
cdk.CfnResource(self, 'amzn-s3-demo-bucket', type="AWS::S3::Bucket", properties=dict( # Note the PascalCase here! These are CloudFormation identifiers. "AnalyticsConfigurations": [ { "Id": "Config", # ... } ] } )
Java
CfnResource.Builder.create(this, "amzn-s3-demo-bucket") .type("AWS::S3::Bucket") .properties(java.util.Map.of( // Map.of requires Java 9 or later // Note the PascalCase here! These are CloudFormation identifiers "AnalyticsConfigurations", Arrays.asList( java.util.Map.of("Id", "Config", // ... )))) .build();
C#
new CfnResource(this, "amzn-s3-demo-bucket", new CfnResourceProps { Type = "AWS::S3::Bucket", Properties = new Dictionary<string, object> { // Note the PascalCase here! These are CloudFormation identifiers ["AnalyticsConfigurations"] = new Dictionary<string, string>[] { new Dictionary<string, string> { ["Id"] = "Config" } } } });

Desenvolver hatches de escape para constructos L2

Se um constructo L2 não tiver um atributo ou você estiver tentando contornar um problema, você pode modificar o constructo L1 que está encapsulado pelo constructo L2.

Todos os constructos L2 contêm dentro deles o constructo L1 correspondente. Por exemplo, o constructo de alto nível do Bucket envolve o constructo de baixo nível do CfnBucket. Como o CfnBucket corresponde diretamente ao atributo do AWS CloudFormation, ele expõe todos os atributos que estão disponíveis por meio do AWS CloudFormation.

A abordagem básica para obter acesso ao constructo L1 é usar construct.node.defaultChild (Python: default_child), convertê-la para o tipo certo (se necessário) e modificar suas propriedades. Novamente, vamos dar o exemplo de um Bucket.

TypeScript
// Get the CloudFormation resource const cfnBucket = bucket.node.defaultChild as s3.CfnBucket; // Change its properties cfnBucket.analyticsConfiguration = [ { id: 'Config', // ... } ];
JavaScript
// Get the CloudFormation resource const cfnBucket = bucket.node.defaultChild; // Change its properties cfnBucket.analyticsConfiguration = [ { id: 'Config' // ... } ];
Python
# Get the CloudFormation resource cfn_bucket = bucket.node.default_child # Change its properties cfn_bucket.analytics_configuration = [ { "id": "Config", # ... } ]
Java
// Get the CloudFormation resource CfnBucket cfnBucket = (CfnBucket)bucket.getNode().getDefaultChild(); cfnBucket.setAnalyticsConfigurations( Arrays.asList(java.util.Map.of( // Java 9 or later "Id", "Config", // ... ));
C#
// Get the CloudFormation resource var cfnBucket = (CfnBucket)bucket.Node.DefaultChild; cfnBucket.AnalyticsConfigurations = new List<object> { new Dictionary<string, string> { ["Id"] = "Config", // ... } };

Você também pode usar esse objeto para alterar opções do AWS CloudFormation, como Metadata e UpdatePolicy.

TypeScript
cfnBucket.cfnOptions.metadata = { MetadataKey: 'MetadataValue' };
JavaScript
cfnBucket.cfnOptions.metadata = { MetadataKey: 'MetadataValue' };
Python
cfn_bucket.cfn_options.metadata = { "MetadataKey": "MetadataValue" }
Java
cfnBucket.getCfnOptions().setMetadata(java.util.Map.of( // Java 9+ "MetadataKey", "Metadatavalue"));
C#
cfnBucket.CfnOptions.Metadata = new Dictionary<string, object> { ["MetadataKey"] = "Metadatavalue" };

Usar hatches de não escape

O AWS CDK também fornece a capacidade de subir um nível de abstração, que podemos chamar de hatch de “não escape”. Se você tiver um constructo L1, como CfnBucket, você pode criar um novo constructo L2 (Bucket nesse caso) para encapsular o constructo L1.

Isso é conveniente quando você cria um recurso L1, mas deseja usá-lo com um constructo que requer um recurso L2. Também é útil quando você deseja usar métodos de conveniência, como .grantXxxxx(), que não estão disponíveis no constructo L1.

Você passa para o nível de abstração mais alto usando um método estático na classe L2 chamado .fromCfnXxxxx(), por exemplo, Bucket.fromCfnBucket() para buckets do Amazon S3. O recurso L1 é o único parâmetro.

TypeScript
b1 = new s3.CfnBucket(this, "buck09", { ... }); b2 = s3.Bucket.fromCfnBucket(b1);
JavaScript
b1 = new s3.CfnBucket(this, "buck09", { ...} ); b2 = s3.Bucket.fromCfnBucket(b1);
Python
b1 = s3.CfnBucket(self, "buck09", ...) b2 = s3.from_cfn_bucket(b1)
Java
CfnBucket b1 = CfnBucket.Builder.create(this, "buck09") // .... .build(); IBucket b2 = Bucket.fromCfnBucket(b1);
C#
var b1 = new CfnBucket(this, "buck09", new CfnBucketProps { ... }); var v2 = Bucket.FromCfnBucket(b1);

Os constructos L2 criados a partir de constructos L1 são objetos proxy que se referem ao recurso L1, semelhantes aos criados a partir de nomes de recursos, ARNs ou pesquisas. As modificações nesses constructos não afetam o modelo final sintetizado do AWS CloudFormation (já que você tem o recurso L1, no entanto, você pode modificá-lo). Para obter mais informações sobre objetos proxy, consulte Referenciando recursos em sua conta AWS.

Para evitar confusão, não crie vários constructos L2 que se refiram ao mesmo constructo L1. Por exemplo, se você extrair o CfnBucket de um Bucket usando a técnica da seção anterior, você não deve criar uma segunda instância do Bucket chamando Bucket.fromCfnBucket() com esse CfnBucket. Na verdade, funciona conforme o esperado (apenas um AWS::S3::Bucket é sintetizado), mas dificulta a manutenção do código.

Usar substituições brutas

Se faltarem propriedades no constructo L1, você poderá ignorar toda a digitação usando substituições brutas. Isso também possibilita a exclusão de propriedades sintetizadas.

Use um dos métodos addOverride (Python: add_override), conforme mostrado no exemplo a seguir.

TypeScript
// Get the CloudFormation resource const cfnBucket = bucket.node.defaultChild as s3.CfnBucket; // Use dot notation to address inside the resource template fragment cfnBucket.addOverride('Properties.VersioningConfiguration.Status', 'NewStatus'); cfnBucket.addDeletionOverride('Properties.VersioningConfiguration.Status'); // use index (0 here) to address an element of a list cfnBucket.addOverride('Properties.Tags.0.Value', 'NewValue'); cfnBucket.addDeletionOverride('Properties.Tags.0'); // addPropertyOverride is a convenience function for paths starting with "Properties." cfnBucket.addPropertyOverride('VersioningConfiguration.Status', 'NewStatus'); cfnBucket.addPropertyDeletionOverride('VersioningConfiguration.Status'); cfnBucket.addPropertyOverride('Tags.0.Value', 'NewValue'); cfnBucket.addPropertyDeletionOverride('Tags.0');
JavaScript
// Get the CloudFormation resource const cfnBucket = bucket.node.defaultChild ; // Use dot notation to address inside the resource template fragment cfnBucket.addOverride('Properties.VersioningConfiguration.Status', 'NewStatus'); cfnBucket.addDeletionOverride('Properties.VersioningConfiguration.Status'); // use index (0 here) to address an element of a list cfnBucket.addOverride('Properties.Tags.0.Value', 'NewValue'); cfnBucket.addDeletionOverride('Properties.Tags.0'); // addPropertyOverride is a convenience function for paths starting with "Properties." cfnBucket.addPropertyOverride('VersioningConfiguration.Status', 'NewStatus'); cfnBucket.addPropertyDeletionOverride('VersioningConfiguration.Status'); cfnBucket.addPropertyOverride('Tags.0.Value', 'NewValue'); cfnBucket.addPropertyDeletionOverride('Tags.0');
Python
# Get the CloudFormation resource cfn_bucket = bucket.node.default_child # Use dot notation to address inside the resource template fragment cfn_bucket.add_override("Properties.VersioningConfiguration.Status", "NewStatus") cfn_bucket.add_deletion_override("Properties.VersioningConfiguration.Status") # use index (0 here) to address an element of a list cfn_bucket.add_override("Properties.Tags.0.Value", "NewValue") cfn_bucket.add_deletion_override("Properties.Tags.0") # addPropertyOverride is a convenience function for paths starting with "Properties." cfn_bucket.add_property_override("VersioningConfiguration.Status", "NewStatus") cfn_bucket.add_property_deletion_override("VersioningConfiguration.Status") cfn_bucket.add_property_override("Tags.0.Value", "NewValue") cfn_bucket.add_property_deletion_override("Tags.0")
Java
// Get the CloudFormation resource CfnBucket cfnBucket = (CfnBucket)bucket.getNode().getDefaultChild(); // Use dot notation to address inside the resource template fragment cfnBucket.addOverride("Properties.VersioningConfiguration.Status", "NewStatus"); cfnBucket.addDeletionOverride("Properties.VersioningConfiguration.Status"); // use index (0 here) to address an element of a list cfnBucket.addOverride("Properties.Tags.0.Value", "NewValue"); cfnBucket.addDeletionOverride("Properties.Tags.0"); // addPropertyOverride is a convenience function for paths starting with "Properties." cfnBucket.addPropertyOverride("VersioningConfiguration.Status", "NewStatus"); cfnBucket.addPropertyDeletionOverride("VersioningConfiguration.Status"); cfnBucket.addPropertyOverride("Tags.0.Value", "NewValue"); cfnBucket.addPropertyDeletionOverride("Tags.0");
C#
// Get the CloudFormation resource var cfnBucket = (CfnBucket)bucket.node.defaultChild; // Use dot notation to address inside the resource template fragment cfnBucket.AddOverride("Properties.VersioningConfiguration.Status", "NewStatus"); cfnBucket.AddDeletionOverride("Properties.VersioningConfiguration.Status"); // use index (0 here) to address an element of a list cfnBucket.AddOverride("Properties.Tags.0.Value", "NewValue"); cfnBucket.AddDeletionOverride("Properties.Tags.0"); // addPropertyOverride is a convenience function for paths starting with "Properties." cfnBucket.AddPropertyOverride("VersioningConfiguration.Status", "NewStatus"); cfnBucket.AddPropertyDeletionOverride("VersioningConfiguration.Status"); cfnBucket.AddPropertyOverride("Tags.0.Value", "NewValue"); cfnBucket.AddPropertyDeletionOverride("Tags.0");

Usar recursos personalizados

Se o atributo não estiver disponível por meio do AWS CloudFormation, mas somente por meio de uma chamada direta de API, você deverá escrever um recurso do AWS CloudFormation personalizado para fazer a chamada de API necessária. Você pode usar o AWS CDK para escrever recursos personalizados e agrupá-los em uma interface de constructo regular. Do ponto de vista de um consumidor de seu constructo, a experiência parecerá nativa.

A criação de um recurso personalizado envolve escrever uma função do Lambda que responde aos eventos de ciclo de vida CREATE, UPDATE e DELETE de um recurso. Se seu recurso personalizado precisar fazer apenas uma única chamada de API, considere usar o AwsCustomResource. Isso permite realizar chamadas arbitrárias do SDK durante uma implantação do AWS CloudFormation. Caso contrário, você deve escrever sua própria função do Lambda para realizar o trabalho que precisa ser feito.

O assunto é muito amplo para ser abordado completamente aqui, mas os links a seguir devem ajudar você a começar: