summaryrefslogblamecommitdiffstats
path: root/scripts/mount-store
blob: d4311a10f506085d91d30aa54ecbc713b102af3a (plain) (tree)
1
2
3
4
5
6
7
8
9
10



                                  
                                               

                                                                                                


              




                                 


                                              

           

                            




                                                                       
                               






                                                       
                          
 







                                                                                   

                        

                                                                    
                                      
                                                                  
                                    

                                                        

                               
                                                         

                                           

                                                          



                   






























                                                                                                      
                      



                                        










































                                                                                                                   

                                   

                  

                                                                        
                                                               
                                           
                                                
                                   





                                                                          

                                                 
                       







                                                     
          


                               

    













                                                                                         

                                                 
                               
                                                       
                         
                                                   


              

                                         
                  
 
               
 




                                                          

        










                                                              
                                 












                                                                                                          
            



                     
                                             













                                                                           
                              
                  

                                                            


                                                                                                             
                                      

                                                       
                                                                   


                                                            
                                             



                                                                   

                                                                                                                        





















                                                                                                                                  
                            


                                                                   
                  



                                                  
          




                     
 
       
 



                                                 
                                                       

  
           
 
#!/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
}

# 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"
		enable_nfs_export
		systemctl --no-block restart dnbd3-server.service
		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
systemctl is-active -q nfs-kernel-server.service && NFS_WAS_RUNNING=true
while awk '{print $2}' "/proc/mounts" | grep -Fxq "${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
	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
	enable_nfs_export
	echo "Success. Now using internal storage."
	exit 0
fi

# Using external storage, via NFS or CIFS

disable_nfs_export

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=$?
	[ "$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
fi

exit "$RET"