[28454] in Source-Commits

home help back first fref pref prev next nref lref last post

installer commit: Rewrite stage1 installer to use debconf

daemon@ATHENA.MIT.EDU (Jonathan D Reed)
Mon Sep 29 11:14:21 2014

Date: Mon, 29 Sep 2014 11:14:14 -0400
From: Jonathan D Reed <jdreed@mit.edu>
Message-Id: <201409291514.s8TFEEgb010495@drugstore.mit.edu>
To: source-commits@mit.edu

https://github.com/mit-athena/installer/commit/d17566a893060ae509e9090c1828edcb431dba06
commit d17566a893060ae509e9090c1828edcb431dba06
Author: Jonathan Reed <jdreed@mit.edu>
Date:   Fri Sep 12 12:45:58 2014 -0400

    Rewrite stage1 installer to use debconf
    
    Add a set of templates and rewrite the stage 1 installer to use
    debconf, for a more pleasing UI, rather than relying on a
    poorly-initialized VT5.  The logic is changed a bit, and we ask the
    metapackage question here, as well as making it a bit easier to change
    advanced options.

 pxe/stage1/debathena/debathena.templates |  227 ++++++++
 pxe/stage1/debathena/installer.sh        |  832 +++++++++++++++---------------
 2 files changed, 636 insertions(+), 423 deletions(-)

diff --git a/pxe/stage1/debathena/debathena.templates b/pxe/stage1/debathena/debathena.templates
new file mode 100644
index 0000000..982c51d
--- /dev/null
+++ b/pxe/stage1/debathena/debathena.templates
@@ -0,0 +1,227 @@
+# These two templates are used in automatic network
+# configuration.  Their values are not used elsewhere
+Template: install-debathena/ip_or_hostname
+Type: string
+Description: Enter hostname or IP.
+ A hostname and static IP address is required to install Debathena via
+ PXE.  You may enter either the hostname or the IP address here.
+ .
+ If you don't have a hostname or IP address, consult your local IT
+ staff, or contact helpdesk@mit.edu.  Do not attempt to make up a
+ hostname or IP address -- it will render your system unusable.
+
+Template: install-debathena/autonet_fail
+Type: text
+Description: Will proceed with manual configuration...
+ Unable to automatically determine the correct network settings based on
+ the information provided.
+
+# The actual static IP.  Used as a prompt in manual netconfig
+Template: install-debathena/ipaddr
+Type: string
+Description: Enter IP address
+ Enter the static IP address for your workstation.
+
+# The actual hostname (FQDN).  Used as a prompt in manual netconfig
+Template: install-debathena/hostname
+Type: string
+Description: Enter hostname
+ Enter the fully-qualified hostname (e.g. something.mit.edu) for your
+ machine.
+
+Template: install-debathena/netmask
+Type: string
+Description: Enter the subnet mask
+ Enter your subnet mask ("netmask"), in IPv4 format.
+
+Template: install-debathena/gateway
+Type: string
+Description: Enter your gateway
+ Enter your gateway address.  This may also be called
+ your router or default gateway.
+
+# Feedback during manual net config
+Template: install-debathena/invalid_ip
+Type: text
+Description: Invalid IP address
+ That is not a valid IPv4 address.  Try again.
+
+Template: install-debathena/invalid_hostname
+Type: text
+Description: Hostname invalid
+ That is not a valid hostname.  Starting over...
+
+Template: install-debathena/dns_not_found
+Type: boolean
+Default: false
+Description: Try again?
+ Could not find that hostname in DNS.
+
+Template: install-debathena/confirm_net
+Type: boolean
+Default: true
+Description: Are these settings ok?
+ Hostname: ${HOSTNAME}
+ .
+ IP/Netmask: ${IPADDR}/${NETMASK}
+ .
+ Gateway: ${GATEWAY}
+
+Template: install-debathena/use_dhcp
+Type: boolean
+Default: false
+Description: Accept these DHCP settings?
+ The DHCP server appears to have given you a valid network
+ address.  Normally, you would specify a hostname and static IP
+ address when installing Debathena, but you can use DHCP under some
+ circumstances.  If you elect to use DHCP, you will be unable to install
+ debathena-cluster.
+ .
+ (If you do not understand this question, please answer "No".)
+
+# Installer-related templates
+Template: install-debathena/want_advanced
+Type: boolean
+Default: false
+Description: Enable advanced features?
+ Do you want to enable advanced installer features?
+
+# The choices here mirror the questions below
+Template: install-debathena/advanced
+Type: multiselect
+Choices: mirror, architecture, beta installer, distribution, debug mode, manual partitioning, kernel arguments
+Description: Select features to customize:
+ Beta testers and other advanced users may wish to customize some additional
+ features.
+ .
+ For a normal installation, do not select any features in this list.
+
+Template: install-debathena/mirror
+Type: string
+Default: mirrors.mit.edu
+Description: Enter a mirror address:
+ N.B. This only applies to the base operating system.
+
+Template: install-debathena/architecture
+Type: string
+Default: amd64
+Description: Enter an architecture:
+ Valid architectures are: amd64, i386, and possibly armhf.
+ .
+ Invalid architectures: sparc, mips, m68k, alpha, s390
+
+Template: install-debathena/beta_installer
+Type: boolean
+Default: false
+Description: Use beta installer?
+ The beta installer is a version of install-debathena.sh that is
+ currently in testing.  It may be the same as the production version.
+
+Template: install-debathena/distribution
+Type: string
+Description: Enter distribution codename:
+ Enter the codename of the distribution you wish to install.
+ (e.g. "trusty", "precise", "wheezy")
+
+Template: install-debathena/debug_mode
+Type: boolean
+Default: false
+Description: Enable debugging mode in stage 2?
+
+Template: install-debathena/manual_partitioning
+Type: boolean
+Default: false
+Description: Use manual partitioning?
+ Select whether or not to use manual partitioning.
+ .
+ IMPORTANT: Selecting 'no' will COMPLETELY ERASE YOUR HARD DRIVE.
+ YOU WILL LOSE ALL YOUR DATA.
+
+Template: install-debathena/kernel_arguments
+Type: string
+Default: DEBCONF_DEBUG=5
+Description: Extra kernel arguments?
+ This would be the place to pass netcfg or keyboard-configuration args too.
+ .
+ Here be dragons.
+
+Template: install-debathena/confirm_install
+Type: boolean
+Default: true
+Description: Proceed with installation?
+ Will install *${metapackage}* on *${distro}* (${arch}) from *${mirror}*
+ using *${installer}* installer with *${partitioning}* partitioning.
+ ${debugtxt}
+ .
+ Stage 2 kernel arguments: ${kargs}
+
+# DESTROYS DESTROYS DESTROYS
+Template: install-debathena/destroys
+Type: text
+Description: Otherwise, continue with the installation
+ You have selected automatic partitioning.
+ .
+ **********************************************************
+ .
+ * THIS PROCEDURE DESTROYS THE CONTENTS OF THE HARD DISK. *
+ .
+ **********************************************************
+ .
+ Your entire hard drive will be PERMANENTLY ERASED.  If this is not what
+ you want, please power off your computer now.
+
+Template: install-debathena/really_quit
+Type: boolean
+Description: Are you sure you want to cancel?
+ If you cancel the installation here, you cannot proceed
+ and will have to reboot.
+
+Template: install-debathena/ohnoes
+Type: note
+Description: Installation Aborted
+ ${errormsg}
+ .
+ You should probably reboot at this point.
+ .
+ Advanced users can switch to VT2 or VT3 (Ctrl-Alt-F2 or F3) and
+ start a shell for debugging.
+
+# This is always asked
+Template: install-debathena/metapackage
+Type: select
+Choices: ${meta_choices}
+Description: Select a metapackage:
+ Please select the 'flavor' of Debathena that best suits your needs.
+ .
+  standard: Athena client software and customizations.
+  login: Allow Athena accounts to log in to your machine.
+  login-graphical: Includes Athena graphical login customizations
+  workstation: Managed configuration with automatic updates
+  cluster: IS&T public workstation (no customizations)
+
+# db_progress related templates
+Template: install-debathena/please_wait
+Type: text
+Description: Please wait...
+
+Template: install-debathena/querying_dns
+Type: text
+Description: Querying DNS...
+
+Template: install-debathena/downloading
+Type: text
+Description: Downloading ${thing}
+
+# Not currently in use
+Template: install-debathena/prerelease
+Type: note
+Description: Preliminary Support
+ The release you are running is not yet supported and installing
+ Debathena on it is probably a bad idea, particularly for any
+ purpose other than beta testing.
+ .
+ (New releases are generally supported a couple of weeks
+ after the official release date.  We strongly encourage you
+ to check http://debathena.mit.edu for support information
+ and try again later, or install the previous version of
+ the operating system.)
diff --git a/pxe/stage1/debathena/installer.sh b/pxe/stage1/debathena/installer.sh
old mode 100644
new mode 100755
index c0504fb..d23222d
--- a/pxe/stage1/debathena/installer.sh
+++ b/pxe/stage1/debathena/installer.sh
@@ -1,467 +1,453 @@
 #!/bin/sh
