From f872afaa7976264819814d3e3289e020c0f77eae Mon Sep 17 00:00:00 2001 From: Mark Huang Date: Thu, 6 Apr 2006 21:51:59 +0000 Subject: [PATCH] - split up guest.init (/etc/init.d/plc inside the chroot) into separate steps installed in /etc/plc.d/ for scalability --- build.sh | 5 +- guest.init | 653 ++++------------------------------------------ plc.d/api | 40 +++ plc.d/bootcd | 36 +++ plc.d/bootmanager | 36 +++ plc.d/crond | 63 +++++ plc.d/functions | 93 +++++++ plc.d/gpg | 53 ++++ plc.d/httpd | 146 +++++++++++ plc.d/network | 43 +++ plc.d/postgresql | 126 +++++++++ plc.d/ssh | 53 ++++ plc.d/ssl | 118 +++++++++ plc.d/syslog | 41 +++ 14 files changed, 903 insertions(+), 603 deletions(-) create mode 100755 plc.d/api create mode 100755 plc.d/bootcd create mode 100755 plc.d/bootmanager create mode 100755 plc.d/crond create mode 100644 plc.d/functions create mode 100755 plc.d/gpg create mode 100755 plc.d/httpd create mode 100755 plc.d/network create mode 100755 plc.d/postgresql create mode 100755 plc.d/ssh create mode 100755 plc.d/ssl create mode 100755 plc.d/syslog diff --git a/build.sh b/build.sh index f0243e5..3b7a379 100755 --- a/build.sh +++ b/build.sh @@ -117,8 +117,9 @@ chroot $root sh -c 'cd /tmp; python plc_config.py build; python plc_config.py in install -D -m 755 plc-config $root/usr/bin/plc-config install -D -m 755 api-config $root/usr/bin/api-config -# Install init script -echo "* Installing initscript" +# Install initscripts +echo "* Installing initscripts" +find plc.d | cpio -p -d -u $root/etc/ install -D -m 755 guest.init $root/etc/init.d/plc chroot $root sh -c 'chkconfig --add plc; chkconfig plc on' diff --git a/guest.init b/guest.init index 9c22af3..48f21ba 100755 --- a/guest.init +++ b/guest.init @@ -6,52 +6,30 @@ # # description: Manages all PLC services on this machine # -# $Id: guest.init,v 1.11 2006/04/03 21:50:29 mlhuang Exp $ +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ # -PATH=/sbin:/bin:/usr/bin:/usr/sbin - -# Source function library. -. /etc/init.d/functions +# Source function library and configuration +. /etc/plc.d/functions # Verbosity verbose=0 -# Keep in order! All steps should be idempotent. This means that you -# should be able to run them multiple times without depending on -# anything previously being run. The idea is that when the -# configuration changes, "service plc restart" is called, all -# dependencies are fixed up, and everything just works. -steps=( -network -syslog -postgresql -ssl -gpg -ssh -apache -api -cron -bootcd -bootmanager -) +# All steps should be idempotent. This means that you should be able +# to run them multiple times without depending on anything previously +# being run. The idea is that when the configuration changes, "service +# plc restart" is called, all dependencies are fixed up, and +# everything just works. +steps=($( +for step in /etc/plc.d/* ; do + if [ -x $step ] ; then + priority=$(sed -ne 's/# priority: \(.*\)/\1/p' $step) + echo $priority $(basename $step) + fi +done | sort -n | cut -d' ' -f2 +)) nsteps=${#steps[@]} -# Total number of errors -ERRORS=0 - -# Count the exit status of the last command -check () -{ - ERRORS=$(($ERRORS+$?)) -} - -# Return IP address of hostname if resolvable -gethostbyname () -{ - perl -MSocket -e '($a,$b,$c,$d,@addrs) = gethostbyname($ARGV[0]); print inet_ntoa($addrs[0]) . "\n";' $1 2>/dev/null -} - # Regenerate configuration files reload () { @@ -71,7 +49,7 @@ reload () fi # Need to configure network before resolving hostnames - config_network start + /etc/plc.d/network start 3>/dev/null 4>/dev/null PLC_API_MAINTENANCE_SOURCES=$( for server in API BOOT WWW ; do @@ -151,544 +129,9 @@ define('PLANETLAB_SUPPORT_EMAIL_ONLY', PLC_MAIL_SUPPORT_ADDRESS); EOF } -config_network () -{ - case "$1" in - start) - # Minimal /etc/hosts - echo "127.0.0.1 localhost.localdomain localhost" >/etc/hosts - ( - for server in API BOOT WWW ; do - hostname=PLC_${server}_HOST - ip=$(gethostbyname ${!hostname}) - if [ -n "$ip" ] ; then - echo "$ip $hostname" - fi - done - ) >>/etc/hosts - - # Set up nameservers - ( - [ -n "$PLC_NET_DNS1" ] && echo "nameserver $PLC_NET_DNS1" - [ -n "$PLC_NET_DNS2" ] && echo "nameserver $PLC_NET_DNS2" - ) >/etc/resolv.conf - ;; - esac -} - -config_syslog () -{ - service syslog $1 - check -} - -config_postgresql () -{ - # Default locations - PGDATA=/var/lib/pgsql/data - postgresql_conf=$PGDATA/postgresql.conf - pghba_conf=$PGDATA/pg_hba.conf - - # Export so that we do not have to specify -p to psql invocations - export PGPORT=$PLC_DB_PORT - - case "$1" in - start) - if [ "$PLC_DB_ENABLED" != "1" ] ; then - return 0 - fi - - # Set data directory and redirect startup output to /var/log/pgsql - mkdir -p /etc/sysconfig/pgsql - ( - echo "PGDATA=$PGDATA" - echo "PGLOG=/var/log/pgsql" - echo "PGPORT=$PLC_DB_PORT" - ) >>/etc/sysconfig/pgsql/postgresql - - # Fix ownership (rpm installation may have changed it) - chown -R -H postgres:postgres $(dirname $PGDATA) - - # PostgreSQL must be started at least once to bootstrap - # /var/lib/pgsql/data - if [ ! -f $postgresql_conf ] ; then - service postgresql start - service postgresql stop - fi - - # Enable DB server. PostgreSQL >=8.0 defines listen_addresses, - # PostgreSQL 7.x uses tcpip_socket. - if grep -q listen_addresses $postgresql_conf ; then - sed -i -e '/^listen_addresses/d' $postgresql_conf - echo "listen_addresses = '*'" >>$postgresql_conf - elif grep -q tcpip_socket $postgresql_conf ; then - sed -i -e '/^tcpip_socket/d' $postgresql_conf - echo "tcpip_socket = true" >>$postgresql_conf - fi - - # Disable access to all DBs from all hosts - sed -i -e '/^\(host\|local\)/d' $pghba_conf - - # Enable passwordless localhost access - echo "local all all trust" >>$pghba_conf - - # Enable access from the API and web servers - PLC_API_IP=$(gethostbyname $PLC_API_HOST) - PLC_WWW_IP=$(gethostbyname $PLC_WWW_HOST) - ( - echo "host $PLC_DB_NAME $PLC_DB_USER $PLC_API_IP/32 password" - echo "host $PLC_DB_NAME $PLC_DB_USER $PLC_WWW_IP/32 password" - ) >>$pghba_conf - - # Fix ownership (sed -i changes it) - chown postgres:postgres $postgresql_conf $pghba_conf - - # Start up the server - service postgresql start - # /etc/init.d/postgresql always returns 0, even on failure - status postmaster && [ -f /var/lock/subsys/postgresql ] - check - - # Create/update the unprivileged database user and password - if ! psql -U $PLC_DB_USER -c "" template1 >/dev/null 2>&1 ; then - psql -U postgres -c "CREATE USER $PLC_DB_USER PASSWORD '$PLC_DB_PASSWORD'" template1 - else - psql -U postgres -c "ALTER USER $PLC_DB_USER WITH PASSWORD '$PLC_DB_PASSWORD'" template1 - fi - - # Create the database if necessary - if ! psql -U $PLC_DB_USER -c "" $PLC_DB_NAME >/dev/null 2>&1 ; then - createdb -U postgres $PLC_DB_NAME - psql -U $PLC_DB_USER -f /usr/share/pl_db/plc_schema_3.sql $PLC_DB_NAME - fi - ;; - - stop) - # Drop the current user in case the username changes - psql -U postgres -c "DROP USER $PLC_DB_USER" template1 - - # WARNING: If the DB name changes, the old DB will be left - # intact and a new one will be created. If it changes - # back, the old DB will not be re-created. - - # Shut down the server - service postgresql stop - check - ;; - esac -} - -# Generate GPG keys -config_gpg () -{ - case "$1" in - start) - # Generate GPG keyrings - if [ ! -f $PLC_ROOT_GPG_KEY_PUB -o ! -f $PLC_ROOT_GPG_KEY ] ; then - mkdir -p $(dirname $PLC_ROOT_GPG_KEY_PUB) - mkdir -p $(dirname $PLC_ROOT_GPG_KEY) - - # Temporarily replace /dev/random with /dev/urandom to - # avoid running out of entropy. - rm -f /dev/random - mknod /dev/random c 1 9 - gpg --homedir=/root --batch --gen-key <${!ssl_key} - check - chmod 600 ${!ssl_key} - fi - - # Check if self signed certificate is valid - if [ -f ${!ssl_crt} ] ; then - verify=$(openssl verify ${!ssl_crt}) - # If self signed - if grep -q "self signed certificate" <<<$verify ; then - # Delete if expired or hostname changed - if grep -q "expired" <<<$verify || \ - [ "$(ssl_cname ${!ssl_crt})" != "${!hostname}" ] ; then - rm -f ${!ssl_crt} - fi - else - echo "$verify" >&2 - fi - fi - - # Generate new self signed certificate - if [ ! -f ${!ssl_crt} ] ; then - mkdir -p $(dirname ${!ssl_crt}) - openssl req -new -x509 -days 365 -set_serial $RANDOM \ - -key ${!ssl_key} -out ${!ssl_crt} <$PLC_API_SSL_KEY_PUB - check - fi - - # Install into both /etc/pki (Fedora Core 4) and - # /etc/httpd/conf (Fedora Core 2). If the API, boot, and - # web servers are all running on the same machine, the web - # server certificate takes precedence. - for server in API BOOT WWW ; do - enabled=PLC_${server}_ENABLED - if [ "${!enabled}" != "1" ] ; then - continue - fi - ssl_key=PLC_${server}_SSL_KEY - ssl_crt=PLC_${server}_SSL_CRT - - symlink ${!ssl_crt} /etc/pki/tls/certs/localhost.crt - symlink ${!ssl_key} /etc/pki/tls/private/localhost.key - symlink ${!ssl_crt} /etc/httpd/conf/ssl.crt/server.crt - symlink ${!ssl_key} /etc/httpd/conf/ssl.key/server.key - done - ;; - esac -} - -# Generate SSH keys -config_ssh () -{ - # XXX Could make these configurable - KEY_TYPE_ROOT=rsa - KEY_LEN_ROOT=1024 - KEY_TYPE_DEBUG=rsa - KEY_LEN_DEBUG=2048 - - case "$1" in - start) - tmp=$(mktemp -d /tmp/ssh.XXXXXX) - - # Generate root SSH key - if [ ! -f $PLC_ROOT_SSH_KEY_PUB -o ! -f $PLC_ROOT_SSH_KEY ] ; then - ssh-keygen -N "" -C "$PLC_NAME Central <$PLC_MAIL_SUPPORT_ADDRESS>" \ - -b $KEY_LEN_ROOT -t $KEY_TYPE_ROOT -f $tmp/root - check - install -D -m 600 $tmp/root $PLC_ROOT_SSH_KEY - install -D -m 644 $tmp/root.pub $PLC_ROOT_SSH_KEY_PUB - fi - - # Generate debug SSH key - if [ ! -f $PLC_DEBUG_SSH_KEY_PUB -o ! -f $PLC_DEBUG_SSH_KEY ] ; then - ssh-keygen -N "" -C "$PLC_NAME Central <$PLC_MAIL_SUPPORT_ADDRESS>" \ - -b $KEY_LEN_DEBUG -t $KEY_TYPE_DEBUG -f $tmp/debug - check - install -D -m 600 $tmp/debug $PLC_DEBUG_SSH_KEY - install -D -m 644 $tmp/debug.pub $PLC_DEBUG_SSH_KEY_PUB - fi - - rm -rf $tmp - ;; - esac -} - -# Configure Apache web server -config_apache () -{ - # Default locations - DocumentRoot=/var/www/html - php_ini=/etc/php.ini - httpd_conf=/etc/httpd/conf/httpd.conf - ssl_conf=/etc/httpd/conf.d/ssl.conf - plc_conf=/etc/httpd/conf.d/plc.conf - - case "$1" in - start) - if [ "$PLC_API_ENABLED" != "1" -a \ - "$PLC_BOOT_ENABLED" != "1" -a \ - "$PLC_WWW_ENABLED" != "1" ] ; then - return 0 - fi - - # Set the default include path - include_path=".:$DocumentRoot/includes:$DocumentRoot/generated:/etc/planetlab/php" - sed -i -e "s@;include_path = \"\.:.*\"@include_path = \"$include_path\"@" $php_ini - - # Disable default Listen directive - sed -i -e '/^Listen/d' $httpd_conf - - # Set the port numbers - for server in WWW API BOOT ; do - enabled=PLC_${server}_ENABLED - if [ "${!enabled}" != "1" ] ; then - continue - fi - hostname=PLC_${server}_HOST - http_port=PLC_${server}_PORT - https_port=PLC_${server}_SSL_PORT - - # API should always be accessed via SSL - if [ "$server" = "API" ] ; then - https_port=${!http_port} - http_port= - fi - - # Check if we are already listening on these ports - skip_http=0 - skip_https=0 - for previous_server in WWW API BOOT ; do - if [ "$server" = "$previous_server" ] ; then - break - fi - previous_hostname=PLC_${previous_server}_HOST - previous_http_port=PLC_${previous_server}_PORT - previous_https_port=PLC_${previous_server}_SSL_PORT - - if [ "${!http_port}" = "${!previous_http_port}" ] ; then - skip_http=1 - fi - if [ "${!https_port}" = "${!previous_https_port}" ] ; then - skip_https=1 - fi - done - - # Listen on these ports - if [ $skip_http -eq 0 -a -n "${!http_port}" ] ; then - cat < - Redirect /db https://$PLC_WWW_HOST:$PLC_WWW_SSL_PORT/db - # XXX Not yet until we can get rid of oldapi - # Redirect /$PLC_API_PATH https://$PLC_API_HOST:$PLC_API_PORT/$PLC_API_PATH - -EOF - fi - if [ $skip_https -eq 0 -a -n "${!https_port}" ] ; then - # XXX Cannot support NameVirtualHost over SSL. If - # the API, boot, and web servers are all running - # on the same machine, the web server certificate - # takes precedence. - sed -i \ - -e "s/^Listen .*/Listen ${!https_port}/" \ - -e "s///" \ - $ssl_conf - fi - done >$plc_conf - - # Set custom Apache directives - ( - if [ "$PLC_API_ENABLED" = "1" ] ; then - cat < - SetHandler python-program - PythonPath "sys.path + ['/usr/share/plc_api']" - PythonHandler mod_pythonXMLRPC - -EOF - else - cat < - Deny from all - -EOF - fi - - if [ "$PLC_WWW_ENABLED" != "1" ] ; then - cat < - Deny from all - -EOF - fi - ) >>$plc_conf - - # Make alpina-logs directory writable for bootmanager log upload - chown apache:apache $DocumentRoot/alpina-logs/nodes - - service httpd start - check - ;; - - stop) - service httpd stop - check - ;; - esac -} - -config_api () -{ - case "$1" in - start) - if [ "$PLC_API_ENABLED" != "1" ] ; then - return - fi - - # Update the maintenance account username. This can't be - # done through the api-config script since it uses the - # maintenance account to access the API. The maintenance - # account should be person_id 1 since it is created by the - # DB schema itself. - psql -U $PLC_DB_USER -c "UPDATE persons SET email='$PLC_API_MAINTENANCE_USER' WHERE person_id=1" $PLC_DB_NAME - - # Bootstrap the DB - api-config - check - ;; - esac -} - -config_cron () -{ - case "$1" in - start) - if [ "$PLC_MAIL_ENABLED" = "1" ] ; then - MAILTO=$PLC_MAIL_SUPPORT_ADDRESS - else - MAILTO= - fi - cat >/etc/cron.d/plc.cron <>/var/log/boot.log + exec 2>>/var/log/boot.log +fi + +# Get command shift $(($OPTIND - 1)) if [ -z "$1" ] ; then usage fi +command=$1 -exec 3>&1 -exec 4>&2 -if [ $verbose -eq 0 ] ; then - exec 1>>/var/log/boot.log - exec 2>>/var/log/boot.log +# Get step(s) +shift 1 +if [ -z "$1" ] ; then + # Start or stop everything. Regenerate configuration first. + reload +else + # Start or stop a particular step + steps=("$@") + nsteps=${#steps[@]} fi -# Generate and load configuration -reload -. /etc/planetlab/plc_config - RETVAL=0 start () { for step in "${steps[@]}" ; do - echo -n $"PLC: Starting $step: " >&3 - RETVAL=$ERRORS - config_$step start - if [ $RETVAL -eq $ERRORS ] ; then - success $"PLC: $step startup" >&3 + if [ -x /etc/plc.d/$step ] ; then + /etc/plc.d/$step start else - failure $"PLC: $step startup" >&3 + echo "PLC: $step: unrecognized step" >&4 + exit 1 fi - echo >&3 done } @@ -750,21 +204,18 @@ stop () { for i in $(seq 1 $nsteps) ; do step=${steps[$(($nsteps - $i))]} - echo -n $"PLC: Shutting down $step: " >&3 - RETVAL=$ERRORS - config_$step stop - if [ $RETVAL -eq $ERRORS ] ; then - success $"PLC: $step shutdown" >&3 + if [ -x /etc/plc.d/$step ] ; then + /etc/plc.d/$step stop else - failure $"PLC: $step shutdown" >&3 + echo "PLC: $step: unrecognized step" >&4 + exit 1 fi - echo >&3 done } -case "$1" in +case "$command" in start|stop) - $1 + $command ;; restart) diff --git a/plc.d/api b/plc.d/api new file mode 100755 index 0000000..ab09812 --- /dev/null +++ b/plc.d/api @@ -0,0 +1,40 @@ +#!/bin/bash +# +# priority: 800 +# +# Bootstrap the database +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ +# + +# Source function library and configuration +. /etc/plc.d/functions + +case "$1" in + start) + if [ "$PLC_API_ENABLED" != "1" ] ; then + exit 0 + fi + + MESSAGE=$"Bootstrapping the database" + dialog "$MESSAGE" + + # Update the maintenance account username. This can't be + # done through the api-config script since it uses the + # maintenance account to access the API. The maintenance + # account should be person_id 1 since it is created by the + # DB schema itself. + psql -U $PLC_DB_USER -c "UPDATE persons SET email='$PLC_API_MAINTENANCE_USER' WHERE person_id=1" $PLC_DB_NAME + + # Bootstrap the DB + api-config + check + + result "$MESSAGE" + ;; +esac + +exit $ERRORS diff --git a/plc.d/bootcd b/plc.d/bootcd new file mode 100755 index 0000000..0a3c0a8 --- /dev/null +++ b/plc.d/bootcd @@ -0,0 +1,36 @@ +#!/bin/bash +# +# priority: 1000 +# +# Rebuild the Boot CD +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ +# + +# Source function library and configuration +. /etc/plc.d/functions + +case "$1" in + start) + if [ "$PLC_BOOT_ENABLED" != "1" -a \ + "$PLC_WWW_ENABLED" != "1" ] ; then + return 0 + fi + + MESSAGE=$"Rebuilding Boot CD" + dialog "$MESSAGE" + + # Customize the Boot CD + pushd /var/www/html/download + /usr/share/bootcd/build.sh + check + popd + + result "$MESSAGE" + ;; +esac + +exit $ERRORS diff --git a/plc.d/bootmanager b/plc.d/bootmanager new file mode 100755 index 0000000..e93cffa --- /dev/null +++ b/plc.d/bootmanager @@ -0,0 +1,36 @@ +#!/bin/bash +# +# priority: 1100 +# +# Rebuild the Boot Manager +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ +# + +# Source function library and configuration +. /etc/plc.d/functions + +case "$1" in + start) + if [ "$PLC_BOOT_ENABLED" != "1" -a \ + "$PLC_WWW_ENABLED" != "1" ] ; then + return 0 + fi + + MESSAGE=$"Rebuilding Boot Manager" + dialog "$MESSAGE" + + # Customize the Boot Manager + pushd /var/www/html/boot + /usr/share/bootmanager/build.sh + check + popd + + result "$MESSAGE" + ;; +esac + +exit $ERRORS diff --git a/plc.d/crond b/plc.d/crond new file mode 100755 index 0000000..67cfb3f --- /dev/null +++ b/plc.d/crond @@ -0,0 +1,63 @@ +#!/bin/bash +# +# priority: 900 +# +# Configure cron jobs +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ +# + +# Source function library and configuration +. /etc/plc.d/functions + +case "$1" in + start) + MESSAGE=$"Starting crond" + dialog "$MESSAGE" + + if [ "$PLC_MAIL_ENABLED" = "1" ] ; then + MAILTO=$PLC_MAIL_SUPPORT_ADDRESS + else + MAILTO= + fi + cat >/etc/cron.d/plc.cron < +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ +# + +export PATH=/sbin:/bin:/usr/bin:/usr/sbin + +# Source function library +. /etc/init.d/functions + +# Source configuration +. /etc/planetlab/plc_config + +# Total number of errors +ERRORS=0 + +# Count the exit status of the last command +check () +{ + ERRORS=$(($ERRORS+$?)) +} + +# Print status header +dialog () +{ + echo -n "PLC: $*: " >&3 +} + +# Print result +result () +{ + if [ $ERRORS -eq 0 ] ; then + success "$*" >&3 + else + failure "$*" >&3 + fi + echo >&3 +} + +# Start up a program with a plc_ prefix +plc_daemon () +{ + base=${1##*/} + + # See if it's already running. Look *only* at the pid file. + if [ -f /var/run/plc_${base}.pid ]; then + local line p + read line < /var/run/plc_${base}.pid + for p in $line ; do + [ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && pid="$pid $p" + done + fi + + [ -n "${pid:-}" -a -z "${force:-}" ] && return + + # And start it up. + (exec -a plc_${base} $*) + + if [ -f /var/run/${base}.pid ] ; then + mv /var/run/${base}.pid /var/run/plc_${base}.pid + fi +} + +# Print IP address of hostname if resolvable +gethostbyname () +{ + perl -MSocket -e '($a,$b,$c,$d,@addrs) = gethostbyname($ARGV[0]); print inet_ntoa($addrs[0]) . "\n";' $1 2>/dev/null +} + +# Print the CNAME of an SSL certificate +ssl_cname () +{ + openssl x509 -noout -in $1 -subject | \ + sed -n -e 's@.*/CN=\([^/]*\).*@\1@p' +} + +# Forcefully make a symlink +symlink () +{ + mkdir -p $(dirname $2) + rm -f $2 + ln -s $1 $2 +} + +# Make copies of stdout and stderr. The plc initscript redirects +# stdout and stderr to a logfile if -v is not specified. +[ ! -e /dev/fd/3 ] && exec 3>&1 +[ ! -e /dev/fd/4 ] && exec 4>&2 diff --git a/plc.d/gpg b/plc.d/gpg new file mode 100755 index 0000000..12b8d96 --- /dev/null +++ b/plc.d/gpg @@ -0,0 +1,53 @@ +#!/bin/bash +# +# priority: 500 +# +# Generate GPG keys +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ +# + +# Source function library and configuration +. /etc/plc.d/functions + +case "$1" in + start) + # Generate GPG keyrings + if [ ! -f $PLC_ROOT_GPG_KEY_PUB -o ! -f $PLC_ROOT_GPG_KEY ] ; then + MESSAGE=$"Generating GPG keys" + dialog "$MESSAGE" + + mkdir -p $(dirname $PLC_ROOT_GPG_KEY_PUB) + mkdir -p $(dirname $PLC_ROOT_GPG_KEY) + + # Temporarily replace /dev/random with /dev/urandom to + # avoid running out of entropy. + rm -f /dev/random + mknod /dev/random c 1 9 + gpg --homedir=/root --batch --gen-key < +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ +# + +# Source function library and configuration +. /etc/plc.d/functions + +# Default locations +DocumentRoot=/var/www/html +php_ini=/etc/php.ini +httpd_conf=/etc/httpd/conf/httpd.conf +ssl_conf=/etc/httpd/conf.d/ssl.conf +plc_conf=/etc/httpd/conf.d/plc.conf + +case "$1" in + start) + if [ "$PLC_API_ENABLED" != "1" -a \ + "$PLC_BOOT_ENABLED" != "1" -a \ + "$PLC_WWW_ENABLED" != "1" ] ; then + exit 0 + fi + + MESSAGE=$"Starting web server" + dialog "$MESSAGE" + + # Set the default include path + include_path=".:$DocumentRoot/includes:$DocumentRoot/generated:/etc/planetlab/php" + sed -i -e "s@;include_path = \"\.:.*\"@include_path = \"$include_path\"@" $php_ini + + # Disable default Listen directive + sed -i -e '/^Listen/d' $httpd_conf + + # Set the port numbers + for server in WWW API BOOT ; do + enabled=PLC_${server}_ENABLED + if [ "${!enabled}" != "1" ] ; then + continue + fi + hostname=PLC_${server}_HOST + http_port=PLC_${server}_PORT + https_port=PLC_${server}_SSL_PORT + + # API should always be accessed via SSL + if [ "$server" = "API" ] ; then + https_port=${!http_port} + http_port= + fi + + # Check if we are already listening on these ports + skip_http=0 + skip_https=0 + for previous_server in WWW API BOOT ; do + if [ "$server" = "$previous_server" ] ; then + break + fi + previous_hostname=PLC_${previous_server}_HOST + previous_http_port=PLC_${previous_server}_PORT + previous_https_port=PLC_${previous_server}_SSL_PORT + + if [ "${!http_port}" = "${!previous_http_port}" ] ; then + skip_http=1 + fi + if [ "${!https_port}" = "${!previous_https_port}" ] ; then + skip_https=1 + fi + done + + # Listen on these ports + if [ $skip_http -eq 0 -a -n "${!http_port}" ] ; then + cat < + Redirect /db https://$PLC_WWW_HOST:$PLC_WWW_SSL_PORT/db + # XXX Not yet until we can get rid of oldapi + # Redirect /$PLC_API_PATH https://$PLC_API_HOST:$PLC_API_PORT/$PLC_API_PATH + +EOF + fi + if [ $skip_https -eq 0 -a -n "${!https_port}" ] ; then + # XXX Cannot support NameVirtualHost over SSL. If + # the API, boot, and web servers are all running + # on the same machine, the web server certificate + # takes precedence. + sed -i \ + -e "s/^Listen .*/Listen ${!https_port}/" \ + -e "s///" \ + $ssl_conf + fi + done >$plc_conf + + # Set custom Apache directives + ( + if [ "$PLC_API_ENABLED" = "1" ] ; then + cat < + SetHandler python-program + PythonPath "sys.path + ['/usr/share/plc_api']" + PythonHandler mod_pythonXMLRPC + +EOF + else + cat < + Deny from all + +EOF + fi + + if [ "$PLC_WWW_ENABLED" != "1" ] ; then + cat < + Deny from all + +EOF + fi + ) >>$plc_conf + + # Make alpina-logs directory writable for bootmanager log upload + chown apache:apache $DocumentRoot/alpina-logs/nodes + + plc_daemon httpd + check + + result "$MESSAGE" + ;; + + stop) + MESSAGE=$"Stopping web server" + dialog "$MESSAGE" + + killproc plc_httpd + check + + result "$MESSAGE" + ;; +esac + +exit $ERRORS diff --git a/plc.d/network b/plc.d/network new file mode 100755 index 0000000..b412d18 --- /dev/null +++ b/plc.d/network @@ -0,0 +1,43 @@ +#!/bin/bash +# +# priority: 100 +# +# Manage network related configuration files +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ +# + +# Source function library and configuration +. /etc/plc.d/functions + +case "$1" in + start) + MESSAGE=$"Generating network files" + dialog "$MESSAGE" + + # Minimal /etc/hosts + echo "127.0.0.1 localhost.localdomain localhost" >/etc/hosts + ( + for server in API BOOT WWW ; do + hostname=PLC_${server}_HOST + ip=$(gethostbyname ${!hostname}) + if [ -n "$ip" ] ; then + echo "$ip $hostname" + fi + done + ) >>/etc/hosts + + # Set up nameservers + ( + [ -n "$PLC_NET_DNS1" ] && echo "nameserver $PLC_NET_DNS1" + [ -n "$PLC_NET_DNS2" ] && echo "nameserver $PLC_NET_DNS2" + ) >/etc/resolv.conf + + result "$MESSAGE" + ;; +esac + +exit $ERRORS diff --git a/plc.d/postgresql b/plc.d/postgresql new file mode 100755 index 0000000..2f46e3c --- /dev/null +++ b/plc.d/postgresql @@ -0,0 +1,126 @@ +#!/bin/bash +# +# priority: 300 +# +# Manage the PostgreSQL database server +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ +# + +# Source function library and configuration +. /etc/plc.d/functions + +# Default locations +PGDATA=/var/lib/pgsql/data +postgresql_conf=$PGDATA/postgresql.conf +pghba_conf=$PGDATA/pg_hba.conf + +# Export so that we do not have to specify -p to psql invocations +export PGPORT=$PLC_DB_PORT + +# /etc/init.d/postgresql always returns 0, even on failure +postgresql_start () +{ + service postgresql start + status postmaster && [ -f /var/lock/subsys/postgresql ] +} + +case "$1" in + start) + if [ "$PLC_DB_ENABLED" != "1" ] ; then + exit 0 + fi + + MESSAGE=$"Starting database server" + dialog "$MESSAGE" + + # Set data directory and redirect startup output to /var/log/pgsql + mkdir -p /etc/sysconfig/pgsql + ( + echo "PGDATA=$PGDATA" + echo "PGLOG=/var/log/pgsql" + echo "PGPORT=$PLC_DB_PORT" + ) >>/etc/sysconfig/pgsql/postgresql + + # Fix ownership (rpm installation may have changed it) + chown -R -H postgres:postgres $(dirname $PGDATA) + + # PostgreSQL must be started at least once to bootstrap + # /var/lib/pgsql/data + if [ ! -f $postgresql_conf ] ; then + postgresql_start + check + service postgresql stop + check + fi + + # Enable DB server. PostgreSQL >=8.0 defines listen_addresses, + # PostgreSQL 7.x uses tcpip_socket. + if grep -q listen_addresses $postgresql_conf ; then + sed -i -e '/^listen_addresses/d' $postgresql_conf + echo "listen_addresses = '*'" >>$postgresql_conf + elif grep -q tcpip_socket $postgresql_conf ; then + sed -i -e '/^tcpip_socket/d' $postgresql_conf + echo "tcpip_socket = true" >>$postgresql_conf + fi + + # Disable access to all DBs from all hosts + sed -i -e '/^\(host\|local\)/d' $pghba_conf + + # Enable passwordless localhost access + echo "local all all trust" >>$pghba_conf + + # Enable access from the API and web servers + PLC_API_IP=$(gethostbyname $PLC_API_HOST) + PLC_WWW_IP=$(gethostbyname $PLC_WWW_HOST) + ( + echo "host $PLC_DB_NAME $PLC_DB_USER $PLC_API_IP/32 password" + echo "host $PLC_DB_NAME $PLC_DB_USER $PLC_WWW_IP/32 password" + ) >>$pghba_conf + + # Fix ownership (sed -i changes it) + chown postgres:postgres $postgresql_conf $pghba_conf + + # Start up the server + postgresql_start + check + + # Create/update the unprivileged database user and password + if ! psql -U $PLC_DB_USER -c "" template1 >/dev/null 2>&1 ; then + psql -U postgres -c "CREATE USER $PLC_DB_USER PASSWORD '$PLC_DB_PASSWORD'" template1 + else + psql -U postgres -c "ALTER USER $PLC_DB_USER WITH PASSWORD '$PLC_DB_PASSWORD'" template1 + fi + + # Create the database if necessary + if ! psql -U $PLC_DB_USER -c "" $PLC_DB_NAME >/dev/null 2>&1 ; then + createdb -U postgres $PLC_DB_NAME + psql -U $PLC_DB_USER -f /usr/share/pl_db/plc_schema_3.sql $PLC_DB_NAME + fi + + result "$MESSAGE" + ;; + + stop) + MESSAGE=$"Stopping database server" + dialog "$MESSAGE" + + # Drop the current user in case the username changes + psql -U postgres -c "DROP USER $PLC_DB_USER" template1 + + # WARNING: If the DB name changes, the old DB will be left + # intact and a new one will be created. If it changes + # back, the old DB will not be re-created. + + # Shut down the server + service postgresql stop + check + + result "$MESSAGE" + ;; +esac + +exit $ERRORS diff --git a/plc.d/ssh b/plc.d/ssh new file mode 100755 index 0000000..1476cf1 --- /dev/null +++ b/plc.d/ssh @@ -0,0 +1,53 @@ +#!/bin/bash +# +# priority: 600 +# +# Generate SSH keys +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ +# + +# Source function library and configuration +. /etc/plc.d/functions + +# XXX Could make these configurable +KEY_TYPE_ROOT=rsa +KEY_LEN_ROOT=1024 +KEY_TYPE_DEBUG=rsa +KEY_LEN_DEBUG=2048 + +case "$1" in + start) + MESSAGE=$"Generating SSH keys" + dialog "$MESSAGE" + + tmp=$(mktemp -d /tmp/ssh.XXXXXX) + + # Generate root SSH key + if [ ! -f $PLC_ROOT_SSH_KEY_PUB -o ! -f $PLC_ROOT_SSH_KEY ] ; then + ssh-keygen -N "" -C "$PLC_NAME Central <$PLC_MAIL_SUPPORT_ADDRESS>" \ + -b $KEY_LEN_ROOT -t $KEY_TYPE_ROOT -f $tmp/root + check + install -D -m 600 $tmp/root $PLC_ROOT_SSH_KEY + install -D -m 644 $tmp/root.pub $PLC_ROOT_SSH_KEY_PUB + fi + + # Generate debug SSH key + if [ ! -f $PLC_DEBUG_SSH_KEY_PUB -o ! -f $PLC_DEBUG_SSH_KEY ] ; then + ssh-keygen -N "" -C "$PLC_NAME Central <$PLC_MAIL_SUPPORT_ADDRESS>" \ + -b $KEY_LEN_DEBUG -t $KEY_TYPE_DEBUG -f $tmp/debug + check + install -D -m 600 $tmp/debug $PLC_DEBUG_SSH_KEY + install -D -m 644 $tmp/debug.pub $PLC_DEBUG_SSH_KEY_PUB + fi + + rm -rf $tmp + + result "$MESSAGE" + ;; +esac + +exit $ERRORS diff --git a/plc.d/ssl b/plc.d/ssl new file mode 100755 index 0000000..c813f99 --- /dev/null +++ b/plc.d/ssl @@ -0,0 +1,118 @@ +#!/bin/bash +# +# priority: 400 +# +# Generate SSL certificates +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ +# + +# Source function library and configuration +. /etc/plc.d/functions + +case "$1" in + start) + MESSAGE=$"Generating SSL certificates" + dialog "$MESSAGE" + + # Generate self-signed SSL certificate(s). These nice + # commands come from the mod_ssl spec file for Fedora Core + # 2. We generate a certificate for each enabled server + # with a different hostname. These self-signed + # certificates may be overridden later. + for server in WWW API BOOT ; do + ssl_key=PLC_${server}_SSL_KEY + ssl_crt=PLC_${server}_SSL_CRT + hostname=PLC_${server}_HOST + + # Check if we have already generated a certificate for + # the same hostname. + for previous_server in WWW API BOOT ; do + if [ "$server" = "$previous_server" ] ; then + break + fi + previous_ssl_key=PLC_${previous_server}_SSL_KEY + previous_ssl_crt=PLC_${previous_server}_SSL_CRT + previous_hostname=PLC_${previous_server}_HOST + + if [ -f ${!previous_ssl_crt} ] && \ + [ "$(ssl_cname ${!previous_ssl_crt})" = "${!hostname}" ] ; then + cp -a ${!previous_ssl_key} ${!ssl_key} + cp -a ${!previous_ssl_crt} ${!ssl_crt} + break + fi + done + + # Generate new SSL private key + if [ ! -f ${!ssl_key} ] ; then + mkdir -p $(dirname ${!ssl_key}) + openssl genrsa -rand /proc/apm:/proc/cpuinfo:/proc/dma:/proc/filesystems:/proc/interrupts:/proc/ioports:/proc/pci:/proc/rtc:/proc/uptime 1024 >${!ssl_key} + check + chmod 600 ${!ssl_key} + fi + + # Check if self signed certificate is valid + if [ -f ${!ssl_crt} ] ; then + verify=$(openssl verify ${!ssl_crt}) + # If self signed + if grep -q "self signed certificate" <<<$verify ; then + # Delete if expired or hostname changed + if grep -q "expired" <<<$verify || \ + [ "$(ssl_cname ${!ssl_crt})" != "${!hostname}" ] ; then + rm -f ${!ssl_crt} + fi + else + echo "$verify" >&2 + fi + fi + + # Generate new self signed certificate + if [ ! -f ${!ssl_crt} ] ; then + mkdir -p $(dirname ${!ssl_crt}) + openssl req -new -x509 -days 365 -set_serial $RANDOM \ + -key ${!ssl_key} -out ${!ssl_crt} <$PLC_API_SSL_KEY_PUB + check + fi + + # Install into both /etc/pki (Fedora Core 4) and + # /etc/httpd/conf (Fedora Core 2). If the API, boot, and + # web servers are all running on the same machine, the web + # server certificate takes precedence. + for server in API BOOT WWW ; do + enabled=PLC_${server}_ENABLED + if [ "${!enabled}" != "1" ] ; then + continue + fi + ssl_key=PLC_${server}_SSL_KEY + ssl_crt=PLC_${server}_SSL_CRT + + symlink ${!ssl_crt} /etc/pki/tls/certs/localhost.crt + symlink ${!ssl_key} /etc/pki/tls/private/localhost.key + symlink ${!ssl_crt} /etc/httpd/conf/ssl.crt/server.crt + symlink ${!ssl_key} /etc/httpd/conf/ssl.key/server.key + done + + result "$MESSAGE" + ;; +esac + +exit $ERRORS diff --git a/plc.d/syslog b/plc.d/syslog new file mode 100755 index 0000000..fe3c1bd --- /dev/null +++ b/plc.d/syslog @@ -0,0 +1,41 @@ +#!/bin/bash +# +# priority: 200 +# +# Do not use the standard syslog initscript. It will start up a +# (probably duplicate) copy of klogd, and on shutdown, if a pidfile is +# not found, will (probably) kill the host syslogd and klogd instances +# as well. +# +# Mark Huang +# Copyright (C) 2006 The Trustees of Princeton University +# +# $Id: guest.init,v 1.12 2006/04/04 22:09:47 mlhuang Exp $ +# + +# Source function library and configuration +. /etc/plc.d/functions + +case "$1" in + start) + MESSAGE=$"Starting system logger" + dialog "$MESSAGE" + + plc_daemon syslogd -m 0 + check + + result "$MESSAGE" + ;; + + stop) + MESSAGE=$"Shutting down system logger" + dialog "$MESSAGE" + + killproc plc_syslogd + check + + result "$MESSAGE" + ;; +esac + +exit $ERRORS -- 2.45.2