Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(aws-ssm): configure a default value instead of dummy-value-for-parameterName #7051

Closed
2 tasks
Labels
@aws-cdk/aws-ssm Related to AWS Systems Manager effort/large Large work item – several weeks of effort feature-request A feature should be added or improved. p2

Comments

@atakidev
Copy link

My feature request is that it is useful to be able to return a configured default value from StringParameter.valueFromLookup() instead of dummy-value-for-parameterName.

Use Case

CDK can lookup ssm parameters like this:

const value:string = ssm.StringParameter.valueFromLookup(this, 'keyName');

It usually works well. However, the returned value may be like dummy-value-for-keyName when no context value exist. In this case, if the returned value is used by some other functions like Bucket.fromBucketArn, Topic.fromTopicArn, or etc, it causes an error like this:

ARNs must have at least 6 components: dummy-value-for-keyName

It prevents from working cdk command well.
Based on the above case, I think it is useful to be able to configure the default value or it is good to return the actual ssm parameter value instead of a dummy value.

Other

The testcase to reproduce this issue is like this:

  1. Init cdk app.
 mkdir foo
 cd foo
 cdk init sample-app --language=typescript
  1. Configure a default region and account.

Set env in bin/foo.ts

#!/usr/bin/env node
import * as cdk from '@aws-cdk/core';
import { FooStack } from '../lib/foo-stack';

const myEnv = { account: 'aws account', region: 'a region'};

const app = new cdk.App();
new FooStack(app, 'FooStack', { env: myEnv });
  1. And then edit lib/foo-stack.ts like this.
import * as cdk from '@aws-cdk/core';
import * as ssm from '@aws-cdk/aws-ssm';
import * as s3 from '@aws-cdk/aws-s3';

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

    const arnValue:string = ssm.StringParameter.valueFromLookup(this, 'keyName');
    const bucket = s3.Bucket.fromBucketArn(this, 'FooBucket', arnValue);
  }
}
  1. Then run cdk synth, the application failed even though keyName exists.
$ cdk synth
ARNs must have at least 6 components: dummy-value-for-keyName
Subprocess exited with error 1

I tested it with cdk 1.31.0 .

The workaround of this issue is to comment out fromXxxxArn code in the above step3 to avoid the error of parsing the returned parameter(arnValue). After cdk synth command finish successfully, cdk.context.json is set. So, cdk synth command can success after uncomment the code because the context value is returned instead of a dummy value.
However, the issue reproduces again if you run cdk context --clear true .

This may be similar to #3654 though the issue was closed.
And I think dummy-value-for relates to the following code:
https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/aws-ssm/lib/parameter.ts#L367

  • 👋 I may be able to implement this feature request
  • ⚠️ This feature might incur a breaking change

This is a 🚀 Feature Request

@atakidev atakidev added feature-request A feature should be added or improved. needs-triage This issue or PR still needs to be triaged. labels Mar 28, 2020
@SomayaB SomayaB added the @aws-cdk/aws-ssm Related to AWS Systems Manager label Mar 30, 2020
@MrArnoldPalmer MrArnoldPalmer added effort/large Large work item – several weeks of effort p1 and removed needs-triage This issue or PR still needs to be triaged. labels Apr 10, 2020
@aripalo
Copy link

aripalo commented Jun 8, 2020

I think I have a similar issue where I am trying to fetch account specific configurations - in this case a VPC CIDR - from SSM parameter store and the dummy value is not a valid value for cidr.

Looking at aws-cdk/aws-ssm/lib/parameter.ts#L367 could the implementation be changed to something like this:

interface ValueFromLookupProps {
   dummyValue: string;
}

public static valueFromLookup(scope: Construct, parameterName: string, props?: ValueFromLookupProps): string {
  const value = ContextProvider.getValue(scope, {
    provider: cxschema.ContextProvider.SSM_PARAMETER_PROVIDER,
    props: { parameterName },
    dummyValue: props.dummyValue || `dummy-value-for-${parameterName}`,
  }).value;

  return value;
}

