3 # Copyright (C) The Arvados Authors. All rights reserved.
5 # SPDX-License-Identifier: CC-BY-SA-3.0
7 # If you want to test arvados in a single host, you can run this script, which
8 # will install it using salt masterless
9 # This script is run by the Vagrant file when you run it with
15 # capture the directory that the script is running from
16 SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
20 echo >&2 "Usage: ${0} [-h] [-h]"
22 echo >&2 "${0} options:"
23 echo >&2 " -d, --debug Run salt installation in debug mode"
24 echo >&2 " -p <N>, --ssl-port <N> SSL port to use for the web applications"
25 echo >&2 " -c <local.params>, --config <local.params> Path to the local.params config file"
26 echo >&2 " -t, --test Test installation running a CWL workflow"
27 echo >&2 " -r, --roles List of Arvados roles to apply to the host, comma separated"
28 echo >&2 " Possible values are:"
30 echo >&2 " controller"
34 echo >&2 " workbench2"
38 echo >&2 " dispatcher"
39 echo >&2 " Defaults to applying them all"
40 echo >&2 " -h, --help Display this help and exit"
41 echo >&2 " -v, --vagrant Run in vagrant and use the /vagrant shared dir"
46 # NOTE: This requires GNU getopt (part of the util-linux package on Debian-based distros).
47 TEMP=$(getopt -o c:dhp:r:tv \
48 --long config:,debug,help,ssl-port:,roles:,test,vagrant \
51 if [ ${?} != 0 ] ; then echo "GNU getopt missing? Use -h for help"; exit 1 ; fi
52 # Note the quotes around `$TEMP': they are essential!
55 while [ ${#} -ge 1 ]; do
66 CONTROLLER_EXT_SSL_PORT=${2}
72 # Verify the role exists
73 if [[ ! "database,api,controller,keepstore,websocket,keepweb,workbench2,keepproxy,shell,workbench,dispatcher" == *"$i"* ]]; then
74 echo "The role '${i}' is not a valid role"
102 CONFIG="${SCRIPT_DIR}/local.params"
103 CONFIG_DIR="config_examples/single_host/multiple_hostnames"
105 CONTROLLER_EXT_SSL_PORT=443
111 # Hostnames/IPs used for single-host deploys
113 HOSTNAME_INT="127.0.1.1"
117 INITIAL_USER_EMAIL=""
118 INITIAL_USER_PASSWORD=""
120 CONTROLLER_EXT_SSL_PORT=8000
121 KEEP_EXT_SSL_PORT=25101
122 # Both for collections and downloads
123 KEEPWEB_EXT_SSL_PORT=9002
124 WEBSHELL_EXT_SSL_PORT=4202
125 WEBSOCKET_EXT_SSL_PORT=8002
126 WORKBENCH1_EXT_SSL_PORT=443
127 WORKBENCH2_EXT_SSL_PORT=3001
132 POSTGRES_TAG="v0.41.6"
136 LETSENCRYPT_TAG="v2.1.0"
142 F_DIR="/srv/formulas"
148 if [ -s ${CONFIG_FILE} ]; then
149 source ${CONFIG_FILE}
151 echo >&2 "Please create a '${CONFIG_FILE}' file with initial values, as described in FIXME_URL_TO_DESCR"
155 if grep -q 'fixme_or_this_wont_work' ${CONFIG_FILE} ; then
156 echo >&2 "The config file ${CONFIG_FILE} has some parameters that need to be modified."
157 echo >&2 "Please, fix them and re-run the provision script."
161 if ! grep -E '^[[:alnum:]]{5}$' <<<${CLUSTER} ; then
162 echo >&2 "ERROR: <CLUSTER> must be exactly 5 alphanumeric characters long"
163 echo >&2 "Fix the cluster name in the 'local.params' file and re-run the provision script"
168 apt-get install -y curl git jq
170 if which salt-call; then
171 echo "Salt already installed"
173 curl -L https://bootstrap.saltstack.com -o /tmp/bootstrap_salt.sh
174 sh /tmp/bootstrap_salt.sh -XdfP -x python3
175 /bin/systemctl stop salt-minion.service
176 /bin/systemctl disable salt-minion.service
179 # Set salt to masterless mode
180 cat > /etc/salt/minion << EOFSM
192 mkdir -p ${S_DIR} ${F_DIR} ${P_DIR}
194 # Get the formula and dependencies
195 cd ${F_DIR} || exit 1
196 git clone --branch "${ARVADOS_TAG}" https://github.com/arvados/arvados-formula.git
197 git clone --branch "${DOCKER_TAG}" https://github.com/saltstack-formulas/docker-formula.git
198 git clone --branch "${LOCALE_TAG}" https://github.com/saltstack-formulas/locale-formula.git
199 # git clone --branch "${NGINX_TAG}" https://github.com/saltstack-formulas/nginx-formula.git
200 git clone --branch "${NGINX_TAG}" https://github.com/netmanagers/nginx-formula.git
201 git clone --branch "${POSTGRES_TAG}" https://github.com/saltstack-formulas/postgres-formula.git
202 git clone --branch "${LETSENCRYPT_TAG}" https://github.com/saltstack-formulas/letsencrypt-formula.git
204 # If we want to try a specific branch of the formula
205 if [ "x${BRANCH}" != "x" ]; then
206 cd ${F_DIR}/arvados-formula || exit 1
207 git checkout -t origin/"${BRANCH}" -b "${BRANCH}"
211 if [ "x${VAGRANT}" = "xyes" ]; then
212 SOURCE_PILLARS_DIR="/vagrant/${CONFIG_DIR}/pillars"
213 SOURCE_TESTS_DIR="/vagrant/${TESTS_DIR}"
215 SOURCE_PILLARS_DIR="${SCRIPT_DIR}/${CONFIG_DIR}/pillars"
216 SOURCE_TESTS_DIR="${SCRIPT_DIR}/${TESTS_DIR}"
219 SOURCE_STATES_DIR="${EXTRA_STATES_DIR}"
221 # Replace variables (cluster, domain, etc) in the pillars, states and tests
222 # to ease deployment for newcomers
223 for f in "${SOURCE_PILLARS_DIR}"/*; do
224 sed "s#__ANONYMOUS_USER_TOKEN__#${ANONYMOUS_USER_TOKEN}#g;
225 s#__BLOB_SIGNING_KEY__#${BLOB_SIGNING_KEY}#g;
226 s#__CONTROLLER_EXT_SSL_PORT__#${CONTROLLER_EXT_SSL_PORT}#g;
227 s#__CLUSTER__#${CLUSTER}#g;
228 s#__DOMAIN__#${DOMAIN}#g;
229 s#__HOSTNAME_EXT__#${HOSTNAME_EXT}#g;
230 s#__HOSTNAME_INT__#${HOSTNAME_INT}#g;
231 s#__INITIAL_USER_EMAIL__#${INITIAL_USER_EMAIL}#g;
232 s#__INITIAL_USER_PASSWORD__#${INITIAL_USER_PASSWORD}#g;
233 s#__INITIAL_USER__#${INITIAL_USER}#g;
234 s#__DATABASE_PASSWORD__#${DATABASE_PASSWORD}#g;
235 s#__KEEPWEB_EXT_SSL_PORT__#${KEEPWEB_EXT_SSL_PORT}#g;
236 s#__KEEP_EXT_SSL_PORT__#${KEEP_EXT_SSL_PORT}#g;
237 s#__MANAGEMENT_TOKEN__#${MANAGEMENT_TOKEN}#g;
238 s#__RELEASE__#${RELEASE}#g;
239 s#__SYSTEM_ROOT_TOKEN__#${SYSTEM_ROOT_TOKEN}#g;
240 s#__VERSION__#${VERSION}#g;
241 s#__WEBSHELL_EXT_SSL_PORT__#${WEBSHELL_EXT_SSL_PORT}#g;
242 s#__WEBSOCKET_EXT_SSL_PORT__#${WEBSOCKET_EXT_SSL_PORT}#g;
243 s#__WORKBENCH1_EXT_SSL_PORT__#${WORKBENCH1_EXT_SSL_PORT}#g;
244 s#__WORKBENCH2_EXT_SSL_PORT__#${WORKBENCH2_EXT_SSL_PORT}#g;
245 s#__CLUSTER_INT_CIDR__#${CLUSTER_INT_CIDR}#g;
246 s#__CONTROLLER_INT_IP__#${CONTROLLER_INT_IP}#g;
247 s#__WEBSOCKET_INT_IP__#${WEBSOCKET_INT_IP}#g;
248 s#__KEEP_INT_IP__#${KEEP_INT_IP}#g;
249 s#__KEEPSTORE0_INT_IP__#${KEEPSTORE0_INT_IP}#g;
250 s#__KEEPSTORE1_INT_IP__#${KEEPSTORE1_INT_IP}#g;
251 s#__KEEPWEB_INT_IP__#${KEEPWEB_INT_IP}#g;
252 s#__WEBSHELL_INT_IP__#${WEBSHELL_INT_IP}#g;
253 s#__WORKBENCH1_INT_IP__#${WORKBENCH1_INT_IP}#g;
254 s#__WORKBENCH2_INT_IP__#${WORKBENCH2_INT_IP}#g;
255 s#__DATABASE_INT_IP__#${DATABASE_INT_IP}#g;
256 s#__WORKBENCH_SECRET_KEY__#${WORKBENCH_SECRET_KEY}#g" \
257 "${f}" > "${P_DIR}"/$(basename "${f}")
260 mkdir -p /tmp/cluster_tests
261 # Replace cluster and domain name in the test files
262 for f in "${SOURCE_TESTS_DIR}"/*; do
263 sed "s#__CLUSTER__#${CLUSTER}#g;
264 s#__CONTROLLER_EXT_SSL_PORT__#${CONTROLLER_EXT_SSL_PORT}#g;
265 s#__DOMAIN__#${DOMAIN}#g;
266 s#__HOSTNAME_INT__#${HOSTNAME_INT}#g;
267 s#__INITIAL_USER_EMAIL__#${INITIAL_USER_EMAIL}#g;
268 s#__INITIAL_USER_PASSWORD__#${INITIAL_USER_PASSWORD}#g
269 s#__INITIAL_USER__#${INITIAL_USER}#g;
270 s#__DATABASE_PASSWORD__#${DATABASE_PASSWORD}#g;
271 s#__SYSTEM_ROOT_TOKEN__#${SYSTEM_ROOT_TOKEN}#g" \
272 "${f}" > "/tmp/cluster_tests"/$(basename "${f}")
274 chmod 755 /tmp/cluster_tests/run-test.sh
276 # Replace helper state files that differ from the formula's examples
277 if [ -d "${SOURCE_STATES_DIR}" ]; then
278 mkdir -p "${F_DIR}"/extra/extra
280 for f in "${SOURCE_STATES_DIR}"/*; do
281 sed "s#__ANONYMOUS_USER_TOKEN__#${ANONYMOUS_USER_TOKEN}#g;
282 s#__CLUSTER__#${CLUSTER}#g;
283 s#__BLOB_SIGNING_KEY__#${BLOB_SIGNING_KEY}#g;
284 s#__CONTROLLER_EXT_SSL_PORT__#${CONTROLLER_EXT_SSL_PORT}#g;
285 s#__DOMAIN__#${DOMAIN}#g;
286 s#__HOSTNAME_EXT__#${HOSTNAME_EXT}#g;
287 s#__HOSTNAME_INT__#${HOSTNAME_INT}#g;
288 s#__INITIAL_USER_EMAIL__#${INITIAL_USER_EMAIL}#g;
289 s#__INITIAL_USER_PASSWORD__#${INITIAL_USER_PASSWORD}#g;
290 s#__INITIAL_USER__#${INITIAL_USER}#g;
291 s#__DATABASE_PASSWORD__#${DATABASE_PASSWORD}#g;
292 s#__KEEPWEB_EXT_SSL_PORT__#${KEEPWEB_EXT_SSL_PORT}#g;
293 s#__KEEP_EXT_SSL_PORT__#${KEEP_EXT_SSL_PORT}#g;
294 s#__MANAGEMENT_TOKEN__#${MANAGEMENT_TOKEN}#g;
295 s#__RELEASE__#${RELEASE}#g;
296 s#__SYSTEM_ROOT_TOKEN__#${SYSTEM_ROOT_TOKEN}#g;
297 s#__VERSION__#${VERSION}#g;
298 s#__CLUSTER_INT_CIDR__#${CLUSTER_INT_CIDR}#g;
299 s#__CONTROLLER_INT_IP__#${CONTROLLER_INT_IP}#g;
300 s#__WEBSOCKET_INT_IP__#${WEBSOCKET_INT_IP}#g;
301 s#__KEEP_INT_IP__#${KEEP_INT_IP}#g;
302 s#__KEEPSTORE0_INT_IP__#${KEEPSTORE0_INT_IP}#g;
303 s#__KEEPSTORE1_INT_IP__#${KEEPSTORE1_INT_IP}#g;
304 s#__KEEPWEB_INT_IP__#${KEEPWEB_INT_IP}#g;
305 s#__WEBSHELL_INT_IP__#${WEBSHELL_INT_IP}#g;
306 s#__WORKBENCH1_INT_IP__#${WORKBENCH1_INT_IP}#g;
307 s#__WORKBENCH2_INT_IP__#${WORKBENCH2_INT_IP}#g;
308 s#__DATABASE_INT_IP__#${DATABASE_INT_IP}#g;
309 s#__WEBSHELL_EXT_SSL_PORT__#${WEBSHELL_EXT_SSL_PORT}#g;
310 s#__WEBSOCKET_EXT_SSL_PORT__#${WEBSOCKET_EXT_SSL_PORT}#g;
311 s#__WORKBENCH1_EXT_SSL_PORT__#${WORKBENCH1_EXT_SSL_PORT}#g;
312 s#__WORKBENCH2_EXT_SSL_PORT__#${WORKBENCH2_EXT_SSL_PORT}#g;
313 s#__WORKBENCH_SECRET_KEY__#${WORKBENCH_SECRET_KEY}#g" \
314 "${f}" > "${F_DIR}/extra/extra"/$(basename "${f}")
318 # Now, we build the SALT states/pillars trees
319 # As we need to separate both states and pillars in case we want specific
320 # roles, we iterate on both at the same time
323 cat > ${S_DIR}/top.sls << EOFTSLS
330 cat > ${P_DIR}/top.sls << EOFPSLS
337 # States, extra states
338 if [ -d "${F_DIR}"/extra/extra ]; then
339 for f in "${F_DIR}"/extra/extra/*.sls; do
340 echo " - extra.$(basename ${f} | sed 's/.sls$//g')" >> ${S_DIR}/top.sls
344 # If we want specific roles for a node, just add the desired states
345 # and its dependencies
346 if [ -z "${ROLES}" ]; then
348 echo " - nginx.passenger" >> ${S_DIR}/top.sls
349 if [ "x${USE_LETSENCRYPT}" = "xyes" ]; then
350 grep -q "letsencrypt" ${S_DIR}/top.sls || echo " - letsencrypt" >> ${S_DIR}/top.sls
352 echo " - postgres" >> ${S_DIR}/top.sls
353 echo " - docker" >> ${S_DIR}/top.sls
354 echo " - arvados" >> ${S_DIR}/top.sls
357 echo " - docker" >> ${P_DIR}/top.sls
358 echo " - nginx_api_configuration" >> ${P_DIR}/top.sls
359 echo " - nginx_controller_configuration" >> ${P_DIR}/top.sls
360 echo " - nginx_keepproxy_configuration" >> ${P_DIR}/top.sls
361 echo " - nginx_keepweb_configuration" >> ${P_DIR}/top.sls
362 echo " - nginx_passenger" >> ${P_DIR}/top.sls
363 echo " - nginx_websocket_configuration" >> ${P_DIR}/top.sls
364 echo " - nginx_webshell_configuration" >> ${P_DIR}/top.sls
365 echo " - nginx_workbench2_configuration" >> ${P_DIR}/top.sls
366 echo " - nginx_workbench_configuration" >> ${P_DIR}/top.sls
367 echo " - postgresql" >> ${P_DIR}/top.sls
368 if [ "x${USE_LETSENCRYPT}" = "xyes" ]; then
369 grep -q "letsencrypt" ${P_DIR}/top.sls || echo " - letsencrypt" >> ${P_DIR}/top.sls
372 # If we add individual roles, make sure we add the repo first
373 echo " - arvados.repo" >> ${S_DIR}/top.sls
374 for R in ${ROLES}; do
378 echo " - postgres" >> ${S_DIR}/top.sls
380 echo ' - postgresql' >> ${P_DIR}/top.sls
384 # FIXME: https://dev.arvados.org/issues/17352
385 grep -q "postgres.client" ${S_DIR}/top.sls || echo " - postgres.client" >> ${S_DIR}/top.sls
386 grep -q "nginx.passenger" ${S_DIR}/top.sls || echo " - nginx.passenger" >> ${S_DIR}/top.sls
387 ### If we don't install and run LE before arvados-api-server, it fails and breaks everything
388 ### after it so we add this here, as we are, after all, sharing the host for api and controller
389 if [ "x${USE_LETSENCRYPT}" = "xyes" ]; then
390 grep -q "letsencrypt" ${S_DIR}/top.sls || echo " - letsencrypt" >> ${S_DIR}/top.sls
392 grep -q "arvados.${R}" ${S_DIR}/top.sls || echo " - arvados.${R}" >> ${S_DIR}/top.sls
394 grep -q "docker" ${P_DIR}/top.sls || echo " - docker" >> ${P_DIR}/top.sls
395 grep -q "postgresql" ${P_DIR}/top.sls || echo " - postgresql" >> ${P_DIR}/top.sls
396 grep -q "nginx_passenger" ${P_DIR}/top.sls || echo " - nginx_passenger" >> ${P_DIR}/top.sls
397 grep -q "nginx_${R}_configuration" ${P_DIR}/top.sls || echo " - nginx_${R}_configuration" >> ${P_DIR}/top.sls
399 "controller" | "websocket" | "workbench" | "workbench2" | "keepweb" | "keepproxy")
401 grep -q "nginx.passenger" ${S_DIR}/top.sls || echo " - nginx.passenger" >> ${S_DIR}/top.sls
402 if [ "x${USE_LETSENCRYPT}" = "xyes" ]; then
403 grep -q "letsencrypt" ${S_DIR}/top.sls || echo " - letsencrypt" >> ${S_DIR}/top.sls
405 grep -q "arvados.${R}" ${S_DIR}/top.sls || echo " - arvados.${R}" >> ${S_DIR}/top.sls
407 grep -q "nginx_passenger" ${P_DIR}/top.sls || echo " - nginx_passenger" >> ${P_DIR}/top.sls
408 grep -q "nginx_${R}_configuration" ${P_DIR}/top.sls || echo " - nginx_${R}_configuration" >> ${P_DIR}/top.sls
409 if [ "x${USE_LETSENCRYPT}" = "xyes" ]; then
410 grep -q "letsencrypt" ${P_DIR}/top.sls || echo " - letsencrypt" >> ${P_DIR}/top.sls
411 grep -q "letsencrypt_${R}_configuration" ${P_DIR}/top.sls || echo " - letsencrypt_${R}_configuration" >> ${P_DIR}/top.sls
416 grep -q "docker" ${S_DIR}/top.sls || echo " - docker" >> ${S_DIR}/top.sls
417 grep -q "arvados.${R}" ${S_DIR}/top.sls || echo " - arvados.${R}" >> ${S_DIR}/top.sls
419 grep -q "" ${P_DIR}/top.sls || echo " - docker" >> ${P_DIR}/top.sls
420 grep -q "nginx_webshell_configuration" ${P_DIR}/top.sls || echo " - nginx_webshell_configuration" >> ${P_DIR}/top.sls
424 grep -q "docker" ${S_DIR}/top.sls || echo " - docker" >> ${S_DIR}/top.sls
425 grep -q "arvados.${R}" ${S_DIR}/top.sls || echo " - arvados.${R}" >> ${S_DIR}/top.sls
427 # ATM, no specific pillar needed
431 grep -q "arvados.${R}" ${S_DIR}/top.sls || echo " - arvados.${R}" >> ${S_DIR}/top.sls
433 # ATM, no specific pillar needed
436 echo "Unknown role ${R}"
443 # FIXME! #16992 Temporary fix for psql call in arvados-api-server
444 if [ -e /root/.psqlrc ]; then
445 if ! ( grep 'pset pager off' /root/.psqlrc ); then
447 cp /root/.psqlrc /root/.psqlrc.provision.backup
453 echo '\pset pager off' >> /root/.psqlrc
454 # END FIXME! #16992 Temporary fix for psql call in arvados-api-server
456 # Now run the install
457 salt-call --local state.apply -l ${LOG_LEVEL}
459 # FIXME! #16992 Temporary fix for psql call in arvados-api-server
460 if [ "x${DELETE_PSQL}" = "xyes" ]; then
461 echo "Removing .psql file"
465 if [ "x${RESTORE_PSQL}" = "xyes" ]; then
466 echo "Restoring .psql file"
467 mv -v /root/.psqlrc.provision.backup /root/.psqlrc
469 # END FIXME! #16992 Temporary fix for psql call in arvados-api-server
471 # Leave a copy of the Arvados CA so the user can copy it where it's required
472 echo "Copying the Arvados CA certificate to the installer dir, so you can import it"
473 # If running in a vagrant VM, also add default user to docker group
474 if [ "x${VAGRANT}" = "xyes" ]; then
475 cp /etc/ssl/certs/arvados-snakeoil-ca.pem /vagrant/${CLUSTER}.${DOMAIN}-arvados-snakeoil-ca.pem
477 echo "Adding the vagrant user to the docker group"
478 usermod -a -G docker vagrant
480 cp /etc/ssl/certs/arvados-snakeoil-ca.pem ${SCRIPT_DIR}/${CLUSTER}.${DOMAIN}-arvados-snakeoil-ca.pem
483 # Test that the installation finished correctly
484 if [ "x${TEST}" = "xyes" ]; then
485 cd /tmp/cluster_tests