Summary

As this is a home lab, there is a tenancy to start it up, play around for a bit and then forget about it and go do something else. This is a bit of a problem at the end of the day when you realise everything else has been shutdown but this power hungry monster is still running. Being rather lazy, the thought of finding a laptop or some other method to shut it all down cleanly is not very appealing but neither is the bill for it running all the time. So this is my solution:

graph LR A(Alexa) --> I(IFTTT) I --> S(Slack) S --> H(Hubot) H --> An(Ansible) An --> D>Shutdown Job]

Alexa & IFTTT

IFTTT (If This, Then That) is a nice option that makes adding custom hooks to Amazon’s Alexa nice and easy. The applet in this case will post a message into a particular slack channel saying “Switch off the lab”. The main reason for going this way about it, is I don’t really want anything connecting into the lab or other parts of the home. Rather, a message queue (of sorts) that can be picked up by the lab itself.

IFTTT Applet

Slack & Hubot

So once the message has been posted into the slack channel;

10.44.90.187 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP3QvRkD3b9hIc0FzVABR397yZ5rHob08dLx4ffYdtJP

it gets picked up by Hubot, running with the slack adaptor on the lab box.

Hubot was installed using the npm installer and then set up as a systemd unit to start when the lab does. In order for the bot to read and write into the slack channel, the Hubot app needed to be added to the workspace, this then gives you a legacy bot token for Hubot.

Once Hubot is connected you can then add the scripts required.

This will be moved into Ansible or ideally Ansible Tower so that jobs can be triggered with webhooks, rather than just running arbitrary scripts from Hubot!

This is the Hubot lab.coffee script that’s running:


module.exports = (robot) ->

# Checks into the room so that you know it's online

robot.messageRoom("automation", "I'm online")

robot.hear /whats running/i, (res) ->

# Resonds with a list of running VMs

    @exec = require('child_process').exec
    cmd = 'virsh list'
    res.send "Checking what VMs are running..."

    @exec cmd, (error, stdout, stderr) ->
      if error
        res.send "```#{error}```"
        res.send "```#{stderr}```"
      else
        res.send "```#{stdout}```"

robot.hear /switch off the lab/i, (res) ->

# Runs a bash script to shut down all the VMs cleanly, then powers off the host

    @exec = require('child_process').exec
    cmd = './bash_scripts/shutdown.sh'
    res.send "Shutting down the lab..

    @exec cmd, (error, stdout, stderr) ->
      if error
        res.send "```#{error}```"
        res.send "```#{stderr}```"
      else
        res.send "```#{stdout}```"

And the Hubot service:


[Unit]
Description=Hubot service
Requires=network.target
After=network.target

[Service]
Type=simple
Environment=HUBOT_SLACK_TOKEN=xoxb-<Slack bot token>
WorkingDirectory=<Hubot install directory>
ExecStart=/bin/bash -a -c 'cd <Hubot install directory> && ./bin/hubot --adapter slack'

[Install]
WantedBy=multi-user.target

As Hubot is just looking for particular strings in messages posted to the channel, it’s possible to skip the Alexa / IFTTT setup and just post messages into the channel directly to trigger Hubot jobs.

Ansible

The plan is to move from bash scripts doing the work to an Ansible Tower / AWX setup. This will then allow Hubot to make web calls to start Ansible jobs. This will probably be documented in a future post.