0
votes

Using latest .NET CDK, I am trying to create a stack where Instance AMI is specified at deploy time depending on the region where stack is deployed. With regular CloudFormation I could do that using Mappings, AWS::Region and FindInMap function, but with CDK, GenericLinuxImage or LookupMachineImage appear to not accept Aws.REGION and the output of CfnMapping.FindInMap() - deferred values, and AMI and its region have to be known at synth time, which is not what I need.

When using GenericLinuxImage I get "Unable to determine AMI from AMI map since stack is region-agnostic" error.

Is it possible to use CfnMapping.FindInMap() and Aws.REGION to specify Instance custom AMI?

CFN snippet the behavior of which I want to reproduce:

Mappings:
  RegionMap:
    us-east-1: 
      AmiId: ami-XXXXXXXXXXX
...

Resources:
  ...
  InstanceMachine:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: t3a.large
      ImageId: !FindInMap
        - RegionMap
        - !Ref 'AWS::Region'
        - AmiId

Thanks, Vlad.

1
Can you provide the working Cloudformation code snippet? - Amit Baranes
Please edit the original question and add this code - Amit Baranes

1 Answers

3
votes

2021/04/27 Updates

I've fixed this issue from aws cdk upstream. cdk version >= v1.89.0 should be ok.

Here is the fix: https://github.com/aws/aws-cdk/commit/fbe7e89ba764093ddec9caa7de3ca921f3dc68ac


Old reply

After I dug into cdk source code. You can write in this way. Below is typescript's version, you cloud write a .Net version accordingly.

import * as ec2 from '@aws-cdk/aws-ec2';
import { Construct, Stack, StackProps, CfnMapping, Aws } from '@aws-cdk/core';

export class MyStack extends Stack {
  constructor(scope: Construct, id: string, props: StackProps = {}) {
    super(scope, id, props);

    const regionMap = new CfnMapping(this, 'RegionMap', {
      mapping: {
        'cn-north-1': { ami: 'ami-cn-north-1' },
        'cn-northwest-1': { ami: 'ami-cn-northwest-1' },
      },
    });

    class MyImage implements ec2.IMachineImage {
      public getImage(_: Construct): ec2.MachineImageConfig {
        return {
          imageId: regionMap.findInMap(Aws.REGION, 'ami'),
          userData: ec2.UserData.forLinux(),
          osType: ec2.OperatingSystemType.LINUX,
        };
      }
    }

    const vpc= new ec2.Vpc(this, 'VPC');

    new ec2.Instance(this, 'Instance', {
      vpc,
      instanceType: new ec2.InstanceType('t2.micro'),
      machineImage: new MyImage(),
    });
  }
}