#!/bin/bash if [ $# -lt 2 ]; then echo "Bad call to $0." >&2 echo "Expected: $0 images " >&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 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"