plutownium
plutownium

Reputation: 1988

AWS CDK says Argument of type 'this' is not assignable to parameter of type 'Construct'

I am working with a problem that has a few other similar solutions posted on stackoverflow

(1) Argument of type 'this' is not assignable to parameter of type 'Construct' in AWS CDK

(2) AWS CDK, typescript - Argument of type 'this' is not assignable to parameter of type 'Construct'

I tried making all my aws library versions match per this advice:

"This might happen because you are using CDK module with a different version than the CDK core library. CDK updates very often so it's a quite common error.

For fixing this you need to update all the cdk packages to the same version."

The advice is repeated here in different words, so i did all that:

Delete node_modules folder
Delete package-lock.json
Ensure all dependencies in package.json are using same version.
Remove carrot ^ symbol before dependencies
npm install

Now my package json is this:

{
    "name": "cdk-eb-infra",
    "version": "0.1.0",
    "bin": {
        "cdk-eb-infra": "bin/cdk-eb-infra.js"
    },
    "scripts": {
        "build": "tsc",
        "watch": "tsc -w",
        "test": "jest",
        "cdk": "cdk"
    },
    "devDependencies": {
        "@types/jest": "^29.2.4",
        "@types/node": "18.11.15",
        "aws-cdk": "2.59.0",
        "jest": "^29.3.1",
        "ts-jest": "^29.0.3",
        "ts-node": "^10.9.1",
        "typescript": "~4.9.4"
    },
    "dependencies": {
        "@aws-cdk/aws-elasticbeanstalk": "1.187.0", // note identical versions
        "@aws-cdk/aws-iam": "1.187.0", // note identical versions
        "@aws-cdk/aws-s3-assets": "1.187.0", // note identical versions
        "@aws-cdk/core": "1.187.0", // note identical versions
        "aws-cdk-lib": "2.59.0",
        "constructs": "^10.0.0",
        "source-map-support": "^0.5.21"
    }
}

Now I try to run cdk deploy and I get

lib/cdk-eb-infra-stack.ts:20:57 - error TS2345: Argument of type 'this' is not assignable to parameter of type 'Construct'.
  Type 'CdkEbInfraStack' is missing the following properties from type 'Construct': onValidate, onPrepare, onSynthesize, validate, and 2 more.

