How can I determine the existence of an S3 bucket and, if it doesn't exist, create it using TypeScript CDK?

I am currently facing an issue where I need to verify the existence of a bucket in the account and either create a new one if it doesn't exist or use the existing bucket

My attempt at achieving this is as follows:

import {Bucket} from 'aws-cdk-lib/aws-s3';

const bucketName = 'testing-bucket-12345';
const checkBucket = Bucket.fromBucketName(this, bucketName, bucketName);
if (!checkBucket) {
    console.log("Creating a new bucket for testing")
    // Creating the S3 bucket if it does not exist
    new Bucket(this, bucketName, {
        bucketName: bucketName
    });
}

However, it seems like the CDK is not interpreting these lines correctly.

Answer №1

The concept of Bucket.fromBucketName(...) is crucial in distinguishing a "foreign" bucket, which was not originally created within the current stack. CDK expects this foreign bucket to exist and may encounter errors during stack building if it doesn't. The ideal approach would be to verify the existence of the foreign bucket and, if absent, create a non-"foreign" bucket within the stack that remains intact throughout stack updates. However, this process can become convoluted.

To retain a stack-created bucket through updates, the "new Bucket()" command must be executed unconditionally by CDK, despite its initial complexity. During an update, CDK uses this operation to maintain the presence of the bucket within the stack. Neglecting to execute "new Bucket()" except when the bucket is missing will lead to its creation during the initial build but removal during subsequent updates.

In essence, the goal is to implement a solution where a bucket managed within the stack is created only if a similarly-named foreign bucket does not exist. While achieving this cleanly in CDK might pose challenges, resorting to workaround methods is not advised. It's essential to make a design choice between utilizing a foreign bucket or one generated by the CDK stack. If opting for a foreign bucket, it should be created separately beforehand, either by another stack in /bin, via aws cli, or through the AWS console.

Suggested workaround, endorsed by AWS support:

  1. Include a distinctive tag after initializing new Bucket(...) in the constructor:
if (!foreignBucketExists) {
    // Utilize a stack-managed bucket if no foreign bucket with the same name exists
    const myBucket = new Bucket(this, bucketName, {
        bucketName: bucketName
    });
    Tags.of(myBucket).add("CreatedBy", "<a name for this stack>")
} else {
const myBucket = Bucket.fromBucketName(this, bucketName, bucketName);
}
  1. In /bin, validate the existence of a bucket with the specified name, check its tags to determine whether it's considered "foreign" to this stack, and relay the result to the stack constructor from step 1:
// Verify if a bucket with the given name exists
let request = new AWS.S3().listObjects({
    Bucket: MyBucketName
});

let promise = request.promise();
// Handle promise fulfillment/rejection
await promise.then(result => {
    foreignBucketExists = true
}).catch(err => {
    console.log("No Such Bucket exists.")
    foreignBucketExists = false
})

// If the bucket exists, examine its tags to ascertain its origin with respect to the CDK stack

if (foreignBucketExists) {
    try {
        let tagRequest = new AWS.S3().getBucketTagging({
            Bucket: MyBucketName
        });

        let tagPromise = tagRequest.promise();
        await tagPromise.then(result => {
            for (let KeyVal of result.TagSet) {
                if (KeyVal.Key == "CreatedBy" && KeyVal.Value == "<a name for this stack>") {
                    // This indicates that the bucket was created by CDK and is not foreign
                    foreignBucketExists = false;
                }
            }
        }).catch(err => {
            // A lack of tags signifies a foreign bucket
            foreignBucketExists = true  
        })
    } catch {}
} 

console.log("Does bucket Exist?:", foreignBucketExists)

Answer №2

It seems like you're looking for a solution that AWS CDK (or AWS CloudFormation) already provides: By simply defining your resources, like this:

const myBucket = new Bucket(this, bucketName, {
        bucketName
    });

CloudFormation will either use an existing bucket or create a new one, allowing you to access the bucket object after this line of code.

Initially, it may seem strange that CDK doesn't directly create resources; instead, it 'synthesizes' your code into a JSON template for CloudFormation to interpret and deploy accordingly.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to access the value of an IPC message beyond just using console log?

I am developing an app using electron and angular where I need to send locally stored information from my computer. I have successfully managed to send a message from the electron side to the angular side at the right time. However, I am facing issues acce ...

Troubleshooting the issue of process.nextTick not being recognized in Calgolia places.js

After successfully implementing Algolia's places.js in my Angular 7 project using NPM, I encountered an issue. I have integrated a form where one of the fields should be an input. <form [formGroup]="myForm"> <pre style="color: white; b ...

Troubles encountered while trying to make MediaRecorder function in Angular 9

Recently, I've been working on integrating Media Recorder into my Angular 9 application by following the instructions provided at this link. However, I have encountered some issues along the way. When I access the page with the Media Recorder compone ...

