update: cleanup, docs
authorTero Marttila <terom@paivola.fi>
Tue, 20 Mar 2012 13:38:12 +0200
changeset 567 8f49e2f51c0d
parent 566 b2ac0fd85828
child 568 3d6bf3864d8a
update: cleanup, docs
bin/update
--- a/bin/update	Tue Mar 20 12:55:31 2012 +0200
+++ b/bin/update	Tue Mar 20 13:38:12 2012 +0200
@@ -3,6 +3,8 @@
 
 set -ue
 
+
+### Paths
 ROOT=$(pwd)
 
 # resolve $0
@@ -17,30 +19,29 @@
     fi
 done
 
-# bin dir
+# Our bin dir, with scripts
 BIN=$(dirname $self)
 
-# data files
+# Data files
 DATA=settings
 ZONES=zones
 SERIALS=$DATA
 REPO=
 
-# data args
+# Script/data args
 PROCESS_ARGS='--input-charset latin-1'
 
-FORWARD_MX=mail
-REVERSE_ZONE=194.197.235
-REVERSE_DOMAIN=paivola.fi
-
 # external progs
 NAMED_CHECKZONE=/usr/sbin/named-checkzone
 HG=/usr/bin/hg
 RNDC=/usr/sbin/rndc
 
-## options
+### Command-line argument handling
+
 IS_TTY=
 
+## Options
+LOG_ERROR=y
 LOG_WARN=y
 LOG=y
 LOG_FORCE=y
@@ -63,6 +64,7 @@
 
 DEPLOY_SKIP=
 
+## Output command-line argument help.
 function help_args {
     local prog=$1
 
@@ -93,6 +95,7 @@
 END
 }
 
+## Parse any command-line arguments, setting the global options vars.
 function parse_args {
     OPTIND=1
 
@@ -146,11 +149,13 @@
     done
 }
 
-## lib
+### Logging
+# Output message to stderr.
 function log_msg {
     echo "$*" >&2
 }
 
+# Output message to stderr, optionally with given color, if TTY.
 function log_color {
     local code=$1; shift
 
@@ -161,14 +166,17 @@
     fi
 }
 
+## Log at various log-levels
+
 function log_error {
-    log_color '31' "$*"
+    [ $LOG_ERROR ] && log_color '31' "$*"
 }
 
 function log_warn {
     [ $LOG_WARN ] && log_color '33' "$*" || true
 }
 
+# plain
 function log {
     [ $LOG ] && log_msg "$*" || true
 }
@@ -197,7 +205,7 @@
     [ $LOG_CMD ] && log_color 35 "        \$ $*" || true
 }
 
-# XXX: broken
+# Output stacktrace, broken.
 function log_stack {
     local level=1
 
@@ -210,27 +218,38 @@
     done
 }
 
+# Output calling function's name.
 function func_caller {
     caller 1 | cut -d ' ' -f 2
 }
 
+### High-level logging output
+# Log with func_caller at log_debug
 function debug {
     printf -v prefix "%s" $(func_caller)
 
     log_debug "$prefix: $*"
 }
 
+# Log with func_caller at log_error and exit, intended for internal errors...
 function fail {
     log_error "$(func_caller): $*"
 
     exit 2
 }
 
+# Log at log_error and exit
 function die {
     log_error "$*"
     exit 1
 }
 
+### Command execution
+## Execute command, possibly logging its execution.
+#
+#   cmd     $cmd...
+#
+# Fails if the command returns an error exit code.
 function cmd {
     log_cmd "$@"
 
@@ -247,6 +266,9 @@
     return ${PIPESTATUS[0]}
 }
 
+
+### FS utils
+# Create dir in $ROOT if not exists.
 function ensure_dir {
     local dir=$1
 
@@ -256,21 +278,30 @@
     fi
 }
 
+## Output absolute path from $ROOT:
+#
+#   abspath $path
+#
 function abspath () {
-    echo "$ROOT/$1"
+    local path=$1
+
+    echo "$ROOT/$path"
 }
 
-## hg
+### HG wrappers
+# Run `hg ...` within $REPO.
 function hg {
     local repo=$REPO; shift
 
     cmd $HG -R $ROOT/$repo "$@"
 }
 
+# Does the repo have local modifications?
 function hg_modified {
     hg id | grep -q '+'
 }
 
