# vim: ft=zsh noet ts=4 sts=4 sw=4
#
# confz functions for deploying vservers
#
# load the zstat builtin and keep stat external
zmodload -F zsh/stat b:zstat
# deploy filesystem image from directory, rsync or tarball
confz_deployed_system_check() {
checkvars path source
defvar ignore_pattern 'lost+found'
local existing_entries
fail_reason="${vars[path]}/.confz_deployed missing"
if [[ -e ${vars[path]}/.confz_deployed ]]; then
return 0
else
existing_entries=( ${vars[path]}/*~${vars[path]}/${~vars[ignore_pattern]}(DN) )
if (($#existing_entries)); then
die "Found $#existing_entries existing entries in ${vars[path]} but no .confz_deployed"
else
return 1
fi
fi
}
confz_deployed_system_do() {
local result
result=0
case ${vars[source]} in
(*/)
rsync -aAH ${vars[source]} ${vars[path]}/ || return $?
;;
(scp:*.(tbz|tbz2|bz2))
scp -q ${vars[source]#scp:} /dev/stdout | bzip2 -d | tar -xpC ${vars[path]}
result=$[ $pipestatus[1] | $pipestatus[2] | $pipestatus[3] ]
;;
(scp:*.(tgz|gz))
scp -q ${vars[source]#scp:} /dev/stdout | gzip -d | tar -xpC ${vars[path]}
result=$[ $pipestatus[1] | $pipestatus[2] | $pipestatus[3] ]
;;
(scp:*.xz)
scp -q ${vars[source]#scp:} /dev/stdout | xz -d | tar -xpC ${vars[path]}
result=$[ $pipestatus[1] | $pipestatus[2] | $pipestatus[3] ]
;;
(scp:*)
scp -q ${vars[source]#scp:} /dev/stdout | tar -xpC ${vars[path]}
result=$[ $pipestatus[1] | $pipestatus[2] ]
;;
(sftp:*)
mkdir -p /root/.tmp || return $?
(cd /root/.tmp && sftp ${vars[source]#sftp:}) || return $?
tar -xpC ${vars[path]} -f /root/.tmp/${vars[source]:t}
result=$?
rm -f /root/.tmp/${vars[source]:t}
;;
(*)
tar -xpC ${vars[path]} -f ${vars[source]} || return $?
;;
esac
if (($result)); then
return $result
fi
printf '%s\n' ${vars[source]} >${vars[path]}/.confz_deployed
}
# create required directories
confz_vserver_run_dirs_check() {
local -a run_dirs
local d
run_dirs=( /var/run/{vservers,vservers.rev,vshelper} )
do_command=( mkdir -p $run_dirs )
for d in $run_dirs; do
fail_reason="missing directory: ${(q)d}"
[[ -d $d ]] || return $?
done
return 0
}
# configure and deploy vserver
confz_vserver_check() {
checkvars name size context_id source
defvar root /
setvar etcdir ${vars[root]%/}/etc/vservers/${vars[name]}
setvar vdir ${vars[root]%/}/vservers/${vars[name]}
local ctx ret
local -a fails
if [[ -e ${vars[etcdir]}/context ]]; then
if [[ $(<${vars[etcdir]}/context) != ${vars[context_id]} ]]; then
die "$0: vserver ${(qqq)vars[name]} " \
"has context different from ${(qqq)vars[context_id]}"
fi
else
fails+=( "${vars[etcdir]}/context) missing" )
for ctx in ${vars[root]%/}/etc/vservers/*/context(N); do
if [[ $(<$ctx) == ${vars[context_id]} ]]; then
die "$0: context id already used by $ctx"
fi
done
fi
if ! [[ -e ${vars[etcdir]}/vdir ]]; then
fails=( "${vars[etcdir]}/vdir missing" )
elif ! [[ -h ${vars[etcdir]}/vdir ]]; then
die "${vars[etcdir]}/vdir is not symlink or missing"
fi
require mounted_volume :size \?filesystem \?mkfs_opts \
lv_name=vs_$vars[name] \
label=${${vars[name]}[0,12]} \
mountpoint=$vars[vdir]
require deployed_system :root :source path=${vars[vdir]}
fail_reason="${(j:,:)fails}"
return $#fails
}
confz_vserver_do() {
mkdir -p ${vars[etcdir]} || return $?
if [[ -h ${vars[etcdir]}/vdir ]]; then
rm ${vars[etcdir]}/vdir || return $?
fi
ln -s $vars[vdir] ${vars[etcdir]}/vdir || return $?
print -r - ${vars[context_id]} >${vars[etcdir]}/context
}
confz_vserver_started_check() {
checkvars name
require vserver_run_dirs
do_command=( vserver -- $vars[name] start )
vserver --silent -- $vars[name] running || return $?
local context_id
context_id=$(</etc/vservers/$vars[name]/run)
if ! (($+vars[context_id])); then
vars[context_id]=$context_id
elif (( $vars[context_id] != $context_id )); then
die "vserver ${(qqq)name} running under context id $context_id, expected $vars[context_id]"
fi
}
confz_vserver_stopped_check() {
checkvars name
do_command=( vserver -- $vars[name] stop )
vserver --silent -- $vars[name] running
(( $? == 1 ))
}
confz_vserver_listconfigs_hook_check() {
checkvars name
(($+commands[vserver-listconfigs])) || \
die "can't find vserver-listconfigs in \$PATH"
[[ -x /etc/vservers/$vars[name]/scripts/post-start.d/vserver-listconfigs ]]
}
confz_vserver_listconfigs_hook_do() {
local lnk
lnk=/etc/vservers/$vars[name]/scripts/post-start.d/vserver-listconfigs
mkdir -p $lnk:h || return $?
ln -s $commands[vserver-listconfigs] $lnk || return $?
}
confz_vserver_autorestart_check() {
checkvars name
require vserver_listconfigs_hook :name
require vserver_started :name %context_id
do_command=( vserver -- $vars[name] condrestart )
local -a files mtab vdir failures
local fname mtab_list files_list
vdir=/etc/vservers/$vars[name]/vdir
vdir=$vdir:A
mtab_list=/var/run/vservers/$vars[name].mtab
files_list=/var/run/vservers/$vars[name].files
if ! [[ -f $mtab_list ]]; then
fail_reason="file $mtab_list not found"
return 1
fi
if ! [[ -f $files_list ]]; then
fail_reason="file $files_list not found"
return 1
fi
mtab="$(grep '^[^ ]* '$vdir'[/ ]' /etc/mtab)"
[[ $mtab == "$(</var/run/vservers/$vars[name].mtab)" ]] || \
failures+=( "changes in mountpoints detected over ${(qqq)vdir}" )
while IFS= read fname; do
[[ -e $fname ]] || failures+=( "missing file: ${(qqq)fname}" )
[[ $files_list -nt $fname ]] || failures+=(
"${(qqq)fname} changed since vserver start"
)
done <$files_list
fail_reason=${(j:, :)failures}
return $#failures
}
confz_vserver_autorestart_default_check() {
local mark
for mark in /etc/vservers/*/apps/init/mark(N); do
if [[ $(<$mark) == default ]]; then
require vserver_autorestart name=$mark:h:h:h:t
fi
done
}