Hacking Hubot - Intro

What is Hubot

alt

GitHub, Inc., wrote the first version of Hubot to automate our company chat room. Hubot knew how to deploy the site, automate a lot of tasks, and be a source of fun in the company. Eventually he grew to become a formidable force in GitHub. Hubot on github.

We are about to embark on a 3 part series which will hopefully teach you a thing or two about Hubot, Kudu, and Azure Management services. By the end of the series, I hope you will be inspired and empowered to automate something.

Part 1 - The journey begins

I work at Unboxed Technology located in Richmond, VA. We use HipChat for enterprise chat communication. A long time ago a developer at Unboxed setup a mythical robot named Hubot. He hangs out in all of our HipChat rooms and responds to requests like:

@Hubot pug bomb

pug bomb

Fun right? Last week I decided: let's teach Hubot to build our products. That same day I sent an invite to our intern Hayden to blocked off 2 hours the following Friday.

alt

He accepted, I jumped for joy, and now it was time to realize the dream.

The majority of Unboxed's apps are hosted on Microsoft Azure. We believe in Continuous Deployment. A push to a git results in a deployment to an associated environment( dev, test, qa, production ). We have grown to love and hate Azures out of the box CI solution infamously named Kudu.

Kudu

Kudu is a mini-engine that knows how to listen for changes in git, perform the deployments, has a management web interfaces, as well as some management apis. Kudu's setup is simple. Option A do nothing and it will try to do the deployment for you. For simple .NET APIs this will probably work. However for us it did not work because we also needed to publish our database project.

Don't worry, if you need more than the black magic above, there is an alternative solution. All you need to do is write a .cmd file to script your build process. You know that syntax that was created back 1993 for * Windows NT.* Sounds like a dream right?

It's actually really simple. We have an api deploy cmd script that does the build, and also orchestrates the db project publish process. For our UI (website & ionic app) it's painfully simple because of our build system ubt-gulp. The client delpoy cmd file just needs to run npm install, bower install, gulp pgbuild, then kudu sync. Seems like a lot, but it's as calling those 4 commands.

Hubot

The way we have decided to host Hubot is via Heroku. Its a really simple node app that has been configured to be able to communicate with our HipChat instance. Its really easy to get up and running on Heroku and it's actually free to host.

Want to get up and running fast?

npm install -g generator-hubot
yo hubot

Volia! Once setup, you can create new Hubot commands by adding a simple javascript file to the scripts directory. Source of the "pug me command:"

alt

A ton of OOTB scripts can be found here https://github.com/hubot-scripts

Hubot supports basic commands like hear & respond. Hear translates to listen for this pattern and then do something. Respond is the same but it requires someone to @Hubot directly.

More info can be found here Scripting Hubot

The goal :

@hubot build status projectname

That command should return the current status of the build. Why? Because Kudu is slow as dirt, unreliable, and it's actually hard to get to the logs when a build is running. Another good reason is that the only people that can actually answer the question: "Is the build done," are those that have permissions to access the Kudu console. And you don't want to grant everyone that permission.

So let's now talk rules for any hackathon.

Rule #1: be prepared.

I spent all Friday morning trying to figure out how I could query the status of our Kudu builds. Most respectable api's support token security. They provide ways to provision a "token", or have endpoints where you can acquire one. I spent all morning trying to find a way to securely connect to Azure via a provisioned token. The good news is I figured it out. I figured out how to create a user in Azure portal, provision access to a subset of resources, start with a token, and then exchange that token for management API access. The bad news is Kudu does not support Azure tokens. All that previous work was in vain. Only temporarily because now I plan to use my new found knowledge to automate creating new environments in Azure.

Before giving up hope and canceling my meeting, I found the kudu api documentation. Hidden somewhere inside, the second paragraph, they mention that they accept either your Azure "deploy" credentials or the "site" credentials. Your deploy credentials are used for all apps you have access to in Azure, and your site ones are per app and can be found if you download your publish profile. Regardless of which you choose they both have a username and password and you can use them by sending an Authentication header with a value of Basic: base64( username + ":" + password ).

The good news is most people would not recognize base64 but bad news is it's trivial to decode your username and password. So recommendation is if your going to use the "site" credentials don't. Do the extra effort to register site credentials for all sites that you need be deployed.

Rule #2: don't get distracted.

Most Hubot script's I have seen are written in Coffeescript, I do know Coffeescript, but I didn't want to waste time tracking down space issues. So I'm going to develop in javascript.

I dont want to solve security issues so I decided I would find the easiest way possible to limit access.

Whenever you start a hack make sure you set a goal for yourself. Keep it simple but commit to it. For me I absolutely had to leave with the ability to query status of a build.

Rule 3: Divide and conquer.
Come up with a plan that enables to enable everyone to work freely & quickly. My plan was to have Hayden implement the "brain" and I would work on the interaction with Kudu to request build status. The brain was a poor mans way to add security. Hayden was tasked with coming up with a way to register environment that could be deployed by Hubot.

@Hubot build set nicks-project-dev nicks-dev

@Hubot build set nicks-project-dev dev

Once someone with permission to setup the aliases runs the above command then it would allow others to run build|status for that command.

@hubot build nicks dev

@hubot build dev

We had a plan but that last step was to make sure when we started we could swarm. We came up with this simple prototyped node script.

alt

Really simple. We have one "respond" command that listens for

@Hubot build command:action arguments

We parse the request into an options object that looks like:

{
    command: "deploy",
    action:  "force", // optional
    arguments : ["projectname", "next", "etc],
    argumentString: "projectname next etc"
}

We then look for a function named handle_<command name>. E.g. handle_set, handle_build, handle_deploy. If that command is there we call it passing the options arguments and return the response. If the command function does not exist we just print it out and return.

Hayden was in charge of implementing handle_set and alias_lookup and I was in charge of handle_build and handle_deploy.

What is alias_lookup ? That is the function that will accept a project from the build command, and will check the "brain" to make sure we are allowed to build it. It will return the "project name" of the real app.

Armed and dangerous the Hackathon was a go..


Next week: Hacking Hubot adding a brain and the build set alias command.

Nick Capito

Professional developer in all things generic. Good at AngularJS, CSS3 , Sass, .NET, Azure, Node. Love dogs. In an alternate live I would have been an American Cesar Millan.

Richmond, VA http://nixo.us