first draft of a deployment-friendly bootmanager
authorThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Wed, 13 Jan 2010 16:52:45 +0000 (16:52 +0000)
committerThierry Parmentelat <thierry.parmentelat@sophia.inria.fr>
Wed, 13 Jan 2010 16:52:45 +0000 (16:52 +0000)
  attempt to make some sense of the various locations used
move the nodeconfig script, as well as the plc.d script,
  into bootmanager, where it belongs

Makefile
bootmanager.spec
build.sh
nodeconfig/boot/index.php [new file with mode: 0755]
plc.d/bootmanager [new file with mode: 0755]

index 7cb8a65..7769042 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,26 +2,42 @@
 # $Id: Makefile 682 2007-07-19 09:00:25Z thierry $
 #
 
-########## make sync PLCHOST=hostname
-########## make sync PLCHOST=hostname
+########## sync
+# 2 forms are supported
+# (*) if your plc root context has direct ssh access:
+# make sync PLC=private.one-lab.org
+# (*) otherwise, entering through the root context
+# make sync PLCHOST=testbox1.inria.fr GUEST=vplc03.inria.fr
+
+ifdef GUEST
 ifdef PLCHOST
-ifdef VSERVER
-PLCSSH:=root@$(PLCHOST):/vservers/$(VSERVER)
+SSHURL:=root@$(PLCHOST):/vservers/$(GUEST)
+SSHCOMMAND:=ssh root@$(PLCHOST) vserver $(GUEST)
+endif
 endif
+ifdef PLC
+SSHURL:=root@$(PLC):/
+SSHCOMMAND:=ssh root@$(PLC)
 endif
 
-LOCAL_RSYNC_EXCLUDES   := --exclude '*.pyc' --exclude debug_root_ssh_key
+LOCAL_RSYNC_EXCLUDES   := --exclude '*.pyc' 
 RSYNC_EXCLUDES         := --exclude .svn --exclude CVS --exclude '*~' --exclude TAGS $(LOCAL_RSYNC_EXCLUDES)
 RSYNC_COND_DRY_RUN     := $(if $(findstring n,$(MAKEFLAGS)),--dry-run,)
 RSYNC                  := rsync -a -v $(RSYNC_COND_DRY_RUN) $(RSYNC_EXCLUDES)
 
+DEPLOYMENT ?= regular
+
 sync:
-ifeq (,$(PLCSSH))
-       echo "sync: You must define PLCHOST and VSERVER on the command line"
-       echo " e.g. make sync PLCHOST=private.one-lab.org VSERVER=myplc01" ; exit 1
+ifeq (,$(SSHURL))
+       @echo "sync: You must define, either PLC, or PLCHOST & GUEST, on the command line"
+       @echo " you can optionnally define DEPLOYMENT too, it defaults to 'regular'"
+       @echo "  e.g. make sync PLC=boot.onelab.eu DEPLOYMENT=alpha"
+       @echo "  or   make sync PLCHOST=testbox1.inria.fr GUEST=vplc03.inria.fr"
+       @exit 1
 else
-       +$(RSYNC) source $(PLCSSH)/usr/share/bootmanager/
-       ssh root@$(PLCHOST) vserver $(VSERVER) exec service plc start bootmanager
+       $(SSHCOMMAND) mkdir -p /usr/share/bootmanager/$(DEPLOYMENT)
+       +$(RSYNC) build.sh source $(SSHURL)/usr/share/bootmanager/$(DEPLOYMENT)
+       $(SSHCOMMAND) service plc start bootmanager
 endif
 
 ##########
index cd56d51..8dc4eb5 100644 (file)
@@ -3,7 +3,9 @@
 #
 %define url $URL$
 
-%define name bootmanager
+%define nodefamily %{pldistro}-%{_arch}
+
+%define name bootmanager-%{nodefamily}
 %define version 4.3
 %define taglevel 16
 
@@ -22,13 +24,18 @@ License: BSD
 Group: System Environment/Base
 Source0: %{name}-%{version}.tar.gz
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
+BuildArch: noarch
 
 Requires: tar, gnupg, sharutils, bzip2, pypcilib
 Requires: PLCAPI >= 4.3
