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.3"
141 F_DIR="/srv/formulas"
147 if [ -s ${CONFIG_FILE} ]; then
148 source ${CONFIG_FILE}
150 echo >&2 "Please create a '${CONFIG_FILE}' file with initial values, as described in FIXME_URL_TO_DESCR"
154 if ! grep -E '^[[:alnum:]]{5}$' <<<${CLUSTER} ; then
155 echo >&2 "ERROR: <CLUSTER> must be exactly 5 alphanumeric characters long"
156 echo >&2 "Fix the cluster name in the 'local.params' file and re-run the provision script"
161 apt-get install -y curl git jq
163 if which salt-call; then
164 echo "Salt already installed"
166 curl -L https://bootstrap.saltstack.com -o /tmp/bootstrap_salt.sh
167 sh /tmp/bootstrap_salt.sh -XdfP -x python3
168 /bin/systemctl stop salt-minion.service
169 /bin/systemctl disable salt-minion.service
172 # Set salt to masterless mode
173 cat > /etc/salt/minion << EOFSM
185 mkdir -p ${S_DIR} ${F_DIR} ${P_DIR}
187 # Get the formula and dependencies
188 cd ${F_DIR} || exit 1
189 git clone --branch "${ARVADOS_TAG}" https://github.com/arvados/arvados-formula.git
190 git clone --branch "${DOCKER_TAG}" https://github.com/saltstack-formulas/docker-formula.git
191 git clone --branch "${LOCALE_TAG}" https://github.com/saltstack-formulas/locale-formula.git
192 git clone --branch "${NGINX_TAG}" https://github.com/saltstack-formulas/nginx-formula.git
193 git clone --branch "${POSTGRES_TAG}" https://github.com/saltstack-formulas/postgres-formula.git
195 if [ "x${BRANCH}" != "x" ]; then
196 cd ${F_DIR}/arvados-formula || exit 1
197 git checkout -t origin/"${BRANCH}"
201 if [ "x${VAGRANT}" = "xyes" ]; then
202 SOURCE_PILLARS_DIR="/vagrant/${CONFIG_DIR}/pillars"
203 SOURCE_TESTS_DIR="/vagrant/${TESTS_DIR}"
205 SOURCE_PILLARS_DIR="${SCRIPT_DIR}/${CONFIG_DIR}/pillars"
206 SOURCE_TESTS_DIR="${SCRIPT_DIR}/${TESTS_DIR}"
209 SOURCE_STATES_DIR="${EXTRA_STATES_DIR}"
211 # Replace variables (cluster, domain, etc) in the pillars, states and tests
212 # to ease deployment for newcomers
213 for f in "${SOURCE_PILLARS_DIR}"/*; do
214 sed "s/__ANONYMOUS_USER_TOKEN__/${ANONYMOUS_USER_TOKEN}/g;
215 s/__BLOB_SIGNING_KEY__/${BLOB_SIGNING_KEY}/g;
216 s/__CONTROLLER_EXT_SSL_PORT__/${CONTROLLER_EXT_SSL_PORT}/g;
217 s/__CLUSTER__/${CLUSTER}/g;
218 s/__DOMAIN__/${DOMAIN}/g;
219 s/__HOSTNAME_EXT__/${HOSTNAME_EXT}/g;
220 s/__HOSTNAME_INT__/${HOSTNAME_INT}/g;
221 s/__INITIAL_USER_EMAIL__/${INITIAL_USER_EMAIL}/g;
222 s/__INITIAL_USER_PASSWORD__/${INITIAL_USER_PASSWORD}/g;
223 s/__INITIAL_USER__/${INITIAL_USER}/g;
224 s/__KEEPWEB_EXT_SSL_PORT__/${KEEPWEB_EXT_SSL_PORT}/g;
225 s/__KEEP_EXT_SSL_PORT__/${KEEP_EXT_SSL_PORT}/g;
226 s/__MANAGEMENT_TOKEN__/${MANAGEMENT_TOKEN}/g;
227 s/__RELEASE__/${RELEASE}/g;
228 s/__SYSTEM_ROOT_TOKEN__/${SYSTEM_ROOT_TOKEN}/g;
229 s/__VERSION__/${VERSION}/g;
230 s/__WEBSHELL_EXT_SSL_PORT__/${WEBSHELL_EXT_SSL_PORT}/g;
231 s/__WEBSOCKET_EXT_SSL_PORT__/${WEBSOCKET_EXT_SSL_PORT}/g;
232 s/__WORKBENCH1_EXT_SSL_PORT__/${WORKBENCH1_EXT_SSL_PORT}/g;
233 s/__WORKBENCH2_EXT_SSL_PORT__/${WORKBENCH2_EXT_SSL_PORT}/g;
234 s/__WORKBENCH_SECRET_KEY__/${WORKBENCH_SECRET_KEY}/g" \
235 "${f}" > "${P_DIR}"/$(basename "${f}")
238 mkdir -p /tmp/cluster_tests
239 # Replace cluster and domain name in the test files
240 for f in "${SOURCE_TESTS_DIR}"/*; do
241 sed "s/__CLUSTER__/${CLUSTER}/g;
242 s/__CONTROLLER_EXT_SSL_PORT__/${CONTROLLER_EXT_SSL_PORT}/g;
243 s/__DOMAIN__/${DOMAIN}/g;
244 s/__HOSTNAME_INT__/${HOSTNAME_INT}/g;
245 s/__INITIAL_USER_EMAIL__/${INITIAL_USER_EMAIL}/g;
246 s/__INITIAL_USER_PASSWORD__/${INITIAL_USER_PASSWORD}/g
247 s/__INITIAL_USER__/${INITIAL_USER}/g;
248 s/__SYSTEM_ROOT_TOKEN__/${SYSTEM_ROOT_TOKEN}/g" \
249 "${f}" > "/tmp/cluster_tests"/$(basename "${f}")
251 chmod 755 /tmp/cluster_tests/run-test.sh
253 # Replace helper state files that differ from the formula's examples
254 if [ -d "${SOURCE_STATES_DIR}" ]; then
255 mkdir -p "${F_DIR}"/extra/extra
257 for f in "${SOURCE_STATES_DIR}"/*; do
258 sed "s/__ANONYMOUS_USER_TOKEN__/${ANONYMOUS_USER_TOKEN}/g;
259 s/__CLUSTER__/${CLUSTER}/g;
260 s/__BLOB_SIGNING_KEY__/${BLOB_SIGNING_KEY}/g;
261 s/__CONTROLLER_EXT_SSL_PORT__/${CONTROLLER_EXT_SSL_PORT}/g;
262 s/__DOMAIN__/${DOMAIN}/g;
263 s/__HOSTNAME_EXT__/${HOSTNAME_EXT}/g;
264 s/__HOSTNAME_INT__/${HOSTNAME_INT}/g;
265 s/__INITIAL_USER_EMAIL__/${INITIAL_USER_EMAIL}/g;
266 s/__INITIAL_USER_PASSWORD__/${INITIAL_USER_PASSWORD}/g;
267 s/__INITIAL_USER__/${INITIAL_USER}/g;
268 s/__KEEPWEB_EXT_SSL_PORT__/${KEEPWEB_EXT_SSL_PORT}/g;
269 s/__KEEP_EXT_SSL_PORT__/${KEEP_EXT_SSL_PORT}/g;
270 s/__MANAGEMENT_TOKEN__/${MANAGEMENT_TOKEN}/g;
271 s/__RELEASE__/${RELEASE}/g;
272 s/__SYSTEM_ROOT_TOKEN__/${SYSTEM_ROOT_TOKEN}/g;
273 s/__VERSION__/${VERSION}/g;
274 s/__WEBSHELL_EXT_SSL_PORT__/${WEBSHELL_EXT_SSL_PORT}/g;
275 s/__WEBSOCKET_EXT_SSL_PORT__/${WEBSOCKET_EXT_SSL_PORT}/g;
276 s/__WORKBENCH1_EXT_SSL_PORT__/${WORKBENCH1_EXT_SSL_PORT}/g;
277 s/__WORKBENCH2_EXT_SSL_PORT__/${WORKBENCH2_EXT_SSL_PORT}/g;
278 s/__WORKBENCH_SECRET_KEY__/${WORKBENCH_SECRET_KEY}/g" \
279 "${f}" > "${F_DIR}/extra/extra"/$(basename "${f}")
283 # Now, we build the SALT states/pillars trees
284 # As we need to separate both states and pillars in case we want specific
285 # roles, we iterate on both at the same time
288 cat > ${S_DIR}/top.sls << EOFTSLS
295 cat > ${P_DIR}/top.sls << EOFPSLS
302 # States, extra states
303 if [ -d "${F_DIR}"/extra/extra ]; then
304 for f in "${F_DIR}"/extra/extra/*.sls; do
305 echo " - extra.$(basename ${f} | sed 's/.sls$//g')" >> ${S_DIR}/top.sls
309 # If we want specific roles for a node, just add the desired states
310 # and its dependencies
311 if [ -z "${ROLES}" ]; then
313 echo " - nginx.passenger" >> ${S_DIR}/top.sls
314 echo " - postgres" >> ${S_DIR}/top.sls
315 echo " - docker" >> ${S_DIR}/top.sls
316 echo " - arvados" >> ${S_DIR}/top.sls
319 echo " - docker" >> ${P_DIR}/top.sls
320 echo " - nginx_api_configuration" >> ${P_DIR}/top.sls
321 echo " - nginx_controller_configuration" >> ${P_DIR}/top.sls
322 echo " - nginx_keepproxy_configuration" >> ${P_DIR}/top.sls
323 echo " - nginx_keepweb_configuration" >> ${P_DIR}/top.sls
324 echo " - nginx_passenger" >> ${P_DIR}/top.sls
325 echo " - nginx_websocket_configuration" >> ${P_DIR}/top.sls
326 echo " - nginx_webshell_configuration" >> ${P_DIR}/top.sls
327 echo " - nginx_workbench2_configuration" >> ${P_DIR}/top.sls
328 echo " - nginx_workbench_configuration" >> ${P_DIR}/top.sls
329 echo " - postgresql" >> ${P_DIR}/top.sls
331 # If we add individual roles, make sure we add the repo first
332 echo " - arvados.repo" >> ${S_DIR}/top.sls
333 for R in ${ROLES}; do
337 echo " - postgres" >> ${S_DIR}/top.sls
339 echo ' - postgresql' >> ${P_DIR}/top.sls
343 # FIXME: https://dev.arvados.org/issues/17352
344 grep -q "postgres.client" ${S_DIR}/top.sls || echo " - postgres.client" >> ${S_DIR}/top.sls
345 grep -q "nginx.passenger" ${S_DIR}/top.sls || echo " - nginx.passenger" >> ${S_DIR}/top.sls
346 grep -q "arvados.${R}" ${S_DIR}/top.sls || echo " - arvados.${R}" >> ${S_DIR}/top.sls
348 grep -q "docker" ${P_DIR}/top.sls || echo " - docker" >> ${P_DIR}/top.sls
349 grep -q "postgresql" ${P_DIR}/top.sls || echo " - postgresql" >> ${P_DIR}/top.sls
350 grep -q "nginx_passenger" ${P_DIR}/top.sls || echo " - nginx_passenger" >> ${P_DIR}/top.sls
351 grep -q "nginx_${R}_configuration" ${P_DIR}/top.sls || echo " - nginx_${R}_configuration" >> ${P_DIR}/top.sls
353 "controller" | "websocket" | "workbench" | "workbench2" | "keepweb" | "keepproxy")
355 grep -q "nginx.passenger" ${S_DIR}/top.sls || echo " - nginx.passenger" >> ${S_DIR}/top.sls
356 grep -q "arvados.${R}" ${S_DIR}/top.sls || echo " - arvados.${R}" >> ${S_DIR}/top.sls
358 grep -q "nginx_passenger" ${P_DIR}/top.sls || echo " - nginx_passenger" >> ${P_DIR}/top.sls
359 grep -q "nginx_${R}_configuration" ${P_DIR}/top.sls || echo " - nginx_${R}_configuration" >> ${P_DIR}/top.sls
363 grep -q "docker" ${S_DIR}/top.sls || echo " - docker" >> ${S_DIR}/top.sls
364 grep -q "arvados.${R}" ${S_DIR}/top.sls || echo " - arvados.${R}" >> ${S_DIR}/top.sls
366 grep -q "" ${P_DIR}/top.sls || echo " - docker" >> ${P_DIR}/top.sls
367 grep -q "nginx_webshell_configuration" ${P_DIR}/top.sls || echo " - nginx_webshell_configuration" >> ${P_DIR}/top.sls
371 grep -q "docker" ${S_DIR}/top.sls || echo " - docker" >> ${S_DIR}/top.sls
372 grep -q "arvados.${R}" ${S_DIR}/top.sls || echo " - arvados.${R}" >> ${S_DIR}/top.sls
374 # ATM, no specific pillar needed
378 grep -q "arvados.${R}" ${S_DIR}/top.sls || echo " - arvados.${R}" >> ${S_DIR}/top.sls
380 # ATM, no specific pillar needed
383 echo "Unknown role ${R}"
390 # FIXME! #16992 Temporary fix for psql call in arvados-api-server
391 if [ -e /root/.psqlrc ]; then
392 if ! ( grep 'pset pager off' /root/.psqlrc ); then
394 cp /root/.psqlrc /root/.psqlrc.provision.backup
400 echo '\pset pager off' >> /root/.psqlrc
401 # END FIXME! #16992 Temporary fix for psql call in arvados-api-server
403 # Now run the install
404 salt-call --local state.apply -l ${LOG_LEVEL}
406 # FIXME! #16992 Temporary fix for psql call in arvados-api-server
407 if [ "x${DELETE_PSQL}" = "xyes" ]; then
408 echo "Removing .psql file"
412 if [ "x${RESTORE_PSQL}" = "xyes" ]; then
413 echo "Restoring .psql file"
414 mv -v /root/.psqlrc.provision.backup /root/.psqlrc
416 # END FIXME! #16992 Temporary fix for psql call in arvados-api-server
418 # Leave a copy of the Arvados CA so the user can copy it where it's required
419 echo "Copying the Arvados CA certificate to the installer dir, so you can import it"
420 # If running in a vagrant VM, also add default user to docker group
421 if [ "x${VAGRANT}" = "xyes" ]; then
422 cp /etc/ssl/certs/arvados-snakeoil-ca.pem /vagrant/${CLUSTER}.${DOMAIN}-arvados-snakeoil-ca.pem
424 echo "Adding the vagrant user to the docker group"
425 usermod -a -G docker vagrant
427 cp /etc/ssl/certs/arvados-snakeoil-ca.pem ${SCRIPT_DIR}/${CLUSTER}.${DOMAIN}-arvados-snakeoil-ca.pem
430 # Test that the installation finished correctly
431 if [ "x${TEST}" = "xyes" ]; then
432 cd /tmp/cluster_tests