
Have you ever wanted to be notified quickly if a build succeeds or fails in Jenkins? I did. This tech tip is about creating a simple script to get notified about a Jenkins job.
Since we use Amazon Web Services, it was natural to look to SNS and SQS as a solution. Jenkins has an Amazon SNS Notifier plugin that makes this really easy.
So, to make this work I set up an SNS Topic and an SQS Queue both named jenkins-notifications. I then subscribed the SQS Queue to the SNS Topic I installed the Amazon SNS Notifier and configured it with my AWS credentials then entered the ARN for the SNS Topic I created. Nothing custom yet and it was very intuitive. Now comes the custom stuff.
There’s a Python library that makes executing Applescript very easy; it’s called py-applescript. There’s also a Python library that makes it easy to connect to SQS called Boto; Boto is what powers the awscli project by the way. Configuring Boto to use my AWS credentials was easy, just create a file at ~/.boto
with the contents from the Configuring Boto Credentials part of the Boto documentation.
Now I could create a script to listen to an SQS Queue and tell OSX to notify us about what happened. First, what does the Applescript look like that needs to be executed? Since I wanted to pass in the title and message in order to the script, I ended up with this.
on run argv display notification item 2 of argv with title item 1 of argv end run
What’s going on here? Well, since there are some parameters to the script, I needed to specify that, hence the on run argv
line. Next, since I pass in the title then the message, but the Applescript notification function takes message first, I used item 2 of argv
for the message part and item 1 of argv
for the title. Next, Boto needs to handle a message from our queue. This was my first iteration.
#!/usr/bin/python from boto import sqs import json conn = sqs.connect_to_region("us-west-2") queue = conn.create_queue("jenkins-notifications") read = [] while 1: message = queue.read(wait_time_seconds=20) if message: print "got message" data = json.loads(message.get_body()) if data['Subject'] not in read: print "new message ... handling", data['Subject'], data['Message'] read.append(data['Subject']) if len(read) > 60: print "Removed", read.pop(0), "from read queue" else: print "was old message ... discarded"
Here, I’m connecting to the us-west-2
region and getting the jenkins-notifications
SQS Queue; if the SQS Queue doesn’t exist, it is created. Next, I use long polling with the wait_time_seconds=20
part of the queue.read
function call. If there is a message present, I grab the dictionary from the json message. Next, I check to see if I’ve read that message already; if so, I process the message and put it into the read list. If the read list gets too long, I pop a message from it.
So, how did I integrate Applescript into this? Here’s my final iteration with Applescript put in and print statements removed.
#!/usr/bin/python from boto import sqs import applescript import json conn = sqs.connect_to_region("us-west-2") queue = conn.create_queue("jenkins-notifications") scriptCommand = ''' on run argv display notification item 2 of argv with title item 1 of argv end run ''' script = applescript.AppleScript(scriptCommand) read = [] while 1: message = queue.read(wait_time_seconds=20) if message: data = json.loads(message.get_body()) if data['Subject'] not in read: script.run(data['Subject'], data['Message']) read.append(data['Subject']) if len(read) > 60: read.pop(0)
So, this is the final product; a script that listens to an SQS Queue about Jenkins notifications and uses Applescript to notify me of what’s going on with a Jenkins job.