Qpid on CentOS 5

Build using Fedora

  1. Install the RPM development tools
    sudo yum install rpmdevtools mock
  2. Add yourself to the mock group
    sudo /usr/sbin/usermod --groups mock --append $USER
  3. Setup build directories
    rpmdev-setuptree
  4. Install spec and source files (or get latest here)
    rpm -i ftp://ftp.redhat.com/pub/redhat/linux/enterprise/5Server/en/RHEMRG/SRPMS/qpidc-0.5.752581-17.el5.src.rpm
    rpm -i ftp://ftp.redhat.com/pub/redhat/linux/enterprise/5Server/en/RHEMRG/SRPMS/amqp-1.0.750054-1.el5.src.rpm
    rpm -i ftp://ftp.redhat.com/pub/redhat/linux/enterprise/5Server/en/RHEMRG/SRPMS/python-qpid-0.5.752581-3.el5.src.rpm
  5. Build qpidc
    rpmbuild -bs --nodeps ~/rpmbuild/SRPM/qpidc.spec
    mock -vr epel-5-x86_64 ~/rpmbuild/SRPMS/qpidc-*.src.rpm
    scp /var/lib/mock/epel-5-x86_64/result/*.rpm CENTOS_HOST:SOME_PATH
  6. Build amqp
    rpmbuild -bs --nodeps ~/rpmbuild/SPECS/amqp.spec
    mock -vr epel-5-x86_64 ~/rpmbuild/SRPMS/amqp-*.src.rpm
    scp /var/lib/mock/epel-5-x86_64/result/*.rpm CENTOS_HOST:SOME_PATH
  7. Build python-qpid
    rpmbuild -bs --nodeps ~/rpmbuild/SPECS/python-qpid.spec
    mock -vr epel-5-x86_64 ~/rpmbuild/SRPMS/python-qpid-*.src.rpm
    scp /var/lib/mock/epel-5-x86_64/result/*.rpm CENTOS_HOST:SOME_PATH

Install on CentOS

  1. Become root
    sudo su -
  2. Install Qpid server and Python client packages
    cd SOME_PATH
    yum localinstall --nogpgcheck qpidc-*.el5.x86_64.rpm qpidd-*.el5.x86_64.rpm amqp-*.el5.noarch.rpm python-qpid-*.el5.noarch.rpm
  3. Disable auth for testing
    echo 'auth=no' >> /etc/qpidd.conf
  4. Start qpidd
    service qpidd start
  5. Test using these instructions.

NOTE: I realize you can build the SRPMs without installing them.

Pipe Apache (or any) Logs to Scribe

I created a simple Python script called scribe_log to tail a log file and pipe it to Scribe.

I use Supervisor to start and keep the pipe running.

Relevant supervisord.conf configuration:

[program:scribe.apache.access]
command=/usr/local/sbin/scribe_log --category apache.access --file /var/log/httpd/access_log

Options

usage: scribe_log [options]

options:
  -h, --help           show this help message and exit
  --file=FILE          file to tail into Scribe
  --category=CATEGORY  Scribe category
  --host=HOST          destination Scribe host server
  --port=PORT          destination Scribe port
  --prefix=PREFIX      add to the beginning of each log line
  --postfix=POSTFIX    add to the end of each log line

Scribe – Scalable Real Time Log Aggregation for CentOS 5 / RHEL 5

Scribe is a server for aggregating log data streamed in real time from a large number of servers. It is designed to be scalable, extensible without client-side modification, and robust to failure of the network or any specific machine. Scribe was developed at Facebook and released as open source.”

I’ve packaged Thrift, fb303 and Scribe for CentOS 5 / RHEL 5.

SRPM

Scribe depends on fb303 which in turns depends on Thrift so you’ll need to setup a local repository and build them in that order. To build the above packages for Fedora 9+ you’ll need to tweak the Python sub-packages to include the egg files.

Both fb303 and Scribe need some tweaks upstream before they’re suitable for a package review, but I’d like to get them in Fedora shortly (I’ve already submitted Thrift).

If you’d like to hack around with my latest Fedora specs you can grab them here.

Managing Large Networks with Puppet

Puppet is an open source configuration management tool written in Ruby. It allows a systems administrator to define how a system should be configured using Puppet’s declarative language. Each Puppet client pulls its catalog at a regular interval and figures out how to make the catalog definitions true for the local operating system.

The Puppet Introduction uses the following diagram to show how Puppet works.

Puppet

Currently Puppet is most useful when you have lots of nodes with similar setups. Unfortunately Puppet’s declarative language is a bit weak when it comes to inheritance and users familiar with true object oriented systems will soon become frustrated (at least I did). I’m assuming this issue will be addressed in the future, but for now I’m going to tell you how I setup a 100+ node system while adhering to DRY principles.

A quick note, I’m assuming you already know how to use Puppet.

First lets start with the Puppetmaster configuration layout:

puppet/
 - fileserver.conf
 - manifests/
   - classes/
     - initialize.pp
   - nodes/
     - net/
       - example/
         - web01.pp   # web01.example.net
   - site.pp
   - templates.pp
 - modules/           # application specific modules
   - httpd/
     - files/         # static assets (ex: default HTML file)
     - manifests/     # application configuration logic
     - templates/     # dynamic configuration files (ex: httpd.conf)

The layout was adapted from recommendations in Pulling Strings with Puppet by James Turnbull.

When I was initially designing my Puppet setup the common practice was to define and initialize the various Puppet types and classes throughout the inheritance tree. So if you had a generic resolv.conf configuration you would include it at the top of the inheritance tree. This worked great until I needed to change one attribute of a class further down. I initially tackled this problem by hacking in if/case statements, but eventually it became unmanageable.

After a couple of rewrites I came up with the idea of wrapping the internals of each class in a conditional statement and initializing all classes at the end of each node.

The key components of my setup were:

  • import all modules in the site.pp manifest
  • wrap the code of each class in a conditional statement
  • define and extend attributes throughout the inheritance tree (including the class conditional)
  • include all classes at the end of each node

This lets you both arbitrarily redefine or extend class attributes (including the on/off state) throughout the inheritance tree.

I’ve created a simple example to show how this setup works. The main files are listed below (you’ll want to go through each in order):

Also note that I designed this setup about 8 months ago and I haven’t kept as up-to-date on recent developments as I should. If there is a better way to do this please let me know.

funcshell — A Shell Interface to Func

funcshell is a shell interface to Func which provides some useful features for managing a large number of machines.

Features

  • advanced client selection (you can use + and – to add/remove hosts/groups)
  • tab completion
  • persistent history
  • a command sub-shell
  • quick help (just hit the “?” key)

funcshell took a similar approach to features as Func; it allows developers to easily extend and customize its functionality using a plugin system. It also assumes the most useful commands will be the ones you write yourself. That being said, funcshell currently comes with both the command and service module.

Here are some things you can do with funcshell.

Get a list of all clients (not very useful if you have hundreds):

funcshell> set clients *
funcshell> get clients
webapp001.example.net
webapp002.example.net
webapp003.example.net
webstatic001.example.net
webstatic002.example.net

Assuming webapp00[1-3].example.net are in the app and bpstatic00[1-2].example.net are in the static groups; remove some clients and restart a service:

funcshell> set clients - @static;webapp001*
funcshell> get clients
webapp002.example.net
webapp003.example.net
funcshell> service httpd restart
==> webapp003.example.net <==
True
==> webapp002.example.net <==
True

Run a command and get the results:

funcshell> set clients - webapp003*
funcshell> set clients + webstatic002*
funcshell> command run grep MemTotal /proc/meminfo | awk '{ print $2/1024 }'
==> webstatic002.example.net :: 0 <==
4099.44
==> webapp002.example.net :: 0 <==
8198.88

Get help:

funcshell> command <TAB><TAB>
exists   run      shell
funcshell> command ?
  exists Check if a command exists
  run    Run a command
  shell  Run a command shell

Run a couple of commands in a row:

funcshell> set c<TAB> @static
funcshell> command shell
> du -sh /tmp
==> webstatic002.example.net :: 0 <==
7.2M    /tmp
==> webstatic001.example.net :: 0 <==
3.4M    /tmp
> cp -r /tmp /tmp
==> webstatic002.example.net :: 1 <==
cp: cannot copy a directory, `/tmp', into itself, `/tmp/tmp'
==> webstatic001.example.net :: 1 <==
cp: cannot copy a directory, `/tmp', into itself, `/tmp/tmp'
> asdf
==> webstatic002.example.net :: 127 <==
/bin/sh: asdf: command not found
==> webstatic001.example.net :: 127 <==
/bin/sh: asdf: command not found
> <CTRL-D>
funcshell> exit

String Slicing in Bash (like Python)

A simple function to slice strings in Bash similar to Python’s string slicing functionality.

Examples

[silas@pluto ~]$ string_slice "12345" 0 1
1
[silas@pluto ~]$ string_slice "12345" 0 3
123
[silas@pluto ~]$ string_slice "12345" 2 3
3
[silas@pluto ~]$ string_slice "12345" 2 -2
3
[silas@pluto ~]$ string_slice "12345" -3
345

Implementation

function string_slice {
  STRING="$1"
  declare -i LENGTH="${#STRING}"
  declare -i START="$2"
  declare -i END="$3"
  if [ $START -lt 0 ]; then
    START=$[ $LENGTH + $START ]
  fi
  if [ $END -le 0 ]; then
    END=$[ $LENGTH + $END ]
  fi
  START=$[ $START + 1 ]
  (echo "$STRING" | cut -c $START-$END) 2> /dev/null
}

python-tokyotyrant (pytyrant) RPM

I’ve packaged pytyrant–a pure python client implementation of the Tokyo Tyrant protocol–as an RPM.

python-tokyocabinet (pytc) RPM

I’ve packaged pyrc–Python bindings for Tokyo Cabinet–as an RPM.

Profile Management with Git and GitHub

The following describes a simple way to manage you profile configuration files using GitHub.

Features

  • Centralized configuration management
  • Files live in their native locations (no symbolic linking)
  • Home directory is not a Git repository
  • All the power of git with a simple alias

Setup Repository

  1. Log into GitHub and create a repository named config
  2. Add your public keys to GitHub (if you haven’t done so already)
  3. Open a terminal and switch to your home directory
    cd ~
  4. Create a configuration directory
    mkdir .config.git
  5. Add the following alias to your current session and your .bash_profile
    alias config='git --git-dir=$HOME/.config.git/ --work-tree=$HOME'
    echo "alias config='git --git-dir=$HOME/.config.git/ --work-tree=$HOME'" >> .bash_profile
  6. Add your .bash_profile to the configuration repository
    config add .bash_profile
  7. Commit the changes
    config commit -m 'Initial commit'
  8. Change the origin to GitHub
    config remote add origin git@github.com:GITHUB_USERNAME/config.git
  9. Push the changes
    config push origin master

If you get an error when running config pull to the effect of You asked me to pull without... run the follow:

echo -e '[branch "master"]\n  remote = origin\n  merge = refs/heads/master' >> ~/.config.git/config

Setup Configuration Management on a Different System

  1. Add your public keys to GitHub (if you haven’t done so already)
  2. Switch to your home directory
    cd ~
  3. Backup your local configuration files, example:
    mv .bash_profile .bash_profile.bk
  4. Clone your configuration repository
    git clone git@github.com:GITHUB_USERNAME/config.git config.git
  5. Move the git metadata to ~/.config.git
    mv config.git/.git .config.git
  6. Enable dotglob
    shopt -s dotglob
  7. Move your configuration files to your home directory
    mv -i config.git/* .
  8. Delete the config.git directory
    rmdir config.git
  9. Logout and log back in

Basic Usage

  • config pull – get latest configuration changes
  • config add FILENAME – add a configuration file
  • config commit -a – save all configuration changes
  • config push – push configuration changes to GitHub
  • and any other config GIT_OPTION

You can see my configuration repository at http://github.com/silas/config.

Source: Manage your $HOME with git by Robert Escriva

Updated Fabric RPM to 0.1.0

I’ve updated the Fabric RPM to version 0.1.0 which was released on February 17, 2009.