summaryrefslogtreecommitdiffstats
path: root/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_image_access.inc
blob: 9f18d0ec16a996d07ea074b7644a9e6e1aabea06 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
###########################################################
# Include: Setup dnbd for image access, nfs/cifs fallback #
###########################################################
# This will currently make sure that the variable
# VM_DISKFILE_RO is set which will contain the
# absolute path to the disk image to use for the vm
# session.
# When using DNBD3 this will differ from SRC_IMG_ABSOLUTE,
# otherwise it will be identical.
# In the future DNBD3 (or something else) might provide
# a CoW layer so we don't need snapshots etc. anymore.
# This include should set VM_DISKFILE_RW in that case to
# indicate to the virt plugin that it doesn't need to
# handle creating a temporary CoW layer itself.

# Helper to cleanup the image mounted with dnbd3-fuse
cleanup_dnbd3() {
	if ! isset DNBD3_MOUNT_POINT; then
		writelog "'DNBD3_MOUNT_POINT' is not set! Aborting DNBD3 cleanup."
		return 1
	fi
	# try to umount it now
	for timeout in 1 1 1 2 2 3 FAIL; do
		fs_path_ismountpoint "${DNBD3_MOUNT_POINT}" || break
		fusermount -u "${DNBD3_MOUNT_POINT}" && break
		writelog "dnbd3 still busy...."
		[ "$timeout" = "FAIL" ] && break
		sleep "$timeout"
	done
}

setup_dnbd3_proxy () {
	[ -d "/mnt/dnbd3/images" ] || return 1
	writelog "Trying to access via dnbd3-server-fuse"
	echo "${SRC_IMG_RELATIVE}:0" > "/mnt/dnbd3/control" || return 1
	VM_DISKFILE_REVISION=0
	VM_DISKFILE_RO="/mnt/dnbd3/images/${SRC_IMG_RELATIVE}:0"
	writelog "Success."
	return 0
}

setup_dnbd3 () {
	local dnbd3_tmplog="${TMPDIR}/dnbd3fuse.log"
	local dnbd3_diskfile=
	setup_dnbd3_common

	if isempty dnbd3_diskfile; then
		slxlog "virt-dnbd3" "No dnbd3 server for ${SRC_IMG_RELATIVE} found, trying NFS/CIFS..." "$dnbd3_tmplog"
		writelog "No working dnbd3 server found :-("
		return 1
	fi
	VM_DISKFILE_RO="$dnbd3_diskfile"
	return 0
}

setup_dnbd3_cow () {
	local dnbd3_tmplog="${TMPDIR}/dnbd3fuse.log"
	local dnbd3_diskfile=

	mkdir "${TMPDIR}/cow"
	setup_dnbd3_common -c "${TMPDIR}/cow" -C "${SLX_VMCHOOSER_BASE_URL//"/vmchooser/"/"/cow/"}" --upload-uuid "$DMSD_COW_SESSION" --cow-stats-file --merge

	if isempty dnbd3_diskfile; then
		slxlog "virt-dnbd3" "Failed to setup dnbd3-fuse with copy-on-write" "$dnbd3_tmplog"
		writelog "Error setting up CoW"
		cleanexit 1
	fi
	VM_DISKFILE_RW="$dnbd3_diskfile"
}

setup_dnbd3_common () {
	# Mount path for images mounted with dnbd3-fuse
	declare -rg DNBD3_MOUNT_POINT="${TMPDIR}/dnbd3fuse.mnt"
	mkdir -p "${DNBD3_MOUNT_POINT}"
	# start dnbd3-fuse in subshell
	local DNBD3_EXITFLAG="${TMPDIR}/dnbd3exit$RANDOM"
	local TIMEOUT VM_DISKFILE_REVISION
	rm -f -- "${DNBD3_EXITFLAG}"
	(
		trap 'writelog "[dnbd3-fuse] Received TERM"; kill $dnbd3pid; exit' SIGTERM
		trap 'writelog "[dnbd3-fuse] Received QUIT"; kill -SIGQUIT $dnbd3pid' SIGQUIT
		startup="$( date +%s )"
		while [ "$( date +%s )" -lt "$(( startup + 4 ))" ]; do
			dnbd3-fuse -f -o allow_other,max_readahead=262144 -h "${SLX_DNBD3_SERVERS}" -i "${SRC_IMG_RELATIVE}" "$@" "${DNBD3_MOUNT_POINT}" &> "${dnbd3_tmplog}" &
			dnbd3pid=$!
			wait "$dnbd3pid"
			RET=$?
		done
		touch "${DNBD3_EXITFLAG}"
		if [ "$RET" != "0" ]; then
			writelog "dnbd3-fuse stopped working (Exit code $RET)"
			slxlog "virt-dnbd3-fuse" "dnbd3-fuse stopped/refused serving '${SRC_IMG_RELATIVE}' from '${SLX_DNBD3_SERVERS}' with error code: $RET" "${dnbd3_tmplog}"
		fi
	) &
	declare -rg DNBD3_PID=$!
	# give it a bit of time
	usleep 250000
	# check if we have the image
	for TIMEOUT in 0.5 1 1 1 1 2 OUT; do
		if [ -r "${DNBD3_MOUNT_POINT}/img" ]; then
			VM_DISKFILE_REVISION="$(grep -m 1 "^Revision:" "${DNBD3_MOUNT_POINT}/status" | cut  -d" " -f2)"
			dnbd3_diskfile="${DNBD3_MOUNT_POINT}/img"
			writelog "DNBD3: ${SRC_IMG_RELATIVE} on ${dnbd3_diskfile} with rid ${VM_DISKFILE_REVISION}"
			add_cleanup "cleanup_dnbd3"
			break
		fi
		if [ "$TIMEOUT" = "OUT" ] || [ -e "$DNBD3_EXITFLAG" ]; then
			break
		fi
		sleep "$TIMEOUT"
	done
}

setup_fallback() {
	# Maybe we're reading a dnbd3 directory with RIDs encoded into the filename - use latest one
	unset VM_DISKFILE_REVISION
	local VM_DISKFILE_REVISION=$(ls -1 "${SRC_IMG_ABSOLUTE}.r"* | grep -E -o '\.r[0-9]+$' | grep -o -E '[0-9]+$' | sort -n | tail -n 1)
	if notempty VM_DISKFILE_REVISION; then
		# found
		VM_DISKFILE_RO="${SRC_IMG_ABSOLUTE}.r${VM_DISKFILE_REVISION}"
	elif [ -e "${SRC_IMG_ABSOLUTE}" ]; then
		# try name we got from xml in the first place
		VM_DISKFILE_RO="${SRC_IMG_ABSOLUTE}"
	fi
}

## MAIN PART / Sanity checks ##
setup_image_access() {
	writelog "Setting up virtual hard disk access for virtualizer/emulator ..."
	unset VM_DISKFILE_RO VM_DISKFILE_RW
	declare -g VM_DISKFILE_RO VM_DISKFILE_RW
	run_hooks "image-access"

	if [ -n "$VM_DISKFILE_RW" ]; then
		writelog "A hook in setup_image_access supplied a writable diskfile. Not running default setup."
	elif [ -n "$VM_DISKFILE_RO" ]; then
		writelog "A hook in setup_image_access supplied a read-only diskfile. Not running default setup."
	else
		setup_image_access_default
	fi
	readonly VM_DISKFILE_RO VM_DISKFILE_RW

	if [ -n "$VM_DISKFILE_RW" ]; then
		writelog "\tVM disk file (RW):\t\t$VM_DISKFILE_RW"
		if ! [ -s "$VM_DISKFILE_RW" ]; then
			writelog ".... not found!"
			EXIT_TYPE="user" EXIT_REASON="Schreibbare VM nicht gefunden. Adminmodus fehlgeschlagen." cleanexit 1
		fi
		if ! [ -w "$VM_DISKFILE_RW" ]; then
			writelog ".... not writable!"
			EXIT_TYPE="user" EXIT_REASON="VM-Image auf schreibbarem VM-Speicher nicht schreibbar. Adminmodus fehlgeschlagen." cleanexit 1
		fi
	elif [ -n "$VM_DISKFILE_RO" ]; then
		writelog "\tVM disk file (RO):\t\t$VM_DISKFILE_RO"
		if ! [ -s "$VM_DISKFILE_RO" ]; then
			writelog ".... not found!"
			EXIT_TYPE="user" EXIT_REASON="VM-Image nicht gefunden." cleanexit 1
		fi
		if ! [ -r "$VM_DISKFILE_RO" ]; then
			writelog ".... not readable!"
			EXIT_TYPE="user" EXIT_REASON="VM-Image nicht lesbar." cleanexit 1
		fi
	else
		EXIT_TYPE="user" EXIT_REASON="Kein VM-Image Dateiname angegeben/gefunden." cleanexit 1
	fi
}

setup_image_access_default() {
	# See if we should setup dnbd3 image access at all
	if ! isset SRC_IMG_RELATIVE; then
		writelog "\tCan't use dnbd3 as SRC_IMG_RELATIVE is not set"
	elif isempty SLX_DNBD3_SERVERS || [ "x${SLX_VM_DNBD3}" != "xyes" ]; then
		writelog "\tCan't use dnbd3 as no servers are given in config, or SLX_VM_DNBD3 is not set to yes"
	elif [ -n "$DMSD_COW_SESSION" ]; then
		writelog "Setting up DNBD3 CoW session"
		setup_dnbd3_cow
	elif setup_dnbd3_proxy; then
		writelog "\tImage setup done."
	elif ! check_dep dnbd3-fuse fusermount; then
		writelog "\tCan't use dnbd3 as dnbd3-fuse/fusermount binaries are not in PATH"
	else
		# register setup_dnbd3 as start hook after sourcing this include
		writelog "Trying image access via DNBD3..."
		setup_dnbd3
	fi

	# VM_DISKFILE_RO will be empty if dnbd3 is not used or failed to connect.
	if isempty VM_DISKFILE_RO; then
		# try to fallback to access the image via NFS/CIFS filesystem
		writelog "Trying fallback image access via NFS/CIFS..."
		setup_fallback
	fi
}

call_post_source setup_image_access