2 # shellcheck disable=SC2034,SC2154,SC1091
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 ##############################################################################
13 ##############################################################################
14 # BEGIN of Exit handlers
21 # End of Exit handlers
22 ##############################################################################
24 ##############################################################################
25 # BEGIN of usage description
30 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
31 $(notify "$(basename "$0"): Deploy the Fuel@OPNFV MCP stack" 3)
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] [-f] [-F] [-e] [-d]
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
42 -e Do not launch environment deployment
43 -f Deploy on existing Salt master
44 -F Do only create a Salt master
45 -h Print this message and exit
48 -s Deploy-scenario short-name
49 -S Storage dir for VM images
50 -L Deployment log path and file name
52 $(notify "Description:" 2)
53 Deploys the Fuel@OPNFV stack on the indicated lab resource.
55 This script provides the Fuel@OPNFV deployment abstraction.
56 It depends on the OPNFV official configuration directory/file structure
57 and provides a fairly simple mechanism to execute a deployment.
59 $(notify "Input parameters to the build script are:" 2)
60 -b Base URI to the configuration directory (needs to be provided in URI style,
61 it can be a local resource: file:// or a remote resource http(s)://).
62 A POD Descriptor File (PDF) should be available at:
63 <base-uri>/labs/<lab-name>/<pod-name>.yaml
64 The default is './mcp/config'.
65 -B Bridges to be used by deploy script. It can be specified several times,
66 or as a comma separated list of bridges, or both: -B br1 -B br2,br3
67 First occurence sets PXE Brige, next Mgmt, then Internal and Public.
68 For an empty value, the deploy script will use virsh to create the default
69 expected network (e.g. -B pxe,,,public will use existing "pxe" and "public"
70 bridges, respectively create "mgmt" and "internal").
71 Note that a virtual network "mcpcontrol" is always created. For virtual
72 deploys, "mcpcontrol" is also used for PXE, leaving the PXE bridge unused.
73 For baremetal deploys, PXE bridge is used for baremetal node provisioning,
74 while "mcpcontrol" is used to provision the infrastructure VMs only.
75 The default is 'pxebr'.
76 -d Dry-run - Produce deploy config files, but do not execute deploy
77 -e Do not launch environment deployment
78 -f Deploy on existing Salt master
79 -F Do only create a Salt master
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
88 $(notify "[NOTE] sudo & virsh priviledges are needed for this script to run" 3)
92 $(notify "sudo $(basename "$0") \\
93 -b file:///home/jenkins/securedlab \\
95 -s os-odl-nofeature-ha" 2)
100 # END of usage description
101 ##############################################################################
103 ##############################################################################
104 # BEGIN of colored notification wrapper
107 tput setaf "${2:-1}" || true
108 echo -en "${1:-"[WARN] Unsupported opt arg: $3\\n"}"
112 # END of colored notification wrapper
113 ##############################################################################
115 ##############################################################################
116 # BEGIN of deployment clean-up
119 echo "Cleaning up deploy tmp directories"
122 # END of deployment clean-up
123 ##############################################################################
125 ##############################################################################
126 # BEGIN of variables to customize
128 REPO_ROOT_PATH=$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")
129 DEPLOY_DIR=$(cd "${REPO_ROOT_PATH}/mcp/scripts"; pwd)
130 STORAGE_DIR=$(cd "${REPO_ROOT_PATH}/mcp/deploy/images"; pwd)
131 RECLASS_CLUSTER_DIR=$(cd "${REPO_ROOT_PATH}/mcp/reclass/classes/cluster"; pwd)
132 DEPLOY_TYPE='baremetal'
133 OPNFV_BRIDGES=('pxebr' 'mgmt' 'internal' 'public')
134 URI_REGEXP='(file|https?|ftp)://.*'
135 BASE_CONFIG_URI="file://${REPO_ROOT_PATH}/mcp/config"
137 # Customize deploy workflow
138 DRY_RUN=${DRY_RUN:-0}
139 USE_EXISTING_INFRA=${USE_EXISTING_INFRA:-0}
140 INFRA_CREATION_ONLY=${INFRA_CREATION_ONLY:-0}
141 NO_DEPLOY_ENVIRONMENT=${NO_DEPLOY_ENVIRONMENT:-0}
143 source "${DEPLOY_DIR}/globals.sh"
146 # END of variables to customize
147 ##############################################################################
149 ##############################################################################
154 while getopts "b:B:dfFl:L:p:s:S:he" OPTION
158 BASE_CONFIG_URI=${OPTARG}
159 if [[ ! $BASE_CONFIG_URI =~ ${URI_REGEXP} ]]; then
160 notify "[ERROR] -b $BASE_CONFIG_URI - invalid URI\n"
168 OPT_BRIDGES=($OPTARG)
169 for bridge in "${OPT_BRIDGES[@]}"; do
170 if [ -n "${bridge}" ]; then
171 OPNFV_BRIDGES[${OPNFV_BRIDGE_IDX}]="${bridge}"
173 OPNFV_BRIDGE_IDX=$((OPNFV_BRIDGE_IDX + 1))
184 INFRA_CREATION_ONLY=1
187 NO_DEPLOY_ENVIRONMENT=1
193 DEPLOY_LOG="${OPTARG}"
197 if [[ "${TARGET_POD}" =~ "virtual" ]]; then
198 DEPLOY_TYPE='virtual'
202 DEPLOY_SCENARIO=${OPTARG}
205 if [[ ${OPTARG} ]]; then
206 STORAGE_DIR="${OPTARG}"
214 notify "[ERROR] Arguments not according to new argument style\n"
220 if [[ "$(sudo whoami)" != 'root' ]]; then
221 notify "[ERROR] This script requires sudo rights\n" 1>&2
225 if ! virsh list >/dev/null 2>&1; then
226 notify "[ERROR] This script requires hypervisor access\n" 1>&2
230 # Validate mandatory arguments are set
231 if [ -z "${TARGET_LAB}" ] || [ -z "${TARGET_POD}" ] || \
232 [ -z "${DEPLOY_SCENARIO}" ]; then
233 notify "[ERROR] At least one of the mandatory args is missing!\n" 1>&2
240 # Enable the automatic exit trap
241 trap do_exit SIGINT SIGTERM EXIT
243 # Set no restrictive umask so that Jenkins can remove any residuals
248 pushd "${DEPLOY_DIR}" > /dev/null
249 # Prepare the deploy config files based on lab/pod information, deployment
252 # Install required packages
253 [ -n "$(command -v apt-get)" ] && sudo apt-get install -y \
254 git make rsync mkisofs curl virtinst cpu-checker qemu-kvm
255 [ -n "$(command -v yum)" ] && sudo yum install -y --skip-broken \
256 git make rsync genisoimage curl virt-install qemu-kvm
258 if [ "$(uname -i)" = "aarch64" ]; then
259 [ -n "$(command -v apt-get)" ] && sudo apt-get install -y vgabios && \
260 sudo ln -sf /usr/share/vgabios/vgabios.bin /usr/share/qemu/vgabios-stdvga.bin
261 [ -n "$(command -v yum)" ] && sudo yum install -y --skip-broken vgabios
264 # Clone git submodules and apply our patches
265 make -C "${REPO_ROOT_PATH}/mcp/patches" deepclean patches-import
267 # Convert Pharos-compatible POD Descriptor File (PDF) to reclass model input
268 PHAROS_GEN_CONFIG_SCRIPT="./pharos/config/utils/generate_config.py"
269 PHAROS_INSTALLER_ADAPTER="./pharos/config/installers/fuel/pod_config.yml.j2"
270 BASE_CONFIG_PDF="${BASE_CONFIG_URI}/labs/${TARGET_LAB}/${TARGET_POD}.yaml"
271 BASE_CONFIG_IDF="${BASE_CONFIG_URI}/labs/${TARGET_LAB}/idf-${TARGET_POD}.yaml"
272 LOCAL_PDF="${STORAGE_DIR}/$(basename "${BASE_CONFIG_PDF}")"
273 LOCAL_IDF="${STORAGE_DIR}/$(basename "${BASE_CONFIG_IDF}")"
274 LOCAL_PDF_RECLASS="${STORAGE_DIR}/pod_config.yml"
275 if ! curl --create-dirs -o "${LOCAL_PDF}" "${BASE_CONFIG_PDF}"; then
276 if [ "${DEPLOY_TYPE}" = 'baremetal' ]; then
277 notify "[ERROR] Could not retrieve PDF (Pod Descriptor File)!\n" 1>&2
280 notify "[WARN] Could not retrieve PDF (Pod Descriptor File)!\n" 3
282 elif ! curl -o "${LOCAL_IDF}" "${BASE_CONFIG_IDF}"; then
283 notify "[WARN] POD has no IDF (Installer Descriptor File)!\n" 3
284 elif ! "${PHAROS_GEN_CONFIG_SCRIPT}" -y "${LOCAL_PDF}" \
285 -j "${PHAROS_INSTALLER_ADAPTER}" > "${LOCAL_PDF_RECLASS}"; then
286 notify "[ERROR] Could not convert PDF to reclass model input!\n" 1>&2
290 # Check scenario file existence
291 SCENARIO_DIR="../config/scenario"
292 if [ ! -f "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml" ]; then
293 notify "[WARN] ${DEPLOY_SCENARIO}.yaml not found! \
294 Setting simplest scenario (os-nosdn-nofeature-noha)\n" 3
295 DEPLOY_SCENARIO='os-nosdn-nofeature-noha'
296 if [ ! -f "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml" ]; then
297 notify "[ERROR] Scenario definition file is missing!\n" 1>&2
302 # Check defaults file existence
303 if [ ! -f "${SCENARIO_DIR}/defaults-$(uname -i).yaml" ]; then
304 notify "[ERROR] Scenario defaults file is missing!\n" 1>&2
308 # Get required infra deployment data
311 eval "$(parse_yaml "${SCENARIO_DIR}/defaults-$(uname -i).yaml")"
312 eval "$(parse_yaml "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml")"
313 eval "$(parse_yaml "${LOCAL_PDF_RECLASS}")"
316 export CLUSTER_DOMAIN=${cluster_domain}
318 declare -A virtual_nodes_ram virtual_nodes_vcpus
319 for node in "${virtual_nodes[@]}"; do
320 virtual_custom_ram="virtual_${node}_ram"
321 virtual_custom_vcpus="virtual_${node}_vcpus"
322 virtual_nodes_ram[$node]=${!virtual_custom_ram:-$virtual_default_ram}
323 virtual_nodes_vcpus[$node]=${!virtual_custom_vcpus:-$virtual_default_vcpus}
326 # Expand reclass and virsh network templates
327 for tp in "${RECLASS_CLUSTER_DIR}/all-mcp-ocata-common/opnfv/"*.template \
331 EOF" 2> /dev/null > "${tp%.template}"
334 # Map PDF networks 'admin', 'mgmt', 'private' and 'public' to bridge names
335 BR_NAMES=('admin' 'mgmt' 'private' 'public')
337 "${parameters__param_opnfv_maas_pxe_address}" \
338 "${parameters__param_opnfv_infra_config_address}" \
339 "${parameters__param_opnfv_openstack_compute_node01_tenant_address}" \
340 "${parameters__param_opnfv_openstack_compute_node01_external_address}" \
342 for ((i = 0; i < ${#BR_NETS[@]}; i++)); do
343 br_jump=$(eval echo "\$parameters__param_opnfv_jump_bridge_${BR_NAMES[i]}")
344 if [ -n "${br_jump}" ] && [ "${br_jump}" != 'None' ] && \
345 [ -d "/sys/class/net/${br_jump}/bridge" ]; then
346 notify "[OK] Bridge found for '${BR_NAMES[i]}': ${br_jump}\n" 2
347 OPNFV_BRIDGES[${i}]="${br_jump}"
348 elif [ -n "${BR_NETS[i]}" ]; then
349 bridge=$(ip addr | awk "/${BR_NETS[i]%.*}./ {print \$NF; exit}")
350 if [ -n "${bridge}" ] && [ -d "/sys/class/net/${bridge}/bridge" ]; then
351 notify "[OK] Bridge found for net ${BR_NETS[i]%.*}.0: ${bridge}\n" 2
352 OPNFV_BRIDGES[${i}]="${bridge}"
356 notify "[NOTE] Using bridges: ${OPNFV_BRIDGES[*]}\n" 2
359 if [ ${DRY_RUN} -eq 1 ]; then
360 notify "[NOTE] Dry run, skipping all deployment tasks\n" 2 1>&2
362 elif [ ${USE_EXISTING_INFRA} -eq 1 ]; then
363 notify "[NOTE] Use existing infra\n" 2 1>&2
367 prepare_vms virtual_nodes "${base_image}" "${STORAGE_DIR}"
368 create_networks OPNFV_BRIDGES
369 create_vms virtual_nodes virtual_nodes_ram virtual_nodes_vcpus \
370 OPNFV_BRIDGES "${STORAGE_DIR}"
371 update_mcpcontrol_network
372 start_vms virtual_nodes
374 ./salt.sh "${LOCAL_PDF_RECLASS}"
377 # Openstack cluster setup
379 if [ ${INFRA_CREATION_ONLY} -eq 1 ] || [ ${NO_DEPLOY_ENVIRONMENT} -eq 1 ]; then
380 notify "[NOTE] Skip openstack cluster setup\n" 2
382 for state in "${cluster_states[@]}"; do
383 notify "[STATE] Applying state: ${state}\n" 2
384 # shellcheck disable=SC2086,2029
385 ssh ${SSH_OPTS} "${SSH_SALT}" \
386 sudo "/root/fuel/mcp/config/states/${state} || true"
390 ./log.sh "${DEPLOY_LOG}"
394 notify "\n[DONE] MCP: Openstack installation finished succesfully!\n\n" 2
398 ##############################################################################