-
-dnscgi="http://18.9.60.73/website/dns.cgi"
-
-test=
-if [ "$1" = "--test" ]; then
-  test="test"
-  echo "** TESTING MODE"
-fi
-
-if [ "$test" != "test" ]; then
-    cd /debathena
-fi
+#
+# The Debathena stage 1 installer.  This installer will:
+# - configure networking
+# - determine what metapackage to install, as well as some other advanced
+#   installation options
+# - download the stage2 initrd and kernel
+# - kexec into them.
+
+OWNER="install-debathena"
+: ${PREFIX="/debathena"}
+TEMPLATE_FILE="${PREFIX}/debathena.templates"
+NETPARAMS="${PREFIX}/athena/netparams"
+MASKS_FILE="${PREFIX}/athena/masks"
+DEFAULT_DISTRO=trusty
+NAMESERVERS="18.72.0.3 18.71.0.151 18.70.0.160"
+
+# A URI which, if it can be reached, indicates the machine has
+# a real connection to MITnet
+NETWORK_TEST_URI="http://debathena.mit.edu/net-install"
+
+# Net device to use (filled in later)
+ETH0=
 
 debug () {
-  if [ "$test" != "test" ]; then
+  if [ -z "$DA_DEBUG" ]; then
     logger -t install.debug "$@"
   else
-    echo "DEBUG: $@"
+    echo "$DEBUG: $@" >&2
   fi
 }
 
-pxetype=""
+run () {
+  if [ -n "$DA_DEBUG" ]; then
+    echo "Command: $@"
+  else
+    logger -t install.debug "Running $@"
+    "$@"
+  fi
+}
+
+# Some Debconf helper functions to avoid having to
+# type the owner each time
+
+# Get the value of a question
+get () {
+  question="$1"
+  db_get $OWNER/$question && echo "$RET"
+}
 
