how to restart a gunicorn server without leaving vim

I’ve been using the gunicorn WSGI server lately while I work on my next project. gunicorn is fantastic, except for one tiny nuisance. I have to restart gunicorn as I change my app code. At the beginning, this meant I would switch over to the terminal where gunicorn was running. Then I’d kill the parent process by hitting CTRL+C, and then start it up again, by typing:

gunicorn crazyproject.webapp:make_application

Other frameworks often have a development mode that forks off a helper process that watches the source code folder. When some file changes, the helper tells the server to reload.

I’m not using any frameworks this time, so I don’t have that feature. I never really liked the fact that every time I saved a file, I would restart the server during development. Instead, in this case, I want to easily restart gunicorn, but only when I want to, and I don’t want to leave my editor.

It turned out to be pretty easy to do.

First I read in the excellent gunicorn docs how to tell gunicorn to reload my app:

How do I reload my application in Gunicorn?

You can gracefully reload by sending HUP signal to gunicorn:

$ kill -HUP masterpid

Next I added a –pid /tmp/gunicorn.pid option to the command that I use to start gunicorn, so that gunicorn would write the parent’s process ID into /tmp/gunicorn.pid.

Now any time I want gunicorn to reload, I can do this little command in a terminal window:

$ kill -HUP `cat /tmp/gunicorn.pid`

Those backticks around cat /tmp/gunicorn.pid tell the shell to do that part of the command first, and then feed the result into the rest of the command.

You can always use ! in vim to run some command-line program. If I had to explain the difference between vim and emacs, the one difference that is most interesting to me is that vim makes it super-easy to send buffer contents to other programs or read buffer contents from other programs, while the people behind emacs seem to think that any external dependency should ultimately be moved into emacs itself. I get the feeling that vim wants to be my text editor, but emacs wants to be my OS.

Anyhow, while I’m in vim, I run that command to restart like this:

: !kill -HUP `cat /tmp/gunicorn.pid`

After using that code for a while, and feeling confident it worked right, I mapped F12 in vim to do that action for me by adding this little thing to the end of my ~/.vimrc:

:map :!kill -HUP `cat /tmp/gunicorn.pid`

Now that means I hit F12 when I want to reload gunicorn.

How to connect to a wireless network from the Ubuntu command line

Why use a friendly GUI when there’s cryptic shell commands out there?

Phoenix Coffee offers free wireless access without an access key and they broadcast their ESSID. Here’s how I connect:

$ sudo iwlist eth1 scan # eth1 is my wireless card.
eth1 Scan completed :
Cell 01 - Address: 0A:1D:19:15:C2:C1
ESSID:"bestcoffee"
Mode:Master
Channel:5
Frequency:2.432 GHz (Channel 5)
Quality=88/100 Signal level=-44 dBm Noise level=-81 dBm
Encryption key:off
Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 6 Mb/s
9 Mb/s; 12 Mb/s; 18 Mb/s; 24 Mb/s; 36 Mb/s
48 Mb/s; 54 Mb/s
Extra:tsf=0000003befa89182

That scan lists every available access point. The important piece of information to extract here is the ESSID. Now I set my wireless card up to connect to that ESSID:

$ sudo iwconfig eth1 essid "bestcoffee"

And finally, I tell my card to request an IP address from the router:

$ sudo dhclient eth1 # gimme an IP address plz!
There is already a pid file /var/run/dhclient.pid with pid 6911
killed old client process, removed PID file
Internet Systems Consortium DHCP Client V3.0.6
Copyright 2004-2007 Internet Systems Consortium.
All rights reserved.
For info, please visit http://www.isc.org/sw/dhcp/

wmaster0: unknown hardware address type 801
wmaster0: unknown hardware address type 801
Listening on LPF/eth1/00:1c:bf:96:7e:21
Sending on LPF/eth1/00:1c:bf:96:7e:21
Sending on Socket/fallback
DHCPREQUEST of 192.168.1.112 on eth1 to 255.255.255.255 port 67
DHCPACK of 192.168.1.112 from 192.168.1.1
bound to 192.168.1.112 -- renewal in 251284 seconds.

I can type these three commands way faster than waiting for the GUI to fire up. Here they are again, without all the output:

$ sudo iwlist eth1 scan
$ sudo iwconfig eth1 essid "bestcoffee"
$ sudo dhclient eth1

Sometimes, I need to connect to a network with a hidden ESSID. That’s just as easy. I just configure the ethernet card to connect to anything:

$ sudo iwconfig eth1 essid any # any is a keyword, not the name of an ESSID.

Finally, some networks require an access key. Sometimes, people can give you the human-friendly version, and you can type that in like this:

$ sudo iwconfig eth1 key s:password # translates to the hex for me.

Note the s: in front. That translates what I type into the hex jibberish.

Other times, people insist on giving you the goofy string of hex digits, so you can set it like this:

$ sudo iwconfig eth1 key ACDB-1234-1234-EFG2

