dc5f774274cf772c2a41bf471fba0487e93dfa8b
[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   -h  Print this message and exit
42   -l  Lab-name
43   -p  Pod-name
44   -s  Deploy-scenario short-name
45   -S  Storage dir for VM images
46   -L  Deployment log path and file name
47
48 $(notify "DISABLED OPTIONS (not yet supported with MCP):" 3)
49   -d  (disabled) Dry-run
50   -e  (disabled) Do not launch environment deployment
51   -f  (disabled) Deploy on existing Salt master
52   -F  (disabled) Do only create a Salt master
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 -h Print this message and exit
81 -L Deployment log path and name, eg. -L /home/jenkins/job.log.tar.gz
82 -l Lab name as defined in the configuration directory, e.g. lf
83 -p POD name as defined in the configuration directory, e.g. pod2
84 -s Deployment-scenario, this points to a short deployment scenario name, which
85    has to be defined in config directory (e.g. os-odl-nofeature-ha).
86 -S Storage dir for VM images, default is mcp/deploy/images
87
88 $(notify "Disabled input parameters (not yet supported with MCP):" 3)
89 -d (disabled) Dry-run - Produce deploy config files, but do not execute deploy
90 -f (disabled) Deploy on existing Salt master
91 -e (disabled) Do not launch environment deployment
92 -F (disabled) Do only create a Salt master
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 # Variables below are disabled for now, to be re-introduced or removed later
160 set +x
161 USE_EXISTING_FUEL=''
162 FUEL_CREATION_ONLY=''
163 NO_DEPLOY_ENVIRONMENT=''
164 DRY_RUN=0
165 if ! [ -z "${DEPLOY_TIMEOUT}" ]; then
166     DEPLOY_TIMEOUT="-dt ${DEPLOY_TIMEOUT}"
167 else
168     DEPLOY_TIMEOUT=""
169 fi
170 set -x
171 #
172 # END of variables to customize
173 ##############################################################################
174
175 ##############################################################################
176 # BEGIN of main
177 #
178 set +x
179 OPNFV_BRIDGE_IDX=0
180 while getopts "b:B:dfFl:L:p:s:S:T:i:he" OPTION
181 do
182     case $OPTION in
183         b)
184             BASE_CONFIG_URI=${OPTARG}
185             if [[ ! $BASE_CONFIG_URI =~ ${URI_REGEXP} ]]; then
186                 notify "[ERROR] -b $BASE_CONFIG_URI - invalid URI\n"
187                 usage
188                 exit 1
189             fi
190             ;;
191         B)
192             OIFS=${IFS}
193             IFS=','
194             OPT_BRIDGES=($OPTARG)
195             for bridge in "${OPT_BRIDGES[@]}"; do
196                 if [ -n "${bridge}" ]; then
197                     OPNFV_BRIDGES[${OPNFV_BRIDGE_IDX}]="${bridge}"
198                 fi
199                 OPNFV_BRIDGE_IDX=$((OPNFV_BRIDGE_IDX + 1))
200             done
201             IFS=${OIFS}
202             ;;
203         d)
204             notify '' 3 "${OPTION}"; continue
205             DRY_RUN=1
206             ;;
207         f)
208             notify '' 3 "${OPTION}"; continue
209             USE_EXISTING_FUEL='-nf'
210             ;;
211         F)
212             notify '' 3 "${OPTION}"; continue
213             FUEL_CREATION_ONLY='-fo'
214             ;;
215         e)
216             notify '' 3 "${OPTION}"; continue
217             NO_DEPLOY_ENVIRONMENT='-nde'
218             ;;
219         l)
220             TARGET_LAB=${OPTARG}
221             ;;
222         L)
223             DEPLOY_LOG="${OPTARG}"
224             ;;
225         p)
226             TARGET_POD=${OPTARG}
227             if [[ "${TARGET_POD}" =~ "virtual" ]]; then
228                 DEPLOY_TYPE='virtual'
229             fi
230             ;;
231         s)
232             DEPLOY_SCENARIO=${OPTARG}
233             ;;
234         S)
235             if [[ ${OPTARG} ]]; then
236                 STORAGE_DIR="${OPTARG}"
237             fi
238             ;;
239         T)
240             notify '' 3 "${OPTION}"; continue
241             DEPLOY_TIMEOUT="-dt ${OPTARG}"
242             ;;
243         i)
244             notify '' 3 "${OPTION}"; continue
245             ISO=${OPTARG}
246             if [[ ! $ISO =~ ${URI_REGEXP} ]]; then
247                 notify "[ERROR] -i $ISO - invalid URI\n"
248                 usage
249                 exit 1
250             fi
251             ;;
252         h)
253             usage
254             exit 0
255             ;;
256         *)
257             notify "[ERROR] Arguments not according to new argument style\n"
258             exit 1
259             ;;
260     esac
261 done
262
263 if [[ "$(sudo whoami)" != 'root' ]]; then
264     notify "This script requires sudo rights\n" 1>&2
265     exit 1
266 fi
267
268 if ! virsh list >/dev/null 2>&1; then
269     notify "This script requires hypervisor access\n" 1>&2
270     exit 1
271 fi
272
273 # Validate mandatory arguments are set
274 if [ -z "${TARGET_LAB}" ] || [ -z "${TARGET_POD}" ] || \
275    [ -z "${DEPLOY_SCENARIO}" ]; then
276     notify "[ERROR] At least one of the mandatory args is missing!\n" 1>&2
277     usage
278     exit 1
279 fi
280
281 set -x
282
283 # Enable the automatic exit trap
284 trap do_exit SIGINT SIGTERM EXIT
285
286 # Set no restrictive umask so that Jenkins can remove any residuals
287 umask 0000
288
289 clean
290
291 pushd "${DEPLOY_DIR}" > /dev/null
292 # Prepare the deploy config files based on lab/pod information, deployment
293 # scenario, etc.
294
295 # Install required packages
296 [ -n "$(command -v apt-get)" ] && sudo apt-get install -y \
297   git make rsync mkisofs curl virtinst cpu-checker qemu-kvm
298 [ -n "$(command -v yum)" ] && sudo yum install -y --skip-broken \
299   git make rsync genisoimage curl virt-install qemu-kvm
300
301 if [ "$(uname -i)" = "aarch64" ]; then
302   [ -n "$(command -v apt-get)" ] && sudo apt-get install -y vgabios && \
303   sudo ln -sf /usr/share/vgabios/vgabios.bin /usr/share/qemu/vgabios-stdvga.bin
304   [ -n "$(command -v yum)" ] && sudo yum install -y --skip-broken vgabios
305 fi
306
307 # Clone git submodules and apply our patches
308 make -C "${REPO_ROOT_PATH}/mcp/patches" deepclean patches-import
309
310 # Convert Pharos-compatible POD Descriptor File (PDF) to reclass model input
311 PHAROS_GEN_CONFIG_SCRIPT="./pharos/config/utils/generate_config.py"
312 PHAROS_INSTALLER_ADAPTER="./pharos/config/installers/fuel/pod_config.yml.j2"
313 BASE_CONFIG_PDF="${BASE_CONFIG_URI}/labs/${TARGET_LAB}/${TARGET_POD}.yaml"
314 LOCAL_PDF="${STORAGE_DIR}/$(basename "${BASE_CONFIG_PDF}")"
315 LOCAL_PDF_RECLASS="${STORAGE_DIR}/pod_config.yml"
316 if ! curl --create-dirs -o "${LOCAL_PDF}" "${BASE_CONFIG_PDF}"; then
317     if [ "${DEPLOY_TYPE}" = 'baremetal' ]; then
318         notify "[ERROR] Could not retrieve PDF (Pod Descriptor File)!\n" 1>&2
319         exit 1
320     else
321         notify "[WARN] Could not retrieve PDF (Pod Descriptor File)!\n" 3
322     fi
323 elif ! "${PHAROS_GEN_CONFIG_SCRIPT}" -y "${LOCAL_PDF}" \
324     -j "${PHAROS_INSTALLER_ADAPTER}" > "${LOCAL_PDF_RECLASS}"; then
325     notify "[ERROR] Could not convert PDF to reclass model input!\n" 1>&2
326     exit 1
327 fi
328
329 # Check scenario file existence
330 SCENARIO_DIR="../config/scenario"
331 if [ ! -f  "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml" ]; then
332     notify "[WARN] ${DEPLOY_SCENARIO}.yaml not found! \
333             Setting simplest scenario (os-nosdn-nofeature-noha)\n" 3
334     DEPLOY_SCENARIO='os-nosdn-nofeature-noha'
335     if [ ! -f  "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml" ]; then
336         notify "[ERROR] Scenario definition file is missing!\n" 1>&2
337         exit 1
338     fi
339 fi
340
341 # Check defaults file existence
342 if [ ! -f  "${SCENARIO_DIR}/defaults-$(uname -i).yaml" ]; then
343     notify "[ERROR] Scenario defaults file is missing!\n" 1>&2
344     exit 1
345 fi
346
347 # Get required infra deployment data
348 source lib.sh
349 eval "$(parse_yaml "${SCENARIO_DIR}/defaults-$(uname -i).yaml")"
350 eval "$(parse_yaml "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml")"
351
352 export CLUSTER_DOMAIN=${cluster_domain}
353
354 declare -A virtual_nodes_ram virtual_nodes_vcpus
355 for node in "${virtual_nodes[@]}"; do
356     virtual_custom_ram="virtual_${node}_ram"
357     virtual_custom_vcpus="virtual_${node}_vcpus"
358     virtual_nodes_ram[$node]=${!virtual_custom_ram:-$virtual_default_ram}
359     virtual_nodes_vcpus[$node]=${!virtual_custom_vcpus:-$virtual_default_vcpus}
360 done
361
362 # Expand reclass and virsh network templates
363 for tp in "${RECLASS_CLUSTER_DIR}/all-mcp-ocata-common/opnfv/"*.template \
364     net_*.template; do envsubst < "${tp}" > "${tp%.template}"; done
365
366 # Infra setup
367 generate_ssh_key
368 prepare_vms virtual_nodes "${base_image}" "${STORAGE_DIR}"
369 create_networks OPNFV_BRIDGES
370 create_vms virtual_nodes virtual_nodes_ram virtual_nodes_vcpus \
371     OPNFV_BRIDGES "${STORAGE_DIR}"
372 update_mcpcontrol_network
373 start_vms virtual_nodes
374 check_connection
375
376 ./salt.sh "${LOCAL_PDF_RECLASS}"
377
378 # Openstack cluster setup
379 for state in "${cluster_states[@]}"; do
380     notify "STATE: ${state}\n" 2
381     # shellcheck disable=SC2086,2029
382     ssh ${SSH_OPTS} "ubuntu@${SALT_MASTER}" \
383         sudo "/root/fuel/mcp/config/states/${state} || true"
384 done
385
386 ./log.sh "${DEPLOY_LOG}"
387
388 popd > /dev/null
389
390 #
391 # END of main
392 ##############################################################################