-
 # the python code packaged in these are shipped on the node as well
 Requires: pypcilib pyplnet monitor-runlevelagent
 
+# plc.d/bootmanager is moving
+Conflicts: myplc <= 4.3.37
+# nodeconfig/boot/index.php is moving
+Conflicts: nodeconfig <= 4.3.7
+
 AutoReqProv: no
 %define debug_package %{nil}
 
@@ -46,10 +53,18 @@ gcc -shared -fPIC -ldl -Os -o source/libc-opendir-hack.so source/libc-opendir-ha
 rm -rf $RPM_BUILD_ROOT
 
 # Install source so that it can be rebuilt
-find build.sh source | cpio -p -d -u $RPM_BUILD_ROOT/%{_datadir}/%{name}/
+find build.sh source | cpio -p -d -u $RPM_BUILD_ROOT/%{_datadir}/%{name}/regular/
+
+install -m 644 README  $RPM_BUILD_ROOT/%{_datadir}/%{name}/README
 
-touch bootmanager.sh
-install -D -m 755 bootmanager.sh $RPM_BUILD_ROOT/var/www/html/boot/bootmanager.sh
+# formerly in the nodeconfig module
+install -m 755 nodeconfig/boot/index.php $RPM_BUILD_ROOT/var/www/html/boot/index.php
+
+# formerly in the MyPLC module
+install -m 755 plc.d/bootmanager $RPM_BUILD_ROOT/etc/pld.c/bootmanager
+
+#touch bootmanager.sh
+#install -D -m 755 bootmanager.sh $RPM_BUILD_ROOT/var/www/html/boot/bootmanager.sh
 
 # This is only required for 2.x bootcds.
 install -D -m 644 support-files/uudecode.gz $RPM_BUILD_ROOT/var/www/html/boot/uudecode.gz
@@ -57,32 +72,21 @@ install -D -m 644 support-files/uudecode.gz $RPM_BUILD_ROOT/var/www/html/boot/uu
 %clean
 rm -rf $RPM_BUILD_ROOT
 
-# If run under sudo
-if [ -n "$SUDO_USER" ] ; then
-    # Allow user to delete the build directory
-    chown -h -R $SUDO_USER .
-    # Some temporary cdroot files like /var/empty/sshd and
-    # /usr/bin/sudo get created with non-readable permissions.
-    find . -not -perm +0600 -exec chmod u+rw {} \;
-    # Allow user to delete the built RPM(s)
-    chown -h -R $SUDO_USER %{_rpmdir}/%{_arch}
-fi
-
 %post
-cat <<EOF
-Remember to GPG sign /var/www/html/boot/bootmanager.sh with the
-PlanetLab private key.
-EOF
+# signing of botmanager.sh occurs as part of plc.d/bootmanager
 
 # NOTE: do not run this agent when installed on a myplc.
+# xxx - a bit hacky maybe
 chkconfig monitor-runlevelagent off
 chkconfig --del monitor-runlevelagent
 
 %files
 %defattr(-,root,root,-)
 %{_datadir}/%{name}
-%ghost /var/www/html/boot/bootmanager.sh
+/var/www/html/boot/index.php
+/etc/pld.c/bootmanager
 /var/www/html/boot/uudecode.gz
+#%ghost /var/www/html/boot/bootmanager.sh
 
 %changelog
 * Sat Jan 09 2010 Thierry Parmentelat <thierry.parmentelat@sophia.inria.fr> - BootManager-4.3-16
index 411111c..f9df9bc 100755 (executable)
--- a/build.sh
+++ b/build.sh
 # Copyright (C) 2004-2007 The Trustees of Princeton University
 #
 # $Id: build.sh,v 1.5 2006/04/03 19:40:55 mlhuang Exp $
+# $URL$
 #
 
 # Source PLC configuration
