19215: Fixes installer script by honoring the DEPLOY_USER var when ssh-ing.
[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 checktools() {
46     local MISSING=''
47     for a in git ip ; do
48         if ! which $a ; then
49             MISSING="$MISSING $a"
50         fi
51     done
52     if [[ -n "$MISSING" ]] ; then
53         echo "Some tools are missing, please make sure you have the 'git' and 'iproute2' packages installed"
54         exit 1
55     fi
56 }
57
58 sync() {
59     local NODE=$1
60     local BRANCH=$2
61
62     # Synchronizes the configuration by creating a git repository on
63     # each node, pushing our branch, and updating the checkout.
64
65     if [[ "$NODE" != localhost ]] ; then
66         if ! ssh $DEPLOY_USER@$NODE test -d ${GITTARGET}.git ; then
67
68             # Initialize the git repository (1st time case).  We're
69             # actually going to make two repositories here because git
70             # will complain if you try to push to a repository with a
71             # checkout. So we're going to create a "bare" repository
72             # and then clone a regular repository (with a checkout)
73             # from that.
74
75             ssh $DEPLOY_USER@$NODE git init --bare ${GITTARGET}.git
76             if ! git remote add $NODE $DEPLOY_USER@$NODE:${GITTARGET}.git ; then
77                         git remote set-url $NODE $DEPLOY_USER@$NODE:${GITTARGET}.git
78             fi
79             git push $NODE $BRANCH
80             ssh $DEPLOY_USER@$NODE git clone ${GITTARGET}.git ${GITTARGET}
81         fi
82
83         # The update case.
84         #
85         # Push to the bare repository on the remote node, then in the
86         # remote node repository with the checkout, pull the branch
87         # from the bare repository.
88
89         git push $NODE $BRANCH
90         ssh $DEPLOY_USER@$NODE "git -C ${GITTARGET} checkout ${BRANCH} && git -C ${GITTARGET} pull"
91     fi
92 }
93
94 deploynode() {
95     local NODE=$1
96     local ROLES=$2
97
98     # Deploy a node.  This runs the provision script on the node, with
99     # the appropriate roles.
100
101     if [[ -z "$ROLES" ]] ; then
102         echo "No roles specified for $NODE, will deploy all roles"
103     else
104         ROLES="--roles ${ROLES}"
105     fi
106
107     logfile=deploy-${NODE}-$(date -Iseconds).log
108
109     if [[ "$NODE" = localhost ]] ; then
110         SUDO=''
111         if [[ $(whoami) != 'root' ]] ; then
112             SUDO=sudo
113         fi
114         $SUDO ./provision.sh --config ${CONFIG_FILE} ${ROLES} 2>&1 | tee $logfile
115     else
116         ssh $DEPLOY_USER@$NODE "cd ${GITTARGET} && sudo ./provision.sh --config ${CONFIG_FILE} ${ROLES}" 2>&1 | tee $logfile
117     fi
118 }
119
120 loadconfig() {
121     if [[ ! -s $CONFIG_FILE ]] ; then
122         echo "Must be run from initialized setup dir, maybe you need to 'initialize' first?"
123     fi
124     source ${CONFIG_FILE}
125     GITTARGET=arvados-deploy-config-${CLUSTER}
126 }
127
128 set +u
129 subcmd="$1"
130 set -u
131
132 if [[ -n "$subcmd" ]] ; then
133     shift
134 fi
135 case "$subcmd" in
136     initialize)
137         if [[ ! -f provision.sh ]] ; then
138             echo "Must be run from arvados/tools/salt-install"
139             exit
140         fi
141
142         checktools
143
144         set +u
145         SETUPDIR=$1
146         PARAMS=$2
147         SLS=$3
148         set -u
149
150         err=
151         if [[ -z "$PARAMS" || ! -f local.params.example.$PARAMS ]] ; then
152             echo "Not found: local.params.example.$PARAMS"
153             echo "Expected one of multiple_hosts, single_host_multiple_hostnames, single_host_single_hostname"
154             err=1
155         fi
156
157         if [[ -z "$SLS" || ! -d config_examples/$SLS ]] ; then
158             echo "Not found: config_examples/$SLS"
159             echo "Expected one of multi_host/aws, single_host/multiple_hostnames, single_host/single_hostname"
160             err=1
161         fi
162
163         if [[ -z "$SETUPDIR" || -z "$PARAMS" || -z "$SLS" ]]; then
164             echo "installer.sh <setup dir to initialize> <params template> <config template>"
165             err=1
166         fi
167
168         if [[ -n "$err" ]] ; then
169             exit 1
170         fi
171
172         echo "Initializing $SETUPDIR"
173         git init $SETUPDIR
174         cp -r *.sh tests $SETUPDIR
175
176         cp local.params.example.$PARAMS $SETUPDIR/${CONFIG_FILE}
177         cp -r config_examples/$SLS $SETUPDIR/${CONFIG_DIR}
178
179         cd $SETUPDIR
180         echo '*.log' > .gitignore
181
182         git add *.sh ${CONFIG_FILE} ${CONFIG_DIR} tests .gitignore
183         git commit -m"initial commit"
184
185         echo "setup directory initialized, now go to $SETUPDIR, edit '${CONFIG_FILE}' and '${CONFIG_DIR}' as needed, then run 'installer.sh deploy'"
186         ;;
187     deploy)
188         set +u
189         NODE=$1
190         set -u
191
192         checktools
193
194         loadconfig
195
196         if grep -rni 'fixme' ${CONFIG_FILE} ${CONFIG_DIR} ; then
197             echo
198             echo "Some parameters still need to be updated.  Please fix them and then re-run deploy."
199             exit 1
200         fi
201
202         BRANCH=$(git branch --show-current)
203
204         set -x
205
206         git add -A
207         if ! git diff --cached --exit-code ; then
208             git commit -m"prepare for deploy"
209         fi
210
211         if [[ -z "$NODE" ]]; then
212             for NODE in "${!NODES[@]}"
213             do
214                 # First, push the git repo to each node.  This also
215                 # confirms that we have git and can log into each
216                 # node.
217                 sync $NODE $BRANCH
218             done
219
220             for NODE in "${!NODES[@]}"
221             do
222                 # Do 'database' role first,
223                 if [[ "${NODES[$NODE]}" =~ database ]] ; then
224                     deploynode $NODE "${NODES[$NODE]}"
225                     unset NODES[$NODE]
226                 fi
227             done
228
229             for NODE in "${!NODES[@]}"
230             do
231                 # then  'api' or 'controller' roles
232                 if [[ "${NODES[$NODE]}" =~ (api|controller) ]] ; then
233                     deploynode $NODE "${NODES[$NODE]}"
234                     unset NODES[$NODE]
235                 fi
236             done
237
238             for NODE in "${!NODES[@]}"
239             do
240                 # Everything else (we removed the nodes that we
241                 # already deployed from the list)
242                 deploynode $NODE "${NODES[$NODE]}"
243             done
244         else
245             # Just deploy the node that was supplied on the command line.
246             sync $NODE $BRANCH
247             deploynode $NODE ""
248         fi
249
250         set +x
251         echo
252         echo "Completed deploy, run 'installer.sh diagnostics' to verify the install"
253
254         ;;
255     diagnostics)
256         loadconfig
257
258         set +u
259         declare LOCATION=$1
260         set -u
261
262         if ! which arvados-client ; then
263             echo "arvados-client not found, install 'arvados-client' package with 'apt-get' or 'yum'"
264             exit 1
265         fi
266
267         if [[ -z "$LOCATION" ]] ; then
268             echo "Need to provide '-internal-client' or '-external-client'"
269             echo
270             echo "-internal-client    You are running this on the same private network as the Arvados cluster (e.g. on one of the Arvados nodes)"
271             echo "-external-client    You are running this outside the private network of the Arvados cluster (e.g. your workstation)"
272             exit 1
273         fi
274
275         export ARVADOS_API_HOST="${CLUSTER}.${DOMAIN}:${CONTROLLER_EXT_SSL_PORT}"
276         export ARVADOS_API_TOKEN="$SYSTEM_ROOT_TOKEN"
277
278         arvados-client diagnostics $LOCATION
279         ;;
280     *)
281         echo "Arvados installer"
282         echo ""
283         echo "initialize   initialize the setup directory for configuration"
284         echo "deploy       deploy the configuration from the setup directory"
285         echo "diagnostics  check your install using diagnostics"
286         ;;
287 esac