* Improved Upstart job handling in switch-to-configuration. It no
longer compares the current configuration to the previous configuration, but instead compares the current Upstart state to the intended state. Thus, if the switch script is interrupted, running nixos-rebuild again will resume starting/stopping Upstart jobs where the previous run left off. We determine if an Upstart job has changed by having the pre-start script of each Upstart job put a symlink to its .conf file in /var/run/upstart-jobs. So if this symlink differs from the target of /etc/init/<job>.conf, then the job has changed. This also prevents multiple restarts of dependent jobs. E.g., if job B has "start on started A" and "stop on stopping A", then restarting A will cause B to be restarted, so B shouldn't B restarted a second time. We only start jobs that are not running if 1) they're tasks that have been previously run (like mountall); or 2) they're jobs that have a "start on" condition. This seems a reasonable heuristic. svn path=/nixos/trunk/; revision=33222
This commit is contained in:
parent
5a98d6d514
commit
3495a773f9
|
@ -109,6 +109,11 @@ in
|
|||
mkdir -m 0755 -p /var/run/nix/current-load # for distributed builds
|
||||
mkdir -m 0700 -p /var/run/nix/remote-stores
|
||||
|
||||
# Directory holding symlinks to currently running Upstart
|
||||
# jobs. Used to determine which jobs need to be restarted
|
||||
# when switching to a new configuration.
|
||||
mkdir -m 0700 -p /var/run/upstart-jobs
|
||||
|
||||
mkdir -m 0755 -p /var/log
|
||||
mkdir -m 0755 -p /var/log/upstart
|
||||
|
||||
|
|
|
@ -62,75 +62,95 @@ if [ "$action" = "switch" -o "$action" = "boot" ]; then
|
|||
fi
|
||||
|
||||
# Activate the new configuration.
|
||||
if [ "$action" = "switch" -o "$action" = "test" ]; then
|
||||
if [ "$action" != switch -a "$action" != test ]; then exit 0; fi
|
||||
|
||||
oldVersion=$(cat /var/run/current-system/upstart-interface-version 2> /dev/null || echo 0)
|
||||
newVersion=$(cat @out@/upstart-interface-version 2> /dev/null || echo 0)
|
||||
oldVersion=$(cat /var/run/current-system/upstart-interface-version 2> /dev/null || echo 0)
|
||||
newVersion=$(cat @out@/upstart-interface-version 2> /dev/null || echo 0)
|
||||
|
||||
if test "$oldVersion" -ne "$newVersion"; then
|
||||
if test "$oldVersion" -ne "$newVersion"; then
|
||||
cat <<EOF
|
||||
Warning: the new NixOS configuration has an Upstart version that is
|
||||
incompatible with the current version. The new configuration won't
|
||||
take effect until you reboot the system.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
oldJobs=$(readlink -f /etc/static/init)
|
||||
newJobs=$(readlink -f @out@/etc/init)
|
||||
|
||||
stopJob() {
|
||||
local job=$1
|
||||
initctl stop "$job" || true
|
||||
}
|
||||
|
||||
# Stop all services that are not in the new Upstart
|
||||
# configuration.
|
||||
for job in $(cd $oldJobs && ls *.conf); do
|
||||
job=$(basename $job .conf)
|
||||
if ! test -e "$newJobs/$job.conf"; then
|
||||
echo "stopping $job..."
|
||||
stopJob $job
|
||||
fi
|
||||
done
|
||||
|
||||
# Activate the new configuration (i.e., update /etc, make
|
||||
# accounts, and so on).
|
||||
echo "activating the configuration..."
|
||||
@out@/activate @out@
|
||||
|
||||
# Make Upstart reload its jobs.
|
||||
initctl reload-configuration
|
||||
|
||||
# Start all new services and restart all changed services.
|
||||
for job in $(cd $newJobs && ls *.conf); do
|
||||
|
||||
job=$(basename $job .conf)
|
||||
|
||||
# Hack: skip the shutdown and control-alt-delete jobs.
|
||||
# Another hack: don't restart the X server (that would kill all the clients).
|
||||
# And don't restart dbus, since that causes ConsoleKit to
|
||||
# forget about current sessions.
|
||||
# Idem for the emergeny-shell, because its `console owner'
|
||||
# line screws up the X server.
|
||||
# Idem for xendomains because we don't want to save/restore
|
||||
# Xen domains unless we have to.
|
||||
# TODO: Jobs should be able to declare that they should not be
|
||||
# auto-restarted.
|
||||
if echo "$job" | grep -q "^shutdown$\|^control-alt-delete$\|^xserver$\|^dbus$\|^disnix$\|^emergency-shell$\|^xendomains$\|^udevtrigger$\|^drbd-down$"; then continue; fi
|
||||
|
||||
if ! test -e "$oldJobs/$job.conf"; then
|
||||
echo "starting $job..."
|
||||
initctl start "$job" || true
|
||||
elif test "$(readlink "$oldJobs/$job.conf")" != "$(readlink "$newJobs/$job.conf")"; then
|
||||
echo "restarting $job..."
|
||||
stopJob $job
|
||||
initctl start "$job" || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Signal dbus to reload its configuration.
|
||||
dbusPid=$(initctl status dbus 2> /dev/null | sed -e 's/.*process \([0-9]\+\)/\1/;t;d')
|
||||
[ -n "$dbusPid" ] && kill -HUP "$dbusPid"
|
||||
|
||||
fi
|
||||
|
||||
newJobs=$(readlink -f @out@/etc/init)
|
||||
|
||||
# Stop all currently running jobs that are not in the new Upstart
|
||||
# configuration. (Here "running" means all jobs that are not in the
|
||||
# stop/waiting state.)
|
||||
for job in $(initctl list | sed -e '/ stop\/waiting/ d; /^[^a-z]/ d; s/^\([^ ]\+\).*/\1/' | sort); do
|
||||
if ! [ -e "$newJobs/$job.conf" ] ; then
|
||||
echo "stopping obsolete job ‘$job’..."
|
||||
initctl stop "$job" || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Activate the new configuration (i.e., update /etc, make accounts,
|
||||
# and so on).
|
||||
echo "activating the configuration..."
|
||||
@out@/activate @out@
|
||||
|
||||
# Make Upstart reload its jobs.
|
||||
initctl reload-configuration
|
||||
|
||||
# Allow Upstart jobs to react intelligently to a config change.
|
||||
initctl emit config-changed
|
||||
|
||||
# Restart all running jobs that have changed. (Here "running" means
|
||||
# all jobs that don't have a "stop" goal.) We use the symlinks in
|
||||
# /var/run/upstart-jobs (created by each job's pre-start script) to
|
||||
# determine if a job has changed.
|
||||
for job in $(cd $newJobs && ls *.conf); do
|
||||
job=$(basename $job .conf)
|
||||
status=$(status "$job")
|
||||
if ! [[ "$status" =~ start/ ]]; then continue; fi
|
||||
if [ "$(readlink -f "$newJobs/$job.conf")" = "$(readlink -f "/var/run/upstart-jobs/$job")" ]; then continue; fi
|
||||
# Hack: don't restart the X server (that would kill all the clients).
|
||||
# And don't restart dbus, since that causes ConsoleKit to
|
||||
# forget about current sessions.
|
||||
# Idem for xendomains because we don't want to save/restore
|
||||
# Xen domains unless we have to.
|
||||
# TODO: Jobs should be able to declare that they should not be
|
||||
# auto-restarted.
|
||||
if echo "$job" | grep -q "^xserver$\|^dbus$\|^disnix$\|^xendomains$\|^udevtrigger$"; then
|
||||
echo "not restarting changed service ‘$job’"
|
||||
continue
|
||||
fi
|
||||
echo "restarting changed service ‘$job’..."
|
||||
# Note: can't use "restart" here, since that only restarts the
|
||||
# job's main process.
|
||||
stop "$job" || true
|
||||
start "$job" || true
|
||||
done
|
||||
|
||||
# Start all jobs that are not running but should be. The "should be"
|
||||
# criterion is tricky: the intended semantics is that we end up with
|
||||
# the same jobs as after a reboot. If it's a task, restart it if it
|
||||
# differs from the previous instance of the same task; if it wasn't
|
||||
# previously run, don't run it. If it's a service, only start it if
|
||||
# it has a "start on" condition.
|
||||
for job in $(cd $newJobs && ls *.conf); do
|
||||
job=$(basename $job .conf)
|
||||
status=$(status "$job")
|
||||
if ! [[ "$status" =~ stop/ ]]; then continue; fi
|
||||
|
||||
if grep -q '^task$' "$newJobs/$job.conf"; then
|
||||
if [ ! -e "/var/run/upstart-jobs/$job" -o \
|
||||
"$(readlink -f "$newJobs/$job.conf")" = "$(readlink -f "/var/run/upstart-jobs/$job")" ];
|
||||
then continue; fi
|
||||
echo "starting task ‘$job’..."
|
||||
start "$job" || true
|
||||
else
|
||||
if ! grep -q "^start on" "$newJobs/$job.conf"; then continue; fi
|
||||
echo "starting service ‘$job’..."
|
||||
start "$job" || true
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
# Signal dbus to reload its configuration.
|
||||
dbusPid=$(initctl status dbus 2> /dev/null | sed -e 's/.*process \([0-9]\+\)/\1/;t;d')
|
||||
[ -n "$dbusPid" ] && kill -HUP "$dbusPid"
|
||||
|
|
|
@ -42,13 +42,14 @@ let
|
|||
|
||||
${concatMapStrings (n: "env ${n}=\"${getAttr n env}\"\n") (attrNames env)}
|
||||
|
||||
${optionalString (job.preStart != "") ''
|
||||
pre-start script
|
||||
exec >> ${log} 2>&1
|
||||
pre-start script
|
||||
exec >> ${log} 2>&1
|
||||
ln -sfn "$(readlink -f "/etc/init/${job.name}.conf")" /var/run/upstart-jobs/${job.name}
|
||||
${optionalString (job.preStart != "") ''
|
||||
source ${jobHelpers}
|
||||
${job.preStart}
|
||||
end script
|
||||
''}
|
||||
''}
|
||||
end script
|
||||
|
||||
${if job.script != "" && job.exec != "" then
|
||||
abort "Job ${job.name} has both a `script' and `exec' attribute."
|
||||
|
|
Loading…
Reference in New Issue