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 export SSH_KEY=${SSH_KEY:-"/var/lib/opnfv/mcp.rsa"}
154 export SALT_MASTER=${INSTALLER_IP:-10.20.0.2}
155 export SALT_MASTER_USER=${SALT_MASTER_USER:-ubuntu}
156 export MAAS_IP=${MAAS_IP:-${SALT_MASTER%.*}.3}
158 # These should be determined from PDF later
159 export MAAS_PXE_NETWORK=${MAAS_PXE_NETWORK:-192.168.11.0}
161 # Derivated from above global vars
162 export SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ${SSH_KEY}"
163 export SSH_SALT="${SALT_MASTER_USER}@${SALT_MASTER}"
165 # Variables below are disabled for now, to be re-introduced or removed later
167 if ! [ -z "${DEPLOY_TIMEOUT}" ]; then
168 DEPLOY_TIMEOUT="-dt ${DEPLOY_TIMEOUT}"
174 # END of variables to customize
175 ##############################################################################
177 ##############################################################################
182 while getopts "b:B:dfFl:L:p:s:S:T:i:he" OPTION
186 BASE_CONFIG_URI=${OPTARG}
187 if [[ ! $BASE_CONFIG_URI =~ ${URI_REGEXP} ]]; then
188 notify "[ERROR] -b $BASE_CONFIG_URI - invalid URI\n"
196 OPT_BRIDGES=($OPTARG)
197 for bridge in "${OPT_BRIDGES[@]}"; do
198 if [ -n "${bridge}" ]; then
199 OPNFV_BRIDGES[${OPNFV_BRIDGE_IDX}]="${bridge}"
201 OPNFV_BRIDGE_IDX=$((OPNFV_BRIDGE_IDX + 1))
212 INFRA_CREATION_ONLY=1
215 NO_DEPLOY_ENVIRONMENT=1
221 DEPLOY_LOG="${OPTARG}"
225 if [[ "${TARGET_POD}" =~ "virtual" ]]; then
226 DEPLOY_TYPE='virtual'
230 DEPLOY_SCENARIO=${OPTARG}
233 if [[ ${OPTARG} ]]; then
234 STORAGE_DIR="${OPTARG}"
238 notify '' 3 "${OPTION}"; continue
239 DEPLOY_TIMEOUT="-dt ${OPTARG}"
242 notify '' 3 "${OPTION}"; continue
244 if [[ ! $ISO =~ ${URI_REGEXP} ]]; then
245 notify "[ERROR] -i $ISO - invalid URI\n"
255 notify "[ERROR] Arguments not according to new argument style\n"
261 if [[ "$(sudo whoami)" != 'root' ]]; then
262 notify "This script requires sudo rights\n" 1>&2
266 if ! virsh list >/dev/null 2>&1; then
267 notify "This script requires hypervisor access\n" 1>&2
271 # Validate mandatory arguments are set
272 if [ -z "${TARGET_LAB}" ] || [ -z "${TARGET_POD}" ] || \
273 [ -z "${DEPLOY_SCENARIO}" ]; then
274 notify "[ERROR] At least one of the mandatory args is missing!\n" 1>&2
281 # Enable the automatic exit trap
282 trap do_exit SIGINT SIGTERM EXIT
284 # Set no restrictive umask so that Jenkins can remove any residuals
289 pushd "${DEPLOY_DIR}" > /dev/null
290 # Prepare the deploy config files based on lab/pod information, deployment
293 # Install required packages
294 [ -n "$(command -v apt-get)" ] && sudo apt-get install -y \
295 git make rsync mkisofs curl virtinst cpu-checker qemu-kvm
296 [ -n "$(command -v yum)" ] && sudo yum install -y --skip-broken \
297 git make rsync genisoimage curl virt-install qemu-kvm
299 if [ "$(uname -i)" = "aarch64" ]; then
300 [ -n "$(command -v apt-get)" ] && sudo apt-get install -y vgabios && \
301 sudo ln -sf /usr/share/vgabios/vgabios.bin /usr/share/qemu/vgabios-stdvga.bin
302 [ -n "$(command -v yum)" ] && sudo yum install -y --skip-broken vgabios
305 # Clone git submodules and apply our patches
306 make -C "${REPO_ROOT_PATH}/mcp/patches" deepclean patches-import
308 # Convert Pharos-compatible POD Descriptor File (PDF) to reclass model input
309 PHAROS_GEN_CONFIG_SCRIPT="./pharos/config/utils/generate_config.py"
310 PHAROS_INSTALLER_ADAPTER="./pharos/config/installers/fuel/pod_config.yml.j2"
311 BASE_CONFIG_PDF="${BASE_CONFIG_URI}/labs/${TARGET_LAB}/${TARGET_POD}.yaml"
312 BASE_CONFIG_IDF="${BASE_CONFIG_URI}/labs/${TARGET_LAB}/idf-${TARGET_POD}.yaml"
313 LOCAL_PDF="${STORAGE_DIR}/$(basename "${BASE_CONFIG_PDF}")"
314 LOCAL_IDF="${STORAGE_DIR}/$(basename "${BASE_CONFIG_IDF}")"
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
321 notify "[WARN] Could not retrieve PDF (Pod Descriptor File)!\n" 3
323 elif ! curl -o "${LOCAL_IDF}" "${BASE_CONFIG_IDF}"; then
324 notify "[WARN] POD has no IDF (Installer Descriptor File)!\n" 3
325 elif ! "${PHAROS_GEN_CONFIG_SCRIPT}" -y "${LOCAL_PDF}" \
326 -j "${PHAROS_INSTALLER_ADAPTER}" > "${LOCAL_PDF_RECLASS}"; then
327 notify "[ERROR] Could not convert PDF to reclass model input!\n" 1>&2
331 # Check scenario file existence
332 SCENARIO_DIR="../config/scenario"
333 if [ ! -f "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml" ]; then
334 notify "[WARN] ${DEPLOY_SCENARIO}.yaml not found! \
335 Setting simplest scenario (os-nosdn-nofeature-noha)\n" 3
336 DEPLOY_SCENARIO='os-nosdn-nofeature-noha'
337 if [ ! -f "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml" ]; then
338 notify "[ERROR] Scenario definition file is missing!\n" 1>&2
343 # Check defaults file existence
344 if [ ! -f "${SCENARIO_DIR}/defaults-$(uname -i).yaml" ]; then
345 notify "[ERROR] Scenario defaults file is missing!\n" 1>&2
349 # Get required infra deployment data
351 eval "$(parse_yaml "${SCENARIO_DIR}/defaults-$(uname -i).yaml")"
352 eval "$(parse_yaml "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml")"
353 eval "$(parse_yaml "${LOCAL_PDF_RECLASS}")"
355 export CLUSTER_DOMAIN=${cluster_domain}
357 declare -A virtual_nodes_ram virtual_nodes_vcpus
358 for node in "${virtual_nodes[@]}"; do
359 virtual_custom_ram="virtual_${node}_ram"
360 virtual_custom_vcpus="virtual_${node}_vcpus"
361 virtual_nodes_ram[$node]=${!virtual_custom_ram:-$virtual_default_ram}
362 virtual_nodes_vcpus[$node]=${!virtual_custom_vcpus:-$virtual_default_vcpus}
365 # Expand reclass and virsh network templates
366 for tp in "${RECLASS_CLUSTER_DIR}/all-mcp-ocata-common/opnfv/"*.template \
370 EOF" 2> /dev/null > "${tp%.template}"
373 # Map PDF networks 'admin', 'mgmt', 'private' and 'public' to bridge names
374 BR_NAMES=('admin' 'mgmt' 'private' 'public')
376 "${parameters__param_opnfv_maas_pxe_address}" \
377 "${parameters__param_opnfv_infra_config_address}" \
378 "${parameters__param_opnfv_openstack_compute_node01_tenant_address}" \
379 "${parameters__param_opnfv_openstack_compute_node01_external_address}" \
381 for ((i = 0; i < ${#BR_NETS[@]}; i++)); do
382 br_jump=$(eval echo "\$parameters__param_opnfv_jump_bridge_${BR_NAMES[i]}")
383 if [ -n "${br_jump}" ] && [ "${br_jump}" != 'None' ] && \
384 [ -d "/sys/class/net/${br_jump}/bridge" ]; then
385 notify "[OK] Bridge found for '${BR_NAMES[i]}': ${br_jump}\n" 2
386 OPNFV_BRIDGES[${i}]="${br_jump}"
387 elif [ -n "${BR_NETS[i]}" ]; then
388 bridge=$(ip addr | awk "/${BR_NETS[i]%.*}./ {print \$NF; exit}")
389 if [ -n "${bridge}" ] && [ -d "/sys/class/net/${bridge}/bridge" ]; then
390 notify "[OK] Bridge found for net ${BR_NETS[i]%.*}.0: ${bridge}\n" 2
391 OPNFV_BRIDGES[${i}]="${bridge}"
395 notify "[NOTE] Using bridges: ${OPNFV_BRIDGES[*]}\n" 2
398 if [ ${DRY_RUN} -eq 1 ]; then
399 notify "Dry run, skipping all deployment tasks\n" 2 1>&2
401 elif [ ${USE_EXISTING_INFRA} -eq 1 ]; then
402 notify "Use existing infra\n" 2 1>&2
406 prepare_vms virtual_nodes "${base_image}" "${STORAGE_DIR}"
407 create_networks OPNFV_BRIDGES
408 create_vms virtual_nodes virtual_nodes_ram virtual_nodes_vcpus \
409 OPNFV_BRIDGES "${STORAGE_DIR}"
410 update_mcpcontrol_network
411 start_vms virtual_nodes
413 ./salt.sh "${LOCAL_PDF_RECLASS}"
416 if [ ${INFRA_CREATION_ONLY} -eq 1 ] || [ ${NO_DEPLOY_ENVIRONMENT} -eq 1 ]; then
417 notify "Skip openstack cluster setup\n" 2
419 # Openstack cluster setup
420 for state in "${cluster_states[@]}"; do
421 notify "STATE: ${state}\n" 2
422 # shellcheck disable=SC2086,2029
423 ssh ${SSH_OPTS} "ubuntu@${SALT_MASTER}" \
424 sudo "/root/fuel/mcp/config/states/${state} || true"
428 ./log.sh "${DEPLOY_LOG}"
434 ##############################################################################