-if [ -f /etc/planetlab/plc_config ] ; then
-    . /etc/planetlab/plc_config
-else
-    PLC_BOOT_HOST=boot.planet-lab.org
-    PLC_API_HOST=www.planet-lab.org
-    PLC_API_PATH=PLCAPI
-fi
+. /etc/planetlab/plc_config
 
 # Do not tolerate errors
 set -e
 
-NODEGROUP=$1
+# this is set by plc.d/bootmanager
+DEPLOYMENT=$1
 
 BOOTSTRAPDIR="/boot"
-if [ -n "$NODEGROUP" ] ; then
-       BOOTSTRAPDIR="/boot/$NODEGROUP"
-fi
-
 
 # Change to our source directory
-srcdir=$(cd $(dirname $0) && pwd -P)
+cd $(dirname $0)
 
 # Translate configuration file
-sed -i -e "s|SUPPORT_FILE_DIR=.*|SUPPORT_FILE_DIR=$BOOTSTRAPDIR|" $srcdir/source/configuration
+sed -i -e "s|SUPPORT_FILE_DIR=.*|SUPPORT_FILE_DIR=$BOOTSTRAPDIR|" source/configuration
 
 # Source bootmanager configuration
 . $srcdir/source/configuration
 
-# Write boot script. plc_www/boot/index.php writes this script out
-# after a nonce check.
+# Write boot script. nodeconfig/boot/index.php retrieves the contents of this script
+# after checking the node id
+
+BMDIR=/var/www/html/bootmanager
+mkdir -p $BMDIR
+
+DEST_SCRIPT="$BMDIR/${DEPLOYMENT}_bootmanager.sh"
+# Remove the old version or any sym links prior to re-writing
+rm -f ${DEST_SCRIPT}
+rm -f ${DEST_SCRIPT}.sgn
+
+
+# hard code 443 here.
+sed -i -e "s@^BOOT_API_SERVER.*@BOOT_API_SERVER=https://$PLC_API_HOST:443/$PLC_API_PATH/@" source/configuration
+
+sed -i -e "s@^BOOT_SERVER.*@BOOT_SERVER=$PLC_BOOT_HOST@" source/configuration
+if [ "$PLC_MONITOR_ENABLED" = "1" ]; then
+    MONITOR_SERVER=$PLC_MONITOR_HOST
+else
+    MONITOR_SERVER=$PLC_BOOT_HOST
+fi
+sed -i -e "s@^MONITOR_SERVER.*@MONITOR_SERVER=$MONITOR_SERVER@" source/configuration
+
+install -D -m 644 $PLC_BOOT_CA_SSL_CRT source/cacert/$PLC_BOOT_HOST/cacert.pem
+if [ -f $PLC_MONITOR_CA_SSL_CRT ] ; then 
+       install -D -m 644 $PLC_MONITOR_CA_SSL_CRT source/cacert/$PLC_MONITOR_HOST/cacert.pem
+fi
 
-DEST_SCRIPT=bootmanager.sh
-if [ -n "$NODEGROUP" ] ; then
-       DEST_SCRIPT="${NODEGROUP}_bootmanager.sh"
-       # Remove the old version or any sym links prior to re-writing
-       rm -f ${DEST_SCRIPT}
-       rm -f ${DEST_SCRIPT}.sgn
+# Replace the default debug SSH key
+if [ -f "$PLC_DEBUG_SSH_KEY_PUB" ] ; then
+    install -D -m 644 "$PLC_DEBUG_SSH_KEY_PUB" source/debug_files/debug_root_ssh_key
 fi
 
-cat > $DEST_SCRIPT <<EOF
+# Add python code from the following packages
+# make sure they are in the 'Requires' header of the specfile
+required_rpms="pypcilib pyplnet monitor-runlevelagent"
+extra_libs=`mktemp -d "/tmp/.bootmanager.XXXXXX"`
+mkdir $extra_libs/source
+cp -p $(rpm -ql $required_rpms | grep -v '\.py[co]$') $extra_libs/source
+
+
+########## create the bootmanager script
+cat <<EOF > $DEST_SCRIPT
 #!/bin/bash
 #
 # PlanetLab Boot Manager $VERSION
