Category Archives: Code

Provisioning Vault with Code

A couple of years ago, Hashicorp published a blog post “Codifying Vault Policies and Configuration“. We used a heavily modified version of their scripts to get us going with Vault.

However there are a few problems with the approach, some of which are noted in the original post.

The main one is that if we remove a policy from the configuration, applying it again will not remove the objects from Vault. Essentially it is additive only, and while it will modify existing objects and create new ones, removing objects that are no longer declared is arguably just as important.

Another problem is that shell scripts inevitably have dependencies, which you may not want to install on your shell servers. Curl, in particular, is extremely useful for hackers, and we don’t want to have it available in production (in our environment, access to the vault API from outside the network is not allowed).

Finally, shell scripts aren’t easy to test, and don’t scale particularly well as complexity grows. You can do some amazing things in bash, but once it gets beyond a few hundred lines it’s time to break out into a proper language.

So that’s what I did.

The result is a tool called vaultsmith, and it’s designed to do one thing – take a directory of json files and apply them to your vault server.

Continue reading

Upstream Bug? Fix it.

This is a blog post I originally wrote more than two years ago, in reaction to “spirited debates” I was having with developers. I didn’t post it, but perhaps I should have! Anyway the ideas within are as true to me now as they were then, so I thought I’d post it today after a bit of revision.

How many times have you had a developer shrug their shoulders at you and say “it’s an upstream bug”?

I heard it today, and it is so, so wrong, that it is practically an admission of guilt.

Do you say that to your customers when their personal data is leaked from your database? When your app crashes their device? No? Good, because it’s your problem.

It’s great that you can use third party libraries to do your job more efficiently, but doing so does not absolve you of responsibility if the product breaks. You made the decision on what library to use, and you are ultimately responsible for delivering functionality. Continue reading

Building and Packaging a Python command-line tool for Debian

python-logo-notext-svgPython packaging has a chequered past.

Distutils was and still is the original tool included with the standard library. But then setuptools was created to overcome the limitations of distutils, gained wide adoption, subsequently stagnated, and a fork called distribute was created to address some of the issues. Distutils2 was an attempt to take the best of previous tools to support Python 3, but it failed. Then distribute grew to support Python 3, was merged back in to setuptools, and everything else became moot!

Unfortunately, it’s hard to find reliable information on python packaging, because many articles you might find in a Duckduckgo search were created before setuptools was reinvigorated. Many reflect practices that are sub-optimal today, and I would disregard anything written before the distribute merge, which happened in March 2013. Continue reading

Streaming JSON with Flask

I have a SQLAlchemy query (able to behave as an iterator) which could return a large result set. First version of the code was very simple. Release objects have a to_dict() function which returns a dictionary, so I append to a list and jsonify the result:

# releases = <SQLAlchemy query object>

output = []
for r in releases:
    output.append(r.to_dict())

return jsonify(releases=output), 200

(context on github)

This result set could potentially grow to a point that fitting it memory would be impractical – with only a thousand releases there is already a significant lag before we start getting results. Continue reading

Safely running bulk operations on Redis with lua scripts

This article was also posted on the Gumtree devteam blog

If there was one golden rule when working with redis in production, it would be

“Don’t use KEYS”

The reason for this is that it blocks the redis event loop until it completes, i.e. while it’s busy scanning its entire keyspace, it can’t serve any other clients.

Recently, we had a situation where code was storing keys in redis without setting an expiry time, with the result that our keyspace started to grow:
Continue reading

Pausing Spotify and playing a random video in Python – A party trick for Halloween

For a Halloween party last weekend I wrote a python script to pause Spotify, play a random video and start music playback again. The videos were basic ogg files I cobbled together which showed a scary image and evil laughs or screaming with OpenShot. I can’t really share them, as I don’t have rights to the media, but it’s pretty simple to recreate them yourself.

The code for this script is on Github, and I’ve reproduced the latest snapshot below. Feel free to fork and improve if you want to scare your guests, or add support for other OS’s. Presently it only supports Linux because I used dbus to perform the play/pause actions.

#!/usr/bin/python

'''
This is a Halloween party script which pauses Spotify and plays a video
at random intervals.
'''

import random
import subprocess
from subprocess import call
from time import sleep
import os
import datetime

start_time = datetime.time(21, 0, 0)
stop_time = datetime.time(23, 0, 0)

video_dir = '/home/alex/Videos/scream/'
videos = { 'scream1_nofade.ogg': 30,
'happy.ogg': 1,
'evil_laugh.ogg': 5,
}

def time_in_range(start, end, x):
"""Return true if x is in the range [start, end]"""
if start <= end:
print("start<end")
return start <= x <= end
else:
print("end<start")
return start <= x or x <= end

def weighted_choice(weights):
total = sum(weights[video] for video in weights)
r = random.uniform(0, total)
upto = 0
print("total: %s\nrandom: %s" % (total, r))

for video in weights:
w = weights[video]
if upto + w > r:
return video
upto += w
assert False, "shouldn't get here"

def spotifyPause():
command = "dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Pause"
print("pausing spotify")
os.system(command)

def spotifyPlay():
print("playing spotify")
command = "dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause"
os.system(command)

def play_video(video_file):
print("Playing %s" % video_file)
#call(['/usr/bin/mplayer', '-fs', video_file], stdout=None, stderr=None)
#result = subprocess.Popen(['/usr/bin/mplayer', '-really-quiet', '-fs', video_file])
result = subprocess.check_call(['/usr/bin/mplayer', '-really-quiet', '-fs', video_file], stdout=None, stderr=None)
return result

def playBuzz(buzzfile):
print("Buzz...")
result = subprocess.check_call(['/usr/bin/mplayer', '-really-quiet', '-ss', '18', buzzfile], stdout=None, stderr=None)
return result

def infiniteLoop():
while 1:
current_time = datetime.datetime.now().time()
#if current_time > stop_time or current_time < midday:

choice = weighted_choice(videos)

random_time = random.randrange(1200,2400)
random_time = 3

video_file = video_dir + choice
print("Chose video %s after %s seconds" % (video_file, random_time))
sleep(random_time)

# Whether to play buzz
buzz = False
if random.randrange(0,100) > 90:
buzz = True

# Continue if outside time range
if not time_in_range(start_time, stop_time, current_time):
print("Not playing video, outside time range")
continue

# Do it
spotifyPause()
if buzz:
playBuzz('/home/alex/Videos/scream/audio/buzz.mp3')
play_video(video_file)
spotifyPlay()

if __name__ == "__main__":
infiniteLoop()