-netconfig () {
-  echo "Configuring network..."
-  mp=/debathena
-  if [ "$test" = "test" ]; then
-      mp="`dirname $0`"
+# Ask a question with a priority (defaults to 'high')
+# and a title (defaults to "Debathena Installer")
+# Then call db_get, so the value is in RET
+ask () {
+  question="$1"
+  priority="${2:-high}"
+  db_fset $OWNER/$question seen false
+  db_title "${3:-Debathena Installer}"
+  db_input "$priority" $OWNER/$question
+  if [ $? -ge 10 ] && [ $? -le 29 ]; then
+    error "An internal error occurred while asking a question"
   fi
-  export IPADDR NETMASK GATEWAY SYSTEM CONTROL HOSTNAME
-  # This will fail if dhreg addresses ever stop being able to reach net 18
-  # First make sure we're talking to who we think we are
-  havedns=n
-  ipprompt="Enter IP address:"
-  if [ "$(wget -qO - "$dnscgi/q")" = "Debathena DNS-CGI" ]; then
-    havedns=y
-    ipprompt="Enter IP address or hostname:"
+  db_go && db_get $OWNER/$question
+}
+
+# Thin wrapper around db_subst
+swap () {
+  question="$1"
+  db_subst $OWNER/$question "$2" "$3"
+}
+
+# Attempt to run the netparams command.  If it succeeds,
+# pre-seed the netmask and gateway values
+guess_netparams() {
+  local params
+  params="$($NETPARAMS -f "$MASKS_FILE" "$IPADDR" 2>/dev/null)"
+  if [ $? -eq 0 ]; then
+    # netparams returns its output in this format:
+    #    NETMASK NETWORK BROADCAST GATEWAY MASKBITS
+    db_set $OWNER/netmask "$(echo "$params" | cut -d ' ' -f 1)"
+    db_set $OWNER/gateway "$(echo "$params" | cut -d ' ' -f 4)"
+    return 0
+  else
+    return 1
   fi
+}
 
-  while [ -z "$IPADDR" ] ; do
-    HOSTNAME=
-    echo -n "$ipprompt "
-    read IPADDR
-    debug "In netconfig, user entered '$IPADDR'"
-    # RFC1123 does permit hostnames to start with digits, moira doesn't
-    # If you do that, suck it up and type the IP
-    if echo "$IPADDR" | grep -q '[a-zA-Z]'; then
-      HOSTNAME="$IPADDR"
-      IPADDR=
-      if [ "$havedns" != "y" ]; then
-	echo "Enter a valid IP address.  (DNS not available)".
-	continue
-      fi
-      echo "Looking up IP for $HOSTNAME..."
-      dig="$(wget -qO - "$dnscgi/a/$HOSTNAME")"
-      if echo "$dig" | grep -q '^OK:'; then
-	IPADDR="$(echo "$dig" | sed 's/^OK: //')"
-	echo "Found $IPADDR..."
-      else
-	echo "$dig"
-	echo "Could not look up IP address for $HOSTNAME.  Try again."
-      fi
-    fi
+confirm_net() {
+  swap confirm_net IPADDR "$(get ipaddr)"
+  swap confirm_net HOSTNAME "$(get hostname)"
+  swap confirm_net NETMASK "$(get netmask)"
+  swap confirm_net GATEWAY "$(get gateway)"
+  db_set $OWNER/confirm_net true
+  ask confirm_net
+}
+
+error () {
+  msg="${1:-The installation cannot continue.}"
+  swap ohnoes errormsg "$msg"
+  ask ohnoes critical
+  while true; do
+    echo "Please reboot now."
+    read dummy
   done
+}
 
-  if [ -z "$HOSTNAME" ] && [ "$havedns" = "y" ]; then
-    dig="$(wget -qO - "$dnscgi/ptr/$IPADDR")"
-    if echo "$dig" | grep -q '^OK:'; then
-      HOSTNAME="$(echo "$dig" | sed 's/^OK: //')"
-      echo "$IPADDR reverse-resolves to $HOSTNAME..."
-    else
-      echo "$dig"
-      echo "Could not look up hostname for $IPADDR."
-      echo "Cannot continue without a valid hostname."
-      echo "Please note that if this address was newly requested,"
-      echo "or its hostname was changed, it can take up to 2 business days"
-      echo "before DNS information is correct."
-      echo 
-      echo "Please try again once DNS has been updated or use a different"
-      echo "IP address.  You may now restart or shut down this workstation."
-      while true; do
-	  read foo
-	  if [ "$foo" = "xyzzy" ]; then 
-	      break
-	  fi
-      done
+# Ask a question, requiring the answer to be a valid IP
+ask_valid_ip() {
+  while true; do
+    ask "$1"
+    if ! dahost -i "$RET"; then
+      ask invalid_ip critical
+      continue
     fi
+    break
+  done
+}
+
+# Determine which interface to use
+select_interface() {
+  IFACES="$(ip -o link show | grep -v loopback | cut -d : -f 2 | tr -d ' ')"
+  NUMIF="$(echo "$IFACES" | wc -l)"
+  debug "Found $NUMIF interfaces: $IFACES"
+  if [ "$NUMIF" -gt 1 ]; then
+    # Do something clever here in the future
+    ETH0="$(echo "$IFACES" | head -1)"
+  elif [ "$NUMIF" -eq 1 ]; then
+    ETH0="$IFACES"
+  else
+    return 1
   fi
-  if [ -z "$HOSTNAME" ]; then
-      HOSTNAME=install-target-host
-  fi
-  
-  HOSTNAME="$(echo "$HOSTNAME" | tr A-Z a-z | sed 's/\.mit\.edu$//')"
-
-  NETMASK=`$mp/athena/netparams -f $mp/athena/masks "$IPADDR"|cut -d\  -f 1`
-  net=`$mp/athena/netparams -f $mp/athena/masks "$IPADDR"|cut -d\  -f 2`
-  bc=`$mp/athena/netparams -f $mp/athena/masks "$IPADDR"|cut -d\  -f 3`
-  GATEWAY=`$mp/athena/netparams -f $mp/athena/masks "$IPADDR"|cut -d\  -f 4`
-  maskbits=`$mp/athena/netparams -f $mp/athena/masks "$IPADDR"|cut -d\  -f 5`
-
-  echo "Address: $IPADDR"
-  echo
-  echo "Autoconfigured settings:"
-  echo "  Netmask bits: $maskbits"
-  echo "  Broadcast: $bc"
-  echo "  Gateway: $GATEWAY"
-
-  debug "Calculated values: $HOSTNAME $NETMASK $GATEWAY $bc"
-
-  if [ "$pxetype" != cluster ] ; then
-    echo -n "Are these OK? [Y/n]: "; read response
-    case $response in
-      y|Y|"") ;;
-      *) 
-      echo -n "Netmask bits [$maskbits]: "; read r; if [ -n "$r" ] ; then maskbits=$r ; fi
-      echo -n "Broadcast [$bc]: "; read r; if [ -n "$r" ] ; then bc=$r ; fi
-      echo -n "Gateway [$GATEWAY]: "; read r; if [ -n "$r" ] ; then GATEWAY=$r ; fi
+  return 0
+}
+
+# Configure the network manually
+manual_netconfig() {
+  local IPADDR params
+  while true; do
+    ask_valid_ip ipaddr critical
+    IPADDR="$RET"
+    debug manual_netconfig IPADDR "$IPADDR"
+    query_dns "$IPADDR"
+    if [ $? -eq 0 ]; then
+      db_set $OWNER/hostname "$DAHOSTNAME"
+    fi
+    ask hostname critical
+    if ! dahost -h "$RET" || dahost -i "$RET"; then
+      # It's either not a valid hostname, or it's an IP address, and
+      # thus invalid.  If you really really want to, you can have a
+      # hostname of 999999 in a TLD of .8888.  Don't do that.
+      ask invalid_hostname critical
+      continue
+    fi
+    guess_netparams
+    ask_valid_ip netmask
+    ask_valid_ip gateway
+    confirm_net
+    [ "$RET" = "true" ] && break
+  done
+}
+
+# Configure the network automagically, either from an IP
+# or hostname.  If any step of this fails, fall back to manual config
+auto_netconfig() {
+  while true; do
+    ask ip_or_hostname critical
+    IP_OR_HOST="$RET"
+    [ -n "$IP_OR_HOST" ] || continue
+    query_dns "$IP_OR_HOST"
+    case $? in
+      0)
+        break
+        ;;
+      128)
+        if ! dahost -i "$IP_OR_HOST"; then
+          db_reset "$OWNER/dns_not_found"
+          ask dns_not_found
+          [ "$RET" = "true" ] || return 1
+        else
+          # Pre-seed the value for manual config
+          db_set $OWNER/ipaddr "$IP_OR_HOST"
+          return 1
+        fi
+        ;;
+      *)
+        return 1
+        ;;
     esac
