Configuring notifications for third-party services

When your Cloud Build builds change states, you can send notifications about these changes via third-party messaging services or email.

Services such as Slack offer incoming webhooks, a simple way to post messages from apps into Slack. Cloud Functions is a lightweight compute solution to create single-purpose, stand-alone functions that respond to cloud events, such as builds, without the need to manage a server or runtime environment. When a cloud event occurs, a trigger responds by executing an action, such as sending a Cloud Pub/Sub message.

There are many third-party services built with cross-application messaging functionality, such as SendGrid and IFTTT. You can use this tutorial as a template for connecting with such services.

This tutorial demonstrates how you can use Cloud Functions and Cloud Pub/Sub to send notifications about Cloud Build via Slack and Mailgun.

Objectives

  • Deploy a Slack application to receive external notifications from Cloud Build.
  • Write a Cloud Function for sending Pub/Sub notifications to Slack.
  • Set up Mailgun to receive external notifications from Cloud Build.
  • Write a Cloud Function for sending Pub/Sub notifications to Mailgun.

Costs

This tutorial uses billable components of Cloud Platform, including:

  • Cloud Functions
  • Cloud Pub/Sub
  • Cloud Build

Use the Pricing Calculator to generate a cost estimate based on your projected usage.

New Cloud Platform users might be eligible for a free trial.

Before you begin

  1. Sign in to your Google Account.

    If you don't already have one, sign up for a new account.

  2. In the Cloud Console, on the project selector page, select or create a Google Cloud project.

    Go to the project selector page

  3. Make sure that billing is enabled for your Google Cloud project. Learn how to confirm billing is enabled for your project.

  4. Enable the Cloud Functions and Cloud Pub/Sub APIs.

    Enable the APIs

  5. Install and initialize the Cloud SDK.
  6. Update and install gcloud components:
    gcloud components update &&
    gcloud components install alpha beta

Slack notifications

The following sections walk you through how to set up Slack notifications.

Preparing the Slack application

  1. Download Slack for your computer. You also need to join a Slack workspace, either by registering with your email or by using an invitation sent by a Workspace Admin.

  2. Sign in to Slack using your workspace name and your Slack account credentials.

  3. Create a new Slack app:

    1. Choose the app's name and your Slack workspace. Click Create App.
    2. Under Features, click Incoming Webhooks.
    3. Enable Activate Incoming Webhooks.
    4. Click Add New Webhook to Workspace. An authorization page opens.
    5. From the drop-down menu, select the channel to which you would like notifications sent.
    6. Click Install.
    7. A webhook for your Slack application has been created. Copy the Webhook URL and save it for later use.

Writing the Cloud Function

Create a new directory named gcb_slack and change directory into it:

mkdir ~/gcb_slack
cd ~/gcb_slack

Then, create files index.js and package.json in the gcb_slack directory:

index.js

const { IncomingWebhook } = require('@slack/webhook');
const url = process.env.SLACK_WEBHOOK_URL;

const webhook = new IncomingWebhook(url);

// subscribeSlack is the main function called by Cloud Functions.
module.exports.subscribeSlack = (pubSubEvent, context) => {
  const build = eventToBuild(pubSubEvent.data);

  // Skip if the current status is not in the status list.
  // Add additional statuses to list if you'd like:
  // QUEUED, WORKING, SUCCESS, FAILURE,
  // INTERNAL_ERROR, TIMEOUT, CANCELLED
  const status = ['SUCCESS', 'FAILURE', 'INTERNAL_ERROR', 'TIMEOUT'];
  if (status.indexOf(build.status) === -1) {
    return;
  }

  // Send message to Slack.
  const message = createSlackMessage(build);
  webhook.send(message);
};

// eventToBuild transforms pubsub event message to a build object.
const eventToBuild = (data) => {
  return JSON.parse(Buffer.from(data, 'base64').toString());
}

// createSlackMessage creates a message from a build object.
const createSlackMessage = (build) => {
  const message = {
    text: `Build \`${build.id}\``,
    mrkdwn: true,
    attachments: [
      {
        title: 'Build logs',
        title_link: build.logUrl,
        fields: [{
          title: 'Status',
          value: build.status
        }]
      }
    ]
  };
  return message;
}

SLACK_WEBHOOK_URL is a Cloud Functions environment variable specifying the webhook URL created for your Slack application. This environment variable will be defined when deploying the function.

