在 Amazon 的 CodeDeploy 上获得 successful/failed 构建通知

Get notified of successful/failed builds on Amazon's CodeDeploy

我想构建一个工具,每次在 CodeDeploy 上构建成功或失败时都会通过任何通信媒介(电子邮件、slack 等)通知用户。我已经浏览了他们的文档......除了长轮询之外什么都没有想到。知道是否有一些 webhook 选项可以让我注册 URL 并收到通知?

2016-04-27更新

AWS 官方 announced this in February 2016:

You can now create triggers that send Amazon SNS notifications before, during, and after the deployment process for your applications. Triggers can be set for the deployment as a whole or for the individual instances targeted by the deployment, and are sent on both successes and failures.

原回答

还没有。

this AWS forum thread 中,要求 CodeDeploy 发出事件,以便您可以使用 Lambda 处理它们而不是轮询详细信息。

AWS 工作人员的回答(强调我的):

We here on CodeDeploy agree. Unfortunately, I can't give you an exact release date but keep an eye on our announcements, it's coming soon.

虽然没有本机解决方案,但您可以使用一种解决方法来完成此操作。您可以使用 lambda 来触发这些事件。在 AWS 博客上,他们展示了当您将文件上传到 S3 (https://blogs.aws.amazon.com/application-management/post/Tx3TPMTH0EVGA64/Automatically-Deploy-from-Amazon-S3-using-AWS-CodeDeploy). Using this same concept, you can have your lambda function listen to a error/success bucket, and modify your codedeploy package to upload a file to s3 which in turn you can use as an event trigger to send an email via SES (https://peekandpoke.wordpress.com/2015/02/26/dancing-the-lambada-with-aws-lambda-or-sending-emails-on-s3-events/) 或联系网络 service/page 时如何通过 lambda 触发 codedeploy 来执行您想要的操作。这可能有点矫揉造作,但它完成了工作。

这里是 AWS Lambda 函数的要点,该函数将格式化的 CodeDeploy 通知发布到 Slack

https://gist.github.com/MrRoyce/097edc0de2fe001288be2e8633f4b22a

var services = '/services/...';  // Update this with your Slack service...
var channel = "#aws-deployments"  // And this with the Slack channel

var https = require('https');
var util = require('util');

var formatFields = function(string) {
  var
    message = JSON.parse(string),
    fields  = [],
    deploymentOverview;

  // Make sure we have a valid response
  if (message) {
    fields = [
      {
        "title" : "Task",
        "value" : message.eventTriggerName,
        "short" : true
      },
      {
        "title" : "Status",
        "value" : message.status,
        "short" : true
      },
      {
        "title" : "Application",
        "value" : message.applicationName,
        "short" : true
      },
      {
        "title" : "Deployment Group",
        "value" : message.deploymentGroupName,
        "short" : true
      },
      {
        "title" : "Region",
        "value" : message.region,
        "short" : true
      },
      {
        "title" : "Deployment Id",
        "value" : message.deploymentId,
        "short" : true
      },
      {
        "title" : "Create Time",
        "value" : message.createTime,
        "short" : true
      },
      {
        "title" : "Complete Time",
        "value" : ((message.completeTime) ? message.completeTime : ''),
        "short" : true
      }
    ];

    if (message.deploymentOverview) {
     deploymentOverview = JSON.parse(message.deploymentOverview);
     
      fields.push(
        {
          "title" : "Succeeded",
          "value" : deploymentOverview.Succeeded,
          "short" : true
        },
        {
          "title" : "Failed",
          "value" : deploymentOverview.Failed,
          "short" : true
        },
        {
          "title" : "Skipped",
          "value" : deploymentOverview.Skipped,
          "short" : true
        },
        {
          "title" : "In Progress",
          "value" : deploymentOverview.InProgress,
          "short" : true
        },
        {
          "title" : "Pending",
          "value" : deploymentOverview.Pending,
          "short" : true
        }
      );
    }
  }

  return fields;

}

exports.handler = function(event, context) {

    var postData = {
        "channel": channel,
        "username": "AWS SNS via Lamda :: CodeDeploy Status",
        "text": "*" + event.Records[0].Sns.Subject + "*",
        "icon_emoji": ":aws:"
    };

    var fields = formatFields(event.Records[0].Sns.Message);
    var message = event.Records[0].Sns.Message;
    var severity = "good";

    var dangerMessages = [
        " but with errors",
        " to RED",
        "During an aborted deployment",
        "FAILED",
        "Failed to deploy application",
        "Failed to deploy configuration",
        "has a dependent object",
        "is not authorized to perform",
        "Pending to Degraded",
        "Stack deletion failed",
        "Unsuccessful command execution",
        "You do not have permission",
        "Your quota allows for 0 more running instance"];

    var warningMessages = [
        " aborted operation.",
        " to YELLOW",
        "Adding instance ",
        "Degraded to Info",
        "Deleting SNS topic",
        "is currently running under desired capacity",
        "Ok to Info",
        "Ok to Warning",
        "Pending Initialization",
        "Removed instance ",
        "Rollback of environment"
        ];

    for(var dangerMessagesItem in dangerMessages) {
        if (message.indexOf(dangerMessages[dangerMessagesItem]) != -1) {
            severity = "danger";
            break;
        }
    }

    // Only check for warning messages if necessary
    if (severity == "good") {
        for(var warningMessagesItem in warningMessages) {
            if (message.indexOf(warningMessages[warningMessagesItem]) != -1) {
                severity = "warning";
                break;
            }
        }
    }

    postData.attachments = [
        {
            "color": severity,
            "fields": fields
        }
    ];

    var options = {
        method: 'POST',
        hostname: 'hooks.slack.com',
        port: 443,
        path: services  // Defined above
    };

    var req = https.request(options, function(res) {
      res.setEncoding('utf8');
      res.on('data', function (chunk) {
        context.done(null);
      });
    });

    req.on('error', function(e) {
      console.log('problem with request: ' + e.message);
    });

    req.write(util.format("%j", postData));
    req.end();
};

在较高级别,您需要:

  • 设置 SNS 主题
  • 创建 CodeDeploy 触发器
  • 向 CodeDeploy IAM 角色添加 sns:Publish 权限
  • 使用传入 Webhook 配置 Slack
  • 编写并配置一个 Lambda 函数来处理 CodeDeploy 的 SNS 消息,构造 Slack 消息并将它们发送到 Incoming Webhook 处的 Slack

我使用与上述要点类似的代码为 CodeDeploy 事件的 Slack 通知设置 Lambda 函数。我记录了整个过程,包括截图 over here.

我在其他地方找不到类似的端到端指南,所以我希望这对遇到这个问题的其他人有所帮助。