+  done
+  IPADDR="$DAIPADDR"
+  db_set $OWNER/ipaddr "$IPADDR"
+  db_set $OWNER/hostname "$DAHOSTNAME"
+  guess_netparams
+}
+
+# Look up something in DNS, with a debconf progress bar
+query_dns() {
+  db_progress START 0 2 $OWNER/please_wait
+  db_progress STEP 1
+  db_progress INFO $OWNER/querying_dns
+  LOOKUP="$(dahost -s "$@")"
+  rv=$?
+  debug "query_dns" "rv=$rv" "LOOKUP=$LOOKUP"
+  db_progress SET 2
+  db_progress STOP
+  if [ $rv -eq 0 ]; then
+    eval "$LOOKUP"
+  else
+    DAIPADDR=
+    DAHOSTNAME=
   fi
+  debug "query_dns" "DAIPADDR=$DAIPADDR DAHOSTNAME=$DAHOSTNAME"
+  unset LOOKUP
+  return $rv
+}
 
-  if [ "$test" != "test" ]; then
-  # We can not set the hostname here; running "debconf-set netcfg/get_hostname"
-  # causes fatal reentry problems.  Setting values directly with preseeding
-  # also fails, as the DHCP values override it.
-  echo "Killing dhcp client."
-  killall dhclient
-  echo -n "Determining which interface to use... "
-  ETH0="$(ip -o link show | grep -v loopback | cut -d: -f 2 | tr -d ' ' | head -1)"
-  echo "$ETH0"
-  echo "Running: ip addr flush dev $ETH0"
-  ip addr flush dev $ETH0
-  echo "Running: ip addr add $IPADDR/$maskbits broadcast $bc dev $ETH0"
-  ip addr add "$IPADDR/$maskbits" broadcast "$bc" dev $ETH0
-  echo "Flushing old default route."
-  route delete default 2> /dev/null
-  echo "Running: route add default gw $GATEWAY"
-  route add default gw "$GATEWAY"
-  echo "Replacing installer DHCP nameserver with MIT nameservers."
-  sed -e '/nameserver/s/ .*/ 18.72.0.3/' < /etc/resolv.conf > /etc/resolv.conf.new
-  echo "nameserver	18.70.0.160" >> /etc/resolv.conf.new
-  echo "nameserver	18.71.0.151" >> /etc/resolv.conf.new
-  mv -f /etc/resolv.conf.new /etc/resolv.conf
+apply_netconfig() {
+  IPADDR="$(get ipaddr)"
+  NETMASK="$(get netmask)"
+  GATEWAY="$(get gateway)"
+
+  if [ -n "$IPADDR" ] && [ -n "$NETMASK" ] && [ -n "$GATEWAY" ]; then
+    run killall dhclient
+    run ip addr flush dev $ETH0
+    run ip addr add $IPADDR/$NETMASK dev $ETH0
+    run route delete default 2>/dev/null
+    run route add default gw "$GATEWAY"
+    rm -f $PREFIX/resolv.conf.tmp
+    for ns in $NAMESERVERS; do
+      echo "nameserver $ns" >> $PREFIX/resolv.conf.tmp
+    done
+    mv -f $PREFIX/resolv.conf.tmp /etc/resolv.conf
   fi
+  unset IPADDR NETMASK GATEWAY
 }
 