20         const app = new elasticbeanstalk.CfnApplication(this, "Application", {
                                                           ~~~~
lib/cdk-eb-infra-stack.ts:25:76 - error TS2345: Argument of type 'this' is not assignable to parameter of type 'Construct'.

25         const appVersionProps = new elasticbeanstalk.CfnApplicationVersion(this, "AppVersion", {
                                                                              ~~~~
lib/cdk-eb-infra-stack.ts:37:37 - error TS2345: Argument of type 'this' is not assignable to parameter of type 'Construct'.

37         const myRole = new iam.Role(this, `${appName}-aws-elasticbeanstalk-ec2-role`, {
                                       ~~~~
lib/cdk-eb-infra-stack.ts:46:60 - error TS2345: Argument of type 'this' is not assignable to parameter of type 'Construct'.

46         const instanceProfile = new iam.CfnInstanceProfile(this, myProfileName, {

What is the solution?

edit: Sharing the (sorry, long) code of my cdk-eb-infra-stack.ts file in the /lib folder:

import * as cdk from "aws-cdk-lib";
import iam = require("@aws-cdk/aws-iam");
import elasticbeanstalk = require("@aws-cdk/aws-elasticbeanstalk");
import s3assets = require("@aws-cdk/aws-s3-assets");
import { Construct } from "constructs";
// import * as sqs from 'aws-cdk-lib/aws-sqs';

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

        // The code that defines your stack goes here
        // Construct an S3 asset from the ZIP located from directory up.
        const webAppZipArchive = new s3assets.Asset(this, "WebAppZip", {
            path: `${__dirname}/../app.zip`,
        });

        // Create a ElasticBeanStalk app.
        const appName = "MyWebApp";
        const app = new elasticbeanstalk.CfnApplication(this, "Application", {
            applicationName: appName,
        });

        // Create an app version from the S3 asset defined earlier
        const appVersionProps = new elasticbeanstalk.CfnApplicationVersion(this, "AppVersion", {
            applicationName: appName,
            sourceBundle: {
                s3Bucket: webAppZipArchive.s3BucketName,
                s3Key: webAppZipArchive.s3ObjectKey,
            },
        });

        // Make sure that Elastic Beanstalk app exists before creating an app version
        appVersionProps.addDependsOn(app);

        // Create role and instance profile
        const myRole = new iam.Role(this, `${appName}-aws-elasticbeanstalk-ec2-role`, {
            assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"),
        });

        const managedPolicy = iam.ManagedPolicy.fromAwsManagedPolicyName("AWSElasticBeanstalkWebTier");
        myRole.addManagedPolicy(managedPolicy);

        const myProfileName = `${appName}-InstanceProfile`;

        const instanceProfile = new iam.CfnInstanceProfile(this, myProfileName, {
            instanceProfileName: myProfileName,
            roles: [myRole.roleName],
        });
    }
}

I did exclusively copy-paste from Module 2: Create Infrastructure using AWS CDK

Upvotes: 1

Views: 2385

Answers (3)

fedonev
fedonev

Reputation: 25659

You are mixing V1 and V2 dependencies. Remove the V1 dependencies, that is, the packages in your package.json with version 1.187.0. Import service-specific packages from aws-cdk-lib:

import {
  aws_iam as iam,
  aws_elasticbeanstalk as elasticbeanstalk,
  aws_s3_assets as s3_assets,
} from "aws-cdk-lib";

In V2, only the non-stable "alpha" modules are in separate packages:

Package CDK Version Constructs
aws-cdk-lib v2 L1 (CfnSomething) and stable L2/L3 constructs
@aws-cdk/aws-something-alpha v2 experimental L2/L3 consturcts
@aws-cdk/aws-something v1 all

Upvotes: 1

Jacob Greenbow
Jacob Greenbow

Reputation: 161

It appears you are mixing CDKv1 and CDKv2 packages.

CDKv2 Migration docs

This would fall under Ensure all dependencies in package.json are using same version.

Change

"dependencies": {
    "@aws-cdk/aws-elasticbeanstalk": "1.187.0", // note identical versions
    "@aws-cdk/aws-iam": "1.187.0", // note identical versions
    "@aws-cdk/aws-s3-assets": "1.187.0", // note identical versions
    "@aws-cdk/core": "1.187.0", // note identical versions
    "aws-cdk-lib": "2.59.0",
    "constructs": "^10.0.0",
    "source-map-support": "^0.5.21"
}

to

"dependencies": {
    "aws-cdk-lib": "2.59.0", // CDKv2
    "constructs": "^10.0.0",
    "source-map-support": "^0.5.21"
}

Edit: per the answer from @fedonev

Update your imports like so:

import {
  aws_iam as iam,
  aws_elasticbeanstalk as elasticbeanstalk,
  aws_s3_assets as s3_assets,
} from "aws-cdk-lib";

In V2, only the non-stable "alpha" modules are in separate packages.

Pardon me, I am new to citing on StackOverflow. Edit if there is a better way to attribute @fedonev

Upvotes: 3

plutownium
plutownium

Reputation: 1988

Both Fedonev and Jacob Greenbow posted helpful responses. I was able to make the following changes and get it working:

import { Stack, StackProps, aws_iam as iam, aws_elasticbeanstalk as elasticbeanstalk, aws_s3_assets as s3_assets } from "aws-cdk-lib";
import { Construct } from "constructs";
// import * as sqs from 'aws-cdk-lib/aws-sqs';

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

        // The code that defines your stack goes here
        // Construct an S3 asset from the ZIP located from directory up.
        const webAppZipArchive = new s3_assets.Asset(this, "WebAppZip", {
            path: `${__dirname}/../app.zip`,
        });

        // Create a ElasticBeanStalk app.
        const appName = "MyWebApp";
        const app = new elasticbeanstalk.CfnApplication(this, "Application", {
            applicationName: appName,
        });

        // Create an app version from the S3 asset defined earlier
        const appVersionProps = new elasticbeanstalk.CfnApplicationVersion(this, "AppVersion", {
            applicationName: appName,
            sourceBundle: {
                s3Bucket: webAppZipArchive.s3BucketName,
                s3Key: webAppZipArchive.s3ObjectKey,
            },
        });

        // Make sure that Elastic Beanstalk app exists before creating an app version
        appVersionProps.addDependsOn(app);

        // Create role and instance profile
        const myRole = new iam.Role(this, `${appName}-aws-elasticbeanstalk-ec2-role`, {
            assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"),
        });

        const managedPolicy = iam.ManagedPolicy.fromAwsManagedPolicyName("AWSElasticBeanstalkWebTier");
        myRole.addManagedPolicy(managedPolicy);

        const myProfileName = `${appName}-InstanceProfile`;

        const instanceProfile = new iam.CfnInstanceProfile(this, myProfileName, {
            instanceProfileName: myProfileName,
            roles: [myRole.roleName],
        });
    }
}

Note that the Stack and StackProps had to be imported too to avoid breaking the rest of amazon's example.

Upvotes: 0

Related Questions