As you may know I love to play with new toys. I especially love connecting new toys with my old toys. What you may not know is that I am also an avid World of Warcraft fan and player! In order to run what are known as “raids”, group content designed for 10 – 30 players, I use a program called Discord.
My goal was simple – could I send myself messages in Discord from my Ansible playbooks with network state data? Could I create a #chatbot in this way ?
As it turns out not only could I achieve this – it is actually pretty straight forward and simple to do!
Setup
There are not a lot of steps in the setup.
- Download and install Discord
- Setup an account
- Create a Server
- Create a Channel
- I named my channel AutomateYourNetwork and set it up as private with invite only RBAC to see the channel
- Once we have a server and channel setup we need to setup the Integrations
- Now setup a WebHook
- Select the channel you want your chatbot to send messages to
- We will need the Webhook URL
Postman Development
As with all new API development I always start in Postman to sort out the authentication, headers, and body to POST against this new Discord Webhook.
First let’s setup a new Postman Collection called Discord; add a new POST request to this collection
For the request itself make sure you change the default GET to a POST and then use the following URL:
https://discord./com/api/webhooks/< your URL copied from Discord here>
The body is flexible but to get started let’s just use a small set of values.
Set your body to RAW JSON
And add this body (change your username unless you want this message to look like it came from me!!)
Now if you really want to see how fast / real-time / amazingly cool this is – make sure you have your Discord logged in but minimized to your system tray
Hit SEND in Postman
Your Discord should have notified you about a new message! In my system tray the icon has also changed!
Which is no surprise because back in Postman we see we received a valid 204 No Content response from the API
Lets see what Discord looks like
How cool is this?!?
Integrating with Network Automation and Infrastructure as Code
Ok this is great – but can we now integrate this into our CI/CD pipeline Ansible playbooks?
Can I send myself network state data ? Can we create a #chatops bot ?
Yes we can!
Lets start with Ansible Facts – and see if we can chat ourselves the current version of a device.
First let’s setup our credential prompts
Then, let’s use ios_facts
Thats more or less all I need to do – next let’s use the URI module to send ourselves a chat!
I will break down this next URI task; first setup the URL – again after /webhooks/ {{your URL here }}
This is a POST
I like to do this next step for two reasons; one to set the body of the POST to JSON (obvious) but also to allow me to use YAML syntax in Ansible to write the body of the POST (not so obvious). Without this my body would need the JSON formatting (think moustaches and brackets) which is hard enough to write on it’s own, and very hard to write inside a YAML Ansible task
Meaning I can format the body as such (in YAML):
And, like we saw in Postman, we are expecting a 204 back and no content
Make sure you are delegating to the localhost (you dont want this step to run on your Cisco switch)
Again back to the body we are accessing the Ansible magic variable ansible_facts and the key net_version
Lets run the playbook!
Discord looks happy
And, with the power of Internet Magic, here is our message!
This is incredible – let me integrate Cisco Genie / pyATS now and send some parsed network state data next – to show the real power here
The playbook structure is more or less the same so save the Ansible Facts version playbook and copy / rename it to Show Int Status.
Keep the prompts; remove the ios_facts task and replace it with this task
Followed by the Genie parsing step
Then we need to adjust the Discord message – for my example I only want a message if, for example, an interface is configured to be UP / UP (meaning it is not administratively down) but is DOWN / DOWN (notconnected state). I don’t care about UP/UP or Administratively Down interfaces.
Again, I will break down this
Most of this is the same
Here comes my magic with Genie. We want to loop over each interface Genie has parsed into the registered variable pyatsint_status_raw.interfaces. We need to convert this dictionary into a list of items so filter it | dict2items
Now we want a condition on this loop; only call the Discord API when the {{ item.value.status }} key (that is to say each iteration in the loops status value) when it equals “notconnect“
Now we can reference the item.value for the per-interface name and the item.value.status for the notconnect status when it hits a match in the body of the message we are sending to Discord.
The task as a whole looks like this:
So we run this new playbook which sort of looks like this. Remember we have a condition so the light blue text indicates non-matches / skipped interfaces (because they are connected or admin down); green indicates a hit.
Drumroll please
And now in Discord I have this wonderful, pager-like, real-time “alert”
Now go build one!
Here is the GitHub repository – go try to build one for your network!
DiscordNetworkChatBot (this link opens in a new window) by automateyournetwork (this link opens in a new window)
Ansible playbooks that chat with Discord using Ansible, Genie/pyATS, and the Discord webhooks that send network state information as a Discord message!
I would *love* to see your #chatbot in action – please hit me up on Twitter and show me what you got !
Amazing stuff John. Thanks for sharing your skills