Frustration with postfix and sending email to a script

I want to set up an email address that executes a script with every incoming email, so in my /etc/aliases, I did this:

runscript: |/usr/local/bin/email_reading_script.py

Then I rebuilt the postfix alias db with sudo postalias /etc/aliases, and then sent an email to runscript@localhost. That’s when the fun began. The script is run by nobody/nogroup, so it couldn’t log to my logging directory, because I require people to be in the adm unix group.

Then I created a user named runscript, and moved that | /usr/local/bin/email_reading_script.py line into a .forward file. I added adm to runscript’s unix groups.

AND STILL NO JOY.

I don’t know why, but when the script runs, the shell only seems to get the primary group. So, I kept getting permission-denied errors. I finally got stuff to work when I set adm to be the primary group for my runscript user. Now everything is OK.

This ate up the better part of the @#$@#$ing day. Grr.

If this didn’t work, I was going to install procmail and go down that route.

Am using ubuntu hardy heron.

Keeping your system clock synchronized with Ubuntu is trivial

I have a few Ubuntu servers scattered across the earth. This is all I had to do to make sure that their system clocks were synchronized:

sudo apt-get install ntp ntpdate

Those Ubuntu packages are automatically configured to make your box use the time server at ntp.ubuntu.com. It couldn’t be any simpler.

By the way, if you want to point to a different time server, the config file in /etc/ntp.conf is full of helpful comments.

Ubuntu Gutsy twill package breaks the showforms command

On one computer named snowball, I installed the ubuntu twill package, then tried to test my webapp:

$ twill-sh -u http://coleridge:8181/login2
==> at http://coleridge:8181/login2

-= Welcome to twill! =-

current page: http://coleridge:8181/login2
>> showforms
current page: http://coleridge:8181/login2
>> show




Login 2

Login 2



current page: http://coleridge:8181/login2
>>

The page clearly contains a form, but twill’s showforms command doesn’t display it. Fortunately, I found this post on the twill mailing list and so I didn’t waste too much time scratching my head. Then on this other box, coleridge, I installed twill using easy_install, and all was well:

$ twill-sh -u http://localhost:8181/login2
==> at http://localhost:8181/login2

-= Welcome to twill! =-

current page: http://localhost:8181/login2
>> showforms

Form name=login2 (#1)
## ## __Name__________________ __Type___ __ID________ __Value__________________
1 user_name text (None)
2 passwd password (None)
3 1 None submit (None)

current page: http://localhost:8181/login2

Sidenote: snowball is my new computer. She is a beaut; a 600mhz Compaq Presario with 60mb of ram, and a hard drive that makes clicking sounds when anything happens. I think Clinton was still in office when she was manufactured. I’d like to thank my son for helping decorate her with some very cool Godzilla stickers.

Photo0250.jpg

Installing on such an old machine meant I had to monkey a fair amount with some kernel modules, which is always a blast, and I am now much more aware of how much every program really costs in terms of CPU utilization and memory footprint.

My .screenrc is a testament to obsession over meaningless details

Most every time I start a new screen session, I set up four windows using particular window names. After several hours of reading the screen man page and trying stuff out, I discovered how to automate the process. I added this section to my .screenrc:

screen -t ipython 0 /usr/bin/ipython -p matt
screen -t code 1 # This is where I use vi.
screen -t psql 2 /usr/bin/psql -U mydbusername mydb
screen -t irssi 3 /usr/bin/irssi

You can use the -c option when you start screen to specify a file other than $HOME/.screenrc. So I might write a bunch of different .screenrc config files and then I can choose what ever one I want. I can already imagine a .screenrc customized for doing python work, and another one customized for writing rants, and another one for doing sysadmin work.

A few other useful screen options:

  • screen -S sessionname will start a screen session and name it sessionname.
  • screen -ls will list all the screen sessions already running. Those session names are helpful in this case.
  • screen -r sessionname will attach a screen session that you specify.

Ubuntu and TurboGears

It shouldn’t be so hard to set up turbogears on ubuntu Feisty Fox. The easy_install-2.4 turbogears approach crashes when trying to install Cheetah.

So, here’s a list of everything I had to do:

  • I installed the Ubuntu package for Cheetah: sudo apt-get install python-cheetah
  • Then I could run the easy install: sudo easy_install-2.4 turbogears
  • I edited /etc/apt/sources.list and added multiverse to the list of available packages. In other words, I changed this section:

deb http://archive.ubuntu.com/ubuntu/ feisty universe
deb-src http://archive.ubuntu.com/ubuntu/ feisty universe

to look like this:

deb http://archive.ubuntu.com/ubuntu/ feisty universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ feisty universe multiverse

  • Then I installed the python profiler package: sudo apt-get install python-profiler.
  • I tried installing pysqlite2 through easy_install, but that blew up, so I installed ubuntu package for pysqlite2 instead: sudo apt-get install python-pysqlite2.

Now everything works.