tmux: synchronize in all windows (not really)

A neat feature in tmux(1) is the :setw synchronize-panes option, which causes tmux to repeat in all panes the keys typed in the window. But if you’re not using panes and have a bunch of windows which you want to send the same keystrokes to you’re out of luck. Fortunately it’s easy to simulate a synchronize-windows option:

Advertisements

Quick’n’dirty ELB healthcheck

Sometimes you have a service you are running on multiple instances in an AWS autoscaling group, and you want to monitor the application health with ELB so that if an instance become unhealthy your autoscaling group will launch a new instance. But if the service doesn’t expose any ports, such as a web server would, ELB health-checks cannot work because they rely on connecting via TCP or HTTP to monitor the health of it’s instances. So? If you can check the health of your service with some local command or script then all you need is the files in this gist and you’re off!

The idea is to use (or abuse) systemd‘s socket activation feature to run a script whenever ELB asks for a certain URL on a certain port. Ideally this port should not be accessible from the public internet or really anywhere else than where ELB will be connecting from. But this is outside the scope of this document (you are running your instances in a VPC right?).

So, assuming /path/to/somecommand is a an executable that will succeed or fail depending on the health of your service, you need the following script to respond to ELB health checks:

Then you configure the status.socket and status@.service unit files (usually in /usr/lib/systemd/system/). And then prof.. ehm test it first!.

This is perhaps just a hack, but it works OK in many cases.

keeping your shell connected to an agent

One of the most annoying things about using an ssh-agent type process is making sure that the environment in your shell (either from an xterm, from an ssh session or embedded in another application) is always properly setup to connect to that process. Since I use gnupg’s gpg-agent, I wrote the following shell script (sourced in my ~/.shrc) to try and always do the right thing™:

send Graphite output to Slack

Just a quick recipe to send rendered graphs from Graphite to Slack, using your crontab(5) and Incoming Webhooks:

0  5  *  *  * /path/to/script.sh >/dev/null

This will send a message to your webhook’s default channel every day at 5am, and Slack show you a preview of the graph in the channel. For completeness’ sake (!) here’s the contents of `/path/to/script.sh`:

#!/bin/sh
METRIC="stats.gauges.somemetric"
OPTS="from=-2hours&until=now&width=400&height=250"
BASE="https://graph.host.com/render"
GRAPH="${BASE}?${OPTS}&target=${METRIC}&title=${METRIC}"
PAYLOAD="payload={\"text\": \"<$GRAPH|daily metric graph>\"}"
curl -s --dump-header - -X POST --data-urlencode "$PAYLOAD" \
 'https://my.slack.com/services/hooks/incoming-webhook?token=XXXXXXXXXXXXX'

UPDATE: the initial version had a bug with single quotes which ought to have been double quotes. Thanks to GregTheRules for catching that.

Simple autoreload for wsgi python apps running in uWSGI

While developing, it’s usefull to have uwsgi autoreload your application. In my case I rsync changed files to the server running uWSGI. But uWSGI only monitors the app configuration file, which generally doesn’t change. In order to have your app auto-reload (like django does) you can switch to your app’s base directory and execute:

while true ; do
  find . -name \*.py                  \ # for python
         -newer /path/app.ini         \ # if changed
         -exec touch /path/app.ini \; \ # reload
         -print                         # print
  sleep 2
done

Everytime you rsync or scp some python file to the server the -newer predicate will turn true for this file and find will touch the configuration file (thereby making it newer than all the source files).

Spell check XML files without VIM syntax problems

I’ve been using XMLMind’s XML Editor lately to write some documentation in the Docbook XML format. The editor has very good support and I’m very glad to be using it. There’s one catch though, and it’s to do with the spell check support. XMLMind have implemented their own system for which there are no Greek dictionaries available. Not having the time to go and create one myself I looked at other solutions.

I have the Hunspell dictionaries on my system anyway but the command line program that comes with Hunspell garbles Greek characters in the terminal. I don’t know what that’s about and Google didn’t come up with any quick solutions. So my next try was using spell check support in VIM 7 and after a bit of trial and error I’m happy with the result. So here’s what I did:

  1. Download a Myspell compatible Greek dictionary word list and affix file, either the original one by Steve Stavropoulos or the one by Dimitrios Gianitsaros which combines the Greek words and English words as well as provides for Greek fully capitalized words with no accents.
  2. :mkspell el /path/to/hunspell/dictionaries/el_GR
  3. make sure the resulting .spl file gets copied to ~/.vim/spell
  4. create the file ~/.vim/after/syntax/xml.vim as described below.
  5. Open an XML file and execute :set spell spelllang=el,en or something to that effect.

One little problem with spell checking XML files in VIM is that the syntax highlighting interferes in a sub-optimal way. For example by default the text content of elements is not spell checked. Another example is that URL’s in href and xmlns attributes are reported as mistakes. These problems can be solved by the following syntax commands:

syn match xmlHref +href="[^"]*"+ contained contains=xmlAttrib,@NoSpell
syn match xmlXmlns +xmlns\(:[a-z]*\)\?="[^"]*"+ contained contains=xmlAttrib,@NoSpell
syn cluster xmlStartTagHook add=xmlHref
syn cluster xmlStartTagHook add=xmlXmlns
syn spell toplevel

Now you should be good to go with spell checking XML in VIM. Another little detail about my work-flow is that I have configured gvim as a helper application in XMLMind XML Editor and that permits me to type “Ctrl-Shift-D” while editing an XML file and get the file opened in VIM ready to be spell checked. After my corrections the file is reloaded in the XML editor.

Mass/Bulk Follow with py-twitter

While trying to maintain the Greek Liberals twitter account, specifically trying to follow a bunch of people that I also follow, I didn’t manage to find a satisfactory solution to automatically follow a specific list of screen names.

Zac Bowling‘s bulk following tool wasn’t working for me (I get an authentication error). The only other promising solution is Flashtweet but they insist on loading the list of new people to follow from another twitter account’s follow list. At first that might not seem like a problem, since I could simply load my personal twitter account friends in Flashtweet and check the people I wanted to follow. But I already had a hand-picked list of people that I wanted the GreekLiberals twitter account to follow. I created this list by going through the CSV file that Tweeple exports where I can browse all the details of a user instead of just the twitter name like in Flashtweet’s interface. I don’t want to start mindlessly following people who for starters might not even speak greek or be otherwise interested in dialogue with the Greek Liberals.

So I decided to write a py-twitter script to do the importing. Here it is:

import twitter
import simplejson
from urllib2 import HTTPError, URLError

class MassFollower(twitter.Api):
   ''' Follow a list of people '''

   def AllFriends(self):
      friends = []
      while (not len(friends) % 100) :
         # see http://code.google.com/p/python-twitter/issues/detail?id=20
         friends.extend(self.GetFriends(page=((len(friends)/100)+1)))
      return friends

   def MassFollow(self,names):
      for name in set(names)-set([f.screen_name for f in self.AllFriends()]):
         if not self.GetUser(name).protected:
            try:
               self.CreateFriendship(name)
            except HTTPError, e:
               print "got error with code",e.code
               # see http://code.google.com/p/python-twitter/issues/detail?id=33 
               if e.code == 401 or e.code == 403:
                  data=simplejson.loads(e.read())
                  print "got data", data
                  if (hasattr(data,'error')):
                     print "can't follow ", name, " because ", err.error
                     continue
               raise

if __name__ == "__main__":
   import sys
   import getpass
   u=sys.argv[1]
   file=open(sys.argv[2],'r')
   p=getpass.getpass("Twitter password: ")
   try:
      api = MassFollower(username=u,password=p)
      api.MassFollow([ line.strip() for line in file ])
   except IOError, e:
      if hasattr(e, 'reason'):
         print "Can't contact twitter:", e.reason
      elif hasattr(e, 'code'):
         if e.code==400:
            print "Probably struck rate limit, try again later."
         else:
            print 'The server couldn\'t fulfill the request: code',e.code

Kudos to Niklas Saers whose own py-twitter utility, lasttweet.py, tipped me off to the page parameter argument to GetFriends method. At the time of this writing, an observant fellow will notice that, according to the aforelinked docs, there is no parameter named page. This is why this script is currently dependent on a version of py-twitter greater than 0.5, which is currently the stable version. So basically you need to get a svn checkout and install it manually on your system.

Apart from being my first use of the twitter API it is also the first semi-usefull thing I’ve written in python, so I would be gratefull for criticism or comments regarding the code above.