Enable options for customizing deploy workflow
[fuel.git] / ci / deploy.sh
1 #!/bin/bash
2 # shellcheck disable=SC2034,SC2154,SC1091
3 set -ex
4 ##############################################################################
5 # Copyright (c) 2017 Ericsson AB, Mirantis Inc., Enea AB and others.
6 # jonas.bjurel@ericsson.com
7 # All rights reserved. This program and the accompanying materials
8 # are made available under the terms of the Apache License, Version 2.0
9 # which accompanies this distribution, and is available at
10 # http://www.apache.org/licenses/LICENSE-2.0
11 ##############################################################################
12
13 ##############################################################################
14 # BEGIN of Exit handlers
15 #
16 do_exit () {
17     clean
18     echo "Exiting ..."
19 }
20 #
21 # End of Exit handlers
22 ##############################################################################
23
24 ##############################################################################
25 # BEGIN of usage description
26 #
27 usage ()
28 {
29 cat << EOF
30 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
31 $(notify "$(basename "$0"): Deploy the Fuel@OPNFV MCP stack" 3)
32
33 $(notify "USAGE:" 2)
34   $(basename "$0") -b base-uri -l lab-name -p pod-name -s deploy-scenario \\
35     [-B PXE Bridge [-B Mgmt Bridge [-B Internal Bridge [-B Public Bridge]]]] \\
36     [-S storage-dir] [-L /path/to/log/file.tar.gz]
37
38 $(notify "OPTIONS:" 2)
39   -b  Base-uri for the stack-configuration structure
40   -B  Bridge(s): 1st usage = PXE, 2nd = Mgmt, 3rd = Internal, 4th = Public
41   -e  Do not launch environment deployment
42   -f  Deploy on existing Salt master
43   -F  Do only create a Salt master
44   -h  Print this message and exit
45   -l  Lab-name
46   -p  Pod-name
47   -s  Deploy-scenario short-name
48   -S  Storage dir for VM images
49   -L  Deployment log path and file name
50
51 $(notify "DISABLED OPTIONS (not yet supported with MCP):" 3)
52   -d  (disabled) Dry-run
53   -i  (disabled) iso url
54   -T  (disabled) Timeout, in minutes, for the deploy.
55
56 $(notify "Description:" 2)
57 Deploys the Fuel@OPNFV stack on the indicated lab resource.
58
59 This script provides the Fuel@OPNFV deployment abstraction.
60 It depends on the OPNFV official configuration directory/file structure
61 and provides a fairly simple mechanism to execute a deployment.
62
63 $(notify "Input parameters to the build script are:" 2)
64 -b Base URI to the configuration directory (needs to be provided in URI style,
65    it can be a local resource: file:// or a remote resource http(s)://).
66    A POD Descriptor File (PDF) should be available at:
67    <base-uri>/labs/<lab-name>/<pod-name>.yaml
68    The default is './mcp/config'.
69 -B Bridges to be used by deploy script. It can be specified several times,
70    or as a comma separated list of bridges, or both: -B br1 -B br2,br3
71    First occurence sets PXE Brige, next Mgmt, then Internal and Public.
72    For an empty value, the deploy script will use virsh to create the default
73    expected network (e.g. -B pxe,,,public will use existing "pxe" and "public"
74    bridges, respectively create "mgmt" and "internal").
75    Note that a virtual network "mcpcontrol" is always created. For virtual
76    deploys, "mcpcontrol" is also used for PXE, leaving the PXE bridge unused.
77    For baremetal deploys, PXE bridge is used for baremetal node provisioning,
78    while "mcpcontrol" is used to provision the infrastructure VMs only.
79    The default is 'pxebr'.
80 -e Do not launch environment deployment
81 -f Deploy on existing Salt master
82 -F Do only create a Salt master
83 -h Print this message and exit
84 -L Deployment log path and name, eg. -L /home/jenkins/job.log.tar.gz
85 -l Lab name as defined in the configuration directory, e.g. lf
86 -p POD name as defined in the configuration directory, e.g. pod2
87 -s Deployment-scenario, this points to a short deployment scenario name, which
88    has to be defined in config directory (e.g. os-odl-nofeature-ha).
89 -S Storage dir for VM images, default is mcp/deploy/images
90
91 $(notify "Disabled input parameters (not yet supported with MCP):" 3)
92 -d (disabled) Dry-run - Produce deploy config files, but do not execute deploy
93 -T (disabled) Timeout, in minutes, for the deploy.
94    It defaults to using the DEPLOY_TIMEOUT environment variable when defined.
95 -i (disabled) .iso image to be deployed (needs to be provided in a URI
96    style, it can be a local resource: file:// or a remote resource http(s)://)
97
98 $(notify "[NOTE] sudo & virsh priviledges are needed for this script to run" 3)
99
100 Example:
101
102 $(notify "sudo $(basename "$0") \\
103   -b file:///home/jenkins/securedlab \\
104   -l lf -p pod2 \\
105   -s os-odl-nofeature-ha" 2)
106 EOF
107 }
108
109 #
110 # END of usage description
111 ##############################################################################
112
113 ##############################################################################
114 # BEGIN of colored notification wrapper
115 #
116 notify() {
117     tput setaf "${2:-1}" || true
118     echo -en "${1:-"[WARN] Unsupported opt arg: $3\\n"}"
119     tput sgr0
120 }
121 #
122 # END of colored notification wrapper
123 ##############################################################################
124
125 ##############################################################################
126 # BEGIN of deployment clean-up
127 #
128 clean() {
129     echo "Cleaning up deploy tmp directories"
130 }
131 #
132 # END of deployment clean-up
133 ##############################################################################
134
135 ##############################################################################
136 # BEGIN of variables to customize
137 #
138 REPO_ROOT_PATH=$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")
139 DEPLOY_DIR=$(cd "${REPO_ROOT_PATH}/mcp/scripts"; pwd)
140 STORAGE_DIR=$(cd "${REPO_ROOT_PATH}/mcp/deploy/images"; pwd)
141 RECLASS_CLUSTER_DIR=$(cd "${REPO_ROOT_PATH}/mcp/reclass/classes/cluster"; pwd)
142 DEPLOY_TYPE='baremetal'
143 OPNFV_BRIDGES=('pxebr' 'mgmt' 'internal' 'public')
144 URI_REGEXP='(file|https?|ftp)://.*'
145 BASE_CONFIG_URI="file://${REPO_ROOT_PATH}/mcp/config"
146
147 export SSH_KEY=${SSH_KEY:-"/var/lib/opnfv/mcp.rsa"}
148 export SALT_MASTER=${INSTALLER_IP:-10.20.0.2}
149 export SALT_MASTER_USER=${SALT_MASTER_USER:-ubuntu}
150 export MAAS_IP=${MAAS_IP:-${SALT_MASTER%.*}.3}
151 export MAAS_PXE_NETWORK=${MAAS_PXE_NETWORK:-192.168.11.0}
152
153 # Derivated from above global vars
154 export MCP_CTRL_NETWORK_ROOTSTR=${SALT_MASTER%.*}
155 export MAAS_PXE_NETWORK_ROOTSTR=${MAAS_PXE_NETWORK%.*}
156 export SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ${SSH_KEY}"
157 export SSH_SALT="${SALT_MASTER_USER}@${SALT_MASTER}"
158
159 # Customize deploy workflow
160 export USE_EXISTING_INFRA=${USE_EXISTING_INFRA:-0}
161 export INFRA_CREATION_ONLY=${INFRA_CREATION_ONLY:-0}
162 export NO_DEPLOY_ENVIRONMENT=${NO_DEPLOY_ENVIRONMENT:-0}
163
164 # Variables below are disabled for now, to be re-introduced or removed later
165 set +x
166 DRY_RUN=0
167 if ! [ -z "${DEPLOY_TIMEOUT}" ]; then
168     DEPLOY_TIMEOUT="-dt ${DEPLOY_TIMEOUT}"
169 else
170     DEPLOY_TIMEOUT=""
171 fi
172 set -x
173 #
174 # END of variables to customize
175 ##############################################################################
176
177 ##############################################################################
178 # BEGIN of main
179 #
180 set +x
181 OPNFV_BRIDGE_IDX=0
182 while getopts "b:B:dfFl:L:p:s:S:T:i:he" OPTION
183 do
184     case $OPTION in
185         b)
186             BASE_CONFIG_URI=${OPTARG}
187             if [[ ! $BASE_CONFIG_URI =~ ${URI_REGEXP} ]]; then
188                 notify "[ERROR] -b $BASE_CONFIG_URI - invalid URI\n"
189                 usage
190                 exit 1
191             fi
192             ;;
193         B)
194             OIFS=${IFS}
195             IFS=','
196             OPT_BRIDGES=($OPTARG)
197             for bridge in "${OPT_BRIDGES[@]}"; do
198                 if [ -n "${bridge}" ]; then
199                     OPNFV_BRIDGES[${OPNFV_BRIDGE_IDX}]="${bridge}"
200                 fi
201                 OPNFV_BRIDGE_IDX=$((OPNFV_BRIDGE_IDX + 1))
202             done
203             IFS=${OIFS}
204             ;;
205         d)
206             notify '' 3 "${OPTION}"; continue
207             DRY_RUN=1
208             ;;
209         f)
210             USE_EXISTING_INFRA=1
211             ;;
212         F)
213             INFRA_CREATION_ONLY=1
214             ;;
215         e)
216             NO_DEPLOY_ENVIRONMENT=1
217             ;;
218         l)
219             TARGET_LAB=${OPTARG}
220             ;;
221         L)
222             DEPLOY_LOG="${OPTARG}"
223             ;;
224         p)
225             TARGET_POD=${OPTARG}
226             if [[ "${TARGET_POD}" =~ "virtual" ]]; then
227                 DEPLOY_TYPE='virtual'
228             fi
229             ;;
230         s)
231             DEPLOY_SCENARIO=${OPTARG}
232             ;;
233         S)
234             if [[ ${OPTARG} ]]; then
235                 STORAGE_DIR="${OPTARG}"
236             fi
237             ;;
238         T)
239             notify '' 3 "${OPTION}"; continue
240             DEPLOY_TIMEOUT="-dt ${OPTARG}"
241             ;;
242         i)
243             notify '' 3 "${OPTION}"; continue
244             ISO=${OPTARG}
245             if [[ ! $ISO =~ ${URI_REGEXP} ]]; then
246                 notify "[ERROR] -i $ISO - invalid URI\n"
247                 usage
248                 exit 1
249             fi
250             ;;
251         h)
252             usage
253             exit 0
254             ;;
255         *)
256             notify "[ERROR] Arguments not according to new argument style\n"
257             exit 1
258             ;;
259     esac
260 done
261
262 if [[ "$(sudo whoami)" != 'root' ]]; then
263     notify "This script requires sudo rights\n" 1>&2
264     exit 1
265 fi
266
267 if ! virsh list >/dev/null 2>&1; then
268     notify "This script requires hypervisor access\n" 1>&2
269     exit 1
270 fi
271
272 # Validate mandatory arguments are set
273 if [ -z "${TARGET_LAB}" ] || [ -z "${TARGET_POD}" ] || \
274    [ -z "${DEPLOY_SCENARIO}" ]; then
275     notify "[ERROR] At least one of the mandatory args is missing!\n" 1>&2
276     usage
277     exit 1
278 fi
279
280 set -x
281
282 # Enable the automatic exit trap
283 trap do_exit SIGINT SIGTERM EXIT
284
285 # Set no restrictive umask so that Jenkins can remove any residuals
286 umask 0000
287
288 clean
289
290 pushd "${DEPLOY_DIR}" > /dev/null
291 # Prepare the deploy config files based on lab/pod information, deployment
292 # scenario, etc.
293
294 # Install required packages
295 [ -n "$(command -v apt-get)" ] && sudo apt-get install -y \
296   git make rsync mkisofs curl virtinst cpu-checker qemu-kvm
297 [ -n "$(command -v yum)" ] && sudo yum install -y --skip-broken \
298   git make rsync genisoimage curl virt-install qemu-kvm
299
300 if [ "$(uname -i)" = "aarch64" ]; then
301   [ -n "$(command -v apt-get)" ] && sudo apt-get install -y vgabios && \
302   sudo ln -sf /usr/share/vgabios/vgabios.bin /usr/share/qemu/vgabios-stdvga.bin
303   [ -n "$(command -v yum)" ] && sudo yum install -y --skip-broken vgabios
304 fi
305
306 # Clone git submodules and apply our patches
307 make -C "${REPO_ROOT_PATH}/mcp/patches" deepclean patches-import
308
309 # Convert Pharos-compatible POD Descriptor File (PDF) to reclass model input
310 PHAROS_GEN_CONFIG_SCRIPT="./pharos/config/utils/generate_config.py"
311 PHAROS_INSTALLER_ADAPTER="./pharos/config/installers/fuel/pod_config.yml.j2"
312 BASE_CONFIG_PDF="${BASE_CONFIG_URI}/labs/${TARGET_LAB}/${TARGET_POD}.yaml"
313 LOCAL_PDF="${STORAGE_DIR}/$(basename "${BASE_CONFIG_PDF}")"
314 LOCAL_PDF_RECLASS="${STORAGE_DIR}/pod_config.yml"
315 if ! curl --create-dirs -o "${LOCAL_PDF}" "${BASE_CONFIG_PDF}"; then
316     if [ "${DEPLOY_TYPE}" = 'baremetal' ]; then
317         notify "[ERROR] Could not retrieve PDF (Pod Descriptor File)!\n" 1>&2
318         exit 1
319     else
320         notify "[WARN] Could not retrieve PDF (Pod Descriptor File)!\n" 3
321     fi
322 elif ! "${PHAROS_GEN_CONFIG_SCRIPT}" -y "${LOCAL_PDF}" \
323     -j "${PHAROS_INSTALLER_ADAPTER}" > "${LOCAL_PDF_RECLASS}"; then
324     notify "[ERROR] Could not convert PDF to reclass model input!\n" 1>&2
325     exit 1
326 fi
327
328 # Check scenario file existence
329 SCENARIO_DIR="../config/scenario"
330 if [ ! -f  "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml" ]; then
331     notify "[WARN] ${DEPLOY_SCENARIO}.yaml not found! \
332             Setting simplest scenario (os-nosdn-nofeature-noha)\n" 3
333     DEPLOY_SCENARIO='os-nosdn-nofeature-noha'
334     if [ ! -f  "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml" ]; then
335         notify "[ERROR] Scenario definition file is missing!\n" 1>&2
336         exit 1
337     fi
338 fi
339
340 # Check defaults file existence
341 if [ ! -f  "${SCENARIO_DIR}/defaults-$(uname -i).yaml" ]; then
342     notify "[ERROR] Scenario defaults file is missing!\n" 1>&2
343     exit 1
344 fi
345
346 # Get required infra deployment data
347 source lib.sh
348 eval "$(parse_yaml "${SCENARIO_DIR}/defaults-$(uname -i).yaml")"
349 eval "$(parse_yaml "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml")"
350
351 export CLUSTER_DOMAIN=${cluster_domain}
352
353 declare -A virtual_nodes_ram virtual_nodes_vcpus
354 for node in "${virtual_nodes[@]}"; do
355     virtual_custom_ram="virtual_${node}_ram"
356     virtual_custom_vcpus="virtual_${node}_vcpus"
357     virtual_nodes_ram[$node]=${!virtual_custom_ram:-$virtual_default_ram}
358     virtual_nodes_vcpus[$node]=${!virtual_custom_vcpus:-$virtual_default_vcpus}
359 done
360
361 # Expand reclass and virsh network templates
362 for tp in "${RECLASS_CLUSTER_DIR}/all-mcp-ocata-common/opnfv/"*.template \
363     net_*.template; do envsubst < "${tp}" > "${tp%.template}"; done
364
365 # Infra setup
366 if [ ${USE_EXISTING_INFRA} -eq 1 ]; then
367     notify "Use existing infra\n" 2 1>&2
368     check_connection
369 else
370     generate_ssh_key
371     prepare_vms virtual_nodes "${base_image}" "${STORAGE_DIR}"
372     create_networks OPNFV_BRIDGES
373     create_vms virtual_nodes virtual_nodes_ram virtual_nodes_vcpus \
374       OPNFV_BRIDGES "${STORAGE_DIR}"
375     update_mcpcontrol_network
376     start_vms virtual_nodes
377     check_connection
378     ./salt.sh "${LOCAL_PDF_RECLASS}"
379 fi
380
381 if [ ${INFRA_CREATION_ONLY} -eq 1 ] || [ ${NO_DEPLOY_ENVIRONMENT} -eq 1 ]; then
382     echo "Skip openstack cluster setup\n" 2
383 else
384     # Openstack cluster setup
385     for state in "${cluster_states[@]}"; do
386         notify "STATE: ${state}\n" 2
387         # shellcheck disable=SC2086,2029
388         ssh ${SSH_OPTS} "ubuntu@${SALT_MASTER}" \
389             sudo "/root/fuel/mcp/config/states/${state} || true"
390     done
391 fi
392
393 ./log.sh "${DEPLOY_LOG}"
394
395 popd > /dev/null
396
397 #
398 # END of main
399 ##############################################################################