+# Output possible -u flag for commit.
 function hg_user {
     if [ ${SUDO_USER:-} ]; then
         echo '-u' "$SUDO_USER"
@@ -284,12 +315,17 @@
     fi
 }
 
+# Show changes in repo
 function hg_diff {
     hg diff
 }
 
+## Commit changes in repo, with given message:
+#
+#   hg_commit   $msg
+#
 function hg_commit {
-    local msg=$2
+    local msg=$1
     local user_opt=$(hg_user)
     
     debug "$user_opt: $msg"
@@ -297,17 +333,18 @@
 }
 
 
-## functions
+### Dependency-based updates
 
-## Dependency-based updates
-# Compare the given output file with all given source files.
+## Compare the given output file with all given source files:
+#
+#   check_update $out ${deps[@]} && do_update $out ... || ...
 #
 # Returns true if the output file needs to be updated.
 function check_update {
     # target
-    local dst=$1; shift
+    local out=$1; shift
 
-    debug "$dst"
+    debug "$out"
 
     # need update?
     local update=
@@ -316,7 +353,7 @@
         debug "  update: unknown deps"
         update=y
 
-    elif [ ! -e $dst ]; then
+    elif [ ! -e $out ]; then
         debug "  update: dest missing"
         update=y
         
@@ -334,7 +371,7 @@
         if [ ! -e $ROOT/$dep ]; then
             fail "$dst: Missing source: $dep"
 
-        elif [ $ROOT/$dst -ot $ROOT/$dep ]; then
+        elif [ $ROOT/$out -ot $ROOT/$dep ]; then
             debug "  update: $dep"
             update=y
         else
@@ -348,21 +385,28 @@
     [ $update ]
 }
 
+## Generate updated output file from given command's stdout:
+#
+#   do_update $out $BIN/cmd --args
+#
+# Writes output to a temporary .new file, optionally shows a diff of changes, and commits
+# the new version to $out (unless noop'd).
 function do_update {
-    local dst=$1; shift
-    local tmp=$dst.new
+    local out=$1; shift
+    local tmp=$out.new
 
-    debug "$dst"
+    debug "$out"
     cmd "$@" > $ROOT/$tmp
 
     # compare
-    if [ -e $ROOT/$dst ] && [ $UPDATE_DIFF ]; then
+    if [ -e $ROOT/$out ] && [ $UPDATE_DIFF ]; then
         debug "  changes:"
 
         # terse
-        indent "        " diff --unified=1 $ROOT/$dst $ROOT/$tmp || true
+        indent "        " diff --unified=1 $ROOT/$out $ROOT/$tmp || true
     fi
     
+    # deploy
     if [ $UPDATE_NOOP ]; then
         # cleanup
         debug "  no-op"
@@ -370,20 +414,49 @@
         cmd rm $ROOT/$tmp
     else
         # commit
-        debug "  commit"
+        debug "  deploy"
 
-        cmd mv $ROOT/$tmp $ROOT/$dst
+        cmd mv $ROOT/$tmp $ROOT/$out
     fi
 }
 
-# links
+## Look for a link target:
+#
+#   find_link   $lnk    $tgt...
+#
+# Outputs the first given target to exist, skipping any that are the same as the given $lnk.
+# If no $tgt matches, outputs the last one, or '-'.
+function choose_link {
+    local lnk=$1; shift
+    local tgt=-
+
+    for tgt in "$@"; do
+        [ $tgt != $out ] && [ -e $ROOT/$tgt ] && break
+    done
+    
+    echo $tgt
+}
+
+
+## Compare symlink to target:
+#
+#   check_link $lnk $tgt && do_link $lnk $tgt || ...
+#
+# Tests if the symlink exists, and the target matches.
+# Fails if the target does not exist.
 function check_link {
     local lnk=$1
     local tgt=$2
+
+    [ ! -e $ROOT/$tgt ] && fail "$tgt: target does not exist"
     
     [ ! -e $ROOT/$lnk ] || [ $(readlink $ROOT/$lnk) != $ROOT/$tgt ]
 }
 
+## Update symlink to point to target:
+#
+#   do_link $lnk $tgt
+#
 function do_link {
     local lnk=$1
     local tgt=$2
@@ -391,39 +464,11 @@
     cmd ln -sf $ROOT/$tgt $ROOT/$lnk
 }
 
