#!/bin/bash # $HeadURL$ $LastChangedRevision$ # Properties MY_ID=system_boot_net_dhcp PARENT_ID=system_boot_net MY_PRIVATE_ATTRIBUTES="uname status" MY_PUBLIC_ATTRIBUTES= MY_ATTRIBUTES="$MY_PRIVATE_ATTRIBUTES $MY_PUBLIC_ATTRIBUTES" MY_HELPER_IDS= for MY_ATTRIBUTE in ${MY_ATTRIBUTES^^}; do eval "$MY_ATTRIBUTE="; done # Defaults for the questions we ask (should only used here) # Other globals PXESERVER_IPADDR=$(host $(uname -n) 2> /dev/null | sed 's/.*has address //') DHCP_CLIENT_IPADDRS=$(echo 192.168.1.{60..69}) GATEWAY_IPADDR=192.168.1.1 # Hooks init_prologue() { inherit DB_FILE SQLITE_CMD DHCP_CLIENT_IPADDRS local DHCP_CLIENT_IPADDR CMDLINE # Create other tables debug 10 "init_prologue: creating other tables ..." $SQLITE_CMD $DB_FILE "drop table if exists dhcp_reservations;" $SQLITE_CMD $DB_FILE "create table dhcp_reservations ( ipaddr text, status text, macaddr text unique, uname text unique, primary key (ipaddr), check (status == 'available' or uname not null), check (status == 'available' or status == 'reserved'), check (status == 'available' or macaddr not null) );" debug 10 "init_prologue: preparing and running sql script to create empty DHCP reservation slots ..." { for DHCP_CLIENT_IPADDR in $DHCP_CLIENT_IPADDRS; do echo "INSERT INTO dhcp_reservations (ipaddr,status,macaddr,uname) VALUES ('$DHCP_CLIENT_IPADDR','available',NULL,NULL);" done } > /tmp/$PROGNAME.$$.init.sql $SQLITE_CMD $DB_FILE < /tmp/$PROGNAME.$$.init.sql ||{ error "failed to initialse DHCP status table" return 1 } rm -f /tmp/$PROGNAME.$$.init.sql # Thu Jun 20 11:27:20 CEST 2013 - This function used to use a duplicate variable for DNS, # DNS_DOMAIN instead of DNSCLIENT_DOMAIN. Now that it uses DNSCLIENT_DOMAIN, which is an # attribute stored in the database, which is *right now* being created, then this *init* # function cannot use that variable. Instead of reverting to the old (and confusing way) # we simply do not initialise the DHCP server here; this way it does not need to know # the DNS domain in this function. #debug 10 "init_prologue: generating (empty) dhcpd.conf ..." #compile_dhcpd_conf || return $? } create_prologue() { inherit ${MY_ATTRIBUTES^^} inherit MY_INHERITED_ATTRIBUTES ${MY_INHERITED_ATTRIBUTES^^} debug 10 "create_prologue: MY_INHERITED_ATTRIBUTES=\"$MY_INHERITED_ATTRIBUTES\", MACADDR=$MACADDR" info "creating DHCP reservations ..." reserve_dhcp_ipaddr_sql $MACADDR $UNAME || return $? # If another DHCP server answers then this won't work. warning "be sure to disable any other DHCP server!!!" return 0 } delete_epilogue() { inherit ${MY_ATTRIBUTES^^} info "deleting DHCP reservations ..." release_dhcp_ipaddr_sql $MACADDR $UNAME || return $? return 0 } list_prologue() { UNAMES=$($SQLITE_CMD $DB_FILE "select group_concat(uname,' ') from attribute_values where helper == '$MY_ID' and attribute == 'status' and value == 'installing';") debug 10 "list_prologue: the following hosts are marked installing: $UNAMES" echo "DHCP reservations" echo "=================" echo $SQLITE_CMD -column -header $DB_FILE "select ipaddr,uname,macaddr from dhcp_reservations where (status!='available');" echo } # Support functions compile_dhcpd_conf() { local DHCPSERVER_RELEASE DHCPDCONF_FILE DHCPD_OUTPUT inherit DNSCLIENT_FLAG DNSCLIENT_DOMAIN DNSCLIENT_SERVERS GATEWAY_IPADDR PXESERVER_IPADDR debug 10 "compile_dhcpd_conf: restarting DHCP server ..." get_release_by_inspection DHCPSERVER_RELEASE || return $? case $DHCPSERVER_RELEASE in lenny) DHCPDCONF_FILE=/etc/dhcp3/dhcpd.conf ;; squeeze) DHCPDCONF_FILE=/etc/dhcp/dhcpd.conf ;; wheezy) DHCPDCONF_FILE=/etc/dhcp/dhcpd.conf ;; *) internal "$DHCPSERVER_RELEASE: unhandled" ;; esac debug 10 "compile_dhcpd_conf: recreating $DHCPDCONF_FILE ..." { echo "# This file written by $PROGNAME at $(date)" if $DNSCLIENT_FLAG; then echo "option domain-name \"$DNSCLIENT_DOMAIN\";" echo "option domain-name-servers ${DNSCLIENT_SERVERS// /, };" fi echo "not authoritative;" echo "ddns-update-style none;" echo "update-static-leases on;" echo "deny unknown-clients;" echo "subnet 192.168.1.0 netmask 255.255.255.0 {" echo " group {" echo " option routers $GATEWAY_IPADDR;" echo " next-server $PXESERVER_IPADDR;" echo " filename \"pxelinux.0\";" $SQLITE_CMD -column $DB_FILE "select ' host ' || uname || ' { hardware ethernet ' || macaddr || '; fixed-address ' || ipaddr || '; } # ' || uname from dhcp_reservations WHERE (status == 'reserved');" echo " }" echo "}" } > $DHCPDCONF_FILE case $DHCPSERVER_RELEASE in lenny) CMDLINE="/etc/init.d/dhcp3-server restart" ;; squeeze) CMDLINE="service isc-dhcp-server restart" ;; wheezy) CMDLINE="service isc-dhcp-server restart" ;; *) internal "$DHCPSERVER_RELEASE: unhandled" ;; esac DHCPD_OUTPUT=$(eval "$CMDLINE" 2>&1) || { error "dhcpd: failed (output was: $DHCPD_OUTPUT)"; return 1; } return 0 } reserve_dhcp_ipaddr_sql() { local MACADDR UNAME CMDLINE UPDATE_COUNT MACADDR=$1 UNAME=$2 CMDLINE="$SQLITE_CMD $DB_FILE \"UPDATE dhcp_reservations SET status='reserved',macaddr='$MACADDR',uname='$UNAME' WHERE (rowid IN (SELECT rowid FROM dhcp_reservations where (status=='available') limit 1)); SELECT CHANGES();\"" debug 10 "reserve_dhcp_ipaddr_sql: running [$CMDLINE] ..." UPDATE_COUNT=$(eval "$CMDLINE") || internal "reserve_dhcp_ipaddr_sql: $SQLITE_CMD failed" debug 10 "reserve_dhcp_ipaddr_sql: UPDATE_COUNT=$UPDATE_COUNT" [ $UPDATE_COUNT = 1 ] || { error "failed to make DHCP reservation (is the SQL table of DHCP allocations full?)"; return 1; } compile_dhcpd_conf || return $? return 0 } release_dhcp_ipaddr_sql() { local MACADDR UNAME local CMDLINE MACADDR=$1 UNAME=$2 CMDLINE="$SQLITE_CMD $DB_FILE \"UPDATE dhcp_reservations SET status='available',macaddr=NULL,uname=NULL WHERE (uname == '$UNAME');\"" debug 10 "reserve_dhcp_ipaddr_sql: running [$CMDLINE] ..." eval "$CMDLINE" || internal "release_dhcp_ipaddr_sql: $SQLITE_CMD failed" compile_dhcpd_conf || return $? return 0 }