This program uses Slack's webhook to listen for and receive messages from the Cloud Function. When an event is fired, a message is sent to the webhook then relayed to Slack.

The createSlackMessage function has been simplified for this example. You can expand the message to include much more, including text colors, images, and build duration.

package.json

{
  "name": "google-container-slack",
  "version": "0.0.1",
  "description": "Slack integration for Google Cloud Build, using Google Cloud Functions",
  "main": "index.js",
  "dependencies": {
    "@slack/webhook": "5.0.1"
  }
}

package.json describes:

  • the program's name, version, and description
  • its primary runtime file(s)
  • its dependencies

This file is deceptively simple: you can add more dependencies, requirements, and other information as needed.

You should now have index.js and package.json in the gcb_slack directory.

Deploying the Cloud Function

To deploy the subscribeSlack function with a Cloud Pub/Sub trigger, run the following command in the gcb_slack directory:

gcloud functions deploy subscribeSlack --trigger-topic cloud-builds --runtime nodejs10 --set-env-vars "SLACK_WEBHOOK_URL=https://hooks.slack.com/…"

where SLACK_WEBHOOK_URL defines the webhook URL created for your Slack application. The URL format is: https://hooks.slack.com/services/T…/B…/….

You should see something like the following output:

Deploying function…
availableMemoryMb: 256
entryPoint: subscribeSlack
environmentVariables:
  SLACK_WEBHOOK_URL: https://hooks.slack.com/services/…
eventTrigger:
  eventType: google.pubsub.topic.publish
  failurePolicy: {}
  resource: projects/[PROJECT-ID]/topics/cloud-builds
  service: pubsub.googleapis.com
labels:
  deployment-tool: cli-gcloud
name: projects/[PROJECT-ID]/locations/us-central1/functions/subscribeSlack
runtime: nodejs10
serviceAccountEmail: [PROJECT-ID]@appspot.gserviceaccount.com
sourceUploadUrl: https://storage.googleapis.com/…
status: ACTIVE
timeout: 60s
updateTime: 'YYYY-MM-DDThh:mm:ssZ'
versionId: '1'

After you've completed deployment of the Cloud Function, you will receive a Slack notification when a build event occurs.

Email notifications

The following sections walk you through setting up email notifications using the Mailgun API.

If you are new to Mailgun, follow their quickstart documentation.

Prepare Mailgun settings

  1. If you haven't already, create a Mailgun account.
  2. Either use a Mailgun's sandbox domain or add a new domain, then follow Mailgun's instructions.
  3. From the domains page, click your domain to open its settings page.
  4. Under API, click Select, Node.js, and copy the domain's API key to save it for later use.

You must also have the following:

  • An email address for sending email. This email address can belong to the domain you provide. If you are not sure which email address to use, check with your domain provider. You can also provide a nonexistent email if you do not expect a response from the recipient, such as noreply@mydomain.com.
  • An email address for receiving email.

Writing the Cloud Function

Create a new directory named gcb_email and change directory into it:

mkdir ~/gcb_email
cd ~/gcb_email

Then, create files index.js, config.json, and package.json in the gcb_email directory:

index.js

const Mailgun = require('mailgun-js');
const humanizeDuration = require('humanize-duration');
const config = require('./config.json');

const mailgun = Mailgun({
  apiKey: config.MAILGUN_API_KEY,
  domain: config.MAILGUN_DOMAIN,
});

// subscribeMailgun is the main function called by Cloud Functions.
module.exports.subscribeMailgun = (pubSubEvent, context) => {
  const build = eventToBuild(pubSubEvent.data);

  // Skip if the current status is not in the status list.
  const status = ['SUCCESS', 'FAILURE', 'INTERNAL_ERROR', 'TIMEOUT'];
  if (status.indexOf(build.status) === -1) {
    return;
  }

  // Send email.
  const message = createEmail(build);
  mailgun.messages().send(message, (error, body) => console.log(body.message));
};

// eventToBuild transforms pubsub event message to a build object.
const eventToBuild = (data) => {
  return JSON.parse(Buffer.from(data, 'base64').toString());
}

