Aws-cdk: this.node.tryGetContext to evaluate props from cdk.json

Created on 20 May 2020  路  13Comments  路  Source: aws/aws-cdk

Would be nice if this.node.tryGetContext could evaluate the props from cdk.json context file

Use Case

So instead of using :
const nginx_sec_group = new ec2.SecurityGroup(this, "NGINXSecGroup", {
vpc: props.vpc_from_vpc_stack,
allowAllOutbound: true,
securityGroupName: "ecs-nginx-sg",
description: "security group for nginx",
}

I could run :
const nginx_props =this.node.tryGetContext("nginx")
const nginx_sec_group = new ec2.SecurityGroup(this, "NGINXSecGroup", nginx_props)
Now it does not evaluate props.vpc_from_vpc_stack after reading context.

Proposed Solution

Other

  • [ ] :wave: I may be able to implement this feature request
  • [ ] :warning: This feature might incur a breaking change

This is a :rocket: Feature Request

feature-request needs-triage

Most helpful comment

@shivlaks Thank you

All 13 comments

@CONJAUMCGCG

what version of the CLI are you using? This is how runtime context lookup should be working.

sample cdk.json

{
  "app": "npx ts-node bin/sample.ts",
  "context": {
      "myKey": "hey-a-value"
   }
}

Using it by this.node.tryGetContext('myKey') should return hey-a-value (undefined if lookup failed). Learn more about runtime context

@shivlaks
Yes this works, but what I expect is:
{
"app": "npx ts-node bin/sample.ts",
"context": {
"myKey": "props.vpcId" - imaging vpcId is property of VpcProps(StackProps)
}
}
this.node.tryGetContext('myKey') to return me evaluated value like vpc-0XXXXXXXX. Or it can be any other variable

@CONJAUMCGCG context is intended to be at the app level (as it should be available to all stacks that maybe created). It's the reason we preclude the ability to call setContext after child stacks have been added.

what's the primary pain point you're facing? What's missing by referencing the vpc?

image
image
image
Context is defined in advance from cdk.json. I have attached images. As you see vpcId is property and value I may not know before it's stack is executed.
Mayber there is a way to setContext for dev.NginxStack.vpcId ?

So is your primary issue that you can't determine the VPC id until the stack is created?

Some options:

  • If your VPC is being created in the same stack, you can reference it directly.

  • Alternatively, you can look up your VPC via fromLookup and fromVpcAttributes and reference it.

  • finally you can also reference resources with something like

stack.node.tryFindChild('myVpc') as ec2.IVPC

aside from that, you should just be able to read the rest of your config from the context and reference the resources within your app.

@shivlaks
No, it is not my case.
Let me paste more screenshots.
image

and inside of InfraPipelineStack I create InfraPipelineStackProps

export interface InfraPipelineStackProps extends StackProps {
//readonly lambdaCode: lambda.CfnParametersCode;
readonly code_build_role: CfnRole;
readonly code_deploy_role: CfnRole;
readonly code_pipeline_role: CfnRole;
readonly s3_bucket: s3.CfnBucket;
}

so inside InfraPipelineStack I created code_build_project
image

But as you see all CfnProjectProps are hardcoded, but I could move them all to CDK.json and use this.node.tryGetContext to retrieve all props as one context value , but I cant because props.code_build_role.attrArn is variable and I can't store in CDK.json.

If for example this.node.tryGetContext had in it's body check for variable and evaluate it like:
for (let key in Context) {
let value = Context[key];
if(value. includes("props"){
Context[key]=eval(value)// So it can evaluate props.code_build_role.attrArn when reading from CDK.json
}
}
I dont know if it is possible

Or if there would be a way to update in runtime cdk.json like this.node.setContext("key","value")
Also this.node.setContext("key","value") only allows you to set root key, is it possible to set setContext(key[innerkey],"value") as cdk.json is json structure

accidentally closed

got it, so you want to substitute in properties and one can't be resolved because it's a reference.

in that case:

cdk.json

{
  "app": "npx ts-node bin/example.ts",
  "context": {
    "@aws-cdk/core:enableStackNameDuplicates": "true",
    "aws-cdk:enableDiffNoFail": "true",
    "buildConfig": {
      "source":  {
        "type": "GitHub",
        "location": "https://github.com",
        "buildSpec": "buildSpec.yml"
      },
      "artifacts": { "type": "NO_ARTIFACTS"},
      "name": "codebuildproject",
      "environment": {
        "image": "my-image",
        "type": "LINUX_CONTAINER",
        "computeType": "BUILD_GENERAL1_SMALL"
      }
    }
  }
}

example-stack

import * as cdk from '@aws-cdk/core';
import { CfnProject } from '@aws-cdk/aws-codebuild';
import * as iam from '@aws-cdk/aws-iam';

export class ExampleStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const role = new iam.Role(this, 'MyRole', {
      assumedBy: new iam.ServicePrincipal('cloudformation.amazonaws.com'),
    });

    const code_build_project = new CfnProject(this, 'proj', {
      ...this.node.tryGetContext('buildConfig'),
      serviceRole: role.roleArn // in your case this is props.code_build_role.attrArn
    });

  }
}

