使用AWS CDK实现CodePipeline QA阶段每日定时触发的方案问询
解决方案:定时触发CodePipeline QA阶段
需求回顾
- 代码合并至master分支时,自动触发CodePipeline的DEV阶段,完成后暂停流程,不自动进入QA阶段。
- 每日印度标准时间(IST)12点,自动触发QA阶段继续执行。
关键修改点
- Pipeline阶段结构调整:在DEV阶段后添加手动审批阶段
Pre_QA_Approval,确保DEV完成后流程暂停在此处。 - Lambda权限补充:添加
codepipeline:GetPipelineState权限,允许Lambda获取Pipeline状态以获取审批token。 - Scheduler定时规则修正:IST12点对应UTC时间6:30,修正Cron表达式为
cron(30 6 * * ? *)。 - 参数硬编码修复:Scheduler输入中的流水线名称改为CDK变量引用,避免硬编码错误。
- Lambda逻辑优化:移除事件中的
approvalToken参数,Lambda自动从Pipeline状态中获取最新的审批token。
修正后的Lambda函数代码
import { CodePipeline } from "aws-sdk"; import { Handler } from "aws-lambda"; // 初始化CodePipeline客户端 const codePipeline = new CodePipeline(); interface LambdaEvent { pipelineName: string; stageName: string; actionName: string; } export const handler: Handler<LambdaEvent> = async (event) => { const { pipelineName, stageName, actionName } = event; try { // 获取流水线状态 const pipelineState = await codePipeline.getPipelineState({ name: pipelineName }).promise(); if (!pipelineState.stageStates) { throw new Error("未找到流水线的阶段状态"); } // 定位目标阶段 const targetStage = pipelineState.stageStates.find(stage => stage.stageName === stageName); if (!targetStage || !targetStage.actionStates) { throw new Error(`未找到阶段 ${stageName} 或该阶段无操作状态`); } // 定位审批操作 const approvalAction = targetStage.actionStates.find(actionState => actionState.actionName === actionName); if (!approvalAction || !approvalAction.latestExecution || !approvalAction.latestExecution.token) { throw new Error(`未找到审批操作 ${actionName} 或该操作无可用审批token`); } const approvalToken = approvalAction.latestExecution.token; // 提交审批通过结果 const approvalParams = { pipelineName, stageName, actionName, result: { status: "Approved", summary: "Lambda自动审批通过QA阶段" }, token: approvalToken }; console.log("审批参数:", approvalParams); const response = await codePipeline.putApprovalResult(approvalParams).promise(); console.log("审批结果提交成功:", response); return { message: "QA阶段审批提交成功" }; } catch (error) { console.error("提交审批结果失败:", error); throw error; } };
修正后的CDK栈代码
import * as cdk from "aws-cdk-lib"; import { Construct } from "constructs"; import { Pipeline, Artifact } from "aws-cdk-lib/aws-codepipeline"; import { GitHubSourceAction, CodeBuildAction, ManualApprovalAction, } from "aws-cdk-lib/aws-codepipeline-actions"; import { Project, BuildSpec } from "aws-cdk-lib/aws-codebuild"; import { Effect, Policy, PolicyDocument, PolicyStatement, Role, ServicePrincipal, } from "aws-cdk-lib/aws-iam"; import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"; import { Runtime } from "aws-cdk-lib/aws-lambda"; import { CfnResource, Duration } from "aws-cdk-lib"; export class CdkPocStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // GitHub仓库配置 const githubRepoOwner = "owner"; const githubRepoName = "sample-repo"; const githubBranch = "master"; const githubOAuthToken = cdk.SecretValue.secretsManager("token"); // 创建CodePipeline const pipeline = new Pipeline(this, "MyCodePipeline", { pipelineName: "MyCodePipeline", }); // 流水线产物定义 const sourceOutput = new Artifact(); const devBuildOutput = new Artifact(); // 源阶段:从GitHub拉取代码 const sourceAction = new GitHubSourceAction({ actionName: "GitHub_Source", owner: githubRepoOwner, repo: githubRepoName, oauthToken: githubOAuthToken, output: sourceOutput, branch: githubBranch, }); pipeline.addStage({ stageName: "Source", actions: [sourceAction], }); // DEV阶段:构建任务 const devProject = new Project(this, "DevBuildStageProject", { buildSpec: BuildSpec.fromObject({ version: "0.2", phases: { install: { runtimeVersions: { nodejs: 18, }, commands: ["npm install"], }, }, artifacts: { files: "**/*", }, }), }); const devAction = new CodeBuildAction({ actionName: "Dev_Stage_Build", project: devProject, input: sourceOutput, outputs: [devBuildOutput], }); pipeline.addStage({ stageName: "DEV", actions: [devAction], }); // QA前置审批阶段:手动审批节点,DEV完成后暂停在此 const manualApprovalAction = new ManualApprovalAction({ actionName: "Approve_QA", }); pipeline.addStage({ stageName: "Pre_QA_Approval", actions: [manualApprovalAction], }); // QA阶段:测试任务,需等待审批通过后执行 const qaProject = new Project(this, "QaBuildStageProject", { buildSpec: BuildSpec.fromObject({ version: "0.2", phases: { install: { runtimeVersions: { nodejs: 18, }, commands: ["npm install"], }, }, artifacts: { files: "**/*", }, }), }); const qaAction = new CodeBuildAction({ actionName: "QA_Stage_Test", project: qaProject, input: sourceOutput, }); pipeline.addStage({ stageName: "QA", actions: [qaAction], }); // Lambda执行角色:权限包括日志、CodePipeline操作 const lambdaRole = new Role(this, "LambdaExecutionRole", { assumedBy: new ServicePrincipal("lambda.amazonaws.com"), }); lambdaRole.addManagedPolicy({ managedPolicyArn: "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", }); lambdaRole.addToPolicy( new PolicyStatement({ actions: [ "codepipeline:GetPipelineState", "codepipeline:PutApprovalResult" ], resources: [pipeline.pipelineArn], effect: Effect.ALLOW, }), ); // 用于自动审批QA阶段的Lambda const qaApprovalLambda = new NodejsFunction(this, "QaApprovalLambda", { entry: "./lib/lambda/qa-stage-trigger.ts", // 确保路径与实际文件位置一致 handler: "handler", runtime: Runtime.NODEJS_20_X, timeout: Duration.seconds(10), role: lambdaRole, environment: { PIPELINE_NAME: pipeline.pipelineName, }, }); // Scheduler执行角色:允许调用Lambda const schedulerRole = new Role(this, "SchedulerExecutionRole", { assumedBy: new ServicePrincipal("scheduler.amazonaws.com"), }); schedulerRole.addToPolicy( new PolicyStatement({ actions: ["lambda:InvokeFunction"], resources: [qaApprovalLambda.functionArn], effect: Effect.ALLOW, }), ); // 每日IST12点触发的Scheduler规则(对应UTC 6:30) new CfnResource(this, "DailyQaTriggerSchedule", { type: "AWS::Scheduler::Schedule", properties: { Name: "DailyQaTriggerSchedule", Description: "每日IST12点自动触发QA阶段", FlexibleTimeWindow: { Mode: "OFF" }, ScheduleExpression: "cron(30 6 * * ? *)", // UTC 6:30 = IST 12:00 Target: { Arn: qaApprovalLambda.functionArn, RoleArn: schedulerRole.roleArn, Input: JSON.stringify({ pipelineName: pipeline.pipelineName, stageName: "Pre_QA_Approval", actionName: "Approve_QA", }), }, }, }); } }
内容的提问来源于stack exchange,提问作者Surya Prakash Chaudhary
相关产品推荐
相关产品推荐

