terom@583: #!/bin/bash terom@575: ## vim: set ft=sh : terom@575: # terom@575: # Operations on zonefiles/hosts/whatever terom@575: terom@585: function link_generic { terom@585: local out=$1 terom@585: local tgt=$2 terom@585: terom@585: if check_link $out $tgt; then terom@585: log_update "Linking $out -> $tgt..." terom@585: terom@585: do_link $out $tgt terom@585: terom@585: else terom@585: log_skip "Linking $out -> $tgt: not changed" terom@585: fi terom@585: } terom@585: terom@587: function copy_generic { terom@587: local out=$1 terom@587: local src=$2 terom@587: terom@587: if check_update $out $src; then terom@587: log_update "Copying $out <- $src..." terom@587: terom@587: do_update $out \ terom@587: cat $ROOT/$src terom@587: else terom@587: log_skip "Copying $out <- $src: not changed" terom@587: fi terom@587: } terom@585: terom@589: ## Run check-command on given file, outputting results: terom@589: # terom@589: # check_generic $src $cmd $args... terom@589: # terom@589: function check_generic { terom@589: local src=$1; shift terom@589: local cmd=$1; shift terom@589: terom@589: if cmd_test $cmd -q "$@"; then terom@589: log_skip "Check $src: OK" terom@589: terom@589: else terom@589: log_error " Check $src: Failed" terom@589: terom@589: indent " " $cmd "$@" terom@589: terom@589: exit 1 terom@589: fi terom@589: } terom@589: terom@575: ## Hosts terom@575: ## Update hosts from verbatim from input zone data: terom@575: # terom@575: # copy_hosts $ZONES/$zone $DATA/$base terom@575: # terom@575: # Writes updated zone to $zone, deps on $base. terom@575: function copy_hosts { terom@575: local zone=$1 terom@575: local base=$2 terom@575: terom@587: # XXX: filenames given directly terom@587: local out=$zone terom@587: local src=$base terom@575: terom@587: copy_generic $out $src terom@575: } terom@575: terom@575: ## Generate hosts from input zone data using $BIN/process-zone: terom@575: # terom@575: # update_hosts $ZONES/$zone $DATA/$base terom@575: # terom@575: # Writes process-zone'd data to $zone, deps on $base. terom@575: function update_hosts { terom@575: local zone=$1; shift terom@575: local base=$1; shift terom@575: terom@575: if check_update $zone $base; then terom@575: log_update "Generating hosts $zone <- $base..." terom@575: terom@575: do_update $zone \ terom@594: $BIN/process-zone $HOSTS_FILE_ARGS $ROOT/$base "$@" terom@575: else terom@575: log_skip "Generating hosts $zone <- $base: not changed" terom@575: fi terom@575: } terom@575: terom@584: ## Update .serial number: terom@584: # terom@584: # do_update_serial $serial terom@584: # terom@584: # Shows old/new serial on debug. terom@584: function do_update_serial { terom@584: local serial=$1 terom@584: terom@584: # read terom@584: local old=$(test -e $ROOT/$serial && cat $ROOT/$serial || echo '') terom@584: terom@584: terom@584: cmd $BIN/update-serial $ROOT/$serial terom@584: terom@584: # read terom@584: local new=$(cat $ROOT/$serial) terom@584: terom@584: debug " $old -> $new" terom@584: } terom@584: terom@584: terom@575: ## Generate new serial for zone using $BIN/update-serial, if the zone data has changed: terom@575: # terom@575: # update_serial $zone $deps... terom@575: # terom@575: # Supports SERIAL_FORCE/NOOP. terom@575: # Updates $SERIALS/$zone.serial. terom@575: function update_serial { terom@575: local zone=$1; shift terom@575: terom@575: local serial=$SERIALS/$zone.serial terom@575: terom@575: # test terom@575: if [ $SERIAL_FORCE ]; then terom@575: log_force "Updating $serial: forced" terom@575: terom@575: do_update_serial $serial terom@575: terom@575: elif ! check_update $serial "$@"; then terom@575: log_skip "Updating $serial: not changed" terom@575: terom@575: elif [ $SERIAL_NOOP ]; then terom@575: log_noop "Updating $serial: skipped" terom@575: terom@575: else terom@575: log_update "Updating $serial..." terom@575: terom@575: do_update_serial $serial terom@575: fi terom@575: } terom@575: terom@575: ## Link serial for zone from given base-zone: terom@575: # terom@575: # link_serial $zone $base terom@575: function link_serial { terom@575: local zone=$1 terom@575: local base=$2 terom@575: terom@585: local out=$SERIALS/$zone.serial terom@575: local tgt=$SERIALS/$base.serial terom@575: terom@585: link_generic $out $tgt terom@575: } terom@575: terom@575: ## Update zone file verbatim from source: terom@575: # terom@575: # copy_zone $view $zone [$base] terom@575: # terom@575: # Copies changed $DATA/$base zone data to $ZONES/$view/$zone. terom@575: function copy_zone { terom@575: local view=$1 terom@575: local zone=$2 terom@575: local base=${3:-$zone} terom@575: terom@575: local out=$ZONES/$view/$zone terom@575: local src=$DATA/$base terom@575: terom@587: copy_generic $out $src terom@575: } terom@575: terom@595: ## Return the first zone that exists under $DATA/$name.zone terom@595: # terom@595: # base=$(choose_zone $name...) terom@595: function choose_zone { terom@595: # look terom@595: for name in "$@"; do terom@595: if [ $name ] && [ -e $DATA/$name.zone ]; then terom@595: echo $name terom@595: return 0 terom@595: fi terom@595: done terom@595: terom@595: # failed to find terom@595: die "Unable to find zone in $DATA/*.zone: $@" terom@595: } terom@595: terom@575: ## Expand zone file from source using $BIN/expand-zone: terom@575: # terom@575: # update_zone $view $zone [$base] terom@575: # terom@595: # Updates $ZONES/$view/$zone from $DATA/$base.{zone,serial} using $BIN/expand-zone. terom@575: function update_zone { terom@575: local view=$1 terom@575: local zone=$2 terom@575: local base=${3:-$zone} terom@575: terom@595: # zones <- data+serial file terom@575: local out=$ZONES/$view/$zone terom@575: local src=$DATA/$base.zone terom@575: local serial=$SERIALS/$base.serial terom@575: terom@575: if check_update $out $src $serial; then terom@575: log_update "Generating $out <- $src..." terom@575: terom@575: do_update $out \ terom@575: $BIN/expand-zone $ROOT/$src \ terom@575: --serial $ROOT/$serial \ terom@575: --expand zones=$(abspath $ZONES) \ terom@575: --expand view=$view terom@575: else terom@575: log_skip "Generating $out <- $src: not changed" terom@575: fi terom@575: } terom@575: terom@575: ## Link zone file to ues given shared zone. terom@575: # terom@575: # link_zone $view $zone [$base] terom@575: # terom@575: # Looks for shared zone at: terom@575: # $ZONES/$view/$base terom@575: # $ZONES/common/$base terom@575: function link_zone { terom@575: local view=$1 terom@575: local zone=$2 terom@575: local base=${3:-$zone} terom@575: terom@575: local out=$ZONES/$view/$zone terom@575: local tgt=$(choose_link $out $ZONES/$view/$base $ZONES/common/$base) terom@575: terom@585: link_generic $out $tgt terom@585: } terom@575: terom@586: ## Link dhcp file directly from data to $DHCP terom@586: function link_dhcp_conf { terom@586: local conf=$1 terom@586: local base=${2:-$conf} terom@575: terom@586: local out=$DHCP/$conf.conf terom@585: local tgt=$(choose_link $out $DHCP/$base.conf $DHCP_DATA/$base.conf) terom@585: terom@585: link_generic $out $tgt terom@575: } terom@575: terom@587: ## Copy dhcp conf from data to $DHCP terom@587: function copy_dhcp_conf { terom@587: local conf=$1 terom@587: local base=${2:-$conf} terom@587: terom@587: local out=$DHCP/$conf.conf terom@587: local src=$DHCP_DATA/$base.conf terom@587: terom@587: copy_generic $out $src terom@587: } terom@587: terom@575: ## Test hosts zone for validity: terom@575: # terom@575: # check_hosts $DATA/$hosts --check-exempt ... terom@575: # terom@575: # Fails if the check fails. terom@575: function check_hosts { terom@575: local hosts=$1; shift 1 terom@575: terom@594: local cmd=($BIN/process-zone $HOSTS_FILE_ARGS $ROOT/$hosts --check-hosts "$@") terom@575: terom@575: if "${cmd[@]}" -q; then terom@575: log_skip "Check $hosts: OK" terom@575: else terom@575: log_error " Check $hosts: Failed" terom@575: terom@575: indent " " "${cmd[@]}" terom@575: terom@575: exit 1 terom@575: fi terom@575: } terom@575: terom@575: ## Test zone file for validity using named-checkzone: terom@575: # terom@575: # check_zone $view $zone $origin terom@575: # terom@575: # Uses the zonefile at $ZONES/$view/$zone, loading it with given initial $ORIGIN. terom@575: # Fails if the check fails. terom@575: function check_zone { terom@575: local view=$1 terom@575: local zone=$2 terom@575: local origin=$3 terom@575: terom@575: local src=$ZONES/$view/$zone terom@575: terom@575: local cmd=($NAMED_CHECKZONE $origin $ROOT/$src) terom@575: terom@575: # test terom@575: # XXX: checkzone is very specific about the order of arguments, -q must be first terom@575: if $NAMED_CHECKZONE -q $origin $ROOT/$src; then terom@575: log_skip "Check $src ($origin): OK" terom@575: else terom@575: log_error " Check $src ($origin): Failed:" terom@575: terom@575: indent " " "${cmd[@]}" terom@575: terom@575: exit 1 terom@575: fi terom@575: } terom@575: terom@585: ## Test DHCP configuration for validity using dhcpd -t: terom@585: # terom@585: # check_dhcp [$conf] terom@585: # terom@585: # Defaults to the global $DHCPD_CONF. terom@585: # Fails if the check fails. terom@585: function check_dhcp { terom@585: local conf=${1:-$DHCPD_CONF} terom@585: terom@591: if [ ! -e $DHCPD ]; then terom@591: log_warn "check_dhcp: dhcpd not installed, skipping: $conf" terom@591: return 0 terom@591: fi terom@591: terom@589: check_generic $conf \ terom@589: $DHCPD -cf $conf -t terom@585: } terom@585: terom@586: ## Test DHCP configuration of given settings/dhcp using check_dhcp $DHCP_DATA/$host.conf: terom@585: # terom@586: # check_dhcp_conf $conf terom@586: # terom@586: function check_dhcp_conf { terom@589: local conf=$1; terom@585: terom@586: check_dhcp $DHCP_DATA/$conf.conf terom@585: } terom@585: terom@589: ## Test DHCP hosts source configuration for invalid fixed-address stanzas: terom@589: # terom@589: # check_dhcp_hosts $hosts_conf terom@589: # terom@589: function check_dhcp_hosts { terom@589: local hosts=$1 terom@589: terom@589: # XXX: still too unclear terom@589: local src=$hosts #$DHCP_DATA/$hosts.conf terom@589: terom@589: # set in do_reload_zones below terom@589: if [ $RELOAD_ZONES ]; then terom@589: check_generic $src \ terom@589: $BIN/check-dhcp-hosts $DHCP_FILE_ARGS $ROOT/$src terom@589: else terom@589: log_noop "Check $src: skipped; did not reload DNS zones" terom@589: fi terom@589: } terom@589: terom@582: # Run rndc reload terom@589: function do_reload_zones { terom@582: # run terom@582: indent " rndc: " \ terom@582: $RNDC reload terom@589: terom@589: # set flag terom@589: RELOAD_ZONES=y terom@582: } terom@582: terom@575: ## Load update zonefiles into bind: terom@575: # terom@584: # reload_zones terom@575: # terom@575: # Invokes `rndc reload`, showing its output. terom@584: function reload_zones { terom@575: local msg="Reload zones" terom@575: terom@584: if [ $RELOAD_FORCE ]; then terom@582: log_force "$msg..." terom@582: terom@589: do_reload_zones terom@582: terom@584: elif [ $RELOAD_NOOP ]; then terom@582: log_noop "$msg: skipped" terom@575: terom@591: elif [ ! -e $RNDC ]; then terom@591: log_warn "reload_zones: rndc not installed, skipping" terom@591: terom@591: elif [ ! -e $RNDC_KEY ]; then terom@591: log_warn " $msg: rndc: key not found: $RNDC_KEY" terom@591: terom@575: elif [ ! -r $RNDC_KEY ]; then terom@575: log_error " $msg: rndc: permission denied: $RNDC_KEY" terom@575: terom@582: return 1 terom@582: terom@575: else terom@575: log_update "$msg..." terom@575: terom@575: # run terom@589: do_reload_zones terom@589: fi terom@589: } terom@589: terom@589: ## Reload DHCP by restarting it, if running: terom@589: # terom@589: # do_reload_dhcp terom@589: # terom@589: # Does NOT restart dhcp if it is not running (status). terom@589: function do_reload_dhcp { terom@589: if cmd_test $DHCPD_INIT status >/dev/null; then terom@589: cmd $DHCPD_INIT restart terom@589: else terom@589: log_warn "dhcpd not running; did not restart" terom@589: fi terom@589: } terom@589: terom@589: ## Reload dhcp hosts terom@589: # terom@589: # reload_dhcp terom@589: # terom@589: # noop's if we haven't reloaded zones terom@589: function reload_dhcp { terom@589: local msg="Reload DHCP hosts" terom@589: terom@589: if [ $RELOAD_FORCE ]; then terom@589: log_force "$msg..." terom@589: terom@589: do_reload_dhcp terom@589: terom@589: elif [ $RELOAD_NOOP ]; then terom@589: log_noop "$msg: skipped" terom@591: terom@591: elif [ ! -e $DHCPD ]; then terom@591: log_warn "reload_dhcp: dhcpd not installed, skipping: $conf" terom@591: terom@589: else terom@589: log_update "$msg..." terom@589: terom@589: # run terom@589: do_reload_dhcp terom@575: fi terom@575: } terom@584: terom@584: ## Perform `hg commit` for $DATA terom@584: function do_commit { terom@584: local msg=$1 terom@584: terom@584: [ $LOG_DIFF ] && indent " " hg_diff terom@584: terom@584: hg_commit "$msg" terom@584: } terom@584: terom@584: terom@575: ## Commit changes in $DATA to version control: terom@575: # terom@575: # commit_data terom@575: # terom@575: # Invokes `hg commit` in the $REPO, first showing the diff. terom@575: function commit_data { terom@575: local repo=$REPO terom@575: local commit_msg="$COMMIT_MSG" terom@575: terom@575: local msg="Commit changes in $repo" terom@575: terom@575: # operate? terom@575: if [ $COMMIT_FORCE ]; then terom@575: log_force "$msg..." terom@575: terom@575: do_commit "$commit_msg" terom@575: terom@575: elif ! hg_modified; then terom@575: log_skip "$msg: no changes" terom@575: terom@575: elif [ $COMMIT_SKIP ]; then terom@575: log_noop "$msg: skipped" terom@580: terom@580: # still show diff, though terom@580: [ $LOG_DIFF ] && indent " " hg_diff terom@575: else terom@575: log_update "$msg..." terom@575: terom@575: do_commit "$commit_msg" terom@575: fi terom@575: } terom@575: