AWS CDK: Добавить условие Cfn для всех / нескольких ресурсов - PullRequest
0 голосов
/ 02 апреля 2020

Мне нужно добавить условие (например, isProd или isSpecificRegion) для всех / нескольких моих ресурсов в CDK. Я видел, что могу добавить CfnCondition к указанным c ресурсам CDK, используя эту технику: Добавить условия к ресурсам в CDK . например,

// Create the user using the L2 construct
const user = new iam.User(this, 'User');

// Add the condition on the underlying AWS::IAM::User
(user.node.defaultChild as iam.CfnUser).cfnOptions.condition = regionCondition

Есть ли способ перебрать все ресурсы и применить условие?

Ответы [ 3 ]

1 голос
/ 07 апреля 2020

Как правило, вы не хотите использовать CfnConditional с CDK, если в этом нет особой необходимости c. Как отметил Амит в своем комментарии, idiomati c CDK appraoch будет использовать язык if / else logi c для создания экземпляра конструкции или нет.

Если вам абсолютно нужно чтобы использовать CFNConditional на каждом ресурсе, я думаю, что функция аспектов могла бы применить условное условие к базовым ресурсам облачной информации, используя escape-штриховки, хотя я бы настоятельно * рекомендовал против этого.

0 голосов
/ 15 апреля 2020

Используя Аспекты CDK (, как предложено Ричардом ), я смог просто еще больше упростить свое решение (основываясь на моем предыдущем решении: { ссылка }) :

class ApplyCfnConditionAspect(val cfnCondition: CfnCondition): IAspect {
    override fun visit(construct: IConstruct) {
        (construct as? CfnResource)?.cfnOptions?.condition = this.cfnCondition
    }
}

... и затем в пределах Stack после указания всех ресурсов:

this.node.applyAspect(ApplyCfnConditionAspect(shouldEnableAnalyticsCondition))
0 голосов
/ 15 апреля 2020

Я нашел способ автоматически применить CfnCondition к каждому ресурсу в стеке, используя Construct # onPrepare в Stack

На приведенной выше странице Construct#onPrepare():

Выполнение окончательных модификаций перед синтезом

Этот метод может быть реализован производными конструкциями для выполнения окончательных изменений перед синтезом. prepare () будет вызываться после подготовки дочерних конструкций.

Это расширенная функция фреймворка. Используйте это только в том случае, если вы понимаете последствия.

Следующий код CDK (пример кода - я только вставляю соответствующие биты здесь) находится в Kotlin, но будет применяться к любой поддерживаемый язык CDK:

class MyStack internal constructor(app: App, name: String) : Stack(app, name) {
      private lateinit var myCondition: CfnCondition

    init {
        myCondition = CfnCondition.Builder.create(this, "myCondition")
                .expression(Fn.condition...) // Fill in your condition
                .build()
    }

    /**
     * Use the `Stack#onPrepare` hook to find all CF resources and apply our stack standard CF condition on them.
     * See:
     * * [Stack.onPrepare]: https://docs.aws.amazon.com/cdk/api/latest/typescript/api/core/construct.html#core_Construct_onPrepare
     */
    override fun onPrepare() {
        super.onPrepare()
        findAllCfnResources(this.node).forEach { it.cfnOptions.condition = this.myCondition }
    }

    /**
     * Recurse through all children nodes and accumulate [CfnResource] nodes.
     */
    private fun findAllCfnResources(node: ConstructNode): List<CfnResource> {
        val nodes = node.children.map { it.node } + node
        val cfnResources: List<CfnResource> = nodes.flatMap { it.findAll() }.mapNotNull { it as? CfnResource }

        if (node.children.isEmpty()) {
            return cfnResources
        }

        return node.children.fold(cfnResources) {
            accumulatedCfnResources, it -> accumulatedCfnResources + findAllCfnResources(it.node)
        }
    }
}

Юнит-тест (Junit и AssertJ, также в Kotlin), который я добавил, проверяет, что он охватывает все ресурсы:

private val mapper = ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT)

private lateinit var stack: Stack
private lateinit var synthesizedStackCfTemplate: JsonNode

@BeforeEach
fun setUp() {
    val app = App()
    stack = MyStack(app, "MyUnitTestStack")
    synthesizedStackCfTemplate = mapper.valueToTree(app.synth().getStackArtifact(stack.artifactId).template)
}

@Test
fun `All CfnResources have the expected CF Condition`() {
    val expectedCondition = "myCondition"

    val softly = SoftAssertions()
    synthesizedStackCfTemplate.get("Resources").forEach { resource ->
        softly.assertThat(resource.get("Condition")?.asText())
                .describedAs("Resource is missing expected CF condition [$expectedCondition]: $resource")
                .isEqualTo(expectedCondition)
    }
    softly.assertAll()
}
...