3 # plc Manages all PLC services on this machine
7 # description: Manages all PLC services on this machine
9 # $Id: guest.init,v 1.8 2006/03/29 17:03:15 mlhuang Exp $
12 PATH=/sbin:/bin:/usr/bin:/usr/sbin
14 # Source function library.
15 . /etc/init.d/functions
20 # Keep in order! All steps should be idempotent. This means that you
21 # should be able to run them multiple times without depending on
22 # anything previously being run. The idea is that when the
23 # configuration changes, "service plc restart" is called, all
24 # dependencies are fixed up, and everything just works.
38 # Total number of errors
41 # Count the exit status of the last command
44 ERRORS=$(($ERRORS+$?))
47 # Return IP address of hostname if resolvable
50 perl -MSocket -e '($a,$b,$c,$d,@addrs) = gethostbyname($ARGV[0]); print inet_ntoa($addrs[0]) . "\n";' $1 2>/dev/null
53 # Regenerate configuration files
57 plc-config --shell >/etc/planetlab/plc_config
58 . /etc/planetlab/plc_config
60 # Generate various defaults
61 if [ -z "$PLC_DB_PASSWORD" ] ; then
62 PLC_DB_PASSWORD=$(uuidgen)
63 plc-config --category=plc_db --variable=password --value="$PLC_DB_PASSWORD" --save
66 if [ -z "$PLC_API_MAINTENANCE_PASSWORD" ] ; then
67 PLC_API_MAINTENANCE_PASSWORD=$(uuidgen)
68 plc-config --category=plc_api --variable=maintenance_password --value="$PLC_API_MAINTENANCE_PASSWORD" --save
71 # Need to configure network before resolving hostnames
74 PLC_API_MAINTENANCE_SOURCES=$(
75 for server in API BOOT WWW ; do
76 eval hostname=\${PLC_${server}_HOST}
77 gethostbyname $hostname
80 plc-config --category=plc_api --variable=maintenance_sources --value="$PLC_API_MAINTENANCE_SOURCES" --save
83 mkdir -p /etc/planetlab/php
84 plc-config --php >/etc/planetlab/php/plc_config.php
85 plc-config --shell >/etc/planetlab/plc_config
87 # For backward compatibility, until we can convert all code to use
88 # the now standardized variable names.
90 # DB constants are all named the same
91 ln -sf plc_config /etc/planetlab/plc_db
94 cat >/etc/planetlab/plc_api <<EOF
95 PL_API_SERVER='$PLC_API_HOST'
96 PL_API_PATH='$PLC_API_PATH'
97 PL_API_PORT=$PLC_API_PORT
98 PL_API_CAPABILITY_AUTH_METHOD='capability'
99 PL_API_CAPABILITY_PASS='$PLC_API_MAINTENANCE_PASSWORD'
100 PL_API_CAPABILITY_USERNAME='$PLC_API_MAINTENANCE_USER'
101 PL_API_TICKET_KEY_FILE='$PLC_API_SSL_KEY'
102 PLANETLAB_SUPPORT_EMAIL='$PLC_MAIL_SUPPORT_ADDRESS'
103 BOOT_MESSAGES_EMAIL='$PLC_MAIL_BOOT_ADDRESS'
104 WWW_BASE='$PLC_WWW_HOST'
105 BOOT_BASE='$PLC_BOOT_HOST'
110 # ip:max_role_id:organization_id:password
112 # It is unlikely that we will let federated sites use the
113 # maintenance account to access each others' APIs, so we always
114 # set organization_id to -1.
116 echo -n "PL_API_CAPABILITY_SOURCES='"
118 for ip in $PLC_API_MAINTENANCE_SOURCES ; do
119 if [ $first -ne 1 ] ; then
123 echo -n "$ip:-1:-1:$PLC_API_MAINTENANCE_PASSWORD"
126 ) >>/etc/planetlab/plc_api
128 cat >/etc/planetlab/php/site_constants.php <<"EOF"
130 include('plc_config.php');
132 DEFINE('PL_API_SERVER', PLC_API_HOST);
133 DEFINE('PL_API_PATH', PLC_API_PATH);
134 DEFINE('PL_API_PORT', PLC_API_PORT);
135 DEFINE('PL_API_CAPABILITY_AUTH_METHOD', 'capability');
136 DEFINE('PL_API_CAPABILITY_PASS', PLC_API_MAINTENANCE_PASSWORD);
137 DEFINE('PL_API_CAPABILITY_USERNAME', PLC_API_MAINTENANCE_USER);
138 DEFINE('WWW_BASE', PLC_WWW_HOST);
139 DEFINE('BOOT_BASE', PLC_BOOT_HOST);
140 DEFINE('DEBUG', PLC_WWW_DEBUG);
141 DEFINE('API_CALL_DEBUG', PLC_API_DEBUG);
142 DEFINE('SENDMAIL', PLC_MAIL_ENABLED);
143 DEFINE('PLANETLAB_SUPPORT_EMAIL', PLC_NAME . 'Support <' . PLC_MAIL_SUPPORT_ADDRESS . '>');
144 DEFINE('PLANETLAB_SUPPORT_EMAIL_ONLY', PLC_MAIL_SUPPORT_ADDRESS);
154 echo "127.0.0.1 localhost.localdomain localhost" >/etc/hosts
156 for server in API BOOT WWW ; do
157 eval hostname=\${PLC_${server}_HOST}
158 ip=$(gethostbyname $hostname)
159 if [ -n "$ip" ] ; then
167 [ -n "$PLC_NET_DNS1" ] && echo "nameserver $PLC_NET_DNS1"
168 [ -n "$PLC_NET_DNS2" ] && echo "nameserver $PLC_NET_DNS2"
183 PGDATA=/var/lib/pgsql/data
184 postgresql_conf=$PGDATA/postgresql.conf
185 pghba_conf=$PGDATA/pg_hba.conf
187 # Export so that we do not have to specify -p to psql invocations
188 export PGPORT=$PLC_DB_PORT
192 if [ "$PLC_DB_ENABLED" != "1" ] ; then
196 # Set data directory and redirect startup output to /var/log/pgsql
197 mkdir -p /etc/sysconfig/pgsql
199 echo "PGDATA=$PGDATA"
200 echo "PGLOG=/var/log/pgsql"
201 echo "PGPORT=$PLC_DB_PORT"
202 ) >>/etc/sysconfig/pgsql/postgresql
204 # Fix ownership (rpm installation may have changed it)
205 chown -R -H postgres:postgres $(dirname $PGDATA)
207 # PostgreSQL must be started at least once to bootstrap
208 # /var/lib/pgsql/data
209 if [ ! -f $postgresql_conf ] ; then
210 service postgresql start
211 service postgresql stop
214 # Enable DB server. PostgreSQL >=8.0 defines listen_addresses,
215 # PostgreSQL 7.x uses tcpip_socket.
216 if grep -q listen_addresses $postgresql_conf ; then
217 sed -i -e '/^listen_addresses/d' $postgresql_conf
218 echo "listen_addresses = '*'" >>$postgresql_conf
219 elif grep -q tcpip_socket $postgresql_conf ; then
220 sed -i -e '/^tcpip_socket/d' $postgresql_conf
221 echo "tcpip_socket = true" >>$postgresql_conf
224 # Disable access to all DBs from all hosts
225 sed -i -e '/^\(host\|local\)/d' $pghba_conf
227 # Enable passwordless localhost access
228 echo "local all all trust" >>$pghba_conf
230 # Enable access from the API and web servers
231 PLC_API_IP=$(gethostbyname $PLC_API_HOST)
232 PLC_WWW_IP=$(gethostbyname $PLC_WWW_HOST)
234 echo "host $PLC_DB_NAME $PLC_DB_USER $PLC_API_IP/32 password"
235 echo "host $PLC_DB_NAME $PLC_DB_USER $PLC_WWW_IP/32 password"
238 # Fix ownership (sed -i changes it)
239 chown postgres:postgres $postgresql_conf $pghba_conf
241 # Start up the server
242 service postgresql start
243 # /etc/init.d/postgresql always returns 0, even on failure
244 status postmaster && [ -f /var/lock/subsys/postgresql ]
247 # Create/update the unprivileged database user and password
248 if ! psql -U $PLC_DB_USER -c "" template1 >/dev/null 2>&1 ; then
249 psql -U postgres -c "CREATE USER $PLC_DB_USER PASSWORD '$PLC_DB_PASSWORD'" template1
251 psql -U postgres -c "ALTER USER $PLC_DB_USER WITH PASSWORD '$PLC_DB_PASSWORD'" template1
254 # Create the database if necessary
255 if ! psql -U $PLC_DB_USER -c "" $PLC_DB_NAME >/dev/null 2>&1 ; then
256 createdb -U postgres $PLC_DB_NAME
257 psql -U $PLC_DB_USER -f /usr/share/pl_db/plc_schema_3.sql $PLC_DB_NAME
262 # Drop the current user in case the username changes
263 psql -U postgres -c "DROP USER $PLC_DB_USER" template1
265 # WARNING: If the DB name changes, the old DB will be left
266 # intact and a new one will be created. If it changes
267 # back, the old DB will not be re-created.
269 # Shut down the server
270 service postgresql stop
281 # Generate GPG keyrings
282 if [ ! -f $PLC_ROOT_GPG_KEY_PUB -o ! -f $PLC_ROOT_GPG_KEY ] ; then
283 mkdir -p $(dirname $PLC_ROOT_GPG_KEY_PUB)
284 mkdir -p $(dirname $PLC_ROOT_GPG_KEY)
286 # Temporarily replace /dev/random with /dev/urandom to
287 # avoid running out of entropy.
289 mknod /dev/random c 1 9
290 gpg --homedir=/root --batch --gen-key <<EOF
295 Name-Real: $PLC_NAME Central
296 Name-Comment: http://$PLC_WWW_HOST/
297 Name-Email: $PLC_MAIL_SUPPORT_ADDRESS
299 %pubring $PLC_ROOT_GPG_KEY_PUB
300 %secring $PLC_ROOT_GPG_KEY
305 mknod /dev/random c 1 8
306 chmod 600 $PLC_ROOT_GPG_KEY_PUB $PLC_ROOT_GPG_KEY
314 mkdir -p $(dirname $2)
319 # Generate SSL certificates
324 # Generate a self-signed SSL certificate. These nice
325 # commands came from the mod_ssl spec file for Fedora Core
326 # 2. We generate only a single certificate for the web
327 # server, then make copies for the API and boot
328 # servers. As always, these certificates may be overridden
331 # Generate SSL private key
332 if [ ! -f $PLC_WWW_SSL_KEY ] ; then
333 mkdir -p $(dirname $PLC_WWW_SSL_KEY)
334 openssl genrsa -rand /proc/apm:/proc/cpuinfo:/proc/dma:/proc/filesystems:/proc/interrupts:/proc/ioports:/proc/pci:/proc/rtc:/proc/uptime 1024 >$PLC_WWW_SSL_KEY
336 chmod 600 $PLC_WWW_SSL_KEY
339 # Generate self-signed certificate
340 if [ ! -f $PLC_WWW_SSL_CRT ] ; then
341 mkdir -p $(dirname $PLC_WWW_SSL_CRT)
342 openssl req -new -x509 -days 365 -set_serial $RANDOM \
343 -key $PLC_WWW_SSL_KEY -out $PLC_WWW_SSL_CRT <<EOF
350 $PLC_MAIL_SUPPORT_ADDRESS
353 chmod 644 $PLC_WWW_SSL_CRT
356 # Make copies for the API and boot servers
357 if [ ! -f $PLC_API_SSL_KEY ] ; then
358 cp -a $PLC_WWW_SSL_KEY $PLC_API_SSL_KEY
360 if [ ! -f $PLC_API_SSL_KEY_PUB ] ; then
361 openssl rsa -pubout <$PLC_API_SSL_KEY >$PLC_API_SSL_KEY_PUB
364 if [ ! -f $PLC_API_SSL_CRT ] ; then
365 cp -a $PLC_WWW_SSL_CRT $PLC_API_SSL_CRT
367 if [ ! -f $PLC_BOOT_SSL_KEY ] ; then
368 cp -a $PLC_WWW_SSL_KEY $PLC_BOOT_SSL_KEY
370 if [ ! -f $PLC_BOOT_SSL_CRT ] ; then
371 cp -a $PLC_WWW_SSL_CRT $PLC_BOOT_SSL_CRT
374 # Install into both /etc/pki (Fedora Core 4) and
375 # /etc/httpd/conf (Fedora Core 2). If the API, boot, and
376 # web servers are all running on the same machine, the web
377 # server certificate takes precedence.
378 for server in API BOOT WWW ; do
379 eval enabled=\${PLC_${server}_ENABLED}
380 if [ "$enabled" != "1" ] ; then
383 eval ssl_crt=\${PLC_${server}_SSL_CRT}
384 eval ssl_key=\${PLC_${server}_SSL_KEY}
386 symlink $ssl_crt /etc/pki/tls/certs/localhost.crt
387 symlink $ssl_key /etc/pki/tls/private/localhost.key
388 symlink $ssl_crt /etc/httpd/conf/ssl.crt/server.crt
389 symlink $ssl_key /etc/httpd/conf/ssl.key/server.key
398 # XXX Could make these configurable
406 tmp=$(mktemp -d /tmp/ssh.XXXXXX)
408 # Generate root SSH key
409 if [ ! -f $PLC_ROOT_SSH_KEY_PUB -o ! -f $PLC_ROOT_SSH_KEY ] ; then
410 ssh-keygen -N "" -C "$PLC_NAME Central <$PLC_MAIL_SUPPORT_ADDRESS>" \
411 -b $KEY_LEN_ROOT -t $KEY_TYPE_ROOT -f $tmp/root
413 install -D -m 600 $tmp/root $PLC_ROOT_SSH_KEY
414 install -D -m 600 $tmp/root.pub $PLC_ROOT_SSH_KEY_PUB
417 # Generate debug SSH key
418 if [ ! -f $PLC_DEBUG_SSH_KEY_PUB -o ! -f $PLC_DEBUG_SSH_KEY ] ; then
419 ssh-keygen -N "" -C "$PLC_NAME Central <$PLC_MAIL_SUPPORT_ADDRESS>" \
420 -b $KEY_LEN_DEBUG -t $KEY_TYPE_DEBUG -f $tmp/debug
422 install -D -m 600 $tmp/debug $PLC_DEBUG_SSH_KEY
423 install -D -m 600 $tmp/debug.pub $PLC_DEBUG_SSH_KEY_PUB
431 # Configure Apache web server
435 DocumentRoot=/var/www/html
437 httpd_conf=/etc/httpd/conf/httpd.conf
438 ssl_conf=/etc/httpd/conf.d/ssl.conf
439 plc_conf=/etc/httpd/conf.d/plc.conf
443 if [ "$PLC_API_ENABLED" != "1" -a \
444 "$PLC_BOOT_ENABLED" != "1" -a \
445 "$PLC_WWW_ENABLED" != "1" ] ; then
449 # Set the default include path
450 include_path=".:$DocumentRoot/includes:$DocumentRoot/generated:/etc/planetlab/php"
451 sed -i -e "s@;include_path = \"\.:.*\"@include_path = \"$include_path\"@" $php_ini
453 # Set the port numbers. If the API, boot, and web servers
454 # are all running on the same machine, the web server port
455 # numbers take precedence.
456 for server in API BOOT WWW ; do
457 eval enabled=\${PLC_${server}_ENABLED}
458 if [ "$enabled" != "1" ] ; then
461 eval http_port=\${PLC_${server}_PORT}
462 eval https_port=\${PLC_${server}_SSL_PORT}
464 if [ -n "$http_port" ] ; then
465 sed -i -e "s/^Listen .*/Listen $http_port/" $httpd_conf
467 if [ -n "$https_port" ] ; then
469 -e "s/^Listen .*/Listen $https_port/" \
470 -e "s/<VirtualHost _default_:.*>/<VirtualHost _default_:$https_port>/" \
475 # Set custom Apache directives
477 if [ "$PLC_API_ENABLED" = "1" ] ; then
478 # XXX We should only support non-SSL access to the
479 # API by writing this to conf.d/plc_ssl.conf, then
480 # writing "Include conf.d/plc_ssl.conf" to
481 # conf.d/ssl.conf. Once oldapi, which does not
482 # support SSL, is removed from the web pages, we
485 <Location $PLC_API_PATH>
486 SetHandler python-program
487 PythonPath "sys.path + ['/usr/share/plc_api']"
488 PythonHandler mod_pythonXMLRPC
493 if [ "$PLC_WWW_ENABLED" = "1" ] ; then
495 <VirtualHost *:$PLC_WWW_PORT>
496 Redirect /db https://$PLC_WWW_HOST:$PLC_WWW_SSL_PORT/db
508 # Make alpina-logs directory writable for bootmanager log upload
509 chown apache:apache $DocumentRoot/alpina-logs/nodes
526 if [ "$PLC_API_ENABLED" != "1" ] ; then
530 # Update the maintenance account username. This can't be
531 # done through the api-config script since it uses the
532 # maintenance account to access the API. The maintenance
533 # account should be person_id 1 since it is created by the
535 psql -U $PLC_DB_USER -c "UPDATE persons SET email='$PLC_API_MAINTENANCE_USER' WHERE person_id=1" $PLC_DB_NAME
548 if [ "$PLC_MAIL_ENABLED" = "1" ] ; then
549 MAILTO=$PLC_MAIL_SUPPORT_ADDRESS
553 cat >/etc/cron.d/plc.cron <<EOF
555 PATH=/sbin:/bin:/usr/sbin:/usr/bin
559 # minute hour day-of-month month day-of-week user command
560 */5 * * * * root gen-slices-xml-05.py
561 */15 * * * * root gen-sites-xml.py
562 */15 * * * * root gen-static-content.py
565 # Run them once at startup
570 gen-static-content.py
586 echo "Usage: $0 [OPTION]... [COMMAND]"
587 echo " -v Be verbose"
588 echo " -h This message"
591 echo " start Start all PLC subsystems"
592 echo " stop Stop all PLC subsystems"
593 echo " reload Regenerate configuration files"
594 echo " restart Restart all PLC subsystems"
599 while getopts "vh" opt ; do
611 shift $(($OPTIND - 1))
612 if [ -z "$1" ] ; then
618 if [ $verbose -eq 0 ] ; then
619 exec 1>>/var/log/boot.log
620 exec 2>>/var/log/boot.log
623 # Generate and load configuration
625 . /etc/planetlab/plc_config
631 for step in "${steps[@]}" ; do
632 echo -n $"PLC: Starting $step: " >&3
635 if [ $RETVAL -eq $ERRORS ] ; then
636 success $"PLC: $step startup" >&3
638 failure $"PLC: $step startup" >&3
646 for i in $(seq 1 $nsteps) ; do
647 step=${steps[$(($nsteps - $i))]}
648 echo -n $"PLC: Shutting down $step: " >&3
651 if [ $RETVAL -eq $ERRORS ] ; then
652 success $"PLC: $step shutdown" >&3
654 failure $"PLC: $step shutdown" >&3