-# Color strings. I'd like to use tput, but the installer doesn't have it.
-esc=""
-nnn="${esc}[m"          # Normal
-ccc="${esc}[36m"        # Cyan
-rrr="${esc}[1;31m"      # Bold and red
-ddd="${esc}[1;31;47m"   # Plus gray background
-ddb="${esc}[1;31;47;5m" # Plus blinking
-
-
-mirrorsite="mirrors.mit.edu"
-installertype="production"
-distro="trusty"
-partitioning="auto"
-arch="i386"
-# That is a space and a tab
-if egrep -q '^flags[ 	].* lm( |$)' /proc/cpuinfo;  then 
-  arch="amd64"
-fi
+netconfig() {
+  if ! auto_netconfig; then
+    ask autonet_fail critical
+    manual_netconfig
+  else
+    confirm_net
+    [ "$RET" = "true" ] || manual_netconfig
+  fi
+}
 
-# Of course the installer doesn't have `date`
-# time.mit.edu/kerberos.mit.edu is 18.7.21.144
-# This will probably break eventually
-debug "** Install begins at $(nc -w1 18.7.21.144 13)"
+test_uri() {
+  local WGETARGS
+  WGETARGS="--spider"
+  if run wget --help 2>&1 | grep -q BusyBox; then
+    WGETARGS="-s"
+  fi
+  # Test the mirror
+  wget $WGETARGS "$1" 2>&1 > /dev/null
+}
 
-if [ -f "/debathena/version" ]; then
-  echo -n "SVN version: " && cat /debathena/version
-  debug "SVN: " "$(cat /debathena/version)"
-fi
+split_choices() {
+  # Given a multi $RET value, split it into tab-separated
+  # fields (suitable for the default IFS) and replace spaces
+  # in question names with underscores.
+  SPLIT="$(echo "$RET" | sed -e 's/, /\t/g; s/ /_/g;')"
+}
 
