Skip to content

Commit fc49bd4

Browse files
committed
👷 create a new script to clean old bucket from GCP
Issue: CLDSRV-867
1 parent e741887 commit fc49bd4

File tree

3 files changed

+161
-1
lines changed

3 files changed

+161
-1
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/* eslint-disable no-console */
2+
'use strict';
3+
4+
const {
5+
S3Client,
6+
ListBucketsCommand,
7+
ListObjectsV2Command,
8+
DeleteObjectsCommand,
9+
DeleteBucketCommand,
10+
ListMultipartUploadsCommand,
11+
AbortMultipartUploadCommand,
12+
} = require('@aws-sdk/client-s3');
13+
14+
const GCP_ENDPOINT = 'https://storage.googleapis.com';
15+
const BUCKET_PREFIX = 'cldsrvci-';
16+
const ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1000;
17+
18+
function buildClient() {
19+
const accessKeyId = process.env.AWS_GCP_BACKEND_ACCESS_KEY;
20+
const secretAccessKey = process.env.AWS_GCP_BACKEND_SECRET_KEY;
21+
22+
if (!accessKeyId || !secretAccessKey) {
23+
console.error(
24+
'Missing required environment variables: ' +
25+
'AWS_GCP_BACKEND_ACCESS_KEY and AWS_GCP_BACKEND_SECRET_KEY'
26+
);
27+
process.exit(1);
28+
}
29+
30+
return new S3Client({
31+
endpoint: GCP_ENDPOINT,
32+
region: 'us-east-1',
33+
credentials: { accessKeyId, secretAccessKey },
34+
forcePathStyle: true,
35+
disableS3ExpressSessionAuth: true,
36+
requestChecksumCalculation: 'WHEN_REQUIRED',
37+
responseChecksumValidation: 'WHEN_REQUIRED',
38+
});
39+
}
40+
41+
async function abortMultipartUploads(client, bucketName) {
42+
let uploadIdMarker;
43+
let keyMarker;
44+
45+
do {
46+
const res = await client.send(new ListMultipartUploadsCommand({
47+
Bucket: bucketName,
48+
UploadIdMarker: uploadIdMarker,
49+
KeyMarker: keyMarker,
50+
}));
51+
52+
for (const upload of res.Uploads || []) {
53+
console.log(
54+
` Aborting MPU: ${upload.Key} (${upload.UploadId})`
55+
);
56+
await client.send(new AbortMultipartUploadCommand({
57+
Bucket: bucketName,
58+
Key: upload.Key,
59+
UploadId: upload.UploadId,
60+
}));
61+
}
62+
63+
uploadIdMarker = res.NextUploadIdMarker;
64+
keyMarker = res.NextKeyMarker;
65+
} while (uploadIdMarker);
66+
}
67+
68+
async function deleteAllObjects(client, bucketName) {
69+
let continuationToken;
70+
71+
do {
72+
const res = await client.send(new ListObjectsV2Command({
73+
Bucket: bucketName,
74+
ContinuationToken: continuationToken,
75+
}));
76+
77+
const objects = res.Contents || [];
78+
if (objects.length > 0) {
79+
console.log(` Deleting ${objects.length} object(s)...`);
80+
await client.send(new DeleteObjectsCommand({
81+
Bucket: bucketName,
82+
Delete: {
83+
Objects: objects.map(o => ({ Key: o.Key })),
84+
Quiet: true,
85+
},
86+
}));
87+
}
88+
89+
continuationToken = res.NextContinuationToken;
90+
} while (continuationToken);
91+
}
92+
93+
async function cleanupBucket(client, bucketName) {
94+
console.log(`Cleaning up bucket: ${bucketName}`);
95+
try {
96+
await abortMultipartUploads(client, bucketName);
97+
await deleteAllObjects(client, bucketName);
98+
await client.send(new DeleteBucketCommand({ Bucket: bucketName }));
99+
console.log(`Deleted bucket: ${bucketName}`);
100+
} catch (err) {
101+
console.error(`Failed to delete bucket ${bucketName}: ${err.message}`);
102+
}
103+
}
104+
105+
async function main() {
106+
const client = buildClient();
107+
108+
console.log('Listing GCP buckets...');
109+
const { Buckets = [] } = await client.send(new ListBucketsCommand({}));
110+
111+
const now = Date.now();
112+
const stale = Buckets.filter(b =>
113+
b.Name.startsWith(BUCKET_PREFIX) &&
114+
now - new Date(b.CreationDate).getTime() > ONE_WEEK_MS
115+
);
116+
117+
if (stale.length === 0) {
118+
console.log('No stale GCP CI buckets found.');
119+
return;
120+
}
121+
122+
console.log(
123+
`Found ${stale.length} stale GCP CI bucket(s) to clean up: ${
124+
stale.map(b => b.Name).join(', ')}`
125+
);
126+
127+
for (const bucket of stale) {
128+
await cleanupBucket(client, bucket.Name);
129+
}
130+
131+
console.log('GCP CI bucket cleanup complete.');
132+
}
133+
134+
main().catch(err => {
135+
console.error('GCP cleanup script failed:', err);
136+
process.exit(1);
137+
});

.github/workflows/tests.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,3 +1026,26 @@ jobs:
10261026
password: ${{ secrets.ARTIFACTS_PASSWORD }}
10271027
source: /tmp/artifacts
10281028
if: always()
1029+
1030+
cleanup-gcp-buckets:
1031+
runs-on: ubuntu-24.04
1032+
needs:
1033+
- multiple-backend
1034+
- mongo-v0-ft-tests
1035+
- mongo-v1-ft-tests
1036+
- file-ft-tests
1037+
if: always()
1038+
steps:
1039+
- name: Checkout
1040+
uses: actions/checkout@v4
1041+
- uses: actions/setup-node@v4
1042+
with:
1043+
node-version: '22'
1044+
cache: yarn
1045+
- name: Install dependencies
1046+
run: yarn install --frozen-lockfile --network-concurrency 1
1047+
- name: Delete stale GCP CI buckets
1048+
run: yarn run cleanup_gcp_buckets
1049+
env:
1050+
AWS_GCP_BACKEND_ACCESS_KEY: ${{ secrets.AWS_GCP_BACKEND_ACCESS_KEY }}
1051+
AWS_GCP_BACKEND_SECRET_KEY: ${{ secrets.AWS_GCP_BACKEND_SECRET_KEY }}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
"ft_node_routes": "cd tests/functional/raw-node && yarn run test-routes",
106106
"ft_route_backbeat": "cd tests/multipleBackend/routes && mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json -t 40000 routeBackbeat.js routeBackbeatForReplication.js --exit",
107107
"ft_gcp": "cd tests/functional/raw-node && yarn run test-gcp",
108-
"cleanup_gcp_buckets": "node scripts/cleanupOldGCPBuckets.js",
108+
"cleanup_gcp_buckets": "node .github/scripts/cleanupOldGCPBuckets.js",
109109
"ft_healthchecks": "cd tests/functional/healthchecks && yarn test",
110110
"ft_s3cmd": "cd tests/functional/s3cmd && mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json -t 40000 *.js --exit",
111111
"ft_s3curl": "cd tests/functional/s3curl && mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json -t 40000 *.js --exit",

0 commit comments

Comments
 (0)