Friday, May 13, 2011

Fabric and Pageant

Here's an example of using Fabric with Pageant, the ssh key agent that comes with PuTTY.

We're using ssh keys in PuTTY (.ppk) format, not in OpenSSH format.

It's a long example, but the work of connecting to Pageant happens in the _start_pageant_and_store_key function.


# Regular Python imports
#
# Note: In the fabfile, don't do regular python imports like this
#
#from urllib import urlopen
#
# rather do them like this
#
#import urllib
#
# Any functions imported into this fabfile will be regarded as possible fabric
# tasks (in the example above, urlopen will show up when the user runs 'fab
# --list'), so instead of importing specific functions from modules, just import
# the whole module.
# http://docs.fabfile.org/en/1.0.1/usage/execution.html#imports
import os.path
import subprocess

# Import Fabric
from fabric.api import env
from fabric.api import run
from fabric.api import sudo

# To run the tasks defined in this file, use the 'fab' command line tool.
# cd \path\to\fabfile.py
# fab dev|prod task1 [task2]
#
# Note that you must specify dev or prod first, to set up the right server
# connection configuration.

# Constants
KEY_DIR = r'\path\to\keys'
PUTTY_DIR = r'C:\Program Files\PuTTY'

# These functions become tasks that can be executed from the command line using
# the 'fab' tool.
# Note: I couldn't find a more elegant way of specifying different connection
# parameters (such as key_filename) for each host, so I just made a 'dev' task
# and a 'prod' task.
def dev():
"""
Set up for connection to the dev server
"""
# Once DNS is set up for these hosts, I can use hostname instead of ip address
env.user = 'admin_user'
env.hosts = ['dev_server']
_start_pageant_and_store_key('key2.ppk')

def prod():
"""
Set up for connection to the prod server
"""
env.user = 'admin_user'
env.hosts = ['prod_server']
_start_pageant_and_store_key('key1.ppk')

def install_all_all():
"""
Install everything to all servers
"""
dev()
install_all_dev()
prod()
install_all_prod()

def install_all():
"""
Does all the installation.
"""
ps()
add_group('admins')
# Note: put actual installation steps here.


# These utility functions are the building blocks of the install process. The
# can also be called individually on the command line, using the 'fab' tool, and
# specifying the target host and values for the arguments.
def ps():
"""
Prints a process listing
"""
run('ps -ef')

def add_group(group_name):
"""
Adds a linux user group.
"""
# --force This option causes the command to simply exit with success
# status if the specified group already exists.
return sudo('groupadd --force %s' % group_name)


# These private python functions do not get exposed on the command line via the
# 'fab' tool. They will not show up when the user runs 'fab --list'
def _start_pageant_and_store_key(keyfile_name):
"""
Starts the Pageant key agent, and loads the private key in to it, prompting
for the passphrase if needed. Also sets the Fabric env.keyfile_name
property.
"""
keyfile_path = os.path.join(KEY_DIR, keyfile_name)

# Start pageant. Note that this works with the PuTTY key format (*.ppk), not
# the OpenSSH format.
path_to_pageant = os.path.join(PUTTY_DIR, 'pageant.exe')
result = subprocess.call([path_to_pageant, keyfile_path])
if result > 0:
raise OSError, "Bad result %s" % result

# Store the path to the key file in fabric's global env dictionary
env.key_filename = keyfile_path


Thanks to Luka Marinko for his instructions for setting up syntax highlighting on Blogger.

Wednesday, May 11, 2011

Monday, May 9, 2011

Line continuations and && in DOS

Notes to myself:

  • && works in DOS too (only do step 2 if step 1 succeeded)

  • Use ^ for line continuation

  • Use %ERRORLEVEL%, labels, and goto, for some primitive flow control.


Here's an example


@echo off

set basedir=Z:\path\to\dir


cd %basedir% && ^
hg fetch -R .\MRA && ^
hg fetch -R ".\Super common" && ^
hg fetch -R .\ServerKpf

goto answer%ERRORLEVEL%
:answer0
echo hg fetch complete
komodo "%basedir%\ServerKpf\dev_util_nds_dev.kpf"
goto end
:answer1
echo Program had return code 1
pause
goto end
:end


References
Multiple Commands in Single Line
DOS IF command