@@ -74,52 +97,21 @@ if [ ! -x \$UUDECODE ]; then
   chmod +x \$UUDECODE
 fi
 
+($UUDECODE | /bin/tar -C /tmp -xj) << _EOF_
 EOF
 
-echo '($UUDECODE | /bin/tar -C /tmp -xj) << _EOF_' >> $DEST_SCRIPT
-
-# XXX Currently, the value of PLC_API_PORT is set to 80 by default, so
-# that the portions of the web site that still use oldapi can continue
-# to work. However, the Boot Manager supports HTTPS access, which we
-# want to remain the default, so hard code 443 here.
-sed -i -e "s@^BOOT_API_SERVER.*@BOOT_API_SERVER=https://$PLC_API_HOST:443/$PLC_API_PATH/@" \
-    $srcdir/source/configuration
-
-sed -i -e "s@^BOOT_SERVER.*@BOOT_SERVER=$PLC_BOOT_HOST@" $srcdir/source/configuration
-if [ "$PLC_MONITOR_ENABLED" = "1" ]; then
-    MONITOR_SERVER=$PLC_MONITOR_HOST
-else
-    MONITOR_SERVER=$PLC_BOOT_HOST
-fi
-sed -i -e "s@^MONITOR_SERVER.*@MONITOR_SERVER=$MONITOR_SERVER@" $srcdir/source/configuration
-
-install -D -m 644 $PLC_BOOT_CA_SSL_CRT $srcdir/source/cacert/$PLC_BOOT_HOST/cacert.pem
-if [ -f $PLC_MONITOR_CA_SSL_CRT ] ; then 
-       install -D -m 644 $PLC_MONITOR_CA_SSL_CRT $srcdir/source/cacert/$PLC_MONITOR_HOST/cacert.pem
-fi
-
-# Replace the default debug SSH key
-if [ -f "$PLC_DEBUG_SSH_KEY_PUB" ] ; then
-    install -D -m 644 "$PLC_DEBUG_SSH_KEY_PUB" $srcdir/source/debug_files/debug_root_ssh_key
-fi
-
-# Add python code from the following packages
-# make sure they are in the 'Requires' header of the specfile
-required_rpms="pypcilib pyplnet monitor-runlevelagent"
-extra_libs=`mktemp -d "/tmp/.bootmanager.XXXXXX"`
-mkdir $extra_libs/source
-cp -p $(rpm -ql $required_rpms | grep -v '\.py[co]$') $extra_libs/source
 
 # Embed the uuencoded tarball in the script
 tar -cj -C $srcdir source/ -C $extra_libs source/ | uuencode -m - >> $DEST_SCRIPT
 
-# Remove temp directory
-rm -fr $extra_libs
-
+# wrap up the script
 echo '_EOF_' >> $DEST_SCRIPT
 echo 'cd /tmp/source' >> $DEST_SCRIPT
 echo 'chmod +x BootManager.py && ./BootManager.py' >> $DEST_SCRIPT
 
+# Remove temp directory
+rm -fr $extra_libs
+
 # Sign the whole script, if the keyring is on this machine.
 if [ -f "$PLC_ROOT_GPG_KEY" -a -f "$PLC_ROOT_GPG_KEY_PUB" ] ; then
     gpg --homedir=/root \
@@ -131,3 +123,4 @@ if [ -f "$PLC_ROOT_GPG_KEY" -a -f "$PLC_ROOT_GPG_KEY_PUB" ] ; then
 else
     echo "Warning: Remember to sign $PWD/$DEST_SCRIPT!" >&2
 fi
