NerdVana

Beware of computer programmers that carry screwdrivers.

File distribution via udpcast

Written by Eric Schwimmer

Okay, lets push a bunch of files to remote servers. But let's just do it once to reduce bandwidth contention/consumption. None of this BitTorrent crap. You'll either need a flat network (i.e. a single broadcast domain) or multicast routing set up, and you'll need DSH from the ClusterIt tools package. And udpcast of course :)

#!/bin/bash

fatal() {
    echo FATAL: $1
    shift
    for f in "$@"; do cat $f; done
    cleanup
    exit 1
}

cleanup() {
    exit
    [[ -n $DSH_PID ]] && kill -9 $DSH_PID
    rm -f $CLIENT_OUT_FILE $SERVER_OUT_FILE $TAR_OUT_FILE
}

usage() {
    echo "Usage: sendfile_udpcast <comma-delimited host list> " \
        "<comma-delimited local file list> <remote directory>"
    exit 1
}

client() {
    LOCAL_DIR=$1
    BASE_PORT=$2
    UDP_RCV=$(which udp-receiver) || UDP_RCV=/sbin/udp-receiver
    [[ -e $UDP_RCV ]] || fatal "udp-sender binary missing or not executable."
    udp-receiver --portbase $BASE_PORT --nokbd --start-timeout 15 \
        --receive-timeout 5 | tar x -C $LOCAL_DIR || echo ERROR
    exit 0
}

# Check to see if we are running in client mode
[[ $1 == "client" ]] && client $2 $3 

# Make sure that we receive the correct # of arguments
[[ $# == 3 ]] || usage

# Verify our DSH binary
DSH_BIN=$(which dsh) || DSH_BIN=/usr/bin/dsh
[[ -e $DSH_BIN ]] || fatal "DSH binary missing or not executable."
UDP_SND=$(which udp-sender) || UDP_SND=/sbin/udp-sender
[[ -e $UDP_SND ]] || fatal "udp-sender binary missing or not executable."

# Set our globals
HOST_LIST=$1
FILE_LIST=${2//,/ }
REMOTE_DIR=$3

FILE_ROOT=/tmp/$(basename $0).$$
CLIENT_OUT_FILE=${FILE_ROOT}.client
TAR_OUT_FILE=${FILE_ROOT}.tar
SERVER_OUT_FILE=${FILE_ROOT}.server
BASE_PORT=$(( ( RANDOM + RANDOM ) % 64510 + 1024 ))

# Silence STDERR.  We'll output error messages as required
exec 2> /dev/null

# Fire off our udp-receivers
echo -n "Starting receivers... "
$DSH_BIN -t -e -w $HOST_LIST -s $0 client $REMOTE_DIR $BASE_PORT &> \
    $CLIENT_OUT_FILE && echo COMPLETED >> $CLIENT_OUT_FILE &
DSH_PID=$!

# Sleep to sanity check udp-receiver startup
sleep 2
grep -q ERROR $CLIENT_OUT_FILE || ! kill -0 $DSH_PID && \
    fatal "Unable to start udp receivers!" $CLIENT_OUT_FILE

# Now start that sweet, sweet udp-sender
echo -n "starting file copy... "
(tar c $FILE_LIST 2> $TAR_OUT_FILE || echo ERROR >> $TAR_OUT_FILE) | \
    $UDP_SND --portbase $BASE_PORT --nokbd --max-wait 1 &> $SERVER_OUT_FILE || \
    echo ERROR >> $SERVER_OUT_FILE

grep -q ERROR $TAR_OUT_FILE $SERVER_OUT_FILE && \
    fatal "Unable to start udp sender!" $TAR_OUT_FILE $SERVER_OUT_FILE

# Sleep a bit to ensure that things are cleaned up
sleep 1
grep -q ERROR $CLIENT_OUT_FILE || ! grep -q COMPLETED $CLIENT_OUT_FILE || 
    kill -0 $DSH_PID && \
    fatal "UDP receiver did not finish cleanly!" $CLIENT_OUT_FILE

echo "finished successfully!"
cleanup


comments powered by Disqus