#!/bin/bash
if [ $# -lt 2 ]; then
echo "Bad call to $0." >&2
echo "Expected: $0 images <source>" >&2
echo "TM_USERNAME and TM_PASSWORD are expected environment variables for CIFS" >&2
echo "TM_MOUNT_OPTIONS can be supplied in both cases to override automatic guessing" >&2
exit 1
fi
USERNAME="$TM_USERNAME"
PASSWORD="$TM_PASSWORD"
MOUNT_OPTIONS="$TM_MOUNT_OPTIONS"
unset TM_PASSWORD
declare -rg CIFS_OPTS="/opt/openslx/cifs.opts"
declare -rg NFS_OPTS="/opt/openslx/nfs.opts"
WHAT="$1"
SOURCE="$2"
[ -n "$3" ] && USERNAME="$3"
[ -n "$4" ] && PASSWORD="$4"
# Currently WHAT can only be images (the central store for all images),
# but maybe there will be other storage types in the future.
case "$WHAT" in
images)
DEST="/srv/openslx/nfs"
;;
*)
echo "Invalid/Unknown mount type: '$WHAT'." >&2
exit 1
;;
esac
FLAG="${DEST}/.notmounted"
prepare_dir () {
local owner="$1"
local testuser="$2"
local dir="$3"
echo "Preparing ${dir}..."
mkdir -p "${dir}"
if ! [ -d "${dir}" ]; then
echo "Error: Could not create directory! Storage not writable!" >&2
return 6
fi
echo "Applying owner/group..."
find "${dir}" -type d -exec chown "$owner" {} \; 2>/dev/null
echo "Applying permissions..."
find "${dir}" -type d -exec chmod ug+rwx {} \; 2>/dev/null
echo "Creating test file..."
local TEST="${dir}/.deleteme-$RANDOM-$RANDOM-$$"
sudo -n -u "${testuser}" touch "$TEST"
local RET=$?
if [ -e "$TEST" ]; then
sudo -n -u "${testuser}" rm -f -- "$TEST"
else
[ "$RET" = "0" ] && RET=127
echo "Error: Storage is not writable." >&2
ls -al "${DEST}" "${dir}" >&2
fi
return $RET
}
prepare_storage () {
local cifs=false
local type dnbd3_owner
case "$1" in
nfs*) type="remote" ;;
cifs) type="remote" ; cifs=true ;;
local) type="local" ;;
*) echo "Invalid storage type '$1'" ; return 1 ;;
esac
rm -f -- "${FLAG}"
if [ -e "${FLAG}" ]; then
echo "Error: File '.notmounted' exists on $type storage and could not be deleted." >&2
echo "Error: Make sure it is writable." >&2
return 5
fi
if ! prepare_dir "root:images" "dmsd" "${DEST}/bwlehrpool_store"; then
return 8
fi
if $cifs; then
adduser dnbd3 images 2> /dev/null
dnbd3_owner="root:images"
else
deluser dnbd3 images 2> /dev/null
dnbd3_owner="dnbd3:dnbd3"
fi
if ! prepare_dir "${dnbd3_owner}" "dnbd3" "${DEST}/stage4"; then
return 9
fi
return 0
}
enable_nfs_export () {
if [ -n "$TM_NOLOCALNFS" ]; then
disable_nfs_export
return
fi
# Enable nfs server
systemctl enable nfs-kernel-server.service
# Enable our export
sed -r -i 's,^\s*#\s*(/srv/openslx/nfs),\1,' "/etc/exports"
# Line was not present? add!
grep -Eq '^\s*/srv/openslx/nfs' "/etc/exports" \
|| echo '/srv/openslx/nfs *(ro,async,insecure,no_root_squash,no_subtree_check)' >> "/etc/exports"
# Restart
systemctl --no-block restart nfs-kernel-server.service
}
disable_nfs_export () {
# Disable our export
sed -r -i 's,^\s*(/srv/openslx/nfs),#\1,' "/etc/exports"
# See if there are any foreign exports and nfs-server was running and if so, keep nfs server running
if grep -Eq '^\s*/' /etc/exports; then
if "$NFS_WAS_RUNNING"; then
systemctl --no-block restart nfs-kernel-server.service
fi
else
# No valid exports left, disable and stop NFS server
systemctl disable nfs-kernel-server.service
systemctl --no-block stop nfs-kernel-server.service
fi
}
start_dmsd () {
if "$DMSD_WAS_RUNNING"; then
systemctl --no-block start dmsd.service
fi
}
# Quick safty measure -- if any local FS is mounted, do nothing and print warning if different type is requested
CURRENT_TYPE="$( awk -v DEST="$DEST" '$2 == DEST {print $3}' /proc/mounts )"
if [ -n "$CURRENT_TYPE" ] && ! [[ "$CURRENT_TYPE" == nfs* || "$CURRENT_TYPE" == cifs* ]]; then
# Currently mounted, but neither CIFS or NFS...
if [ "$SOURCE" = "null" ]; then
echo "Internal storage requested, something of type $CURRENT_TYPE already mounted, doing nothing."
rm -f -- "$FLAG"
prepare_storage "local"
systemctl --no-block restart dnbd3-server.service
enable_nfs_export
exit 0
fi
echo "There's something of type $CURRENT_TYPE mounted at $DEST, but the satellite server's configuration"
echo "requests $SOURCE to be used as the VM store. If you modified your fstab or added a .mount service"
echo "to use a custom storage backend, please set the VM storage type in slx-admin to INTERNAL."
exit 1
fi
systemctl stop dnbd3-server.service
# Already mounted?
TRIES=0
NFS_WAS_RUNNING=false
DMSD_WAS_RUNNING=false
systemctl is-active -q nfs-kernel-server.service && NFS_WAS_RUNNING=true
systemctl is-active -q dmsd.service && DMSD_WAS_RUNNING=true
while mountpoint "${DEST}"; do
echo "Trying to unmount '$DEST'..."
systemctl stop nfs-kernel-server.service
if [ "$TRIES" -gt 5 ]; then
cat >&2 <<-HEREDOC
Error: Cannot unmount '$DEST'!
Storage might be in use (running VM upload etc.)
Try stopping DMSD first
If the problem persists, try rebooting the server.
Possible troublemaker(s):
HEREDOC
lsof -n | grep "$DEST" >&2
exit 99 # marker that nothing changed
elif [ "$TRIES" -gt 3 ]; then
umount -v -f "$DEST"
RET=$?
else
umount -v "$DEST"
RET=$?
fi
[ "$RET" = 0 ] && break
systemctl stop dmsd.service
sleep 1
TRIES=$(( TRIES + 1 ))
done
# Sanity checks: Destination exists?
if [ ! -d "$DEST" ]; then
mkdir -p "$DEST"
chown root:images "$DEST"
chmod 0775 "$DEST"
fi
# Still a no?
if [ ! -d "$DEST" ]; then
echo "Mount point '$DEST' does not exist and could not be created!" >&2
echo "This should not happen and means this server is severely messed up. :(" >&2
exit 1
fi
# Unmount and not requested to mount (local mode)
if [[ "${SOURCE}" == "null" ]]; then
prepare_storage "local"
systemctl --no-block start dnbd3-server.service
start_dmsd
enable_nfs_export
echo "Success. Now using internal storage."
exit 0
fi
# Using external storage, via NFS or CIFS
disable_nfs_export
if mountpoint "${DEST}"; then
echo "**** Something was mounted to $DEST in the meantime. Aborting ****"
# Use the "nothing changed" exit code, as another concurrent invocation has changed stuff, apparently
exit 99
fi
touch "${FLAG}"
if [[ "${SOURCE}" == "unknown" ]]; then
echo "Storage type not configured, doing nothing."
exit 0
fi
# Mount!
# exec_mount <type> <options> <source> <dest>
exec_mount () {
local fstype="$1"
local mntopts="$2"
local SOURCE="$3"
local DEST="$4"
echo " * Trying ${fstype} with ${mntopts}..."
mount -v -t "$fstype" -o "$mntopts" "$SOURCE" "$DEST"
RET=$?
[ "$RET" -ne "0" ] && return "$RET"
echo "Mount succeeded, checking write permissions...."
prepare_storage "$fstype"
RET=$?
mountpoint "$DEST" && rm -f -- "$FLAG"
[ "$RET" -eq "0" ] && return 0
umount -v "$DEST" || umount -v -f -l "$DEST"
return "$RET"
}
remove_option () {
local opt
while [ $# -gt 0 ]; do
opt=$1
shift
[[ "$MOUNT_OPTIONS" =~ (^|,)$opt($|,|=) ]] || continue
MOUNT_OPTIONS=$( echo "$MOUNT_OPTIONS" | sed -r "s/(^|,)$opt(|=[^,]*)(,|$)/\\1/g;s/,$//" )
done
}
main () {
local RET=999
if [[ "$SOURCE" =~ ^[^/].+:. ]]; then
# seems to be NFS
if [ "$RET" != 0 ] && [ -n "$MOUNT_OPTIONS" ]; then
remove_option bg retry ro
MOUNT_OPTIONS="$MOUNT_OPTIONS,fg,retry=0,rw"
exec_mount "nfs" "$MOUNT_OPTIONS" "$SOURCE" "$DEST"
return $?
fi
OPTSTR=
if [ -f "$NFS_OPTS" ]; then
OPTSTR=$(cat "$NFS_OPTS")
fi
if [ "$RET" != 0 ] && [ -n "$OPTSTR" ]; then
echo " * Trying last successful mount options..."
exec_mount "nfs" "$OPTSTR" "$SOURCE" "$DEST"
RET=$?
fi
if [ "$RET" != 0 ]; then
for opt in "#" "vers=4" "vers=3"; do
OPTSTR="rw,noatime,noexec,nodev,async,nolock,fg,ac,retry=0,timeo=200,sec=sys"
[ "$opt" != "#" ] && OPTSTR="$OPTSTR,$opt"
exec_mount "nfs" "$OPTSTR" "$SOURCE" "$DEST"
RET=$?
[ "$RET" = 0 ] && break
done
if [ "$RET" = 0 ] && [ -n "$OPTSTR" ]; then
echo "$OPTSTR" > "$NFS_OPTS"
fi
fi
elif [[ "$SOURCE" =~ ^//.+/. ]]; then
# seems to be SMB
export USER="$USERNAME"
export PASSWD="$PASSWORD"
if [ "$RET" != 0 ] && [ -n "$MOUNT_OPTIONS" ]; then
remove_option uid gid file_mode dir_mode umask ro
MOUNT_OPTIONS="$MOUNT_OPTIONS,uid=0,gid=12345,forceuid,forcegid,file_mode=0664,dir_mode=0775,rw"
exec_mount "cifs" "$MOUNT_OPTIONS" "$SOURCE" "$DEST"
return $?
fi
OPTSTR=
if [ -f "$CIFS_OPTS" ]; then
OPTSTR=$(cat "$CIFS_OPTS")
fi
if [ "$RET" != 0 ] && [ -n "$OPTSTR" ]; then
echo " * Trying last successful mount options..."
exec_mount "cifs" "$OPTSTR" "$SOURCE" "$DEST"
RET=$?
fi
if [ "$RET" != 0 ]; then
for vers in "" "3.0" "2.1" "2.0" "1.0"; do
[ -n "$vers" ] && vers=",vers=${vers}"
for sec in "" "ntlmssp" "ntlmv2" "ntlm"; do
[ -n "$sec" ] && sec=",sec=${sec}"
OPTSTR="rw,uid=0,gid=12345,forceuid,forcegid,nounix,file_mode=0664,dir_mode=0775$vers$sec"
exec_mount "cifs" "$OPTSTR" "$SOURCE" "$DEST"
RET=$?
[ "$RET" = 0 ] && break 2
done
done
if [ "$RET" = 0 ] && [ -n "$OPTSTR" ]; then
echo "$OPTSTR" > "$CIFS_OPTS"
fi
fi
unset USER PASSWD
else
echo "Unknown mount type: $SOURCE"
RET=1
fi
return "$RET"
}
main
RET=$?
echo ""
if [ "$RET" = "0" ]; then
echo "----------------------------------"
echo "-- Share mounted successfully! --"
echo "----------------------------------"
systemctl --no-block start dnbd3-server.service
start_dmsd
fi
exit "$RET"