@aripalo
Copy link

aripalo commented Jun 8, 2020

Well I solved it temporarely by hacking it myself:

import cdk = require("@aws-cdk/core");
import cxschema = require('@aws-cdk/cloud-assembly-schema');

export function ssmStringParameterLookupWithDummyValue(
  scope: cdk.Construct, 
  parameterName: string,
  dummyValue: string
): string {
  return cdk.ContextProvider.getValue(scope, {
    provider: cxschema.ContextProvider.SSM_PARAMETER_PROVIDER,
    props: {
      parameterName,
    },
    dummyValue: dummyValue,
  }).value;
}

@hgolding
Copy link

Well I solved it temporarely by hacking it myself:

import cdk = require("@aws-cdk/core");
import cxschema = require('@aws-cdk/cloud-assembly-schema');

export function ssmStringParameterLookupWithDummyValue(
  scope: cdk.Construct, 
  parameterName: string,
  dummyValue: string
): string {
  return cdk.ContextProvider.getValue(scope, {
    provider: cxschema.ContextProvider.SSM_PARAMETER_PROVIDER,
    props: {
      parameterName,
    },
    dummyValue: dummyValue,
  }).value;
}

Thank you @aripalo, the equivalent Python hack worked for me:

from aws_cdk import (
    core as cdk,
    aws_cognito as cognito
)

def ssm_string_parameter_lookup_with_dummy_value(
        scope: cdk.Construct,
        parameter_name: str,
        dummy_value: str
) -> str:
    return cdk.ContextProvider.get_value(
        scope,
        dummy_value=dummy_value,
        provider='ssm',
        props={
            'parameterName': parameter_name
        }
    ).value