In TypeScript, values other than numbers or strings can be accepted as parameters, even when the expected type is a

The issue I am encountering with TypeScript is quite perplexing, especially since I am new to this language and framework. Coming from a Java background, I have never faced such a problem before and it's presenting challenges in my bug-fixing efforts ...

The Angular Date Pipe is currently unable to display solely the Month and Year; it instead presents the complete date, including day, month,

I'm currently using the Bootstrap input date feature to save a new Date from a dialog box. However, I only want to display the month and year when showing the date. Even though I added a pipe to show just the month and year, it still displays the mont ...

What could be the reason behind my Vue file triggering a TS6504 error and suggesting to "allowJs"?

My Vue 3 project, which incorporates TypeScript, is encountering an issue when I attempt to execute vue-tsc --noEmit. error TS6504: File '/proj/src/pages/Index.vue.__VLS_template.jsx' is a JavaScript file. Did you mean to enable the 'allowJs ...

Retrieve data from an HTML form within an Angular 2 ag-grid component

I'm facing a challenge with incorporating form values from a modal into an ag-grid array in my HTML file. I'm unsure of the process to achieve this. Below is an excerpt from my file.html: <template #addTrainContent let-c="close" let-d="dismi ...

Resolving DOMException issue in Google Chrome: A Step-by-Step Guide

In my browser game, I am experiencing an issue with sound playback specifically in Google Chrome. Although the sound manager functions properly in other browsers, it returns a DOMException error after playing sounds in 50% of cases. I'm unsure what co ...

Encountering an ERROR during the compilation of ./src/polyfills.ts while running ng test - Angular 6. The module build

I encountered a problem in an angular project I am working on where the karma.config was missing. To resolve this, I manually added it and attempted to run the test using the command ng test. However, during the execution, an error message appeared: [./src ...

Tips for sending a value to a container component

Within my task management application, I have implemented two selectors: export const selectFilter = (state: RootState) => state.visibilityFilter export const selectVisibleTodos = createSelector( [selectTodos, selectFilter], (todos: Todo[], filter : ...

There is no universal best common type that can cover all return expressions

While implementing Collection2 in my angular2-meteor project, I noticed that the code snippets from the demo on GitHub always result in a warning message being displayed in the terminal: "No best common type exists among return expressions." Is there a ...

Is it correct to implement an interface with a constructor in TypeScript using this method?

I am completely new to TypeScript (and JavaScript for the most part). I recently came across the article discussing the differences between the static and instance sides of classes in the TypeScript handbook. It suggested separating the constructor into an ...

Developing interconnected dynamic components in Angular

Can you help me figure out how to create nested dynamic components while maintaining the parent-child relationship? For instance, if I have data structured like this: - A --A.1 --A.2 -B --B.1 -C I want to build components that reflect this structure, su ...

Next.js Enhanced with Google Analytics

I've been experimenting with integrating Google Analytics into Next.js, following a tutorial on YouTube - https://www.youtube.com/watch?v=lMSBNBDjaH8 Following the instructions in the video, I added these two scripts in _document.js: <script async ...

The lack of invocation of Angular 4's ngOnInit function following a call to router

In my Angular application, I have 3 tabs where one tab displays a table listing employees. Initially, everything works well when the data is loaded for the first time in ngOnInit using an HTTP get request. However, after adding a new employee through a for ...

The Ionic 5 app features a white iframe that functions perfectly on the web platform

Whenever I run my web application's function, the iframe is displayed. However, on Android, all I see is a white screen. Can anyone assist with resolving this issue? HMTL html <ion-content> <ion-button expand="full" color="warning" (clic ...

The function is failing to return the expected value received from the observable subscription

I am attempting to verify the existence of a user in an Angular's in-memory API by validating their username. The function checkUsernameExists(username) is supposed to return an Observable<boolean> based on whether the API responds with undefine ...

Creating Typescript libraries with bidirectional peer dependencies: A complete guide

One of my libraries is responsible for handling requests, while the other takes care of logging. Both libraries need configuration input from the client, and they are always used together. The request library makes calls to the logging library in various ...

TS Mapped Type: Dynamically exclude specific keys based on their values

Seeking a method to create a mapped type that excludes specific keys based on the value of the mapped key. For instance: Consider an option: Options struct, where Options is a union type defined as: { type: DataType } or { type: DataType, params: DataPar ...

What are some ways to utilize TypeScript in incorporating extensions to `koa.Request` packages?

Struggling to utilize both koa-tree-router and koa-bodyparser simultaneously, encountering persistent TypeScript errors: export const userLoggingRouter = new KoaTreeRouter<any, DefaultContext>(); userLoggingRouter.post('/logs/action', (ctx ...