-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdocker.sh
429 lines (383 loc) · 11.8 KB
/
docker.sh
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
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
#!/bin/bash
#
# Start container if it's not running.
# Run commands inside user container.
#
# Special commands (SSH_ORIGINAL_COMMAND):
# commit - commit container
# remove - remove continaer
#
# Created by Peter Bryzgalov
# Copyright (c) 2013-2015 RIKEN AICS.
version="0.46a"
# Will be substituted with path to cofig file during installation
source diaasconfig
# mount table file lists folders, that should be mount on container startup (docker run command)
# file format:
# username@mountcommand1;mountcommand2;...
# mountcommand format:
# [host-dir]:[container-dir]:[rw|ro]
# Verbose logs for debugging
debuglog=1
# 1 if we started container
container_started=0
# FUNCTIONS
# Return status of container
getContainerState() {
if [ -n $1 ]; then
name=$1
else
name=$USER
fi
state=$($dockercommand inspect $name | jq .[0].State.Running)
echo $state
}
# Return host-side port number mapped to the port
getPort() {
cont_port=""
if [ -z $1 ]
then
cont_port="22/tcp"
else
cont_port=$1
fi
PORT=$($dockercommand inspect $cont_name | jq .[0].NetworkSettings.Ports | jq '.["'"$1"'"]' | jq -r .[0].HostPort)
if [ $debuglog -eq 1 ]
then
echo "Port mapping $cont_port->$PORT" >> $forcecommandlog
fi
echo $PORT
}
# Print free port number.
# Loops through the port range and returns first port number that is not used.
getFreePort() {
# Port range. Use dynamic port numbers.
startport=49152
endport=65535
# Which netstat?
test=$(netstat -V 2>/dev/null)
if [[ $test == *"net-tools"* ]]
then
# Array of used port numbers
used=( $(netstat -n -t | grep : | awk '{ print $4 }' | awk -F ':' '{ print $2 }') )
else
used4=( $(netstat -n -p tcp | grep "tcp4" | awk '{ print $4 }' | awk -F '.' '{ print $5 }') )
used6=( $(netstat -n -p tcp | grep "tcp6" | awk '{ print $4 }' | awk -F '.' '{ print $2 }') )
used=( "${used4[@]}" "${used6[@]}" )
fi
for port in $(seq $startport $endport)
do
isused="false"
for uport in "${used[@]}"
do
if [ "$port" == "$uport" ]
then
isused="true"
break
fi
done
if [ "$isused" == "false" ]
then
echo "$port"
break
fi
done
}
# Read from mountfile, search for username@... line,
# return part of Docker run command for mounting volumes
# like this: "-v hostdir:contdir -v hostdir:contdir:ro"
getMounts() {
mount_command=""
mounts=$(grep $1 $mountfile | awk -F"@" '{ print $2 }')
if [ -z "$mounts" ]; then
echo ""
exit 0
fi
IFS=';' read -ra mounts_arr <<< "$mounts"
for mnt in "${mounts_arr[@]}"; do
mount_command="$mount_command-v=$mnt "
done
echo $mount_command
}
# Return home directory in container (e.g. /root)
getContainerHome() {
homedir=$($dockercommand exec $cont_name env | grep "HOME=")
homedir=${homedir:5}
echo "$homedir"
}
# Return destination path, relative to home directory
dirs=()
getPath() {
currentdir=$( IFS=$'/'; echo "${dirs[*]}" )
echo "$currentdir/$1"
}
# Add directory to dirs array
addPath() {
n=${#dirs[@]}
dirs[$n]="$1"
}
# Remove last element from dirs array
delPath() {
n=${#dirs[@]}
p=$((n-1))
unset dirs[$p]
}
# Parse line with path and mode
# Sample line: D0744 0 tmp_dir
pathmode() {
read -ra pathmode <<< $(echo "$1")
mod="${pathmode[0]}"
mod="${mod:1}"
path="${pathmode[2]}"
echo "mod=$mod;path=$path"
}
# Parse scp logs one line at a time
# get file path, mod and type
# or save file contents into a new file in container
infile=0 # flag that we're reading next line of file contents
copyfile="$HOME/tmp_file" # contents of the file to copy
contents=""
parseLogLine() {
if [[ $line =~ ^[.]*[\>\<] ]]; then
# Service string
echo " $line" >> $forcecommandlog
if [[ "$infile" == "1" ]]; then
# Finished reading file
# Copy new file in container and set its access permissions
# echo -e "$contents" > $copyfile
copyfile="$host_tmp_dir/$path"
homedir=$(getContainerHome)
echo "COPY $mod:$copyfile->$cont_name:$homedir/$path" >> $forcecommandlog
$dockercommand cp $copyfile "$cont_name:$homedir/$path"
$dockercommand exec $cont_name chmod $mod $homedir/$path
$dockercommand exec $cont_name ls -l $homedir/$path >> $forcecommandlog
contents=""
infile=0
fi
elif [[ $line =~ ^[CD][0-9]+ ]]; then
# Have mode line
echo " $line" >> $forcecommandlog
homedir=$(getContainerHome)
if [[ $line =~ ^C ]]; then
# Have file
eval $(pathmode "$line")
path=$(getPath $path)
echo "mod $mod $homedir/$path" >> $forcecommandlog
elif [[ $line =~ ^D ]]; then
# Have directory
# Create new directory and set its permissions
eval $(pathmode "$line")
addPath "$path" # Add new directory to dirs array
path=$(getPath)
$dockercommand exec $cont_name mkdir -p $homedir/$path
$dockercommand exec $cont_name chmod $mod $homedir/$path
echo "Created dir $homedir/$path with $mod in container" >> $forcecommandlog
fi
elif [[ $line =~ ^E ]]; then
# End directory
delPath
else
# File contents
if [[ "$infile" == "0" ]]; then
infile=1
contents="$line"
else
contents="$contents"$'\n'"$line"
fi
fi
}
if [ ! -w $forcecommandlog ];then
touch $forcecommandlog
fi
if [ ! -f $usersfile ];then
echo "Cannot find file $usersfile" >> $forcecommandlog
exit 1;
fi
# Start socat if docker is not accessible with dockercommand
error=$( { $dockercommand ps > /dev/null; } 2>&1 )
if [[ -n "$error" ]]; then
${install_path}/socat-start.sh >> $forcecommandlog
fi
echo "$0 $version" >> $forcecommandlog
echo "----- start -----" >> $forcecommandlog
date >> $forcecommandlog
echo "ORC: $SSH_ORIGINAL_COMMAND" >> $forcecommandlog
if [ $debuglog -eq 1 ]; then
echo "USR: $USER" >> $forcecommandlog
echo "CON: $SSH_CONNECTION" >> $forcecommandlog
fi
# Get user container name from table in file usersfile
cont_name=$(grep -E "^$USER " $usersfile| awk '{ print $2 }')
if [ -z "$cont_name" ]; then
echo "No user $USER registered here." >&2
exit 1
fi
image="localhost/$USER"
if [ $debuglog -eq 1 ]; then
echo "User container: $cont_name, Image: $image" >> $forcecommandlog
fi
# Check SSH_ORIGINAL_COMMAND
if [ "$SSH_ORIGINAL_COMMAND" = commit ]; then
if [ $debuglog -eq 1 ]; then
echo "Commit container $cont_name" >> $forcecommandlog
fi
command="$dockercommand commit $cont_name $image"
$command
exit 0
fi
if [ "$SSH_ORIGINAL_COMMAND" = stop ]; then
if [ $debuglog -eq 1 ]; then
echo "Stop container $cont_name" >> $forcecommandlog
fi
command="$dockercommand kill $cont_name"
$command
exit 0
fi
if [ "$SSH_ORIGINAL_COMMAND" = remove ]; then
if [ $debuglog -eq 1 ]; then
echo "Remove container $cont_name" >> $forcecommandlog
fi
command="$dockercommand rm $cont_name"
$command
exit 0
fi
if [ "$SSH_ORIGINAL_COMMAND" = port ]; then
if [ $debuglog -eq 1 ]; then
echo "Return container $cont_name ssh port number" >> $forcecommandlog
fi
PORT=$(getPort "22/tcp")
echo $PORT
exit 0
fi
if [ "$SSH_ORIGINAL_COMMAND" = freeport ]; then
if [ $debuglog -eq 1 ]; then
echo "Return free server port number" >> $forcecommandlog
fi
PORT=$(getFreePort)
echo $PORT
exit 0
fi
# Action (command) on container
# empty string -- container is running, no actions performed
# start -- container has been stopped and was started
# run -- there were no container and a new container was created
container_action=""
# Get running containers names
# If user container name not in the list,
# start user container,
# get SSH port external number
# TODO Check that container for user nic would not get confused with users panic container!
state=$(getContainerState "$cont_name")
if [ "$state" == "true" ] && [ $debuglog -eq 1 ]
then
echo "Container is running" >> $forcecommandlog
else
if [ "$state" == "false" ]
then
if [ $debuglog -eq 1 ]
then
echo "Container is stopped" >> $forcecommandlog
fi
# Start container
cont=$($dockercommand start $cont_name)
if [ $debuglog -eq 1 ]
then
echo "Start container $cont" >> $forcecommandlog
fi
container_action="start"
sleep 1
else
if [ $debuglog -eq 1 ]; then
echo "No container. Run from image." >> $forcecommandlog
fi
# Run container
mounts=$(getMounts $USER)
# Permissions to mount with sshfs inside container
moptions=""
if [ "permit_mounts" ]
then
moptions=" --cap-add SYS_ADMIN --device /dev/fuse --security-opt apparmor:unconfined"
fi
options="run -d --name $cont_name $mounts $moptions -P=true $image"
cont=$($dockercommand $options)
if [ $debuglog -eq 1 ]
then
echo "Start container $cont with command: $options" >> $forcecommandlog
fi
container_action="run"
sleep 1
fi
# get running container port number
PORT=$(getPort "22/tcp")
sshcommand=( ssh -p "$PORT" -A -o StrictHostKeyChecking=no root@localhost )
echo "started container with open port $PORT" >> $forcecommandlog
fi
# get running container port number
if [ -z "$PORT" ]
then
PORT=$(getPort "22/tcp")
sshcommand=( ssh -p "$PORT" -A -o StrictHostKeyChecking=no root@localhost )
fi
echo "> $(date)" >> $forcecommandlog
# Execute commands in container
# -----------------------------
# SCP / SFTP
SCP=0
if [[ "$SSH_ORIGINAL_COMMAND" =~ ^scp\ [-a-zA-Z0-9\ \.]* ]];then
SCP=1
fi
if [[ "$SSH_ORIGINAL_COMMAND" =~ sftp-server ]];then
SCP=1
fi
if [[ "$SCP" == "1" ]]; then
socat_tmpfile="$HOME/scp.sh"
#host_tmp_dir="$HOME/tmp_scp_dir"
#mkdir -p $host_tmp_dir
echo "SCP detected at $(pwd)" >> $forcecommandlog
short_scp_commad=$(expr "$SSH_ORIGINAL_COMMAND" : '^\(scp\( -[a-z]\)*\)')
echo "scp command: $short_scp_commad" >> $forcecommandlog
# Get filename
ipath=$(echo "$SSH_ORIGINAL_COMMAND" | sed 's/^scp\( -[a-z]\)* //')
#
if [[ "$SSH_ORIGINAL_COMMAND" =~ ^scp\ .*-t ]];then
echo "Destination path is $ipath" >> $forcecommandlog
if [[ "${ipath:0:1}" == "/" ]]; then
# Absolute path
homedir=""
else
# Relative path
homedir="$(getContainerHome)/"
fi
command="$dockercommand exec -i $cont_name $short_scp_commad $homedir$ipath"
echo "Executing $command" >> $forcecommandlog
$command 2>> $forcecommandlog
else
echo "Source path is $ipath" >> $forcecommandlog
if [[ "${ipath:0:1}" == "/" ]]; then
# Absolute path
homedir=""
else
# Relative path
homedir="$(getContainerHome)/"
fi
command="$dockercommand exec -i $cont_name $short_scp_commad $homedir$ipath"
echo "Executing $command" >> $forcecommandlog
$command 2>> $forcecommandlog
fi
commands=()
#rm -rf $host_tmp_dir
elif [[ -n "$SSH_ORIGINAL_COMMAND" ]]; then
commands=( "${sshcommand[@]}" "$SSH_ORIGINAL_COMMAND" )
else
# Interactive login
sshcommand=( ssh -p "$PORT" -Y -A -o StrictHostKeyChecking=no root@localhost )
commands=( "${sshcommand[@]}" "$SSH_ORIGINAL_COMMAND" )
fi
if [ $debuglog -eq 1 ]
then
echo "${commands[@]}" >> $forcecommandlog
fi
"${commands[@]}"
# -----------------------------
echo "<" $(date) >> $forcecommandlog
echo " " >> $forcecommandlog