class AStack(cdk.Stack):

    def __init__(self, scope: cdk.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        a_user_pool_arn = ssm_string_parameter_lookup_with_dummy_value(
            self, "/a-user-pool/arn", "arn:aws:service:eu-central-1:123456789012:entity/dummy-value")

        a_user_pool = cognito.UserPool.from_user_pool_arn(self, "AUserPool", a_user_pool_arn)

@MrArnoldPalmer MrArnoldPalmer removed their assignment Jun 21, 2021
@comcalvi comcalvi added p2 and removed p1 labels Feb 13, 2024
@github-actions github-actions bot added p1 and removed p2 labels Feb 18, 2024
Copy link

This issue has received a significant amount of attention so we are automatically upgrading its priority. A member of the community will see the re-prioritization and provide an update on the issue.

@aashishgk7760
Copy link

aashishgk7760 commented Apr 17, 2024

When using valueFromLookup for SSM parameters , initially it returns a dummy value , I tried the workaround which is given which still returns a dummy value initially , Below is the sample replicate code , I see this issue is due from long time , any update with respect to this .

import * as  cxschema from '@aws-cdk/cloud-assembly-schema'
export function ssmStringParameterLookupWithDummyValue(
  scope: Construct, 
  parameterName: string,
  dummyValue: string
): string {
  return cdk.ContextProvider.getValue(scope, {
    provider: cxschema.ContextProvider.SSM_PARAMETER_PROVIDER,
    props: {
      parameterName,
    },
    dummyValue: dummyValue,
  }).value;
}

  export class Stack5 extends cdk.Stack {

    constructor(scope: Construct, id: string, props: cdk.StackProps) {
      super(scope, id, props);

      const s1 = ssmStringParameterLookupWithDummyValue(this, config.environments.dev.ssmname,config.environments.dev.ssmname)

      console.log(s1)
  

@khushail khushail changed the title Feature request to configure a default value instead of dummy-value-for-parameterName (aws-ssm): configure a default value instead of dummy-value-for-parameterName Apr 23, 2024
@khushail
Copy link
Contributor

internal ticket created -P127209296

@khushail khushail added p2 p1 and removed p1 p2 labels Apr 24, 2024
@pahud
Copy link
Contributor

pahud commented Apr 24, 2024

This is because when valueFromLookup, which is trying to lookup the context through a context provider and retrieve from ssm parameter if not found. If the value exists in local context, we would be able to get that value in the CDK construct/prepare stage(see app lifecycle). If it does not, our currently implementation would just insert a dummy string in the construct stage which means “we don’t know it yet but we'll find out later” until the synthesize stage. So you have to handle that arn validation as described in our doc here.

In your case you can do it this way:

import * as cdk from '@aws-cdk/core';
import * as ssm from '@aws-cdk/aws-ssm';
import * as s3 from '@aws-cdk/aws-s3';

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

    const arnLookup:string = ssm.StringParameter.valueFromLookup(this, 'keyName');
    let arnLookupValue: string;
if (arnLookup.includes('dummy-value')) {
	arnLookupValue = this.formatArn({
	service: 's3',
	resource: 'bucket',
	region: '',
	resourceName: arnLookup,
	});
} else {
	arnLookupValue = arnLookup;
}
    const bucket = s3.Bucket.fromBucketArn(this, 'FooBucket', arnValue);
  }
}

or simply

const bucket = s3.Bucket.fromBucketArn(this, 'FooBucket', Lazy.string({ produce: () => arnLookup }));

However, if for some reasons you REALLY need to know exactly the ARN value in the construct/prepare stages, you can retrieve that with AWS CLI before you run cdk deploy and pass that value as a context variable to it. e.g.

// get ssm parameter value with CLI
bucketArn = $(aws ssm get-parameter --name foo --query 'Parameter.Value' --output text)
npx cdk deploy -c bucketArn=${bucketArn}

And in your cdk.app you can simply get that value with tryGetContext().

Let me know if it works for you.

@pahud pahud added the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Apr 24, 2024
@sklibanov312
Copy link

sklibanov312 commented Apr 24, 2024

As an aside, is there an option to, in any way, 'just' fetch any non-locally-available context immediately? I don't have a requirement to synthesize anything offline, so reaching inside the currently logged in AWS profile to retrieve actual SSM parameter store values, or inspect other actual resources (subnets for a VPC, as one example) seems like an easy way to avoid dummy anything.

(EDIT: For clarity, let's pretend there's a VPC that was created with human hands, with an SSM parameter store string value that has the VPC's ARN. The SSM parameter has a name that the CDK stack knows. It needs to assign a resource to a specific subnet within a VPC, by matching the subnet's availability zone to some string it knows.)

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Apr 25, 2024
@gshpychka
Copy link
Contributor

As an aside, is there an option to, in any way, 'just' fetch any non-locally-available context immediately? I don't have a requirement to synthesize anything offline, so reaching inside the currently logged in AWS profile to retrieve actual SSM parameter store values, or inspect other actual resources (subnets for a VPC, as one example) seems like an easy way to avoid dummy anything.

(EDIT: For clarity, let's pretend there's a VPC that was created with human hands, with an SSM parameter store string value that has the VPC's ARN. The SSM parameter has a name that the CDK stack knows. It needs to assign a resource to a specific subnet within a VPC, by matching the subnet's availability zone to some string it knows.)

No - it does all the SDK calls in one go, after synthing once to figure out what calls it needs to make.

What you're describing already works, kind of - after fetching the data it immediately does a second synth, this time with actual values.

@sklibanov312
Copy link

sklibanov312 commented Apr 25, 2024

No - it does all the SDK calls in one go, after synthing once to figure out what calls it needs to make.

I agree, that's absolutely what it does today. That's exactly the behavior that's causing 'dummy' to show up in people's code (as documented ). Why is that? Is the reason for the current behavior something that can be changed, at least optionally?

Copy link

Comments on closed issues and PRs are hard for our team to see.
If you need help, please open a new issue that references this one.

1 similar comment
Copy link

Comments on closed issues and PRs are hard for our team to see.
If you need help, please open a new issue that references this one.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 13, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.