-## hosts
-# copy hosts input zone verbatim
-function copy_hosts {
-    local zone=$1
-    local base=$2
-
-    if check_update $zone $base; then
-        log_update "Copying hosts $zone <- $base..."
-
-        do_update $zone \
-            cat $ROOT/$base
-    else
-        log_skip "Copying hosts $zone <- $base: not changed"
-    fi
-}
-
-# generate hosts zone from input zone
-function update_hosts {
-    local zone=$1; shift
-    local base=$1; shift
-
-    if check_update $zone $base; then
-        log_update "Generating hosts $zone <- $base..."
-
-        do_update $zone \
-            $BIN/process-zone $PROCESS_ARGS $ROOT/$base "$@"
-    else
-        log_skip "Generating hosts $zone <- $base: not changed"
-    fi
-}
-
-## actions
-# serial
+## Update .serial number:
+#
+#   do_update_serial $serial
+#
+# Shows old/new serial on debug.
 function do_update_serial {
     local serial=$1
 
@@ -439,6 +484,60 @@
     debug "  $old -> $new"
 }
 
+## Perform `hg commit` for $DATA
+function do_commit {
+    local msg=$1
+
+    indent "    " hg_diff
+
+    hg_commit "$msg"
+}
+
+### Hosts
+## Update hosts from verbatim from input zone data:
+#
+#   copy_hosts      $ZONES/$zone    $DATA/$base
+#
+# Writes updated zone to $zone, deps on $base.
+function copy_hosts {
+    local zone=$1
+    local base=$2
+
+    if check_update $zone $base; then
+        log_update "Copying hosts $zone <- $base..."
+
+        do_update $zone \
+            cat $ROOT/$base
+    else
+        log_skip "Copying hosts $zone <- $base: not changed"
+    fi
+}
+
+## Generate hosts from input zone data using $BIN/process-zone:
+#
+#   update_hosts    $ZONES/$zone    $DATA/$base
+#
+# Writes process-zone'd data to $zone, deps on $base.
+function update_hosts {
+    local zone=$1; shift
+    local base=$1; shift
+
+    if check_update $zone $base; then
+        log_update "Generating hosts $zone <- $base..."
+
+        do_update $zone \
+            $BIN/process-zone $PROCESS_ARGS $ROOT/$base "$@"
+    else
+        log_skip "Generating hosts $zone <- $base: not changed"
+    fi
+}
+
+## Generate new serial for zone using $BIN/update-serial, if the zone data has changed:
+#
+#   update_serial   $zone   $deps...
+#
+# Supports SERIAL_FORCE/NOOP.
+# Updates $SERIALS/$zone.serial.
 function update_serial {
     local zone=$1; shift
     
@@ -463,6 +562,9 @@
     fi
 }
 
+## Link serial for zone from given base-zone:
+#
+#   link_serial $zone $base
 function link_serial {
     local zone=$1
     local base=$2
@@ -480,7 +582,11 @@
     fi
 }
 
-# zone
+## Update zone file verbatim from source:
+#
+#   copy_zone   $view   $zone   [$base]
+#
+# Copies changed $DATA/$base zone data to $ZONES/$view/$zone.
 function copy_zone {
     local view=$1
     local zone=$2
@@ -499,6 +605,11 @@
     fi
 }
 
+## Expand zone file from source using $BIN/expand-zone:
+#
+#   update_zone $view   $zone   [$base]
+#
+# Processed $DATA/$base zone data through $BIN/expand-zone, writing output to $ZONES/$view/$zone.
 function update_zone {
     local view=$1
     local zone=$2
@@ -523,28 +634,36 @@
     fi
 }
 
+## Link zone file to ues given shared zone.
+#
+#   link_zone   $view   $zone   [$base]
+#
+# Looks for shared zone at:
+#   $ZONES/$view/$base
+#   $ZONES/common/$base
 function link_zone {
     local view=$1
     local zone=$2
     local base=${3:-$zone}
 
     local out=$ZONES/$view/$zone
-   
-    # find tgt
-    for tgt in $ZONES/$view/$base $ZONES/common/$base; do
-        [ $tgt != $out ] && [ -e $tgt ] && break
-    done
+    local tgt=$(choose_link $out $ZONES/$view/$base $ZONES/common/$base)
 
     if check_link $out $tgt; then
         log_update "Linking $out -> $tgt..."
 
         do_link $out $tgt
+
     else
         log_skip "Linking $out -> $tgt: not changed"
     fi
 }
 
