18870: Added a bunch of comments & documentation
[arvados.git] / tools / salt-install / installer.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 #
8 # installer.sh
9 #
10 # Helps manage the configuration in a git repository, and then deploy
11 # nodes by pushing a copy of the git repository to each node and
12 # running the provision script to do the actual installation and
13 # configuration.
14 #
15
16 set -eu
17
18 # The parameter file
19 declare CONFIG_FILE=local.params
20
21 # The salt template directory
22 declare CONFIG_DIR=local_config_dir
23
24 # The 5-character Arvados cluster id
25 # This will be populated by loadconfig()
26 declare CLUSTER
27
28 # The parent domain (not including the cluster id)
29 # This will be populated by loadconfig()
30 declare DOMAIN
31
32 # A bash associative array listing each node and mapping to the roles
33 # that should be provisioned on those nodes.
34 # This will be populated by loadconfig()
35 declare -A NODES
36
37 # The ssh user we'll use
38 # This will be populated by loadconfig()
39 declare DEPLOY_USER
40
41 # The git repository that we'll push to on all the nodes
42 # This will be populated by loadconfig()
43 declare GITTARGET
44
45 sync() {
46     local NODE=$1
47     local BRANCH=$2
48
49     # Synchronizes the configuration by creating a git repository on
50     # each node, pushing our branch, and updating the checkout.
51
52     if [[ "$NODE" != localhost ]] ; then
53         if ! ssh $NODE test -d ${GITTARGET}.git ; then
54
55             # Initialize the git repository (1st time case).  We're
56             # actually going to make two repositories here because git
57             # will complain if you try to push to a repository with a
58             # checkout. So we're going to create a "bare" repository
59             # and then clone a regular repository (with a checkout)
60             # from that.
61
62             ssh $NODE git init --bare ${GITTARGET}.git
63             if ! git remote add $NODE $DEPLOY_USER@$NODE:${GITTARGET}.git ; then
64                 git remote set-url $NODE $DEPLOY_USER@$NODE:${GITTARGET}.git
65             fi
66             git push $NODE $BRANCH
67             ssh $NODE git clone ${GITTARGET}.git ${GITTARGET}
68         fi
69
70         # The update case.
71         #
72         # Push to the bare repository on the remote node, then in the
73         # remote node repository with the checkout, pull the branch
74         # from the bare repository.
75
76         git push $NODE $BRANCH
77         ssh $NODE "git -C ${GITTARGET} checkout ${BRANCH} && git -C ${GITTARGET} pull"
78     fi
79 }
80
81 deploynode() {
82     local NODE=$1
83     local ROLES=$2
84
85     # Deploy a node.  This runs the provision script on the node, with
86     # the appropriate roles.
87
88     if [[ -z "$ROLES" ]] ; then
89         echo "No roles declared for '$NODE' in ${CONFIG_FILE}"
90         exit 1
91     fi
92
93     if [[ "$NODE" = localhost ]] ; then
94         sudo ./provision.sh --config ${CONFIG_FILE} --roles ${ROLES}
95     else
96         ssh $DEPLOY_USER@$NODE "cd ${GITTARGET} && sudo ./provision.sh --config ${CONFIG_FILE} --roles ${ROLES}"
97     fi
98 }
99
100 loadconfig() {
101     if [[ ! -s $CONFIG_FILE ]] ; then
102         echo "Must be run from initialized setup dir, maybe you need to 'initialize' first?"
103     fi
104     source ${CONFIG_FILE}
105     GITTARGET=arvados-deploy-config-${CLUSTER}
106 }
107
108 subcmd="$1"
109 if [[ -n "$subcmd" ]] ; then
110     shift
111 fi
112 case "$subcmd" in
113     initialize)
114         if [[ ! -f provision.sh ]] ; then
115             echo "Must be run from arvados/tools/salt-install"
116             exit
117         fi
118
119         SETUPDIR=$1
120         PARAMS=$2
121         SLS=$3
122
123         err=
124         if [[ -z "$PARAMS" || ! -f local.params.example.$PARAMS ]] ; then
125             echo "Not found: local.params.example.$PARAMS"
126             echo "Expected one of multiple_hosts, single_host_multiple_hostnames, single_host_single_hostname"
127             err=1
128         fi
129
130         if [[ -z "$SLS" || ! -d config_examples/$SLS ]] ; then
131             echo "Not found: config_examples/$SLS"
132             echo "Expected one of multi_host/aws, single_host/multiple_hostnames, single_host/single_hostname"
133             err=1
134         fi
135
136         if [[ -z "$SETUPDIR" || -z "$PARAMS" || -z "$SLS" ]]; then
137             echo "installer.sh <setup dir to initialize> <params template> <config template>"
138             err=1
139         fi
140
141         if [[ -n "$err" ]] ; then
142             exit 1
143         fi
144
145         echo "Initializing $SETUPDIR"
146         git init $SETUPDIR
147         cp -r *.sh tests $SETUPDIR
148
149         cp local.params.example.$PARAMS $SETUPDIR/${CONFIG_FILE}
150         cp -r config_examples/$SLS $SETUPDIR/${CONFIG_DIR}
151
152         cd $SETUPDIR
153         git add *.sh ${CONFIG_FILE} ${CONFIG_DIR} tests
154         git commit -m"initial commit"
155
156         echo "setup directory initialized, now go to $SETUPDIR, edit '${CONFIG_FILE}' and '${CONFIG_DIR}' as needed, then run 'installer.sh deploy'"
157         ;;
158     deploy)
159         NODE=$1
160
161         loadconfig
162
163         if grep -rni 'fixme' ${CONFIG_FILE} ${CONFIG_DIR} ; then
164             echo
165             echo "Some parameters still need to be updated.  Please fix them and then re-run deploy."
166             exit 1
167         fi
168
169         BRANCH=$(git branch --show-current)
170
171         set -x
172
173         git add -A
174         if ! git diff --cached --exit-code ; then
175             git commit -m"prepare for deploy"
176         fi
177
178         if [[ -z "$NODE" ]]; then
179             for NODE in "${!NODES[@]}"
180             do
181                 # First, push the git repo to each node.  This also
182                 # confirms that we have git and can log into each
183                 # node.
184                 sync $NODE $BRANCH
185             done
186
187             for NODE in "${!NODES[@]}"
188             do
189                 # Do 'database' role first,
190                 if [[ "${NODES[$NODE]}" =~ database ]] ; then
191                     deploynode $NODE ${NODES[$NODE]}
192                     unset NODES[$NODE]
193                 fi
194             done
195
196             for NODE in "${!NODES[@]}"
197             do
198                 # then  'api' or 'controller' roles
199                 if [[ "${NODES[$NODE]}" =~ (api|controller) ]] ; then
200                     deploynode $NODE ${NODES[$NODE]}
201                     unset NODES[$NODE]
202                 fi
203             done
204
205             for NODE in "${!NODES[@]}"
206             do
207                 # Everything else (we removed the nodes that we
208                 # already deployed from the list)
209                 deploynode $NODE ${NODES[$NODE]}
210             done
211         else
212             # Just deploy the node that was supplied on the command line.
213             sync $NODE $BRANCH
214             deploynode $NODE
215         fi
216
217         ;;
218     diagnostics)
219         loadconfig
220
221         declare LOCATION=$1
222
223         if ! which arvados-client ; then
224             echo "arvados-client not found, install 'arvados-client' package with 'apt-get' or 'yum'"
225             exit 1
226         fi
227
228         if [[ -z "$LOCATION" ]] ; then
229             echo "Need to provide '-internal-client' or '-external-client'"
230             echo
231             echo "-internal-client    You are running this on the same private network as the Arvados cluster (e.g. on one of the Arvados nodes)"
232             echo "-external-client    You are running this outside the private network of the Arvados cluster (e.g. your workstation)"
233             exit 1
234         fi
235
236         export ARVADOS_API_HOST="${CLUSTER}.${DOMAIN}"
237         export ARVADOS_API_TOKEN="$SYSTEM_ROOT_TOKEN"
238
239         arvados-client diagnostics $LOCATION
240         ;;
241     *)
242         echo "Arvados installer"
243         echo ""
244         echo "initialize   initialize the setup directory for configuration"
245         echo "deploy       deploy the configuration from the setup directory"
246         echo "diagnostics  check your install using diagnostics"
247         ;;
248 esac