start-vnc 8.66 KB
Newer Older
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
1
2
#!/bin/bash
#
3
# Copyright 2019 Deutsches Klimarechenzentrum GmbH
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
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
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above
#    copyright notice, this list of conditions and the following
#    disclaimer in the documentation and/or other materials provided
#    with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
#
#
32
# start-vnc
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
33
#
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
34
35
36
37
38
39
40
41
# This script is intended to be used on your local workstation running
# Ubuntu or Fedora Linux or macOS (tested). Other Unix flavors may
# work as well. It allows you to connect to one of DKRZ's
# visualization nodes to work remotely on your visualizations.
#
# Technically, it starts a VNC server on one of the GPU nodes by
# submitting a generated job script. A local vncviewer client is used
# to connect to the server over an encypted ssh tunnel. After the
42
43
# client shuts down, the server job is terminated. TigerVNC, TightVNC,
# and TurboVNC are known to work.
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
44
#
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
45
# In case of problems contact Mathis Rosenhauer <rosenhauer@dkrz.de>.
46
#
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
47

48
set -eufo pipefail
49

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
50
# Default settings
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
51
52
53
54
#
# You can change the settings here or override them with command line
# options. SVNC_ACCTCODE is the only parameter you have to provide if
# your local username matches your username on the frontend and if
55
56
# vncviewer is installed in the search path (tight/tigervnc on Linux
# for example).
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
57
58
59
60

# Project account code
SVNC_ACCTCODE=""

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
61
62
63
64
# LDAP username
#
# Specify your username on the login node if it is not your local
# username.
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
65
SVNC_USERNAME="$(id -un)"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
66

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
67
68
# Path to local vncviewer
#
69
70
71
# If your local vnc client is not in the search path or named
# differently (e.g. TurboVNC, macOS), then change this parameter.
SVNC_VNCVIEWER="vncviewer"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
72
73

# Resolution of remote desktop window
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
74
75
76
#
# This is just the initial resolution. Resizing the vncviewer window
# later should also work.
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
77
78
SVNC_GEOMETRY="1920x1200"

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
79
80
# Session run time in minutes
SVNC_RUNTIME=240
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
81

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
82
83
84
85
86
# Number of GPU nodes reserved. Default is the special value "half"
# which allocates 24 cores of a node. To allocate one or more nodes,
# set to the integer number of nodes.
SVNC_NODES="half"

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
87
88
# Quality of service
SVNC_QOS="normal"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
89

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# Uncomment this if you use TurboVNC as vncviewer.
#
# TurboVNC will work without this option but then it will use its own
# implementation of ssh which dosen't support public key auth among other
# things.
#
# readonly SVNC_VNC_OPTIONS="-extssh"

# Frontend host
#
# Must be directly accessible from client. The frontend and the node
# where vncserver is running need a shared home file system. You will
# have to change this for other sites than DKRZ (along with many other
# things).
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
104
105
106
readonly SVNC_FRONTEND_HOST="mistral.dkrz.de"

# Copy vncpassword temporarily to the local workstation
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
107
108
109
#
# If your vncviewer client has trouble with TurboVNC's password format
# then disable this option (set to "false" or comment).
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
110
readonly SVNC_PASSWORD="true"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
111

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
112

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
113
clean_up () {
114
    trap - ERR EXIT
115
    set +e
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
116

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
117
    if [[ -n ${vnc_host:-} ]]; then
118
        echo "Killing vncserver :${vnc_display} on ${vnc_host}."
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
119
120
        ssh_frontend "ssh ${vnc_host} \"/opt/TurboVNC/bin/vncserver \
                     -kill :${vnc_display}\""
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
121
122
    fi

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
123
    if [[ -n ${job_id:-} ]]; then
124
        echo "Removing job ${job_id}."
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
125
        ssh_frontend "scancel -Q ${job_id}; sleep 1; \
126
                     rm -f .startvnc/out.${job_id}"
127
128
    else
        echo "Job ID not available. Make sure the vncjob is not running!"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
129
        ssh_frontend "squeue -u ${SVNC_USERNAME}"
130
131
    fi

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
132
133
    ssh_frontend "" "-O exit"
    rmdir "${ssh_socket_dir}"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
134

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
135
    # Remove local vnc PasswordFile
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
136
    if [[ ${SVNC_PASSWORD} = "true" ]]; then
137
        rm -f "vnc_passwd"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
138
    fi
139
    exit
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
140
141
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
142
usage () {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    cat <<EOF
Usage: $(basename "$0") [OPTION]

Available values for OPTION include:

  -A acctcode  acctcode of job
  -g geometry  initial geometry of vnc window
  -n nodes     number of nodes
  -q qos       job qos
  -t time      job runtime
  -u username  use username for login
  -v path      path to vncviewer program
  -x options   addidtional options for vncviewer

EOF
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
158
159
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
160
ssh_frontend () {
Mathis Rosenhauer's avatar
set -u    
Mathis Rosenhauer committed
161
162
    local command="$1"
    local extra_options="${2:-}"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
163
164
165
    local options
    options="${extra_options} -o ForwardX11=no \
            -o ControlPath=${ssh_socket_dir}/control:%h:%p:%r"
Mathis Rosenhauer's avatar
set -u    
Mathis Rosenhauer committed
166
    ssh ${options} "${SVNC_USERNAME}@${SVNC_FRONTEND_HOST}" "${command}"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
167
168
169
170
}

parse_options () {
    local option
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
171
    while getopts 'A:g:n:q:t:u:v:x:' option; do
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
172
173
174
175
176
        case ${option} in
            A) SVNC_ACCTCODE="$OPTARG"
               ;;
            g) SVNC_GEOMETRY="$OPTARG"
               ;;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
177
178
            n) SVNC_NODES="$OPTARG"
               ;;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
