Skip to content

Commit

Permalink
add forceDeploy to bucket
Browse files Browse the repository at this point in the history
  • Loading branch information
ShaiBer committed Oct 31, 2024
1 parent 1408ea0 commit ef267d9
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 3 deletions.
6 changes: 5 additions & 1 deletion packages/@winglang/platform-awscdk/src/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,16 @@ export class Bucket extends cloud.Bucket implements IAwsBucket {

private readonly bucket: S3Bucket;
private readonly public: boolean;
private readonly forceDestroy: boolean;
private bucketDeployment?: BucketDeployment;

constructor(scope: Construct, id: string, props: cloud.BucketProps = {}) {
super(scope, id, props);

this.public = props.public ?? false;
this.forceDestroy = props.forceDeploy ?? false;

this.bucket = createEncryptedBucket(this, this.public);
this.bucket = createEncryptedBucket(this, this.public, this.forceDestroy);

if (props.cors ?? true) {
this.addCorsRule(
Expand Down Expand Up @@ -254,6 +256,7 @@ export class Bucket extends cloud.Bucket implements IAwsBucket {
export function createEncryptedBucket(
scope: Construct,
isPublic: boolean,
forceDestroy: boolean,
name: string = "Default"
): S3Bucket {
const isTestEnvironment = App.of(scope).isTestEnvironment;
Expand All @@ -271,5 +274,6 @@ export function createEncryptedBucket(
publicReadAccess: isPublic ? true : false,
removalPolicy: RemovalPolicy.DESTROY,
autoDeleteObjects: isTestEnvironment ? true : false,
forceDestroy: forceDestroy,
});
}
11 changes: 11 additions & 0 deletions packages/@winglang/platform-awscdk/test/bucket.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ test("bucket is public", () => {
expect(awscdkSanitize(template)).toMatchSnapshot();
});

test("bucket is force destroy", () => {
// GIVEN
const app = new AwsCdkApp();
new cloud.Bucket(app, "my_bucket", { forceDestroy: true });
const output = app.synth();

// THEN
const template = Template.fromJSON(JSON.parse(output));
expect(awscdkSanitize(template)).toMatchSnapshot();
});

test("bucket with two preflight objects", () => {
// GIVEN
const app = new AwsCdkApp();
Expand Down
6 changes: 6 additions & 0 deletions packages/@winglang/sdk/src/cloud/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ export interface BucketProps {
*/
readonly public?: boolean;

/**
* Whether to allow the bucket to be deleted even if it is not empty.
* @default false
*/
readonly forceDestroy?: boolean;

/**
* Whether to add default cors configuration.
*
Expand Down
3 changes: 3 additions & 0 deletions packages/@winglang/sdk/src/target-sim/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ export class Bucket extends cloud.Bucket implements ISimulatorResource {
}

private readonly public: boolean;
private readonly forceDestroy: boolean;
private readonly initialObjects: Record<string, string> = {};
private readonly policy: Policy;

constructor(scope: Construct, id: string, props: cloud.BucketProps = {}) {
super(scope, id, props);

this.public = props.public ?? false;
this.forceDestroy = props.forceDestroy ?? false;
this.policy = new Policy(this, "Policy", { principal: this });
}

Expand Down Expand Up @@ -129,6 +131,7 @@ export class Bucket extends cloud.Bucket implements ISimulatorResource {
public toSimulator(): ToSimulatorOutput {
const props: BucketSchema = {
public: this.public,
forceDeploy: this.forceDestroy,
initialObjects: this.initialObjects,
topics: this.convertTopicsToHandles(),
};
Expand Down
2 changes: 2 additions & 0 deletions packages/@winglang/sdk/src/target-sim/schema-resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ export interface TopicSubscriber extends EventSubscription {
export interface BucketSchema {
/** Whether the bucket should be publicly accessible. */
readonly public: boolean;
/** Whether to allow the bucket to be deleted even if it is not empty. */
readonly forceDestroy: boolean;
/** The initial objects uploaded to the bucket. */
readonly initialObjects: Record<string, string>;
/** Event notification topics- the record has BucketEventType as a key and a topic handle as a value */
Expand Down
9 changes: 8 additions & 1 deletion packages/@winglang/sdk/src/target-tf-aws/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export class Bucket extends cloud.Bucket implements IAwsBucket {

private readonly bucket: S3Bucket;
private readonly public: boolean;
private readonly forceDestroy: boolean;
private readonly notificationTopics: S3BucketNotificationTopic[] = [];
private readonly notificationDependencies: ITerraformDependable[] = [];
private readonly corsRules: cloud.BucketCorsOptions[] = [];
Expand All @@ -74,8 +75,9 @@ export class Bucket extends cloud.Bucket implements IAwsBucket {
super(scope, id, props);

this.public = props.public ?? false;
this.forceDestroy = props.forceDestroy ?? false;

this.bucket = createEncryptedBucket(this, this.public);
this.bucket = createEncryptedBucket(this, this.public, this.forceDestroy);

if (props.cors ?? true) {
this.addCorsRule(
Expand Down Expand Up @@ -220,6 +222,7 @@ export class Bucket extends cloud.Bucket implements IAwsBucket {
export function createEncryptedBucket(
scope: Construct,
isPublic: boolean,
forceDestroy: boolean,
name: string = "Default"
): S3Bucket {
const bucketPrefix = ResourceNames.generateName(scope, BUCKET_PREFIX_OPTS);
Expand Down Expand Up @@ -275,5 +278,9 @@ export function createEncryptedBucket(
});
}

if (forceDestroy) {
bucket.forceDestroy = true;
}

return bucket;
}
3 changes: 3 additions & 0 deletions packages/@winglang/sdk/src/target-tf-azure/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@ export class Bucket extends cloud.Bucket {

public readonly storageContainer: StorageContainer;
private readonly public: boolean;
private readonly forceDestroy: boolean;
private readonly storageAccount: StorageAccount;

constructor(scope: Construct, id: string, props: cloud.BucketProps = {}) {
super(scope, id, props);

this.public = props.public ?? false;
this.forceDestroy = props.forceDestroy ?? false;

const app = App.of(this) as App;
if (app._target !== "tf-azure") {
Expand All @@ -93,6 +95,7 @@ export class Bucket extends cloud.Bucket {
name: storageContainerName,
storageAccountName: this.storageAccount.name,
containerAccessType: this.public ? "blob" : "private",
rm_delete: this.forceDestroy,
});
}

Expand Down
2 changes: 1 addition & 1 deletion packages/@winglang/sdk/src/target-tf-gcp/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export class Bucket extends cloud.Bucket {
// recommended by GCP: https://cloud.google.com/storage/docs/uniform-bucket-level-access#should-you-use
uniformBucketLevelAccess: true,
publicAccessPrevention: props.public ? "inherited" : "enforced",
forceDestroy: !!isTestEnvironment,
forceDestroy: !!isTestEnvironment || props.forceDestroy,
dependsOn: [iamServiceAccountCredentialsApi],
});

Expand Down
14 changes: 14 additions & 0 deletions packages/@winglang/sdk/test/target-tf-aws/bucket.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@ test("bucket is public", () => {
expect(treeJsonOf(app.outdir)).toMatchSnapshot();
});

test("bucket is force destroy", () => {
// GIVEN
const app = new AwsApp();
new Bucket(app, "my_bucket", { forceDestroy: true });
const output = app.synth();

// THEN
expect(
JSON.parse(output).resource.aws_s3_bucket.my_bucket.force_destroy
).toBe(true);
expect(tfSanitize(output)).toMatchSnapshot();
expect(treeJsonOf(app.outdir)).toMatchSnapshot();
});

test("bucket with cors disabled", () => {
// GIVEN
const app = new AwsApp();
Expand Down
12 changes: 12 additions & 0 deletions packages/@winglang/sdk/test/target-tf-azure/bucket.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ test("bucket is public", () => {
expect(treeJsonOf(app.outdir)).toMatchSnapshot();
});

test("bucket is force destroy", () => {
// GIVEN
const app = new AzureApp();
new Bucket(app, "my_bucket", { forceDestroy: true });
const output = app.synth();

// THEN
expect(tfResourcesOfCount(output, "azurerm_storage_container")).toEqual(1);
expect(tfSanitize(output)).toMatchSnapshot();
expect(treeJsonOf(app.outdir)).toMatchSnapshot();
});

test("bucket with two preflight objects", () => {
// GIVEN
const app = new AzureApp();
Expand Down
11 changes: 11 additions & 0 deletions packages/@winglang/sdk/test/target-tf-gcp/bucket.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ test("bucket is public", () => {
expect(treeJsonOf(app.outdir)).toMatchSnapshot();
});

test("bucket is force destroy", () => {
// GIVEN
const app = new GcpApp();
new Bucket(app, "my_bucket", { forceDestroy: true });
const output = app.synth();

// THEN
expect(tfSanitize(output)).toMatchSnapshot();
expect(treeJsonOf(app.outdir)).toMatchSnapshot();
});

test("two buckets", () => {
// GIVEN
const app = new GcpApp();
Expand Down

0 comments on commit ef267d9

Please sign in to comment.