Creating GCS buckets with Slack bots in Go

Pauline Ménage
unacastlabs
Published in
6 min readSep 15, 2017

--

In the last blog post about Slack bots, we saw how to create a simple Slack chatbot in Go. We are now going to upgrade and learn how to make it communicate to another service using Google Pub/Sub.

At Unacast, we use a bot to create new AWS and Google Cloud Platform configuration for example. In this blog, we’re going to do a more simple example, we’re going to ask the bot to create a new Google Cloud Storage (GCS) bucket. To do that, we have two services, the first one is the bot, which receives and sends messages on Slack, and the second service actually creates the configuration, and tells the bot when it is done.

These two services will communicate with Google Pub/Sub, when the bot receives a command to create a new GCS bucket, it will publish a message on Google Pub/Sub, and the other service, continuously listening to Google Pub/Sub will receive it, create the bucket, and publish a new message on Pub/Sub with a Success or Failed event.

Requirements

To run the example you will need a Google Cloud Platform project, set up to use GKE, GCS, and Pub/Sub. You should also have followed the last blog post. You can find the whole source code for the project here, if you have set up GCP, it is ready to be run. The code in this article does not handle errors, if you are unsure about error handling in Go, you can check out the examples in my repository.

The bot service

In the last article, we were just creating commands for the bot, while here, we are starting to get more out of the Go by using concurrency. Indeed, the ReceiveAndSend function is running in a go routine and will always be running asynchronously alongside bot.Listen() . Right now, the bot has only one command, but more commands can be added easily.

What is interesting in this bot is that we are going to use events for the different commands. This is the structure of the messages that will be sent to Pub/Sub.

Bucket is the parameter of the bot command and the name of the bucket we want to create. The command can be called on Slack this way: @gcsBot gcsbucket my-gcs-bucket . GCS bucket names are unique and follow some conventions, be sure to enter a compliant name, and you can do a check in your code.

Channel is the channel on which the bot sent the message, to be able send the response back to the right channel. Google Pub/Sub is asynchronous, so if two people send a command to the bot from two different channels, we will not know which message arrives back first in Google Pub/Sub, and therefore which channel to send it to. This is why we include it in the Message structure, to avoid eventual bugs.

The Event is what is used by the bot and the service to communicate to each other and understand what task it should execute. For example, when a command is called:

  • The bot sends a message with an event calledCREATE_GCS_BUCKET to the Pub/Sub topic.
  • The service receives it and knows it should create a new GCS bucket.
  • The service returns GCS_BUCKET_CREATED or GCS_BUCKET_CREATION_FAILED whether it has succeeded or not.
  • The bot receives the message with one of the above events, and, the ReceiveAndSend function publishes a message on the right Slack channel, with a message which depends on that event.

This function has an indefinite for loop, which means that it is constantly looking to receive new messages. When it receives one, it transforms it into the Message structure, and can then check the Event to know what to send back to the Channel which was included in the message.

The SUBSCRIPTION_ID is the Pub/Sub subscription on which the bot listens to see if there are new messages. Here it is set as an environment variable, and it should be created before running the bot, or have a function which checks if it exists and creates it if not. The same should be applied to the project id, and the Pub/Sub topic on which the messages are being published.

The SUBSCRIPTION_ID should be different for the bot service and the creation service, or else both services will be listening to the same subscription and only one of them will get the messages.

The Handle function looks very much like the functions implemented in the last blog article, they specify what to do when the corresponding command is called. Here, when the gcsbucket command is called, we check if the parameter bucket was included by the user, and then just have to publish a message to Pub/Sub with the correct event, here CREATE_GCS_BUCKET .

The bot replies to the user that it is creating the bucket, and the user may have to wait a few seconds to receive an answer.

When the command gcsbucket is called, the handle calls another function, SendPubsubMessage. Here, we are publishing a message to Pub/Sub, with the event CREATE_GCS_BUCKET (you can see it in the Handle function), the GCS bucket to create, and the channel from which the command was called.

In the following code, we have to:

  • Create a new Google Pub/Sub client.
  • Get the topic we wish to publish the message to.
  • Create the message structure.
  • Encode the message.
  • Publish the message on Pub/Sub.

That is all for the bot service, as you can see it mainly publishes and gets Pub/Sub message, and manages which events are sent for which commands, and what to send back to a Slack channel depending on the event it received back once the work is done.

The bucket creation service

This is the whole service which gets the Pub/Sub message, creates the GCS bucket, and publishes a new Pub/Sub message.

As you can see at the beginning of the code, the Message structure is the same than in the bot, it makes it easier to communicate between the two services (and you can leave out the fields you do not want to use). This structure will eventually grow as you add commands.

The Receive and PublishMessage are very alike the functions which receive and publish messages to Pub/Sub in the bot.

What is interesting in this service is the main function. The main is a for loop, running indefinitely and receiving Pub/Sub messages. When it receives one, it checks the event, and knows thanks to it what it should do.

Here, the event is CREATE_GCS_BUCKET , so it creates a new Google Storage client, and creates the bucket. If the creation fails, it replaces Event in the Message structure by GCS_BUCKET_CREATION_FAILED , and if it succeeds, by GCS_BUCKET_CREATED . It then publishes back to the Pub/Sub topic, where the bot will be able to receive it and react.

In this example, we don’t check if the GCS bucket exists, but you should check to avoid errors. The code for that could be something like this, and you can run it before creating the bucket, as it will return if the bucket already exists. If you do that, you have to publish a message to Pub/Sub before returning, to tell the bot that the bucket exists.

You now have two services ready to create Google Cloud Storage buckets for you, the picture below will show you an example of how it works!

You now have a functional bot to create your GCS buckets! To try this example out, run each of the services in a terminal, you can get the whole source code and explanations here. The next step would now be to deploy these services, for example on Google Container Engine.

--

--