bin/zoneconf: Reload zones after signing them.
authorMark Wooding <mdw@distorted.org.uk>
Sun, 4 Dec 2011 22:00:27 +0000 (22:00 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 4 Dec 2011 22:00:27 +0000 (22:00 +0000)
There are some other changes, too.

  * Move the program-running, output printing logic into `build-program'
    (rename it `run') because it's in too many places.

  * Avoid resigning a zone if we've done it already.

bin/zoneconf

index aad3ac3..772088a 100755 (executable)
@@ -164,6 +164,40 @@ proc set* {names values} {
   }
 }
 
+proc run {what command args} {
+  ## Run a command, reporting the result.  WHAT is shown in the output;
+  ## COMMAND are the command and arguments as a list; these are substituted
+  ## according to the string map ARGS.  Return true if the command succeeded,
+  ## false if it failed.
+
+  global QUIS
+
+  ## Substitute tokens in the command.
+  set cmd {}
+  set subst [concat [list "%%" "%"] $args]
+  foreach item $command { lappend cmd [string map $subst $item] }
+
+  ## Run the command.
+  set rc [catch {
+    set out [eval exec -ignorestderr $cmd 2>@1]
+  } msg]
+
+  ## Sort out the report.
+  if {$rc} { set out $msg }
+  set out "| [string map [list "\n" "\n| "] $out]"
+
+  ## Announce the result.
+  if {$rc} {
+    puts stderr "$QUIS: $what failed..."
+    puts stderr $out
+    return false
+  } else {
+    puts "$QUIS: $what output..."
+    puts $out
+    return true
+  }
+}
+
 ###--------------------------------------------------------------------------
 ### Configuration spaces.
 ###
@@ -1055,17 +1089,6 @@ define-configuration-space toplevel ZONECFG {
 ###--------------------------------------------------------------------------
 ### Processing the results.
 
-proc build-command {command args} {
-  ## Return the COMMAND list, after applying the string map ARGS to each item
-  ## in turn.
-
-  set cmd {}
-  foreach item $command {
-    lappend cmd [string map $args $item]
-  }
-  return $cmd
-}
-
 proc zone-file-name {view config} {
   ## Return the relative file name for the zone described by CONFIG, relative
   ## to the given VIEW.  An absolute filename may be derived later, depending
@@ -1195,26 +1218,12 @@ proc sign-zone-file {info input soafmt} {
   global QUIS
 
   array set zone $info
-  set cmd [build-command $zone(signzone-command) \
-              "%z" $zone(name) \
-              "%f" $zone(file-name) \
-              "%o" $zone(server-file-name) \
-              "%q" $soafmt]
-  set rc [catch {
-    set out [eval exec -ignorestderr $cmd]
-  } msg]
-  if {$rc} { set out $msg }
-  set out "| [string map [list "\n" "\n| "] $out]"
-  set ident "zone `$zone(name)' in view `$zone(mapped-view)'"
-  if {$rc} {
-    puts stderr "$QUIS: signing zone $ident failed..."
-    puts stderr $out
-    return false
-  } else {
-    puts "$QUIS: signing zone $ident output..."
-    puts $out
-    return true
-  }
+  return [run "zone `$zone(name)' in view `$zone(mapped-view)'" \
+             $zone(signzone-command) \
+             "%z" $zone(name) \
+             "%f" $zone(file-name) \
+             "%o" $zone(server-file-name) \
+             "%q" $soafmt]
 }
 
 proc write-zone-stanza {view chan config} {
@@ -1391,23 +1400,12 @@ provided by the named USER"
     close $chan
 
     ## Check the zone for sanity.
-    set cmd [build-command $zone(checkzone-command) \
-                "%z" $name \
-                "%v" $view \
-                "%f" $tmp]
-    set rc [catch {
-      set out [eval exec $cmd]
-    } msg]
-    if {$rc} { set out $msg }
-    set out "| [string map [list "\n" "\n| "] $out]"
-    if {$rc} {
-      puts stderr "$QUIS: zone check failed..."
-      puts stderr $out
+    if {![run "zone check" $zone(checkzone-command) \
+            "%z" $name \
+            "%v" $view \
+            "%f" $tmp]} {
       eval $cleanup
       exit 1
-    } else {
-      puts "$QUIS: zone check output..."
-      puts $out
     }
 
     ## If the zone wants signing, better to do that now.
@@ -1421,9 +1419,12 @@ provided by the named USER"
     file rename -force -- $tmp $zone(file-name)
     set cleanup {}
     foreach view $matchview {
-      eval exec $cmd [build-command $zone(reload-command) \
-                         "%v" $view \
-                         "%z" $zone(name)]
+      if {![run "reload zone `$zone(name) in view `$view'" \
+               $zone(reload-command) \
+               "%v" $view \
+               "%z" $zone(name)]} {
+       exit 3
+      }
     }
   } {
     eval $cleanup
@@ -1441,24 +1442,49 @@ defcmd sign {} {
   confspc-eval toplevel [list source $CONFFILE]
 
   ## Grind through all of the zones.
-  foreach iview $ZONECFG(all-views) {
+  array unset seen
+  foreach view $ZONECFG(all-views) {
     foreach info $ZONES {
+
+      ## Fetch the zone information.
       array unset zone
-      set compinfo [compute-zone-properties $iview $info]
+      set compinfo [compute-zone-properties $view $info]
       array set zone $compinfo
       if {![string equal $zone(config-type) master]} { continue }
+
       if {[string equal $zone(type) static] && $zone(sign)} {
-       if {![sign-zone-file $compinfo $zone(file-name) $zone(soa-format)]} {
-         set rc 2
+       ## Static zone: re-sign it if we haven't seen this user view before,
+       ## and then reload.
+
+       ## Sign the zone file if we haven't tried before.
+       set id [list $zone(name) $zone(mapped-view)]
+       if {![info exists seen($id)]} {
+         if {[sign-zone-file $compinfo \
+                  $zone(file-name) $zone(soa-format)]} {
+           set seen($id) true
+         } else {
+           set rc 2
+           set seen($id) failed
+         }
+       }
+
+       ## If we succeeded, reload the zone in this server view.
+       if {[string equal $seen($id) true]} {
+         if {![run "reload zone `$zone(name) in server view `$view'" \
+                   $zone(reload-command) \
+                   "%z" $zone(name) \
+                   "%v" $view]} {
+           set rc 2
+         }
        }
       } elseif {[string equal $zone(type) dynamic] &&
                ![string equal $zone(auto-dnssec) off]} {
-       set cmd [build-command $zone(autosign-command) \
-                    "%z" $zone(name) \
-                    "%v" $iview]
-       if {[catch { exec $cmd } msg]} {
-         puts stderr "$QUIS: failed to reload `$zone(name)'"
-         puts stderr "| [string map [list "\n" "\n| "] $msg]"
+       ## Dynamic zone: get BIND to re-sign it.
+
+       if {![run "re-sign zone `$zone(name) in server view `$view'" \
+                 $zone(autosign-command) \
+                 "%z" $zone(name) \
+                 "%v" $view]} {
          set rc 2
        }
       }