feat(provision): refactor to manage different infrastructure configurations
[arvados.git] / tools / salt-install / provision.sh
1 #!/bin/bash
2
3 # Copyright (C) The Arvados Authors. All rights reserved.
4 #
5 # SPDX-License-Identifier: CC-BY-SA-3.0
6
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
10 #
11 # vagrant up
12
13 set -o pipefail
14
15 # capture the directory that the script is running from
16 SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
17
18 usage() {
19   echo >&2
20   echo >&2 "Usage: ${0} [-h] [-h]"
21   echo >&2
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:"
29   echo >&2 "                                                api"
30   echo >&2 "                                                controller"
31   echo >&2 "                                                keepstore"
32   echo >&2 "                                                websocket"
33   echo >&2 "                                                keepweb"
34   echo >&2 "                                                workbench2"
35   echo >&2 "                                                keepproxy"
36   echo >&2 "                                                shell"
37   echo >&2 "                                                workbench"
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"
42   echo >&2
43 }
44
45 arguments() {
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 \
49     -n "${0}" -- "${@}")
50
51   if [ ${?} != 0 ] ; then echo "GNU getopt missing? Use -h for help"; exit 1 ; fi
52   # Note the quotes around `$TEMP': they are essential!
53   eval set -- "$TEMP"
54
55   while [ ${#} -ge 1 ]; do
56     case ${1} in
57       -c | --config)
58         CONFIG=${2}
59         shift 2
60         ;;
61       -d | --debug)
62         LOG_LEVEL="debug"
63         shift
64         ;;
65       -p | --ssl-port)
66         HOST_SSL_PORT=${2}
67         shift 2
68         ;;
69       -r | --roles)
70         for i in ${2//,/ }
71           do
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"
75               usage
76               exit 1
77             fi
78             ROLES="${ROLES} ${i}"
79           done
80           shift 2
81         ;;
82       -t | --test)
83         TEST="yes"
84         shift
85         ;;
86       -v | --vagrant)
87         VAGRANT="yes"
88         shift
89         ;;
90       --)
91         shift
92         break
93         ;;
94       *)
95         usage
96         exit 1
97         ;;
98     esac
99   done
100 }
101
102 CONFIG="${SCRIPT_DIR}/local.params"
103 CONFIG_DIR="config_examples/single_host/multiple_hostnames"
104 LOG_LEVEL="info"
105 HOST_SSL_PORT=443
106 TESTS_DIR="tests"
107
108 CLUSTER=""
109 DOMAIN=""
110 HOSTNAME_EXT=""
111 HOSTNAME_INT="127.0.1.1"
112 INITIAL_USER=""
113 INITIAL_USER_EMAIL=""
114 INITIAL_USER_PASSWORD=""
115
116 CONTROLLER_EXT_SSL_PORT=8000
117 KEEP_EXT_SSL_PORT=25101
118 # Both for collections and downloads
119 KEEPWEB_EXT_SSL_PORT=9002
120 WEBSHELL_EXT_SSL_PORT=4202
121 WEBSOCKET_EXT_SSL_PORT=8002
122 WORKBENCH1_EXT_SSL_PORT=443
123 WORKBENCH2_EXT_SSL_PORT=3001
124
125 RELEASE="production"
126 VERSION="latest"
127 ARVADOS_TAG="v1.1.4"
128 POSTGRES_TAG="v0.41.3"
129 NGINX_TAG="v2.4.0"
130 DOCKER_TAG="v1.0.0"
131 LOCALE_TAG="v0.3.4"
132
133 arguments ${@}
134
135 if [ -s ${CONFIG} ]; then
136   source ${CONFIG}
137 else
138   echo >&2 "Please create a '${CONFIG}' file with initial values, as described in FIXME_URL_TO_DESCR"
139   exit 1
140 fi
141
142 if ! grep -E '^[[:alnum:]]{5}$' <<<${CLUSTER} ; then
143   echo >&2 "ERROR: <CLUSTER> must be exactly 5 alphanumeric characters long"
144   echo >&2 "Fix the cluster name in the 'local.params' file and re-run the provision script"
145   exit 1
146 fi
147
148 # Salt's dir
149 ## states
150 S_DIR="/srv/salt"
151 ## formulas
152 F_DIR="/srv/formulas"
153 ##pillars
154 P_DIR="/srv/pillars"
155
156 apt-get update
157 apt-get install -y curl git jq
158
159 dpkg -l |grep salt-minion
160 if [ ${?} -eq 0 ]; then
161   echo "Salt already installed"
162 else
163   curl -L https://bootstrap.saltstack.com -o /tmp/bootstrap_salt.sh
164   sh /tmp/bootstrap_salt.sh -XUdfP -x python3
165   /bin/systemctl disable salt-minion.service
166 fi
167
168 # Set salt to masterless mode
169 cat > /etc/salt/minion << EOFSM
170 file_client: local
171 file_roots:
172   base:
173     - ${S_DIR}
174     - ${F_DIR}/*
175     - ${F_DIR}/*/test/salt/states/examples
176
177 pillar_roots:
178   base:
179     - ${P_DIR}
180 EOFSM
181
182 mkdir -p ${S_DIR} ${F_DIR} ${P_DIR}
183
184 # States
185 cat > ${S_DIR}/top.sls << EOFTSLS
186 base:
187   '*':
188     # - single_host.host_entries
189     # - single_host.snakeoil_certs
190     - locale
191 EOFTSLS
192
193 # If we want specific roles for a node, just add the desired states
194 # and its dependencies
195 if [ -z "${ROLES}" ]; then
196   echo '    - nginx.passenger' >> ${S_DIR}/top.sls
197   echo '    - postgres' >> ${S_DIR}/top.sls
198   echo '    - docker' >> ${S_DIR}/top.sls
199   echo '    - arvados' >> ${S_DIR}/top.sls
200 else
201   # If we add individual roles, make sure we add the repo first
202   echo "    - arvados.repo" >> ${S_DIR}/top.sls
203   for R in ${ROLES}; do
204     case "${R}" in
205       "database")
206         echo "    - postgres" >> ${S_DIR}/top.sls
207       ::
208       "api","workbench","workbench2","keepweb","keepproxy")
209         grep -q "nginx.passenger" ${S_DIR}/top.sls || echo "    - nginx.passenger" >> ${S_DIR}/top.sls
210         echo "    - arvados.${R}" >> ${S_DIR}/top.sls
211       ;;
212       "shell","dispatcher")
213         grep -q "docker" ${S_DIR}/top.sls || echo "    - docker" >> ${S_DIR}/top.sls
214         echo "    - arvados.${R}" >> ${S_DIR}/top.sls
215       ;;
216       *)
217         echo "    - arvados.${R}" >> ${S_DIR}/top.sls
218       ::
219     esac
220   done
221 fi
222
223 # Pillars
224 cat > ${P_DIR}/top.sls << EOFPSLS
225 base:
226   '*':
227     - arvados
228     - docker
229     - locale
230     - nginx_api_configuration
231     - nginx_controller_configuration
232     - nginx_keepproxy_configuration
233     - nginx_keepweb_configuration
234     - nginx_passenger
235     - nginx_websocket_configuration
236     - nginx_webshell_configuration
237     - nginx_workbench2_configuration
238     - nginx_workbench_configuration
239     - postgresql
240 EOFPSLS
241
242 # Get the formula and dependencies
243 cd ${F_DIR} || exit 1
244 git clone --branch "${ARVADOS_TAG}" https://github.com/arvados/arvados-formula.git
245 git clone --branch "${DOCKER_TAG}" https://github.com/saltstack-formulas/docker-formula.git
246 git clone --branch "${LOCALE_TAG}" https://github.com/saltstack-formulas/locale-formula.git
247 git clone --branch "${NGINX_TAG}" https://github.com/saltstack-formulas/nginx-formula.git
248 git clone --branch "${POSTGRES_TAG}" https://github.com/saltstack-formulas/postgres-formula.git
249
250 if [ "x${BRANCH}" != "x" ]; then
251   cd ${F_DIR}/arvados-formula || exit 1
252   git checkout -t origin/"${BRANCH}"
253   cd -
254 fi
255
256 if [ "x${VAGRANT}" = "xyes" ]; then
257   SOURCE_PILLARS_DIR="/vagrant/${CONFIG_DIR}/pillars"
258   SOURCE_STATES_DIR="/vagrant/${CONFIG_DIR}/states"
259   TESTS_DIR="/vagrant/${TESTS_DIR}"
260 else
261   SOURCE_PILLARS_DIR="${SCRIPT_DIR}/${CONFIG_DIR}/pillars"
262   SOURCE_STATES_DIR="${SCRIPT_DIR}/${CONFIG_DIR}/states"
263   TESTS_DIR="${SCRIPT_DIR}/${TESTS_DIR}"
264 fi
265
266 # Replace cluster and domain name in the example pillars
267 for f in "${SOURCE_PILLARS_DIR}"/*; do
268   sed "s/__CLUSTER__/${CLUSTER}/g;
269        s/__DOMAIN__/${DOMAIN}/g;
270        s/__RELEASE__/${RELEASE}/g;
271        s/__CONTROLLER_EXT_SSL_PORT__/${CONTROLLER_EXT_SSL_PORT}/g;
272        s/__KEEP_EXT_SSL_PORT__/${KEEP_EXT_SSL_PORT}/g;
273        s/__WEBSHELL_EXT_SSL_PORT__/${WEBSHELL_EXT_SSL_PORT}/g;
274        s/__WORKBENCH1_EXT_SSL_PORT__/${WORKBENCH1_EXT_SSL_PORT}/g;
275        s/__WORKBENCH2_EXT_SSL_PORT__/${WORKBENCH2_EXT_SSL_PORT}/g;
276        s/__WEBSOCKET_EXT_SSL_PORT__/${WEBSOCKET_EXT_SSL_PORT}/g;
277        s/__HOSTNAME_EXT__/${HOSTNAME_EXT}/g;
278        s/__HOSTNAME_INT__/${HOSTNAME_INT}/g;
279        s/__KEEPWEB_EXT_SSL_PORT__/${KEEPWEB_EXT_SSL_PORT}/g;
280        s/__HOST_SSL_PORT__/${HOST_SSL_PORT}/g;
281        s/__INITIAL_USER__/${INITIAL_USER}/g;
282        s/__INITIAL_USER_EMAIL__/${INITIAL_USER_EMAIL}/g;
283        s/__INITIAL_USER_PASSWORD__/${INITIAL_USER_PASSWORD}/g;
284        s/__BLOB_SIGNING_KEY__/${BLOB_SIGNING_KEY}/g;
285        s/__MANAGEMENT_TOKEN__/${MANAGEMENT_TOKEN}/g;
286        s/__SYSTEM_ROOT_TOKEN__/${SYSTEM_ROOT_TOKEN}/g;
287        s/__RAILS_SECRET_TOKEN__/${RAILS_SECRET_TOKEN}/g;
288        s/__ANONYMOUS_USER_TOKEN__/${ANONYMOUS_USER_TOKEN}/g;
289        s/__WORKBENCH_SECRET_KEY__/${WORKBENCH_SECRET_KEY}/g;
290        s/__VERSION__/${VERSION}/g" \
291   "${f}" > "${P_DIR}"/$(basename "${f}")
292 done
293
294 mkdir -p /tmp/cluster_tests
295 # Replace cluster and domain name in the test files
296 for f in "${TESTS_DIR}"/*; do
297   sed "s/__CLUSTER__/${CLUSTER}/g;
298        s/__DOMAIN__/${DOMAIN}/g;
299        s/__HOSTNAME_INT__/${HOSTNAME_INT}/g;
300        s/__HOST_SSL_PORT__/${HOST_SSL_PORT}/g;
301        s/__CONTROLLER_EXT_SSL_PORT__/${CONTROLLER_EXT_SSL_PORT}/g;
302        s/__SYSTEM_ROOT_TOKEN__/${SYSTEM_ROOT_TOKEN}/g;
303        s/__INITIAL_USER__/${INITIAL_USER}/g;
304        s/__INITIAL_USER_EMAIL__/${INITIAL_USER_EMAIL}/g;
305        s/__INITIAL_USER_PASSWORD__/${INITIAL_USER_PASSWORD}/g" \
306   "${f}" > "/tmp/cluster_tests"/$(basename "${f}")
307 done
308 chmod 755 /tmp/cluster_tests/run-test.sh
309
310 # Replace helper state files that differ from the formula's examples
311 if -d "${SOURCE_STATES_DIR}"; then
312   for f in "${SOURCE_STATES_DIR}"/*; do
313     sed "s/__CLUSTER__/${CLUSTER}/g;
314          s/__DOMAIN__/${DOMAIN}/g;
315          s/__RELEASE__/${RELEASE}/g;
316          s/__CONTROLLER_EXT_SSL_PORT__/${CONTROLLER_EXT_SSL_PORT}/g;
317          s/__KEEP_EXT_SSL_PORT__/${KEEP_EXT_SSL_PORT}/g;
318          s/__WEBSHELL_EXT_SSL_PORT__/${WEBSHELL_EXT_SSL_PORT}/g;
319          s/__WORKBENCH1_EXT_SSL_PORT__/${WORKBENCH1_EXT_SSL_PORT}/g;
320          s/__WORKBENCH2_EXT_SSL_PORT__/${WORKBENCH2_EXT_SSL_PORT}/g;
321          s/__WEBSOCKET_EXT_SSL_PORT__/${WEBSOCKET_EXT_SSL_PORT}/g;
322          s/__HOSTNAME_EXT__/${HOSTNAME_EXT}/g;
323          s/__HOSTNAME_INT__/${HOSTNAME_INT}/g;
324          s/__KEEPWEB_EXT_SSL_PORT__/${KEEPWEB_EXT_SSL_PORT}/g;
325          s/__HOST_SSL_PORT__/${HOST_SSL_PORT}/g;
326          s/__INITIAL_USER__/${INITIAL_USER}/g;
327          s/__INITIAL_USER_EMAIL__/${INITIAL_USER_EMAIL}/g;
328          s/__INITIAL_USER_PASSWORD__/${INITIAL_USER_PASSWORD}/g;
329          s/__BLOB_SIGNING_KEY__/${BLOB_SIGNING_KEY}/g;
330          s/__MANAGEMENT_TOKEN__/${MANAGEMENT_TOKEN}/g;
331          s/__SYSTEM_ROOT_TOKEN__/${SYSTEM_ROOT_TOKEN}/g;
332          s/__RAILS_SECRET_TOKEN__/${RAILS_SECRET_TOKEN}/g;
333          s/__ANONYMOUS_USER_TOKEN__/${ANONYMOUS_USER_TOKEN}/g;
334          s/__WORKBENCH_SECRET_KEY__/${WORKBENCH_SECRET_KEY}/g;
335          s/__VERSION__/${VERSION}/g" \
336     "${f}" > "${F_DIR}/arvados-formula/test/salt/states/examples/single_host"/$(basename "${f}")
337   done
338 fi
339
340 # FIXME! #16992 Temporary fix for psql call in arvados-api-server
341 if [ -e /root/.psqlrc ]; then
342   if ! ( grep 'pset pager off' /root/.psqlrc ); then
343     RESTORE_PSQL="yes"
344     cp /root/.psqlrc /root/.psqlrc.provision.backup
345   fi
346 else
347   DELETE_PSQL="yes"
348 fi
349
350 echo '\pset pager off' >> /root/.psqlrc
351 # END FIXME! #16992 Temporary fix for psql call in arvados-api-server
352
353 # Now run the install
354 salt-call --local state.apply -l ${LOG_LEVEL}
355
356 # FIXME! #16992 Temporary fix for psql call in arvados-api-server
357 if [ "x${DELETE_PSQL}" = "xyes" ]; then
358   echo "Removing .psql file"
359   rm /root/.psqlrc
360 fi
361
362 if [ "x${RESTORE_PSQL}" = "xyes" ]; then
363   echo "Restoring .psql file"
364   mv -v /root/.psqlrc.provision.backup /root/.psqlrc
365 fi
366 # END FIXME! #16992 Temporary fix for psql call in arvados-api-server
367
368 # Leave a copy of the Arvados CA so the user can copy it where it's required
369 echo "Copying the Arvados CA certificate to the installer dir, so you can import it"
370 # If running in a vagrant VM, also add default user to docker group
371 if [ "x${VAGRANT}" = "xyes" ]; then
372   cp /etc/ssl/certs/arvados-snakeoil-ca.pem /vagrant
373
374   echo "Adding the vagrant user to the docker group"
375   usermod -a -G docker vagrant
376 else
377   cp /etc/ssl/certs/arvados-snakeoil-ca.pem ${SCRIPT_DIR}
378 fi
379
380 # Test that the installation finished correctly
381 if [ "x${TEST}" = "xyes" ]; then
382   cd /tmp/cluster_tests
383   ./run-test.sh
384 fi