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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
|
#!/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"
|