+
diff --git a/nodeconfig/boot/index.php b/nodeconfig/boot/index.php
new file mode 100755 (executable)
index 0000000..81ec490
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+//
+// Returns node boot script
+//
+// Mark Huang <mlhuang@cs.princeton.edu>
+// Copyright (C) 2006 The Trustees of Princeton University
+//
+// $Id$ $
+//
+
+// Get admin API handle
+require_once 'plc_api.php';
+global $adm;
+
+// location for signed scripts
+$bmdir="/var/www/html/bootmanager";
+
+// Default bootmanager
+$bootmanager = "bootmanager.sh.sgn";
+
+// Look up the node
+$interfaces = $adm->GetInterfaces(array('ip' => $_SERVER['REMOTE_ADDR']));
+if (!empty($interfaces)) {
+  $nodes = $adm->GetNodes(array($interfaces[0]['node_id']));
+  if (!empty($nodes)) {
+    $node = $nodes[0];
+  }
+}
+
+if (isset($node)) {
+  // Allow very old nodes that do not have a node key in their
+  // configuration files to use their "boot nonce" instead. The boot
+  // nonce is a random value generated by the node itself and POSTed
+  // by the Boot CD when it requests the Boot Manager. This is
+  // obviously not very secure, so we only allow it to be used if the
+  // requestor IP is the same as the IP address we have on record for
+  // the node.
+
+  // 3.x CDs post 'version', 2.x CDs post 'id'.
+  if (!empty($_REQUEST['version'])) {
+    $version = trim($_REQUEST['version']);
+  } elseif (!empty($_REQUEST['id'])) {
+    $version = trim($_REQUEST['id']);
+  } else {
+    $version = "2.0";
+  }
+
+  if (empty($node['key']) && !empty($_REQUEST['nonce'])) {
+    // 3.x CDs post the boot nonce in ASCII hex. 2.x CDs post it in binary.
+    if (strstr($version, "2.0") === FALSE) {
+      // 3.x CDs post a trailing newline...sigh
+      $nonce = trim($_REQUEST['nonce']);
+    } else {
+      $nonce = bin2hex($_REQUEST['nonce']);
+    }
+    $adm->UpdateNode($node['node_id'], array('boot_nonce' => $nonce));
+  }
+
+  // Custom bootmanager for the node, e.g.
+  // planetlab-1.cs.princeton.edu_bootmanager.sh.sgn
+  $bootmanagers = array(strtolower($node['hostname']) . "_" . $bootmanager);
+
+  // Custom bootmanager for the deployment tag, e.g.
+
+  if (!empty($node['nodegroup_ids'])) {
+    $nodegroups = $adm->GetNodeDeployment($node['nodegroup_ids']);
+    foreach ($nodegroups as $nodegroup) {
+      $bootmanagers[] = strtolower($nodegroup['groupname']) . "_" . $bootmanager;
+    }
+  }
+}
+
+// Default bootmanager
+$bootmanagers[] = "regular_" . $bootmanager;
+
+foreach ($bootmanagers as $bootmanager) {
+  $candidate=$bmdir . "/" . $bootmanager;
+  if (file_exists($candidate)) {
+    readfile($candidate);
+    exit();
+  }
+}
+
+?>
diff --git a/plc.d/bootmanager b/plc.d/bootmanager
new file mode 100755 (executable)
index 0000000..19b6e03
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/bash
+#
+# priority: 1100
+#
+# Rebuild the Boot Manager
+#
+# Mark Huang <mlhuang@cs.princeton.edu>
+# Copyright (C) 2006 The Trustees of Princeton University
+#
+# $Id$
+#
+
+# Source function library and configuration
+. /etc/plc.d/functions
+. /etc/planetlab/plc_config
+
+# Be verbose
+set -x
+
+case "$1" in
+    start)
+       if [ "$PLC_BOOT_ENABLED" != "1" -a \
+            "$PLC_WWW_ENABLED" != "1" ] ; then
+           exit 0
+       fi
+
+       shopt -s nullglob
+       for topdir in /usr/share/bootmanager/* ; do
+           [ -d "$topdir" ] || continue
+           deployment=$(basename $topdir)
+           if [ "$deployment" = "regular" ] ; then
+               dialog $"Rebuilding Boot Manager"
+               $topdir/build.sh regular
+               check
+           else
+               dialog $"Rebuilding Boot Manager for deployment $deployment"
+               $topdir/build.sh $deployment
+               check
+           fi
+       done
+
+       result "$MESSAGE"
+       ;;
+esac
+
+exit $ERRORS