-debugmode=""
-debug "Mirror $mirrorsite Type $installertype Arch $arch"
-
-echo "Welcome to Athena, Stage 1 Installer"
-echo
-
-while [ -z "$pxetype" ] ; do
-  echo
-  echo "Will install ${ccc}$distro${nnn} ($arch) using $installertype installer"
-  echo -n "from $mirrorsite using $partitioning partitioning"
-  [ -n "$debugmode" ] &&  echo -n " with debugging."
-  echo
-  echo
-  echo "Choose one:"
-  echo
-  echo "  1: Perform an unattended ${ccc}debathena-cluster${nnn} install, ${rrr}ERASING your"
-  echo "     ENTIRE DISK${nnn}. This option is only intended for people setting up"
-  echo "     public cluster machines maintained by IS&T/Athena. "
-  echo
-  echo "  2: Do a ${ccc}normal Debathena install${nnn}.  You'll need to answer normal Ubuntu"
-  echo "     install prompts, and then the Athena-specific prompts, including"
-  echo "     choosing which flavor of Debathena you'd like (e.g., private workstation)."
-  echo
-  echo "  3: Punt to a completely ${ccc}vanilla install of Ubuntu${nnn}."
-  echo "     (Note: locale and keyboard have already been set.)"
-  echo
-  echo "  4: /bin/sh (for rescue purposes)"
-  echo
-  echo "  Advanced users only:"
-  echo "    m: Select a different mirror.           d: Change the distro (version)."
-  echo "    a: Change architecture.                 z: Toggle debug mode."
-  echo "    b: Toggle beta installer                p: Toggle manual partitioning."
-  echo
-  echo -n "Choose: "
-  read r
-  case "$r" in
-    1)
-      echo "Debathena CLUSTER it is."; pxetype=cluster ;;
-    2)
-      echo "Normal Debathena install it is."; pxetype=choose ;;
-    3)
-      echo "Vanilla Ubuntu it is."; pxetype=vanilla;;
-    4)
-      echo "Here's a shell.  You'll return to this prompt when done."
-      echo
-      echo "Note: This shell has no job control, and unless you know"
-      echo "what you're doing, you almost certainly want to switch to"
-      echo "VT2 (by pressing Ctrl-Alt-F2), and use the shell there."
-      echo "You can return to this screen (VT5) by pressing Ctrl-Alt-F5."
-      echo
-      /bin/sh;;
-    m|M)
-      echo
-      echo "NOTE: There is no data validation.  Don't make a typo."
-      echo -n "Enter a new mirror hostname: "
-      read mirrorsite
-      ;;
-    d|D)
-      echo
-      echo "NOTE: There is no data validation.  Don't make a typo."
-      echo -n "Enter a new distro: "
-      read distro
-      ;;
-    b|B)
-      if [ "$installertype" = "production" ]; then
-        echo "Switching to beta installer."
-        installertype="beta"
-      else
-        echo "Switching to production installer."
-        installertype="production"
-      fi
-      ;;
-    p|P)
-      if [ "$partitioning" = "auto" ]; then
-        echo "Switching to manual partitioning."
-	echo "Your disk will (probably) not be erased."
-        partitioning="manual"
-	echo "Normally, cluster machines get:"
-	echo " - a 200MB ext3 /boot partition"
-	echo " - an LVM volume group named 'athena', containing"
-	echo "   - a (3x system RAM)-sized swap LV (at least 512 MB)"
-	echo "   - a root LV taking up half the remaining space (at least 10 GB)"
-	echo
-	echo "You probably want to set up something similar."
-	echo
-	echo "Backups are ALWAYS a good idea.  Stop and make one now."
-	echo "Press Enter to continue."
-	read dummy
-      else
-        echo "Switching to auto partitioning."
-        partitioning="auto"
-      fi
-      ;;
-    a|A)
-      echo
-      oldarch="$arch"
-      echo -n "Enter a new arch (acceptable values: i386, amd64): "
-      read arch
-      if [ "$arch" != "i386" ] && [ "$arch" != "amd64" ]; then
-	  echo "Invalid value.  Reverting to $arch."
-	  arch="$oldarch"
-      fi
-      unset oldarch
-      ;;
-    z|Z)
-      if [ -n "$debugmode" ]; then
-        echo "Turning debug mode off."
-	debugmode=""
-      else
-        echo "Turning debug mode on."
-	debugmode="da/dbg=1"
-      fi
-      ;;
-    *)
-      echo "Choose one of the above, please.";;
-  esac
-done
+advanced() {
+  db_reset $OWNER/advanced
+  db_metaget $OWNER/advanced Choices
+  split_choices
+  for choice in $SPLIT; do
+    db_reset $OWNER/$choice
+  done
+  db_set $OWNER/distribution "$DEFAULT_DISTRO"
+  advanced_opts=
+  ask advanced
+  [ $? -eq 30 ] && return
+  split_choices
+  for adv in $SPLIT; do
+    ask $adv
+  done
+}
 
-debug "*** Main menu complete"
-debug "Mirror: $mirrorsite Type: $installertype Part: $partitioning"
-debug "Arch: $arch Distro: $distro Pxetype: $pxetype"
-debug "$ETH0:"
-debug "$(ip address show $ETH0)"
-debug "routing:"
-debug "$(route)"
-debug "resolv.conf:"
-debug "$(cat /etc/resolv.conf)"
-
-##############################################################################
-
-
-# Consider setting a static IP address, especially if we can't reach the mirror.
-if [ cluster != "$pxetype" ]; then
-  # We're at a point in the install process where we can be fairly sure
-  # that nothing else is happening, so "killall wget" should be safe.
-  (sleep 5; killall wget >/dev/null 2>&1) &
-  if wget -s http://$mirrorsite/ubuntu ; then
-    if ip address show to 18.0.0.0/8 | grep -q . && ! ip address show to 18.2.0.0/16 | grep -q . ; then
-      echo "Your computer seems to be registered on MITnet."
-    else
-      echo "Your computer seems not to be registered on MITnet, but the mirror"
-      echo "site $mirrorsite is accessible."
-    fi
-    echo
-    echo "${ccc}You can continue the install using your existing dynamic address.${nnn}"
-    echo -n "Configure a static address anyway?  [y/N]: "
-    while : ; do
-      read r
-      case "$r" in
-        N*|n*|"") break;;
-        y*|Y*) netconfig; break;;
-      esac
-      echo -n "Choose: [y/N]: "
-    done
+config_network() {
+  if [ "$(get use_dhcp)" = "true" ]; then
+    # Hope for the best
+    db_set $OWNER/hostname "$(hostname)"
   else
-    echo "The mirror site $mirrorsite is NOT accessible in your current"
-    echo "dynamic configuration."
-    echo
-    echo "${rrr}You must specify a static address for the installation.${nnn}"
     netconfig
+    apply_netconfig
   fi
-else
-  netconfig
-fi
+}
 
