Skip to content

Commit

Permalink
fix: adding tag ref in CustomResource
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexTech314 committed Dec 25, 2024
1 parent 70203fc commit 324374f
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 306 deletions.
2 changes: 1 addition & 1 deletion .projen/deps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion .projenrc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const project = new awscdk.AwsCdkConstructLibrary({
author: 'AlexTech314',
authorAddress: '[email protected]',
majorVersion: 1,
cdkVersion: '2.166.0',
cdkVersion: '2.173.2',
defaultReleaseBranch: 'main',
packageManager: NodePackageManager.NPM,
jsiiVersion: '~5.5.0',
Expand Down Expand Up @@ -56,7 +56,9 @@ project.npmignore!.include('isComplete/*.js', 'onEvent/*.js');

project.addScripts({
'local-deploy': 'cdk deploy --app "npx ts-node src/integ.default.ts"',
'local-deploy-no-rollback': 'cdk deploy --no-rollback --app "npx ts-node src/integ.default.ts"',
'local-destroy': 'cdk destroy --app "npx ts-node src/integ.default.ts"',
'local-synth': 'cdk synth --app "npx ts-node src/integ.default.ts"',
});

project.synth();
73 changes: 36 additions & 37 deletions API.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

159 changes: 91 additions & 68 deletions isComplete/isComplete.js
Original file line number Diff line number Diff line change
@@ -1,97 +1,120 @@
const { CodeBuildClient, ListBuildsForProjectCommand, BatchGetBuildsCommand } = require('@aws-sdk/client-codebuild');
const { CloudWatchLogsClient, GetLogEventsCommand } = require('@aws-sdk/client-cloudwatch-logs');

exports.handler = async (event, context) => {
console.log('isCompleteHandler Event:', JSON.stringify(event, null, 2));

// Initialize AWS SDK v3 clients
const codebuildClient = new CodeBuildClient({ region: process.env.AWS_REGION });
const cloudwatchlogsClient = new CloudWatchLogsClient({ region: process.env.AWS_REGION });
const {
CodeBuildClient,
ListBuildsForProjectCommand,
BatchGetBuildsCommand,
} = require('@aws-sdk/client-codebuild');
const {
CloudWatchLogsClient,
GetLogEventsCommand,
} = require('@aws-sdk/client-cloudwatch-logs');

exports.handler = async (event) => {
console.log('--- isComplete Handler Invoked ---');
console.log('AWS_REGION:', process.env.AWS_REGION);
console.log('Event:', JSON.stringify(event, null, 2));

const region = process.env.AWS_REGION;
const codebuildClient = new CodeBuildClient({ region });
const logsClient = new CloudWatchLogsClient({ region });

try {
const projectName = event.ResourceProperties.ProjectName;
const projectName = event.ResourceProperties?.ProjectName;
console.log('ProjectName from ResourceProperties:', projectName);

if (!projectName) {
throw new Error('ProjectName is required in ResourceProperties');
throw new Error('Missing ProjectName in ResourceProperties');
}

console.log(`Checking status for CodeBuild project: ${projectName}`);

// Retrieve the latest build for the given project
const listBuildsCommand = new ListBuildsForProjectCommand({
projectName: projectName,
sortOrder: 'DESCENDING',
maxResults: 1,
});

const listBuildsResp = await codebuildClient.send(listBuildsCommand);
const buildIds = listBuildsResp.ids;
// Handle Delete requests gracefully
if (event.RequestType === 'Delete') {
console.log('Delete request detected. Marking resource as complete.');
return { IsComplete: true };
}

if (!buildIds || buildIds.length === 0) {
// 1) Retrieve the latest build ID for this project
console.log('Querying CodeBuild for the most recent build...');
const listResp = await codebuildClient.send(
new ListBuildsForProjectCommand({
projectName,
sortOrder: 'DESCENDING',
maxResults: 1,
})
);
console.log('ListBuildsForProjectCommand response:', JSON.stringify(listResp, null, 2));

if (!listResp.ids || listResp.ids.length === 0) {
throw new Error(`No builds found for project: ${projectName}`);
}

const buildId = buildIds[0];
console.log(`Latest Build ID: ${buildId}`);
const buildId = listResp.ids[0];
console.log(`Identified latest Build ID: ${buildId}`);

// Get build details
const batchGetBuildsCommand = new BatchGetBuildsCommand({
ids: [buildId],
});

const buildDetailsResp = await codebuildClient.send(batchGetBuildsCommand);
const build = buildDetailsResp.builds[0];
// 2) Get details about that specific build
const batchResp = await codebuildClient.send(
new BatchGetBuildsCommand({ ids: [buildId] })
);
console.log('BatchGetBuildsCommand response:', JSON.stringify(batchResp, null, 2));

const build = batchResp.builds?.[0];
if (!build) {
throw new Error(`Build details not found for Build ID: ${buildId}`);
}

const buildStatus = build.buildStatus;
console.log(`Build Status: ${buildStatus}`);
console.log(`The build status for ID ${buildId} is: ${buildStatus}`);

// Check for in-progress status
if (buildStatus === 'IN_PROGRESS') {
// Build is still in progress
console.log('Build is still in progress.');
console.log('Build is still in progress. Requesting more time...');
return { IsComplete: false };
} else if (buildStatus === 'SUCCEEDED') {
// Build succeeded
console.log('Build succeeded.');
return { IsComplete: true };
} else if (['FAILED', 'FAULT', 'STOPPED', 'TIMED_OUT'].includes(buildStatus)) {
// Build failed; retrieve last 5 log lines
const logsInfo = build.logs;
if (logsInfo && logsInfo.groupName && logsInfo.streamName) {
console.log(`Retrieving logs from CloudWatch Logs Group: ${logsInfo.groupName}, Stream: ${logsInfo.streamName}`);

const getLogEventsCommand = new GetLogEventsCommand({
logGroupName: logsInfo.groupName,
logStreamName: logsInfo.streamName,
startFromHead: false, // Start from the end to get latest logs
limit: 5,
});

const logEventsResp = await cloudwatchlogsClient.send(getLogEventsCommand);
const logEvents = logEventsResp.events;
const lastFiveMessages = logEvents.map((event) => event.message).reverse().join('\n');
}

const errorMessage = `Build failed with status: ${buildStatus}\nLast 5 build logs:\n${lastFiveMessages}`;
console.error(errorMessage);
// If build succeeded, retrieve the final artifact with the digest
if (buildStatus === 'SUCCEEDED') {
return {
IsComplete: true,
Data: {
ImageTag: process.env.IMAGE_TAG,
},
};
}

// Throw an error to indicate failure to the CDK provider
throw new Error(errorMessage);
// If the build is in a failed status, retrieve CloudWatch logs
if (['FAILED', 'FAULT', 'STOPPED', 'TIMED_OUT'].includes(buildStatus)) {
console.log(`Build ended with status: ${buildStatus}. Attempting to retrieve last log lines...`);
const logsInfo = build.logs;
console.log('Logs info:', JSON.stringify(logsInfo, null, 2));

if (logsInfo?.groupName && logsInfo?.streamName) {
console.log(`Retrieving up to 5 log events from CloudWatch Logs in group ${logsInfo.groupName} stream ${logsInfo.streamName}`);
const logResp = await logsClient.send(
new GetLogEventsCommand({
logGroupName: logsInfo.groupName,
logStreamName: logsInfo.streamName,
startFromHead: false,
limit: 5,
})
);
console.log('GetLogEventsCommand response:', JSON.stringify(logResp, null, 2));

const logEvents = logResp.events || [];
const lastFive = logEvents.map(e => e.message).reverse().join('\n');
console.error('Last 5 build log lines:\n', lastFive);

throw new Error(`Build failed with status ${buildStatus}. Last logs:\n${lastFive}`);
} else {
const errorMessage = `Build failed with status: ${buildStatus}, but logs are not available.`;
console.error(errorMessage);
throw new Error(errorMessage);
throw new Error(`Build failed with status: ${buildStatus}, but no logs found.`);
}
} else {
const errorMessage = `Unknown build status: ${buildStatus}`;
console.error(errorMessage);
throw new Error(errorMessage);
}

// If we reach here, it's an unexpected status
console.log(`Encountered unknown build status: ${buildStatus}`);
throw new Error(`Unknown build status: ${buildStatus}`);

} catch (error) {
console.error('Error in isCompleteHandler:', error);
// Rethrow the error to inform the CDK provider of the failure
console.error('--- Caught an error in isComplete handler ---');
console.error('Error details:', error);
// re-throw for CloudFormation to see the error
throw error;
}
};
Loading

0 comments on commit 324374f

Please sign in to comment.