mongodb / awscdk-resources-mongodbatlas

MongoDB Atlas AWS CDK Resources
Apache License 2.0
35 stars 17 forks source link

[Bug]: Getting a 409 when updating a stack with `CfnOnlineArchive` resources #341

Closed lockenj closed 1 month ago

lockenj commented 2 months ago

Is there an existing issue for this?

CDK package version

3.6.0

CFN Resource version

2.1.0

CFN Resource Region

us-east-2

Current Behavior

We have a stack with multiple online archives setup. We recently updated the stack and we are getting this error back.

POST: HTTP 409 Conflict (Error code: "ONLINE_ARCHIVE_ALREADY_EXISTS")

AWS CDK code to reproduce the issue

//MongoAtlasArchiveConstruct.mjs
import {
  CfnOnlineArchive
} from 'awscdk-resources-mongodbatlas';
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';

class MongoAtlasArchiveConstruct extends Construct {
  //FROM PROPS
  #_secretName;
  #_atlasProjectId;
  #_clusterName;

  //COMPUTED
  #_archive;
  constructor(scope, id, props) {
    super(scope, id, props);

    //Optional property that essential says use this project instead of creating one
    this.#_atlasProjectId = props.projectId;

    this.#_clusterName = props.clusterName;
    if (!this.#_clusterName) {
      throw new Error('Must supply an `clusterName` property!');
    }
    this.#_secretName = props.secretName;
    if (!this.#_secretName) {
      throw new Error('Must supply an `secretName` property!');
    }

    /********************************************************************/
    // CREATE A CLUSTER ARCHIVE
    /********************************************************************/
    const rando5Chars = (Math.random() + 1).toString(36).substring(7);
    const archiveName = `${props.dbName}.${props.collName}-${rando5Chars}`;
    this.#_archive = new CfnOnlineArchive(this, archiveName, {
      profile: this.#_secretName,
      projectId: this.#_atlasProjectId,
      // NOTE: Cluster Name has a 21 character max due to the CfnOnlineArchive code (LAME, see https://github.com/mongodb/awscdk-resources-mongodbatlas/issues/286)
      clusterName: this.#_clusterName,
      ...props
    });
  }
  get secretName() {
    return this.#_secretName;
  }
  get clusterName() {
    return this.#_clusterName;
  }
  get projectId() {
    return this.#_atlasProjectId;
  }
  get archive() {
    return this.#_archive;
  }
}
export { MongoAtlasArchiveConstruct };
export default MongoAtlasArchiveConstruct;

//ArchiveStack.mjs
import {
    CfnOnlineArchivePropsCollectionType,
    CriteriaViewType,
    ScheduleViewType,
} from 'awscdk-resources-mongodbatlas';
import { Stack } from 'aws-cdk-lib';

import { MongoAtlasArchiveConstruct } from "@freakingreallyawesomenocode/core-environment-infra-lib";

