35a194af4e42dd978ce987f919354bcc602a5bd9
[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         set +u
120         SETUPDIR=$1
121         PARAMS=$2
122         SLS=$3
123         set -u
124
125         err=
126         if [[ -z "$PARAMS" || ! -f local.params.example.$PARAMS ]] ; then
127             echo "Not found: local.params.example.$PARAMS"
128             echo "Expected one of multiple_hosts, single_host_multiple_hostnames, single_host_single_hostname"
129             err=1
130         fi
131
132         if [[ -z "$SLS" || ! -d config_examples/$SLS ]] ; then
133             echo "Not found: config_examples/$SLS"
134             echo "Expected one of multi_host/aws, single_host/multiple_hostnames, single_host/single_hostname"
135             err=1
136         fi
137
138         if [[ -z "$SETUPDIR" || -z "$PARAMS" || -z "$SLS" ]]; then
139             echo "installer.sh <setup dir to initialize> <params template> <config template>"
140             err=1
141         fi
142
143         if [[ -n "$err" ]] ; then
144             exit 1
145         fi
146
147         echo "Initializing $SETUPDIR"
148         git init $SETUPDIR
149         cp -r *.sh tests $SETUPDIR
150
151         cp local.params.example.$PARAMS $SETUPDIR/${CONFIG_FILE}
152         cp -r config_examples/$SLS $SETUPDIR/${CONFIG_DIR}
153
154         cd $SETUPDIR
155         git add *.sh ${CONFIG_FILE} ${CONFIG_DIR} tests
156         git commit -m"initial commit"
157
158         echo "setup directory initialized, now go to $SETUPDIR, edit '${CONFIG_FILE}' and '${CONFIG_DIR}' as needed, then run 'installer.sh deploy'"
159         ;;
160     deploy)
161         set +u
162         NODE=$1
163         set -u
164
165         loadconfig
166
167         if grep -rni 'fixme' ${CONFIG_FILE} ${CONFIG_DIR} ; then
168             echo
169             echo "Some parameters still need to be updated.  Please fix them and then re-run deploy."
170             exit 1
171         fi
172
173         BRANCH=$(git branch --show-current)
174
175         set -x
176
177         git add -A
178         if ! git diff --cached --exit-code ; then
179             git commit -m"prepare for deploy"
180         fi
181
182         if [[ -z "$NODE" ]]; then
183             for NODE in "${!NODES[@]}"
184             do
185                 # First, push the git repo to each node.  This also
186                 # confirms that we have git and can log into each
187                 # node.
188                 sync $NODE $BRANCH
189             done
190
191             for NODE in "${!NODES[@]}"
192             do
193                 # Do 'database' role first,
194                 if [[ "${NODES[$NODE]}" =~ database ]] ; then
195                     deploynode $NODE ${NODES[$NODE]}
196                     unset NODES[$NODE]
197                 fi
198             done
199
200             for NODE in "${!NODES[@]}"
201             do
202                 # then  'api' or 'controller' roles
203                 if [[ "${NODES[$NODE]}" =~ (api|controller) ]] ; then
204                     deploynode $NODE ${NODES[$NODE]}
205                     unset NODES[$NODE]
206                 fi
207             done
208
209             for NODE in "${!NODES[@]}"
210             do
211                 # Everything else (we removed the nodes that we
212                 # already deployed from the list)
213                 deploynode $NODE ${NODES[$NODE]}
214             done
215         else
216             # Just deploy the node that was supplied on the command line.
217             sync $NODE $BRANCH
218             deploynode $NODE
219         fi
220
221         ;;
222     diagnostics)
223         loadconfig
224
225         set +u
226         declare LOCATION=$1
227         set -u
228
229         if ! which arvados-client ; then
230             echo "arvados-client not found, install 'arvados-client' package with 'apt-get' or 'yum'"
231             exit 1
232         fi
233
234         if [[ -z "$LOCATION" ]] ; then
235             echo "Need to provide '-internal-client' or '-external-client'"
236             echo
237             echo "-internal-client    You are running this on the same private network as the Arvados cluster (e.g. on one of the Arvados nodes)"
238             echo "-external-client    You are running this outside the private network of the Arvados cluster (e.g. your workstation)"
239             exit 1
240         fi
241
242         export ARVADOS_API_HOST="${CLUSTER}.${DOMAIN}"
243         export ARVADOS_API_TOKEN="$SYSTEM_ROOT_TOKEN"
244
245         arvados-client diagnostics $LOCATION
246         ;;
247     *)
248         echo "Arvados installer"
249         echo ""
250         echo "initialize   initialize the setup directory for configuration"
251         echo "deploy       deploy the configuration from the setup directory"
252         echo "diagnostics  check your install using diagnostics"
253         ;;
254 esac