The context is not the right place to be trying to resolve references. It's intended to be a mechanism to pass in static input.

@shivlaks Thank you

@shivlaks Can you please suggest how I can override properties in case like this, it perfectly works for one level properties but fails if I need to override somthing like ...nginx_props["nginx_service"]["loadBalancers"]

const nginx_props = this.node.tryGetContext(env)["NginxStack"];
const nginx = new CfnService(this, "Nginx", {
       ...nginx_props["nginx_service"],
      cluster: props.cluster_from_cluster_stack.clusterName,
      ...nginx_props["nginx_service"]["networkConfiguration"]. 
      ["awsvpcConfiguration"],securityGroups: [nginx_sec_group.securityGroupId],
      ...nginx_props["nginx_service"]["loadBalancers"], targetGroupArn: nginx_tg.ref,
      taskDefinition: nginx_taskdef.ref,
    });
"dev"{
"NginxStack"{
"nginx_service": {
          "cluster": "props.cluster_from_cluster_stack.clusterName",
          "networkConfiguration": {
            "awsvpcConfiguration": {
              "subnets": [
                "subnet-xxxx",
                "subnet-xxxx"
              ],
              "assignPublicIp": "DISABLED",
              "securityGroups": ["nginx_sec_group.securityGroupId"]
            }
          },
          "loadBalancers": [
            {
              "containerPort": 80,
              "containerName": "Nginx",
              "targetGroupArn": "nginx_tg.ref"
            }
          ],
          "serviceName": "Nginx",
          "deploymentConfiguration": {},
          "desiredCount": 2,
          "enableEcsManagedTags": false,
          "taskDefinition": "nginx_taskdef.ref",
          "launchType": "FARGATE"
        }
}
}



md5-f670e2bb1d11dd4c282c03089b1b249c



 const nginx = new CfnService(this, "Nginx", {...nginx_props["nginx_service"],
    cluster: props.cluster_from_cluster_stack.clusterName,
    taskDefinition: nginx_taskdef.ref,
    networkConfiguration: {
      awsvpcConfiguration: {
        subnets: [
          "subnet-xxxx",
          "subnet-xxxx"
        ],
        assignPublicIp: "DISABLED",
        securityGroups: [nginx_sec_group.securityGroupId]
      }
    },
    loadBalancers: [
      {
        containerPort: 80,
        containerName: "Nginx",
        targetGroupArn: nginx_tg.ref
      }
    ]
  }

I wouldn't do any of this at all.

I would create a Construct and encode all of the behaviour within it, and request what's needed as props. That will lead to a much more robust, reusable, and extensible solution. This example is trying to use context outside of it's designed purpose.

I think this question is better suited for StackOverflow or our Gitter channel as we would not try to take this on as a feature.

Thank you Shiv.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

abelmokadem picture abelmokadem  路  3Comments

v-do picture v-do  路  3Comments

PaulMaddox picture PaulMaddox  路  3Comments

mirazmamun picture mirazmamun  路  3Comments

kawamoto picture kawamoto  路  3Comments