-extra_kargs=""
-if [ "$installertype" = "beta" ]; then
-    echo "Any extra kernel arguments to pass to kexec?"
-    echo "(I hope you know what you're doing.  Press Enter for none.)"
-    read extra_kargs
-fi
+config_installer() {
+  db_set $OWNER/distribution "$DEFAULT_DISTRO"
+  default_pkg="workstation"
+  pkg_choices="standard, login, login-graphical, workstation"
+  # You are not allowed to install -cluster with DHCP
+  if [ "$(get use_dhcp)" != "true" ]; then
+    default_pkg="cluster"
+    pkg_choices="${pkg_choices}, cluster"
+  fi
+  swap metapackage meta_choices "$pkg_choices"
+  db_set $OWNER/metapackage "$default_pkg"
+  while true; do
+    # Disable "backing up"
+    db_capb ""
+    ask metapackage
+    # Enable "backing up"
+    db_capb backup
+    ask want_advanced
+    [ $? -eq 30 ] && continue
+    [ "$RET" = "true" ] && advanced
+    metapackage=$(get metapackage)
+    distro=$(get distribution)
+    arch=$(get architecture)
+    installer=production
+    mirror=$(get mirror)
+    [ "$(get beta_installer)" = "true" ] && installer=beta
+    partitioning=auto
+    [ "$(get manual_partitioning)" = "true" ] && partitioning=manual
+    stage2_debug=0
+    debugtxt=
+    if [ "$(get debug_mode)" = "true" ]; then
+      stage2_debug=1
+      debugtxt="Stage 2 debugging enabled."
+    fi
+    extra_kargs="$(get kernel_arguments)"
+    swap confirm_install metapackage "$metapackage"
+    swap confirm_install distro "$distro"
+    swap confirm_install arch "$arch"
+    swap confirm_install installer "$installer"
+    swap confirm_install partitioning "$partitioning"
+    swap confirm_install mirror "$mirror"
+    swap confirm_install extra_kargs "$extra_kargs"
+    swap confirm_install debugtxt "$debugtxt"
+    db_set $OWNER/confirm_install true
+    ask confirm_install
+    [ "$RET" = "true" ] && break
+  done
+  # Turn off back up, since it's pointless now.
+  db_capb ""
+  if [ "$partitioning" = "auto" ]; then
+    ask destroys
+  fi
+}
 
-if [ "$pxetype" = "cluster" ] && [ "$partitioning" = "auto" ]; then
-    cat << EOF
-************************************************************
-               ${ddb}DESTROYS${nnn}
-${rrr}THIS PROCEDURE ${ddd}DESTROYS${nnn}${rrr} THE CONTENTS OF THE HARD DISK.${nnn}
-               ${ddb}DESTROYS${nnn}
+# Begin main installer code
 
-IF YOU DO NOT WISH TO CONTINUE, REBOOT NOW.
+# Load debconf
+. /usr/share/debconf/confmodule
 
-************************************************************
-EOF
-fi
-echo
-echo "Installer configuration complete.  Press Enter to begin"
-echo "or reboot your workstation now to abort installation."
-read r
-
-# Fetch secondary (real) installer, invoking as specified above:
-
-echo "Fetching next installer phase..."
-# Network config now done above.
-if [ "$test" != "test" ]; then
-  mkdir /h; cd /h
-  wget "http://debathena.mit.edu/net-install/kexec"
-  wget "http://debathena.mit.edu/net-install/${distro}/${arch}/initrd.gz"
-  wget "http://debathena.mit.edu/net-install/${distro}/${arch}/linux"
-  chmod 755 kexec
-fi
-dkargs="DEBCONF_DEBUG=5"
+# Unclear if needed, since we're talking to an existing
+# frontend already?
+db_version 2.0
 
-nodhcp="netcfg/disable_autoconfig=true"
-kbdcode="keyboard-configuration/layoutcode=us"
-distrobase=$(echo "$distro" | sed -e 's/-.*//')
-case "$distrobase" in
-    precise|trusty)
-	;;
-    *)
-	echo "I don't know how to preconfigure '$distrobase'"
-	while true; do
-	    echo "Enter the d-i configuration to select a keyboard layout"
-	    echo -n "or leave blank to prompt later: "
-	    read kbdcode
-	    echo "Enter the d-i configuration to disable dhcp"
-	    echo -n "(leaving it blank probably won't work): "
-	    read nodhcp
-	    echo
-	    echo "Will pass these kernel arguments:"
-	    echo "$kbdcode $nodhcp"
-	    echo -n "ok? [Y/n]"
-	    read answer
-	    case $answer in
-		[nN]*)
-		    ;;
-		*)
-		    break
-		    ;;
-	    esac
-	done
-        ;;
-esac
+# Load our template file
+db_x_loadtemplatefile $TEMPLATE_FILE $OWNER
+# in cdebconf (in d-i), this returns 0 even if loading fails,
+# because of course it does
+if [ $? -ne 0 ]; then
+  echo "Failed to load templates!" >&2
+  exit 1
+fi
 
-hname="$HOSTNAME"
-if [ "$IPADDR" = dhcp ] ; then
-  knetinfo="netcfg/get_hostname=$hname "
+arch=unknown
+# If archdetect exists (in d-i) it returns, e.g. amd64/generic
+if hash archdetect > /dev/null 2>&1; then
+  arch="$(archdetect | cut -d / -f 1)"
 else
-  # There's no good way to get a hostname here, but the postinstall will deal.
-  # True, but thanks to wget, there's a bad way to get a hostname
-  knetinfo="$nodhcp \
-netcfg/get_domain=mit.edu \
-netcfg/get_hostname=$hname \
-netcfg/get_nameservers=\"18.72.0.3 18.70.0.160 18.71.0.151\" \
-netcfg/get_ipaddress=$IPADDR \
-netcfg/get_netmask=$NETMASK \
-netcfg/get_gateway=$GATEWAY \
-netcfg/confirm_static=true"
+  case "$(uname -m)" in
+    x86_64)
+      arch=amd64;;
+    i[3-6]86)
+      arch=i386;;
+  esac
+fi
+if ! [ -x "$PREFIX/lib/host.$arch" ]; then
+  error "The installer was unable to locate its DNS helper."
+else
+  ln -s "$PREFIX/lib/host.$arch" "$PREFIX/lib/dahost"
+fi
+if ! [ -x "$PREFIX/lib/kexec" ]; then
+  error "The installer was unable to locate kexec."
 fi
