UNPKG

aws-cdk-lib

Version:

Version 2 of the AWS Cloud Development Kit library

2 lines (1 loc) 14.8 kB
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.STRING_LIST_REFERENCE_DELIMITER=void 0,exports.resolveReferences=resolveReferences,exports.getExportable=getExportable,exports.referenceNestedStackValueInParent=referenceNestedStackValueInParent;var constructs_1=()=>{var tmp=require("constructs");return constructs_1=()=>tmp,tmp},cfn_reference_1=()=>{var tmp=require("./cfn-reference");return cfn_reference_1=()=>tmp,tmp},resolve_1=()=>{var tmp=require("./resolve");return resolve_1=()=>tmp,tmp},uniqueid_1=()=>{var tmp=require("./uniqueid");return uniqueid_1=()=>tmp,tmp},cxapi=()=>{var tmp=require("../../../cx-api");return cxapi=()=>tmp,tmp},annotations_1=()=>{var tmp=require("../annotations");return annotations_1=()=>tmp,tmp},arn_1=()=>{var tmp=require("../arn");return arn_1=()=>tmp,tmp},cfn_element_1=()=>{var tmp=require("../cfn-element");return cfn_element_1=()=>tmp,tmp},cfn_fn_1=()=>{var tmp=require("../cfn-fn");return cfn_fn_1=()=>tmp,tmp},cfn_output_1=()=>{var tmp=require("../cfn-output");return cfn_output_1=()=>tmp,tmp},cfn_parameter_1=()=>{var tmp=require("../cfn-parameter");return cfn_parameter_1=()=>tmp,tmp},export_writer_provider_1=()=>{var tmp=require("../custom-resource-provider/cross-region-export-providers/export-writer-provider");return export_writer_provider_1=()=>tmp,tmp},errors_1=()=>{var tmp=require("../errors");return errors_1=()=>tmp,tmp},names_1=()=>{var tmp=require("../names");return names_1=()=>tmp,tmp},stack_1=()=>{var tmp=require("../stack");return stack_1=()=>tmp,tmp},token_1=()=>{var tmp=require("../token");return token_1=()=>tmp,tmp},type_hints_1=()=>{var tmp=require("../type-hints");return type_hints_1=()=>tmp,tmp},construct_iteration_1=()=>{var tmp=require("./construct-iteration");return construct_iteration_1=()=>tmp,tmp},cfn_resource_1=()=>{var tmp=require("../cfn-resource");return cfn_resource_1=()=>tmp,tmp},literal_string_1=()=>{var tmp=require("./literal-string");return literal_string_1=()=>tmp,tmp};exports.STRING_LIST_REFERENCE_DELIMITER="||";const CROSS_STACK_REFERENCE_VALUES=["strong","weak","both"];function crossStackReferenceStrength(scope){const value=scope.node.tryGetContext(cxapi().DEFAULT_CROSS_STACK_REFERENCES);if(value==null)return"strong";if(CROSS_STACK_REFERENCE_VALUES.includes(value))return value;throw new(errors_1()).UnscopedValidationError((0,literal_string_1().lit)`InvalidCrossStackReferenceStrength`,`Invalid value for ${cxapi().DEFAULT_CROSS_STACK_REFERENCES}: "${value}". Must be "strong", "weak", or "both".`)}function resolveReferences(scope){const edges=findAllReferences(scope);for(const{source,value}of edges){const consumer=stack_1().Stack.of(source);if(!value.hasValueForStack(consumer)){const resolved=resolveValue(consumer,value);value.assignValueForStack(consumer,resolved)}}}function resolveValue(consumer,reference){const producer=stack_1().Stack.of(reference.target),producerAccount=token_1().Token.isUnresolved(producer.account)?cxapi().UNKNOWN_ACCOUNT:producer.account,producerRegion=token_1().Token.isUnresolved(producer.region)?cxapi().UNKNOWN_REGION:producer.region,consumerAccount=token_1().Token.isUnresolved(consumer.account)?cxapi().UNKNOWN_ACCOUNT:consumer.account,consumerRegion=token_1().Token.isUnresolved(consumer.region)?cxapi().UNKNOWN_REGION:consumer.region;if(producer===consumer)return reference;if(producer.node.root!==consumer.node.root)throw new(errors_1()).UnscopedValidationError((0,literal_string_1().lit)`CannotReferenceAcrossApps`,"Cannot reference across apps. Consuming and producing stacks must be defined within the same CDK app.");if(producerAccount!==consumerAccount){if(crossStackReferenceStrength(consumer)==="strong"&&annotations_1().Annotations.of(consumer).addWarningV2("@aws-cdk/core:crossAccountRefsAreAlwaysWeak",`Strong references requested, but cross-account references can only be weak. Acknowledge this warning or set "${cxapi().DEFAULT_CROSS_STACK_REFERENCES}" to "weak" to remove this message.`),consumer.synthesizer.cloudFormationExecutionRole==null)throw new(errors_1()).UnscopedValidationError((0,literal_string_1().lit)`NoCfnExecutionRoleForCrossAccountRefs`,`Stack "${consumer.node.path}" cannot reference ${renderReference(reference)} in stack "${producer.node.path}". Could not find a CloudFormation execution role for the consumer stack. Use a stack synthesizer that provides a CloudFormation execution role, such as DefaultStackSynthesizer (that uses the role from the bootstrap stack), or one that you can customize, such as BootstraplessSynthesizer.`);if(producerRegion===cxapi().UNKNOWN_REGION||consumerRegion===cxapi().UNKNOWN_REGION)throw new(errors_1()).UnscopedValidationError((0,literal_string_1().lit)`CrossRegionReferencesRequireExplicitRegion`,`Stack "${consumer.node.path}" cannot reference ${renderReference(reference)} in stack "${producer.node.path}". Cross stack/region references are only supported for stacks with an explicit region defined. `);const producerStackArn=stack_1().Stack.of(reference.target).formatArn({service:"cloudformation",resource:"stack",resourceName:`${producer.stackName}/*`,region:producerRegion,account:producerAccount});return createGetStackOutput(reference,{consumerRoleArn:cfn_fn_1().Fn.sub(consumer.synthesizer.cloudFormationExecutionRole),producerAccount,producerRegion,producerStackArn})}if(consumer.nestedStackParent&&isNested(consumer,producer)){const parameterValue=resolveValue(consumer.nestedStackParent,reference);return createNestedStackParameter(consumer,reference,parameterValue)}if(producer.nested){const outputValue=createNestedStackOutput(producer,reference),resolvedValue=resolveValue(consumer,outputValue);return reference.typeHint===type_hints_1().ResolutionTypeHint.STRING_LIST?token_1().Tokenization.reverseList(cfn_fn_1().Fn.split(exports.STRING_LIST_REFERENCE_DELIMITER,token_1().Token.asString(resolvedValue))):resolvedValue}if(producerRegion!==consumerRegion){if(producerRegion===cxapi().UNKNOWN_REGION||consumerRegion===cxapi().UNKNOWN_REGION)throw new(errors_1()).UnscopedValidationError((0,literal_string_1().lit)`CrossRegionReferencesRequireExplicitRegion`,`Stack "${consumer.node.path}" cannot reference ${renderReference(reference)} in stack "${producer.node.path}". Cross stack/region references are only supported for stacks with an explicit region defined. `);consumer.addDependency(producer,`${consumer.node.path} -> ${reference.target.node.path}.${reference.displayName}`);const strength2=crossStackReferenceStrength(consumer);if(strength2==="strong")return createCrossRegionImportValue(reference,consumer);strength2==="both"&&createCrossRegionExportOnly(reference,consumer);const producerStackArn=producer.formatArn({service:"cloudformation",resource:"stack",resourceName:`${producer.stackName}/*`,region:producerRegion,account:producerAccount});return createGetStackOutput(reference,{producerStackArn})}consumer.addDependency(producer,`${consumer.node.path} -> ${reference.target.node.path}.${reference.displayName}`);const strength=crossStackReferenceStrength(consumer);return strength==="strong"?createImportValue(reference):(strength==="both"&&createImportValue(reference),createGetStackOutput(reference,{}))}function renderReference(ref){return`{${ref.target.node.path}[${ref.displayName}]}`}function findAllReferences(root){const result=new Array;for(const consumer of(0,construct_iteration_1().iterateDfsPreorder)(root))if(cfn_element_1().CfnElement.isCfnElement(consumer))try{const tokens=(0,resolve_1().findTokens)(consumer,()=>consumer._toCloudFormation());for(const token of tokens)cfn_reference_1().CfnReference.isCfnReference(token)&&result.push({source:consumer,value:token})}catch(e){if(e.type==="CfnSynthesisError")continue;throw e}return result}function createImportValue(reference){const exportingStack=stack_1().Stack.of(reference.target);let importExpr;return reference.typeHint===type_hints_1().ResolutionTypeHint.STRING_LIST?(importExpr=exportingStack.exportStringListValue(reference),token_1().Tokenization.reverseList(importExpr)):(importExpr=exportingStack.exportValue(reference),token_1().Tokenization.reverseCompleteString(importExpr))}function getOrCreateExportWriter(reference,importStack){const referenceStack=stack_1().Stack.of(reference.target),exportingStack=referenceStack.nestedStackParent??referenceStack,exportable=getExportable(exportingStack,reference),id=JSON.stringify(exportingStack.resolve(exportable)),exportName=generateExportName(importStack,reference,id);if(token_1().Token.isUnresolved(exportName))throw new(errors_1()).UnscopedValidationError((0,literal_string_1().lit)`UnresolvedTokenInExportName`,`unresolved token in generated export name: ${JSON.stringify(exportingStack.resolve(exportName))}`);const writerConstructName=(0,uniqueid_1().makeUniqueId)(["ExportsWriter",importStack.region]);return{exportWriter:export_writer_provider_1().ExportWriter.getOrCreate(exportingStack,writerConstructName,{region:importStack.region}),exportName}}function createCrossRegionImportValue(reference,importStack){const{exportWriter,exportName}=getOrCreateExportWriter(reference,importStack),exported=exportWriter.exportValue(exportName,reference,importStack);return importStack.nestedStackParent?createNestedStackParameter(importStack,exported,exported):exported}function createCrossRegionExportOnly(reference,importStack){const{exportWriter,exportName}=getOrCreateExportWriter(reference,importStack);exportWriter.exportValueWriteOnly(exportName,reference,importStack)}function generateExportName(importStack,reference,id){const referenceStack=stack_1().Stack.of(reference.target),components=[referenceStack.stackName??"",referenceStack.region,id],prefix=`${importStack.nestedStackParent?.stackName??importStack.stackName}/`,localPart=(0,uniqueid_1().makeUniqueId)(components);return prefix+localPart.slice(Math.max(0,localPart.length-900+prefix.length))}function createGetStackOutputRole(scope,id,props){const resource=new(cfn_resource_1()).CfnResource(scope,id,{type:"AWS::IAM::Role",properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:props.consumerRoleArn},Action:["sts:AssumeRole"]}]}}}),roleName=names_1().Names.uniqueResourceName(resource,{maxLength:64});resource.addPropertyOverride("RoleName",roleName);const roleArn=stack_1().Stack.of(scope).formatArn({service:"iam",resource:"role",resourceName:roleName,account:props.producerAccount,arnFormat:arn_1().ArnFormat.SLASH_RESOURCE_NAME,region:""});return{resource,roleRef:{roleArn,roleName}}}function createGetStackOutputPolicy(scope,id,props){const resource=new(cfn_resource_1()).CfnResource(scope,id,{type:"AWS::IAM::Policy",properties:{Roles:[cfn_fn_1().Fn.ref(props.role.logicalId)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:"cloudformation:DescribeStacks",Resource:props.producerStackArn}]}}}),policyName=names_1().Names.uniqueResourceName(resource,{maxLength:128});return resource.addPropertyOverride("PolicyName",policyName),{resource,policyRef:{policyId:policyName}}}function createGetStackOutput(reference,options={}){const exportingStack=stack_1().Stack.of(reference.target),resolved=JSON.stringify(exportingStack.resolve(reference)),outputId="Output"+resolved,roleId="Role"+resolved,policyId="Policy"+resolved;function createScope(stack){const scopeName="Publish";let scope2=stack.node.tryFindChild(scopeName);return scope2===void 0&&(scope2=new(constructs_1()).Construct(stack,scopeName)),scope2}const scope=createScope(exportingStack);let output=scope.node.tryFindChild(outputId);output==null&&(output=new(cfn_output_1()).CfnOutput(scope,outputId,{value:token_1().Token.asString(reference)}));let roleArn;if(options.consumerRoleArn){let roleResource=scope.node.tryFindChild(roleId);if(roleResource==null){const{resource,roleRef}=createGetStackOutputRole(scope,roleId,{consumerRoleArn:options.consumerRoleArn,producerAccount:options.producerAccount});roleResource=resource,roleArn=roleRef.roleArn}scope.node.tryFindChild(policyId)==null&&createGetStackOutputPolicy(scope,policyId,{role:roleResource,producerStackArn:options.producerStackArn})}return token_1().Tokenization.reverseCompleteString(cfn_fn_1().Fn.getStackOutput(exportingStack.stackName,output.logicalId,exportingStack.region,roleArn))}function getExportable(stack,reference){return cfn_element_1().CfnElement.isCfnElement(reference.target)&&reference.target._lockLogicalId(),referenceNestedStackValueInParent(reference,stack)}function createNestedStackParameter(nested,reference,value){const paramId=generateUniqueId(nested,reference,"reference-to-");let param=nested.node.tryFindChild(paramId);if(!param){if(param=new(cfn_parameter_1()).CfnParameter(nested,paramId,{type:"String"}),!("setParameter"in nested))throw new(errors_1()).UnscopedValidationError((0,literal_string_1().lit)`NestedStackMustHaveSetParameter`,'assertion failed: nested stack should have a "setParameter" method');nested.setParameter(param.logicalId,token_1().Token.asString(value))}return param.value}function createNestedStackOutput(producer,reference){const outputId=generateUniqueId(producer,reference);let output=producer.node.tryFindChild(outputId);if(output||(reference.typeHint===type_hints_1().ResolutionTypeHint.STRING_LIST?output=new(cfn_output_1()).CfnOutput(producer,outputId,{value:cfn_fn_1().Fn.join(exports.STRING_LIST_REFERENCE_DELIMITER,token_1().Token.asList(reference))}):output=new(cfn_output_1()).CfnOutput(producer,outputId,{value:token_1().Token.asString(reference)})),!producer.nestedStackResource)throw new(errors_1()).AssumptionError((0,literal_string_1().lit)`AssertionFailed`,"assertion failed");return producer.nestedStackResource.getAtt(`Outputs.${output.logicalId}`)}function referenceNestedStackValueInParent(reference,targetStack){let currentStack=stack_1().Stack.of(reference.target);if(currentStack!==targetStack&&!isNested(currentStack,targetStack))throw new(errors_1()).UnscopedValidationError((0,literal_string_1().lit)`ReferencedResourceMustBeInTargetStack`,`Referenced resource must be in stack '${targetStack.node.path}', got '${reference.target.node.path}'`);const isNestedListReference=currentStack!==targetStack&&reference.typeHint===type_hints_1().ResolutionTypeHint.STRING_LIST;for(;currentStack!==targetStack;)reference=createNestedStackOutput(stack_1().Stack.of(reference.target),reference),currentStack=stack_1().Stack.of(reference.target);return isNestedListReference?token_1().Tokenization.reverseList(cfn_fn_1().Fn.split(exports.STRING_LIST_REFERENCE_DELIMITER,token_1().Token.asString(reference))):reference}function isNested(nested,parent){return nested.nestedStackParent===parent?!0:nested.nestedStackParent?isNested(nested.nestedStackParent,parent):!1}function generateUniqueId(stack,ref,prefix=""){return stack.resolve(`${prefix}${names_1().Names.nodeUniqueId(ref.target.node)}${ref.displayName}`)}