-## Tests
+## Test hosts zone for validity:
+#
+#   check_hosts     $DATA/$hosts    --check-exempt ...
+#
+# Fails if the check fails.
 function check_hosts {
     local hosts=$1; shift 1
 
@@ -561,6 +680,12 @@
     fi
 }
 
+## Test zone file for validity using named-checkzone:
+#
+#   check_zone      $view       $zone       $origin
+#
+# Uses the zonefile at $ZONES/$view/$zone, loading it with given initial $ORIGIN.
+# Fails if the check fails.
 function check_zone {
     local view=$1
     local zone=$2
@@ -583,52 +708,83 @@
     fi
 }
 
-## Deploy
-# deploy new zone data to bind
+## Load update zonefiles into bind:
+#
+#   deploy_zones    
+#
+# Invokes `rndc reload`, showing its output.
 function deploy_zones {
-    indent "        rndc: " $RNDC reload
+    if [ $DEPLOY_SKIP ]; then
+        log_skip "Reload zones: skipped"
+
+    else
+        log_update "Reload zones..."
+
+        # run
+        indent "        rndc: " \
+            $RNDC reload
+    fi
 }
-
-# commit data changes
+## Commit changes in $DATA to version control:
+#
+#   commit_data
+#
+# Invokes `hg commit` in the $REPO, first showing the diff.
 function commit_data {
     local repo=$REPO
-
-    if hg_modified; then
-        log_update "Commit changes in $repo:"
+    local commit_msg="$COMMIT_MSG"
 
-        indent "    " hg_diff
+    local msg="Commit changes in $repo..."
 
-        hg_commit "$COMMIT_MSG"
+    # operate?
+    if [ $COMMIT_FORCE ]; then
+        log_force   "$msg..."
+
+        do_commit "$commit_msg"
+
+    elif ! hg_modified; then
+        log_skip    "$msg: no changes"
+
+    elif [ $COMMIT_SKIP ]; then
+        log_noop    "$msg: skipped"
+
     else
-        log_skip "Commit changes in $repo: no changes"
+        log_update  "msg..."
+
+        do_commit "$commit_msg"
     fi
 }
 