// createEmail creates an email message from a build object.
const createEmail = (build) => {
  const duration = humanizeDuration(new Date(build.finishTime) - new Date(build.startTime));
  const msgText = `Build ${build.id} finished with status ${build.status}, in ${duration}.`;
  let msgHtml = `<p>${msgText}</p><p><a href="${build.logUrl}">Build logs</a></p>`;
  if (build.images) {
    const images = build.images.join(',');
    msgHtml += `<p>Images: ${images}</p>`;
  }
  const message = {
    from: config.MAILGUN_FROM,
    to: config.MAILGUN_TO,
    subject: `Build ${build.id} finished`,
    text: msgText,
    html: msgHtml
  };
  return message;
}

config.json

{
  "MAILGUN_API_KEY":"[API_KEY]",
  "MAILGUN_DOMAIN":"email.com",
  "MAILGUN_FROM":"me@email.com",
  "MAILGUN_TO":"someone@email.com"
}

In this file, you must provide the following information:

  • MAILGUN_API_KEY, the API key you collected
  • MAILGUN_DOMAIN, the domain you configured
  • MAILGUN_FROM, the email address belonging to the domain from which email is sent (even one that doesn't exist)
  • MAILGUN_TO, the email address to which email is sent

package.json

{
  "name": "google-container-email",
  "version": "0.0.1",
  "description": "Email integration for Google Cloud Build, using Google Cloud Functions",
  "main": "index.js",
  "dependencies": {
    "humanize-duration": "3.10.0",
    "mailgun-js": "~0.11.2"
  },
  "devDependencies": {
    "async": "^2.1.5",
    "mocha": "3.2.0",
    "should": "11.2.1"
  }
}

package.json describes:

  • the program's name, version, and description
  • its primary runtime file
  • its dependencies

You should now have index.js, config.json, and package.json in the gcb_email directory.

Deploying the Cloud Function

To deploy the function, run the following command in the gcb_email directory:

gcloud functions deploy subscribeMailgun --trigger-topic cloud-builds --runtime nodejs10

After you've completed deployment of the Cloud Function, you should receive an email notification when a build event occurs.

Testing the function

After configuration, you should test your implementation to ensure that it is working as expected. You can test by submitting a build to Cloud Build.

Create a new directory named gcb_test and change directory into it:

mkdir ~/gcb_test
cd ~/gcb_test

Then, create a file called request.json containing the following code. This request triggers a build cloning a repository.

request.json

{
  "steps": [
    {
      "name": "gcr.io/cloud-builders/git",
      "args": [
        "clone",
        "https://github.com/GoogleCloudPlatform/cloud-builders"
      ]
    }
  ]
}

Then, run the following command in the gcb_test directory:

Linux / macOS

curl \
  -X POST \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -T request.json \
  https://cloudbuild.googleapis.com/v1/projects/[PROJECT-ID]/builds

PowerShell

(Invoke-WebRequest `
  -Method POST `
  -Headers @{ "Authorization" = "Bearer $(gcloud auth print-access-token)" } `
  -ContentType "application/json; charset=utf-8" `
  -InFile request.json `
  -Uri https://cloudbuild.googleapis.com/v1/projects/[PROJECT-ID]/builds `
).Content

where [PROJECT-ID] is your project ID.

You should receive a response similar to the following:

{
  "name": "operations/build/[PROJECT-ID]/…",
  "metadata": {
    "@type": "type.googleapis.com/google.devtools.cloudbuild.v1.BuildOperationMetadata",
    "build": {
      "id": "…",
      "status": "QUEUED",
      "createTime": "…",
      "steps": [
        {
          "name": "gcr.io/cloud-builders/git",
          "args": [
            "clone",
            "https://github.com/GoogleCloudPlatform/cloud-builders"
          ]
        }
      ],
…

If you followed the Slack instructions, you should see a Slack notification like this one:

If you followed the Mailgun instructions, you should receive an email about the build.

Cleaning up

To avoid incurring charges to your Google Cloud Platform account for the resources used in this tutorial:

Deleting the project

The easiest way to eliminate billing is to delete the project that you created for the tutorial.

To delete the project:

  1. In the Cloud Console, go to the Manage resources page.

    Go to the Manage resources page

  2. In the project list, select the project you want to delete and click Delete .
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Deleting the Cloud Functions

To delete the Cloud Functions you deployed in this tutorial, run the following commands:

gcloud functions delete subscribeMailgun
gcloud functions delete subscribeSlack

You can also delete Cloud Functions from the Google Cloud Console.

What's next

هل كانت هذه الصفحة مفيدة؟ يرجى تقييم أدائنا:

إرسال تعليقات حول...

Cloud Build Documentation