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 "DISABLED OPTIONS (not yet supported with MCP):" 3)
54 -T (disabled) Timeout, in minutes, for the deploy.
56 $(notify "Description:" 2)
57 Deploys the Fuel@OPNFV stack on the indicated lab resource.
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.
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 -d Dry-run - Produce deploy config files, but do not execute deploy
81 -e Do not launch environment deployment
82 -f Deploy on existing Salt master
83 -F Do only create a Salt master
84 -h Print this message and exit
85 -L Deployment log path and name, eg. -L /home/jenkins/job.log.tar.gz
86 -l Lab name as defined in the configuration directory, e.g. lf
87 -p POD name as defined in the configuration directory, e.g. pod2
88 -s Deployment-scenario, this points to a short deployment scenario name, which
89 has to be defined in config directory (e.g. os-odl-nofeature-ha).
90 -S Storage dir for VM images, default is mcp/deploy/images
92 $(notify "Disabled input parameters (not yet supported with MCP):" 3)
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)://)
98 $(notify "[NOTE] sudo & virsh priviledges are needed for this script to run" 3)
102 $(notify "sudo $(basename "$0") \\
103 -b file:///home/jenkins/securedlab \\
105 -s os-odl-nofeature-ha" 2)
110 # END of usage description
111 ##############################################################################
113 ##############################################################################
114 # BEGIN of colored notification wrapper
117 tput setaf "${2:-1}" || true
118 echo -en "${1:-"[WARN] Unsupported opt arg: $3\\n"}"
122 # END of colored notification wrapper
123 ##############################################################################
125 ##############################################################################
126 # BEGIN of deployment clean-up
129 echo "Cleaning up deploy tmp directories"
132 # END of deployment clean-up
133 ##############################################################################
135 ##############################################################################
136 # BEGIN of variables to customize
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"
147 # Customize deploy workflow
148 DRY_RUN=${DRY_RUN:-0}
149 USE_EXISTING_INFRA=${USE_EXISTING_INFRA:-0}
150 INFRA_CREATION_ONLY=${INFRA_CREATION_ONLY:-0}
151 NO_DEPLOY_ENVIRONMENT=${NO_DEPLOY_ENVIRONMENT:-0}
153 source "${DEPLOY_DIR}/globals.sh"
155 # Variables below are disabled for now, to be re-introduced or removed later
157 if ! [ -z "${DEPLOY_TIMEOUT}" ]; then
158 DEPLOY_TIMEOUT="-dt ${DEPLOY_TIMEOUT}"
164 # END of variables to customize
165 ##############################################################################
167 ##############################################################################
172 while getopts "b:B:dfFl:L:p:s:S:T:i:he" OPTION
176 BASE_CONFIG_URI=${OPTARG}
177 if [[ ! $BASE_CONFIG_URI =~ ${URI_REGEXP} ]]; then
178 notify "[ERROR] -b $BASE_CONFIG_URI - invalid URI\n"
186 OPT_BRIDGES=($OPTARG)
187 for bridge in "${OPT_BRIDGES[@]}"; do
188 if [ -n "${bridge}" ]; then
189 OPNFV_BRIDGES[${OPNFV_BRIDGE_IDX}]="${bridge}"
191 OPNFV_BRIDGE_IDX=$((OPNFV_BRIDGE_IDX + 1))
202 INFRA_CREATION_ONLY=1
205 NO_DEPLOY_ENVIRONMENT=1
211 DEPLOY_LOG="${OPTARG}"
215 if [[ "${TARGET_POD}" =~ "virtual" ]]; then
216 DEPLOY_TYPE='virtual'
220 DEPLOY_SCENARIO=${OPTARG}
223 if [[ ${OPTARG} ]]; then
224 STORAGE_DIR="${OPTARG}"
228 notify '' 3 "${OPTION}"; continue
229 DEPLOY_TIMEOUT="-dt ${OPTARG}"
232 notify '' 3 "${OPTION}"; continue
234 if [[ ! $ISO =~ ${URI_REGEXP} ]]; then
235 notify "[ERROR] -i $ISO - invalid URI\n"
245 notify "[ERROR] Arguments not according to new argument style\n"
251 if [[ "$(sudo whoami)" != 'root' ]]; then
252 notify "This script requires sudo rights\n" 1>&2
256 if ! virsh list >/dev/null 2>&1; then
257 notify "This script requires hypervisor access\n" 1>&2
261 # Validate mandatory arguments are set
262 if [ -z "${TARGET_LAB}" ] || [ -z "${TARGET_POD}" ] || \
263 [ -z "${DEPLOY_SCENARIO}" ]; then
264 notify "[ERROR] At least one of the mandatory args is missing!\n" 1>&2
271 # Enable the automatic exit trap
272 trap do_exit SIGINT SIGTERM EXIT
274 # Set no restrictive umask so that Jenkins can remove any residuals
279 pushd "${DEPLOY_DIR}" > /dev/null
280 # Prepare the deploy config files based on lab/pod information, deployment
283 # Install required packages
284 [ -n "$(command -v apt-get)" ] && sudo apt-get install -y \
285 git make rsync mkisofs curl virtinst cpu-checker qemu-kvm
286 [ -n "$(command -v yum)" ] && sudo yum install -y --skip-broken \
287 git make rsync genisoimage curl virt-install qemu-kvm
289 if [ "$(uname -i)" = "aarch64" ]; then
290 [ -n "$(command -v apt-get)" ] && sudo apt-get install -y vgabios && \
291 sudo ln -sf /usr/share/vgabios/vgabios.bin /usr/share/qemu/vgabios-stdvga.bin
292 [ -n "$(command -v yum)" ] && sudo yum install -y --skip-broken vgabios
295 # Clone git submodules and apply our patches
296 make -C "${REPO_ROOT_PATH}/mcp/patches" deepclean patches-import
298 # Convert Pharos-compatible POD Descriptor File (PDF) to reclass model input
299 PHAROS_GEN_CONFIG_SCRIPT="./pharos/config/utils/generate_config.py"
300 PHAROS_INSTALLER_ADAPTER="./pharos/config/installers/fuel/pod_config.yml.j2"
301 BASE_CONFIG_PDF="${BASE_CONFIG_URI}/labs/${TARGET_LAB}/${TARGET_POD}.yaml"
302 BASE_CONFIG_IDF="${BASE_CONFIG_URI}/labs/${TARGET_LAB}/idf-${TARGET_POD}.yaml"
303 LOCAL_PDF="${STORAGE_DIR}/$(basename "${BASE_CONFIG_PDF}")"
304 LOCAL_IDF="${STORAGE_DIR}/$(basename "${BASE_CONFIG_IDF}")"
305 LOCAL_PDF_RECLASS="${STORAGE_DIR}/pod_config.yml"
306 if ! curl --create-dirs -o "${LOCAL_PDF}" "${BASE_CONFIG_PDF}"; then
307 if [ "${DEPLOY_TYPE}" = 'baremetal' ]; then
308 notify "[ERROR] Could not retrieve PDF (Pod Descriptor File)!\n" 1>&2
311 notify "[WARN] Could not retrieve PDF (Pod Descriptor File)!\n" 3
313 elif ! curl -o "${LOCAL_IDF}" "${BASE_CONFIG_IDF}"; then
314 notify "[WARN] POD has no IDF (Installer Descriptor File)!\n" 3
315 elif ! "${PHAROS_GEN_CONFIG_SCRIPT}" -y "${LOCAL_PDF}" \
316 -j "${PHAROS_INSTALLER_ADAPTER}" > "${LOCAL_PDF_RECLASS}"; then
317 notify "[ERROR] Could not convert PDF to reclass model input!\n" 1>&2
321 # Check scenario file existence
322 SCENARIO_DIR="../config/scenario"
323 if [ ! -f "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml" ]; then
324 notify "[WARN] ${DEPLOY_SCENARIO}.yaml not found! \
325 Setting simplest scenario (os-nosdn-nofeature-noha)\n" 3
326 DEPLOY_SCENARIO='os-nosdn-nofeature-noha'
327 if [ ! -f "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml" ]; then
328 notify "[ERROR] Scenario definition file is missing!\n" 1>&2
333 # Check defaults file existence
334 if [ ! -f "${SCENARIO_DIR}/defaults-$(uname -i).yaml" ]; then
335 notify "[ERROR] Scenario defaults file is missing!\n" 1>&2
339 # Get required infra deployment data
341 eval "$(parse_yaml "${SCENARIO_DIR}/defaults-$(uname -i).yaml")"
342 eval "$(parse_yaml "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml")"
343 eval "$(parse_yaml "${LOCAL_PDF_RECLASS}")"
345 export CLUSTER_DOMAIN=${cluster_domain}
347 declare -A virtual_nodes_ram virtual_nodes_vcpus
348 for node in "${virtual_nodes[@]}"; do
349 virtual_custom_ram="virtual_${node}_ram"
350 virtual_custom_vcpus="virtual_${node}_vcpus"
351 virtual_nodes_ram[$node]=${!virtual_custom_ram:-$virtual_default_ram}
352 virtual_nodes_vcpus[$node]=${!virtual_custom_vcpus:-$virtual_default_vcpus}
355 # Expand reclass and virsh network templates
356 for tp in "${RECLASS_CLUSTER_DIR}/all-mcp-ocata-common/opnfv/"*.template \
360 EOF" 2> /dev/null > "${tp%.template}"
363 # Map PDF networks 'admin', 'mgmt', 'private' and 'public' to bridge names
364 BR_NAMES=('admin' 'mgmt' 'private' 'public')
366 "${parameters__param_opnfv_maas_pxe_address}" \
367 "${parameters__param_opnfv_infra_config_address}" \
368 "${parameters__param_opnfv_openstack_compute_node01_tenant_address}" \
369 "${parameters__param_opnfv_openstack_compute_node01_external_address}" \
371 for ((i = 0; i < ${#BR_NETS[@]}; i++)); do
372 br_jump=$(eval echo "\$parameters__param_opnfv_jump_bridge_${BR_NAMES[i]}")
373 if [ -n "${br_jump}" ] && [ "${br_jump}" != 'None' ] && \
374 [ -d "/sys/class/net/${br_jump}/bridge" ]; then
375 notify "[OK] Bridge found for '${BR_NAMES[i]}': ${br_jump}\n" 2
376 OPNFV_BRIDGES[${i}]="${br_jump}"
377 elif [ -n "${BR_NETS[i]}" ]; then
378 bridge=$(ip addr | awk "/${BR_NETS[i]%.*}./ {print \$NF; exit}")
379 if [ -n "${bridge}" ] && [ -d "/sys/class/net/${bridge}/bridge" ]; then
380 notify "[OK] Bridge found for net ${BR_NETS[i]%.*}.0: ${bridge}\n" 2
381 OPNFV_BRIDGES[${i}]="${bridge}"
385 notify "[NOTE] Using bridges: ${OPNFV_BRIDGES[*]}\n" 2
388 if [ ${DRY_RUN} -eq 1 ]; then
389 notify "Dry run, skipping all deployment tasks\n" 2 1>&2
391 elif [ ${USE_EXISTING_INFRA} -eq 1 ]; then
392 notify "Use existing infra\n" 2 1>&2
396 prepare_vms virtual_nodes "${base_image}" "${STORAGE_DIR}"
397 create_networks OPNFV_BRIDGES
398 create_vms virtual_nodes virtual_nodes_ram virtual_nodes_vcpus \
399 OPNFV_BRIDGES "${STORAGE_DIR}"
400 update_mcpcontrol_network
401 start_vms virtual_nodes
403 ./salt.sh "${LOCAL_PDF_RECLASS}"
406 if [ ${INFRA_CREATION_ONLY} -eq 1 ] || [ ${NO_DEPLOY_ENVIRONMENT} -eq 1 ]; then
407 notify "Skip openstack cluster setup\n" 2
409 # Openstack cluster setup
410 for state in "${cluster_states[@]}"; do
411 notify "STATE: ${state}\n" 2
412 # shellcheck disable=SC2086,2029
413 ssh ${SSH_OPTS} "ubuntu@${SALT_MASTER}" \
414 sudo "/root/fuel/mcp/config/states/${state} || true"
418 ./log.sh "${DEPLOY_LOG}"
424 ##############################################################################