class ArchiveStack extends Stack {
    constructor(scope, id, props) {
        super(scope, id, {
            env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },//Needed to lookup the apex domain Hosted Zone!
            ...props
        });
        const mongoAtlas = props.mongoAtlasConstruct;
        const ARCHIVE_COMMON_DEFAULTS = {
            dbName: 'event-runtime',
            secretName: mongoAtlas.secretName,
            clusterName: mongoAtlas.clusterName,
            projectId: mongoAtlas.projectId,
            collectionType: CfnOnlineArchivePropsCollectionType.STANDARD,
            criteria: {
                type: CriteriaViewType.CUSTOM,
                query: '{ "__toBeArchived": true }',
            },
            partitionFields: [
                {
                    fieldName: '_id',
                }
            ],
            //ScheduleView  Regular frequency and duration when archiving process occurs.
            //Below is 2am-4am EST
            //Note: the idea here is that the snapshot happens prior to this (12am)
            schedule: {
                type: ScheduleViewType.DAILY,
                startHour: 6, //number  Hour of the day when the when the scheduled window to run one online archive starts.
                startMinute: 0, //number    Minute of the hour when the scheduled window to run one online archive starts.
                endHour: 8, //number    Hour of the day when the scheduled window to run one online archive ends.
                endMinute: 0,   //number    Minute of the hour when the scheduled window to run one online archive ends.
            },
        };
        this.eventDetailArchive = new MongoAtlasArchiveConstruct(this, 'MongoAtlasArchiveConstructEventDetail', {
            collName: 'event-detail',
            ...ARCHIVE_COMMON_DEFAULTS
        });
        this.eventDetailArchive.node.addDependency(mongoAtlas);
        this.eventRawActivityArchive = new MongoAtlasArchiveConstruct(this, 'MongoAtlasArchiveConstructEventRawActivity', {
            collName: 'event-raw-activity',
            ...ARCHIVE_COMMON_DEFAULTS
        });
        this.eventRawActivityArchive.node.addDependency(mongoAtlas);
        this.eventActivityArchive = new MongoAtlasArchiveConstruct(this, 'MongoAtlasArchiveConstructEventActivity', {
            collName: 'event-activity',
            ...ARCHIVE_COMMON_DEFAULTS
        });
        this.eventActivityArchive.node.addDependency(mongoAtlas);
        this.itemRawBiddingArchive = new MongoAtlasArchiveConstruct(this, 'MongoAtlasArchiveConstructItemRawBidding', {
            collName: 'item-raw-bidding',
            ...ARCHIVE_COMMON_DEFAULTS
        });
        this.itemRawBiddingArchive.node.addDependency(mongoAtlas);
        this.itemBiddingArchive = new MongoAtlasArchiveConstruct(this, 'MongoAtlasArchiveConstructItemBidding', {
            collName: 'item-bidding',
            ...ARCHIVE_COMMON_DEFAULTS
        });
        this.itemBiddingArchive.node.addDependency(mongoAtlas);
    }
}
export { ArchiveStack };
export default ArchiveStack;

Steps To Reproduce

  1. Using the above stack and construct create a CDK app
  2. deploy the app
  3. redeploy the stack get the 409

cdk synth

No response

Code of Conduct

github-actions[bot] commented 2 months ago

Thanks for opening this issue! Please make sure to provide the following information to help us reproduce the issue:

Thanks for opening this issue. The ticket CLOUDP-267436 was created for internal tracking.

AgustinBettati commented 2 months ago

Hi @lockenj!

Could you provide additional information of CDK commands you are running and resulting logs in each step? Calling out which properties are being modified is also relevant for this case. From the error you are facing it would seem that a new stack is being created, instead of updating an existing stack.

lockenj commented 2 months ago

Hi @AgustinBettati

We are running cdk deploy from within Github Actions. That same command is ran when the archive stack is first deployed and again when we update our system. Unfortunately this runs any time the system is updated even though there are no changes to that stack and does not need to run.

EspenAlbert commented 2 months ago

@lockenj I think it has to do with these two lines:

const rando5Chars = (Math.random() + 1).toString(36).substring(7);
const archiveName = `${props.dbName}.${props.collName}-${rando5Chars}`;

archiveName is passed as the id to the CfnOnlineArchive construct. I believe this id needs to be the same between executions. Since you are using Math.random(), I believe it will change every time you run cdk deploy. Can you try again by setting archiveName to a static string? e.g.: const archiveName = `${props.dbName}.${props.collName}`; // removing rando5Chars

See Logical ID stability in the AWS docs for more information

lockenj commented 2 months ago

Thank you @EspenAlbert I totally forgot I added that to work around a previous bug that didnt teardown the archives when the stack was destroyed.

I will remove this snippet and verify everything works correctly.

EspenAlbert commented 1 month ago

Hi @lockenj, Did it work after the changes? If so, can we close this issue?

lockenj commented 1 month ago

We were able to test things out this morning and it everything worked as expected. Thanks again!