179
180
181
182
183
184
185
186
187
188
189
            q) SVNC_QOS="$OPTARG"
               ;;
            t) SVNC_RUNTIME="$OPTARG"
               ;;
            u) SVNC_USERNAME="$OPTARG"
               ;;
            v) SVNC_VNCVIEWER="$OPTARG"
               ;;
            x) SVNC_VNC_OPTIONS="$OPTARG"
               ;;
            ?) usage
Mathis Rosenhauer's avatar
set -u    
Mathis Rosenhauer committed
190
            exit 1
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
191
192
193
194
195
196
197
198
199
200
201
202
            ;;
        esac
    done

    readonly SVNC_ACCTCODE
    readonly SVNC_GEOMETRY
    readonly SVNC_QOS
    readonly SVNC_RUNTIME
    readonly SVNC_USERNAME
    readonly SVNC_VNCVIEWER
    readonly SVNC_VNC_OPTIONS

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
203
204
    if [[ -z ${SVNC_ACCTCODE} ]]; then
        printf "ERROR: Please specify an acctcode.\n\n" >&2
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
205
        usage
Mathis Rosenhauer's avatar
set -u    
Mathis Rosenhauer committed
206
        exit 1
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
207
208
    fi
}
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
209

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
210
prepare_vncserver () {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
211
212
    ssh_frontend "mkdir -p .startvnc"
    if ! ssh_frontend "test -s .vnc/passwd"; then
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
213
        echo "No VNC password found. Please set now."
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
214
215
216
        ssh_frontend "salloc -Q -n1 -pgpu -A${SVNC_ACCTCODE} -- /bin/bash -c \
                     'ssh -tt \$SLURM_JOB_NODELIST -- mkdir -p .vnc \
                     && /opt/TurboVNC/bin/vncpasswd'" "-t"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
217
218
219
220
    fi
}

submit_vnc_job () {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
221
    local sbatch_resources
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
222
    if [[ ${SVNC_NODES} = "half" ]]; then
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
223
        sbatch_resources="#SBATCH --ntasks=24"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
224
    else
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
225
        sbatch_resources="#SBATCH --nodes=${SVNC_NODES}"
226
        sbatch_resources+=$'\n#SBATCH --exclusive'
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
227
    fi
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
228
    ssh_frontend "cd .startvnc && sbatch" <<EOF
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
229
#!/bin/bash -l
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
230
#SBATCH --partition=gpu
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
231
${sbatch_resources}
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
232
233
234
#SBATCH --qos=${SVNC_QOS}
#SBATCH --time=${SVNC_RUNTIME}
#SBATCH --account=${SVNC_ACCTCODE}
235
#SBATCH --output=out.%j
236
#SBATCH --parsable
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
237
#SBATCH --dkrzepilog=0
238
cd \${HOME}
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
239
/opt/TurboVNC/bin/vncserver -fg -geometry "${SVNC_GEOMETRY}" -localhost
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
240
EOF
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
241
}
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
242

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
243
244
get_vnc_host_and_display () {
    local job_id="$1"
245
    ssh_frontend "/bin/bash -s" <<EOF
246
logfile=\${HOME}/.startvnc/out.${job_id}
247
while [[ -z \${host_and_display} ]]; do
248
    sleep 1
249
    if [[ -f \${logfile} ]]; then
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
250
251
        host_and_display="\$(grep -Po "started on display \Kmg[0-9]+:[0-9]+" \
                          \${logfile})"
252
    fi
253
    printf "." >&2
254
done
255
printf "\n" >&2
256
echo \${host_and_display}
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
257
EOF
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
258
259
260
261
262
}

main () {
    parse_options "$@"
    trap clean_up INT QUIT TERM ERR EXIT
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
263

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
264
    ssh_socket_dir="$(mktemp -d "${HOME}/.ssh/socket.XXXXX")"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
265
    ssh_frontend "" "-MNf"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
266
    prepare_vncserver
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
267
268

    echo "Submitting vncserver job."
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
269
    job_id="$(submit_vnc_job)"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
270

271
    printf "Waiting for job ${job_id} to start" >&2
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
272
273
    local host_and_display
    host_and_display="$(get_vnc_host_and_display "$job_id")"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
274
275
    vnc_host=${host_and_display%:*}
    vnc_display=${host_and_display#*:}
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
276
277
    echo "Vncserver started on node ${vnc_host}.dkrz.de display \
:${vnc_display}."
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
278

279
280
281
282
283
284
    local vnc_port=$((5900+${vnc_display}))
    ssh -o ForwardX11=no \
        -L "${vnc_port}:localhost:${vnc_port}" \
        -Nf \
        "${SVNC_USERNAME}@${vnc_host}.dkrz.de";

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
285
    local vnc_options
286
    vnc_options="${SVNC_VNC_OPTIONS:-}"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
287
    if [[ ${SVNC_PASSWORD} = "true" ]]; then
288
        echo "Fetching password from frontend."
289
290
        ssh_frontend "cat .vnc/passwd" > vnc_passwd
        vnc_options+=" -passwd vnc_passwd"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
291
    fi
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
292
    echo "Connecting vncviewer to ${vnc_host}.dkrz.de"
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
293
    "${SVNC_VNCVIEWER}" ${vnc_options} :${vnc_display}
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
294
}
295

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
296
main "$@"