+export PATH="$PREFIX/lib:$PATH"
 
-# SIGH  See LP #818933
-# This is fixed in Oneiric's kernel, but the PXE server is still serving
-# natty (and will continue to do so until we have hardware that fails)
-acpi=""
-if [ "$(cat /sys/class/dmi/id/product_name)" = "OptiPlex 790" ]; then
-    acpi="reboot=pci"
+if ! select_interface; then
+  error "Could not find an Ethernet interface to use."
 fi
 
-# TODO: Pass the actual interface we're using, not "auto"
-# Or decide that we only support the first interface, and determine
-# the name of it using the same method in stage2
-kargs="$knetinfo $kbdcode $acpi locale=en_US interface=auto \
-url=http://18.9.60.73/installer/$distro/debathena.preseed \
-da/pxe=$pxetype da/i=$installertype da/m=$mirrorsite \
-da/part=$partitioning $debugmode $extra_kargs --"
-
-echo "Continuing in five seconds..."
-if [ "$test" = "test" ]; then
-    echo "Would run kexec with these args:"
-    echo "$dkargs $kargs"
-    exit 0
+if test_uri "$NETWORK_TEST_URI"; then
+  ask use_dhcp critical
 fi
 
-if hash wc > /dev/null 2>&1; then
-    if [ $(echo "$dkargs $kargs" | wc -c) -gt 512 ]; then
-	echo "Kernel arguments exceed 512 bytes.  This will probably"
-	echo "end badly.  If this install fails, be sure to mention"
-	echo "this specific message in your bug report."
-    fi
+# TODO: Once apply_netconfig is idempotent, wrap this in a loop, and
+# allow the user to back up and try again if the mirror can't be contacted.
+config_network
+config_installer
+
+if ! test_uri "http://$mirror/ubuntu"; then
+  error "Cannot contact mirror: $mirror"
+fi
+
+nodhcp="netcfg/disable_autoconfig=true"
+kbdcode="keyboard-configuration/layoutcode=us"
+
+# Networking configuration
+# Hostname is always passed, because we might get one of the
+# broken DHCP addresses that doesn't reverse-resolve
+netcfg="netcfg/get_hostname=$(get hostname)"
+if [ "$(get use_dhcp)" != "true" ]; then
+  netcfg="$netcfg $nodhcp netcfg/get_domain=mit.edu \
+netcfg/get_nameservers=\"$NAMESERVERS\" \
+netcfg/get_ipaddress=$(get ipaddr) netcfg/get_netmask=$(get netmask) \
+netcfg/get_gateway=$(get gateway) netcfg/confirm_static=true"
 fi
 
-debug "About to run kexec with these args: $dkargs $kargs"
-./kexec -l linux --append="$dkargs $kargs" --initrd=initrd.gz \
-	  && sleep 3 && chvt 1 && sleep 2 && ./kexec -e
-curaddr="$(ip address show $ETH0 | grep inet | sed -e 's/^[ ]*inet //' | cut -d/ -f 1)"
-echo "Secondary installed failed; please contact release-team@mit.edu"
-echo "with the circumstances of your install attempt.  Here's a shell for debugging."
-echo "You can type 'httpd' to start an HTTP server which will make"
-echo "the system log available if you connect to http://$curaddr"
-# We don't want to let this fall through to an actual install of whatever
-# kernel we're using.
-while : ; do /bin/sh ; done
-exit 0
+# TODO: Pass the actual interface we're using, not "auto", once we figure out
+#       all the BOOTIF implications
+kargs="$netcfg $kbdcode locale=en_US interface=auto \
+url=http://18.9.60.73/installer/$distro/debathena.preseed \
+da/pxe=$metapackage da/i=$installer da/m=$mirror \
+da/part=$partitioning da/dbg=$stage2_debug $extra_kargs"
+
+# Download the stage 2 components
+# Why don't we just fetch these from the mirror, you ask?  Excellent
+# question.  With the HWE stacks, there is no deterministic way to say
+# "Give me the latest 12.04 installer".  You have to "know" that
+# 12.04.2 is quantal, 12.04.4 is saucy, etc.  So we'll continue to
+# use /net-install for now, because we can't have nice things.
+db_progress START 0 4 $OWNER/please_wait
+db_progress STEP 1
+swap downloading thing "stage 2 kernel"
+db_progress INFO $OWNER/downloading
+run rm -rf "$PREFIX/stage2"
+run mkdir "$PREFIX/stage2"
+run wget -q -P "$PREFIX/stage2" "http://debathena.mit.edu/net-install/$distro/$arch/linux"
+db_progress STEP 2
+swap downloading thing "stage 2 initrd"
+db_progress INFO $OWNER/downloading
+run wget -q -P "$PREFIX/stage2" "http://debathena.mit.edu/net-install/$distro/$arch/initrd.gz"
+db_progress STEP 3
+run kexec -l "$PREFIX/stage2/linux" --append="$kargs" --initrd="$PREFIX/stage2/initrd.gz"
+db_progress STEP 4
+db_progress STOP
+run kexec -e
+
+# If we got here, something above failed.
+error "The installer failed to load stage 2 of the installation."
+
+# This should never fall through, but...
+while true; do
+  echo "Fatal error."
+  read dummy
+done

home help back first fref pref prev next nref lref last post