-function main {
-    # test tty
-    [ -t 1 ] && IS_TTY=y
-    
-    parse_args "$@"
+## Site settings, used as arguments to scripts
+# MX record to generate in hosts --forward-zone
+FORWARD_MX=mail
 
-    ## test env
-    [ -d $ROOT/$DATA ] || die "Missing data: $ROOT/$DATA"
-    ensure_dir  $ZONES
-    
-    # output dirs
-    local views=(internal external)
+# IP network to generate reverse records for in --reverse-zone
+REVERSE_ZONE=194.197.235
 
-    for view in "${views[@]}" "common" "hosts" "includes"; do
-        ensure_dir $ZONES/$view
-    done
+# Origin domain to generate reverse records for in --reverse-zone
+REVERSE_DOMAIN=paivola.fi
 
-    ## hosts
+# Views used
+VIEWS=(internal external)
+
+# Base domain zone for domains
+DOMAIN_BASE=paivola
+
+# List of actual domains used; will be linked to $DOMAIN_BASE
+DOMAINS=(paivola.fi paivola.net paivola.org paivola.info paivola.mobi xn--pivl-load8j.fi)
+
+## Operate!
+function run {
+    ## Hosts
     # test
     log "Testing hosts..."
-        check_hosts     $DATA/paivola.txt --check-exempt ufc
+        #                   data                            args...
+        check_hosts         $DATA/paivola.txt               --check-exempt ufc
 
     # update
     log "Generating host zones..."
-        #                   zone                            base                *args
+        #                   hosts                           data                args...
         update_hosts        $ZONES/hosts/paivola:internal   $DATA/paivola.txt   --forward-zone --forward-txt --forward-mx $FORWARD_MX
         update_hosts        $ZONES/hosts/paivola:external   $DATA/paivola.txt   --forward-zone
         update_hosts        $ZONES/hosts/194.197.235        $DATA/paivola.txt   --reverse-zone $REVERSE_ZONE --reverse-domain $REVERSE_DOMAIN
@@ -641,8 +797,7 @@
         # update_hosts    $ZONES/hosts/pvl                    $DATA/pvl.txt      --forward-zone
         copy_hosts          $ZONES/hosts/pvl                $DATA/pvl.txt
 
-    ## zones
-    # parts
+    ## Includes
     log "Copying zone includes..."
         #                   view            zone                    base
         copy_zone           includes        paivola:internal        paivola.zone.internal
@@ -650,25 +805,25 @@
         copy_zone           includes        paivola.auto            paivola.zone.auto
         copy_zone           includes        paivola.services        paivola.zone.services
 
-    # serials
+    ## Serials
     log "Updating serials..."
 
-    #                   zone            *deps
-    update_serial       pvl             $ZONES/hosts/pvl        $DATA/pvl.zone
-    update_serial       10              $ZONES/hosts/10         $DATA/10.zone
-    update_serial       192.168         $ZONES/hosts/192.168    $DATA/192.168.zone
+        #                   zone            deps...
+        update_serial       pvl             $ZONES/hosts/pvl        $DATA/pvl.zone
+        update_serial       10              $ZONES/hosts/10         $DATA/10.zone
+        update_serial       192.168         $ZONES/hosts/192.168    $DATA/192.168.zone
 
-    update_serial     paivola           \
-        $ZONES/hosts/paivola:*          \
-        $DATA/paivola.zone              \
-        $ZONES/includes/paivola:*       \
-        $ZONES/includes/paivola.*
+        update_serial       paivola         \
+            $ZONES/hosts/paivola:*          \
+            $DATA/paivola.zone              \
+            $ZONES/includes/paivola:*       \
+            $ZONES/includes/paivola.*
 
-    update_serial     194.197.235       \
-        $ZONES/hosts/194.197.235        \
-        $DATA/194.197.235.zone          
+        update_serial       194.197.235     \
+            $ZONES/hosts/194.197.235        \
+            $DATA/194.197.235.zone          
 
-    # zones
+    ## Zones
     log "Updating zones..."
         #                   view        zone            base
         update_zone         internal    pvl
@@ -682,7 +837,7 @@
         link_zone           internal    194.197.235
         link_zone           external    194.197.235
 
-    # test
+    ## Test
     log "Testing zones..."
         #                   view        zone            origin
         check_zone          internal    paivola         paivola.fi
@@ -692,36 +847,45 @@
         check_zone          internal    192.168         192.168.in-addr.arpa
         check_zone          common      194.197.235     235.197.194.in-addr.arpa
 
-    # extra zones...
-    local base=paivola
-    local link_zones=(paivola.fi paivola.net paivola.org paivola.info paivola.mobi xn--pivl-load8j.fi)
+    ## Domains...
+    log "Linking domains..."
+        for view in "${VIEWS[@]}"; do
+            for zone in "${DOMAINS[@]}"; do
+                # link
+                link_zone       $view       $zone           $DOMAIN_BASE
 
-    log "Linking zones..."
-    for view in "${views[@]}"; do
-        for zone in "${link_zones[@]}"; do
-            link_zone       $view       $zone           $base
-            check_zone      $view       $zone           $zone
+                # test
+                check_zone      $view       $zone           $zone
+            done
         done
+
+    ## Deploy
+    log "Deploy zones..."
+        deploy_zones
+
+    ## Commit
+    log "Commit data..."
+        commit_data
+}
+
+## Main entry point
+function main {
+    # test tty
+    [ -t 1 ] && IS_TTY=y
+    
+    parse_args "$@"
+
+    ## test env
+    [ -d $ROOT/$DATA ] || die "Missing data: $ROOT/$DATA"
+    ensure_dir  $ZONES
+    
+    ## Output dirs
+    for dir in "common" "hosts" "includes" "${VIEWS[@]}"; do
+        ensure_dir $ZONES/$dir
     done
 
-    ## deploy
-    if [ $DEPLOY_SKIP ]; then
-        log "Deploy zones: skipped"
-
-    else
-        log "Deploy zones..."
-
-        deploy_zones
-    fi
-
-    ## commit
-    if [ $COMMIT_SKIP ] && [ ! $COMMIT_FORCE ]; then
-        log "Commit data: skipped"
-
-    else
-        log "Commit data..."
-            commit_data
-    fi
+    ## Go
+    run
 }
 
 main "$@"