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

Combining property values based on a common property in an array of objects using JavaScript

I have a large array filled with various objects structured like: [ { "type": "bananas", "count": 15 }, { "type": "kiwis", "count": 20 }, { "type": "bananas", ...

SystemJS TypeScript Project

I am embarking on a journey to initiate a new TypeScript project. My aim is to keep it simple and lightweight without unnecessary complexities, while ensuring the following: - Utilize npm - Implement TypeScript - Include import statements like: import ...

Why is the dateclick event in PrimeNG's FullCalendar not being emitted when clicking on a date? What is the best way to handle click events on specific dates within the calendar?

I am new to using Angular and PrimeNG, and I am facing challenges while trying to implement the FullCalendar component. The specific component I am referring to can be found here: The issue arises when I attempt to trigger an event when a user clicks on a ...

Using amplify.yml to retrieve secrets from Parameter Store

Currently, I am working on an Amplify project with Next.js and trying to follow the documentation to call a parameter store secret in my amplify.yml file. This secret is crucial for configuring my nextauth implementation. However, it seems to be failing af ...

When trying to reload Angular 8 pages, encountering an error that reads "Cannot GET /login" and also receiving a notification stating the image '/favicon.ico' cannot be loaded due to a violation of

Encountering an issue with the error message "Cannot GET login/" appearing on the page body of my latest Angular 8 app. Despite attempting various solutions found on forums, I have been unable to resolve this error. Any suggestions or advice would be great ...

Invoking a nested class while declaring types in TypeScript

This is the specific format of data that I am in need of this.structure=[ { id: 1, name: 'root1', children: [ { id: 2, name: 'child1' }, { id: 3, name: 'child2' } ] }, { ...

Troubleshooting the error message "TypeError: Cannot read property 'name' of undefined" when working with data binding in Angular 4

I am brand new to Angular and I have been working on creating a custom Component. Specifically, I am trying to display a list of Courses (objects) which consist of two properties: id and name. So far, this logic is functioning properly. However, when attem ...

Using Angular: A guide to setting individual values for select dropdowns with form controls

I am working on a project that involves organizing food items into categories. Each item has a corresponding table entry, with a field indicating which category it belongs to. The category is represented by a Guid but displayed in a user-friendly format. C ...

Is there a way to access the value or key of a JSON property in an Angular template for rendering purposes?

Having trouble displaying the JSON values of certain properties on screen. Utilizing Angular Material table to showcase my JSON response. The code snippet below is responsible for rendering the JSON data: <mat-card-content class="dashboard-card-cont ...

The type 'any' cannot be assigned to the type 'never' as a parameter

const [files, setFiles] = useState([]) const handleChange = (event: any) => { setFiles.push(event.target.files[0].name) return (<div> {files.map((file: any) => ( <p>Hello!</p> ))} </ ...

Using styled-components in React

I came across this interesting code snippet in the styled-components documentation. Here it is: const Button = styled.button<{ $primary?: boolean; }>` background: ${props => props.$primary ? "#BF4F74" : "white"}; color: ${p ...

Issue encountered while implementing async functionality in AngularFireObject

I'm encountering difficulties with the async feature in AngularFireObject. Is there a solution available? Snippet from HomePage.ts: import { AngularFireObject } from 'angularfire2/database'; export class HomePage { profileData: Angu ...

Is there a way to conceal 'private' methods using JSDoc TypeScript declarations?

If we consider a scenario where there is a JavaScript class /** * @element my-element */ export class MyElement extends HTMLElement { publicMethod() {} /** @private */ privateMethod() {} } customElements.define('my-element', MyElement) ...

This error is being thrown because the element has an implicit 'any' type due to the fact that a 'string' type expression cannot be used to index the 'Users' type

As I attempt to extract data from a json file and create an HTML table, certain sections of the code are functioning correctly while others are displaying index errors. All relevant files are provided below. This issue pertains to Angular. This is my json ...

Tips for invoking an Android function from an AngularJS directive?

I am facing an issue with my HTML that uses an AngularJS directive. This HTML file is being used in an Android WebView, and I want to be able to call an Android method from this directive (Learn how to call Android method from JS here). Below is the code ...

What is causing the issue of URL parameters becoming undefined when performing service injection in the app component?

When working with a service that reads parameters from the URL, everything seems to be functioning properly until attempting to inject the service into the constructor of the app.component.ts file or trying to call a service method from the app.component.t ...

Oops! There seems to be a syntax error near "NOT" in TypeORM

I am currently developing an app using NestJs with a Postgres database and TypeOrm as the ORM. I have created my migration file, configured the package.json file, but when I try to run yarn typeorm migration:run, I encounter the following error: query fail ...

Leveraging the power of the Async pipe within an Angular TypeScript file

Using the async pipe in HTML involves utilizing the syntax "Products$ | async as products". But can we also access these same products in the TypeScript file? Is this possible? ...

Click on a link to open it in the current tab with customized headers

In my Angular project, I am attempting to open a link by clicking a button that redirects to the specified URL using the following code: window.open(MY_LINK, "_self"); However, in this scenario, I also need to include an access token in the header when t ...

Struggling with creating a generic TypeScript structure?

My goal is to manipulate data structured like this: const exampleState = { elements : { element1: { values: { value1: 10, value2: 10, }, elementDetails : { detail1 : { values: { value1: ...