2 # shellcheck disable=SC2034,SC2154,SC1090,SC1091
3 ##############################################################################
4 # Copyright (c) 2017 Ericsson AB, Mirantis Inc., Enea AB and others.
5 # jonas.bjurel@ericsson.com
6 # All rights reserved. This program and the accompanying materials
7 # are made available under the terms of the Apache License, Version 2.0
8 # which accompanies this distribution, and is available at
9 # http://www.apache.org/licenses/LICENSE-2.0
10 ##############################################################################
12 ##############################################################################
13 # BEGIN of Exit handlers
20 # End of Exit handlers
21 ##############################################################################
23 ##############################################################################
24 # BEGIN of usage description
29 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
30 $(notify "$(basename "$0"): Deploy the Fuel@OPNFV MCP stack" 3)
33 $(basename "$0") -b base-uri -l lab-name -p pod-name -s deploy-scenario \\
34 [-B PXE Bridge [-B Mgmt Bridge [-B Internal Bridge [-B Public Bridge]]]] \\
35 [-S storage-dir] [-L /path/to/log/file.tar.gz] [-f] [-F] [-e] [-d]
37 $(notify "OPTIONS:" 2)
38 -b Base-uri for the stack-configuration structure
39 -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
47 -s Deploy-scenario short-name
48 -S Storage dir for VM images
49 -L Deployment log path and file name
51 $(notify "Description:" 2)
52 Deploys the Fuel@OPNFV stack on the indicated lab resource.
54 This script provides the Fuel@OPNFV deployment abstraction.
55 It depends on the OPNFV official configuration directory/file structure
56 and provides a fairly simple mechanism to execute a deployment.
58 $(notify "Input parameters to the build script are:" 2)
59 -b Base URI to the configuration directory (needs to be provided in URI style,
60 it can be a local resource: file:// or a remote resource http(s)://).
61 A POD Descriptor File (PDF) should be available at:
62 <base-uri>/labs/<lab-name>/<pod-name>.yaml
63 The default is './mcp/config'.
64 -B Bridges to be used by deploy script. It can be specified several times,
65 or as a comma separated list of bridges, or both: -B br1 -B br2,br3
66 First occurence sets PXE Brige, next Mgmt, then Internal and Public.
67 For an empty value, the deploy script will use virsh to create the default
68 expected network (e.g. -B pxe,,,public will use existing "pxe" and "public"
69 bridges, respectively create "mgmt" and "internal").
70 Note that a virtual network "mcpcontrol" is always created. For virtual
71 deploys, "mcpcontrol" is also used for PXE, leaving the PXE bridge unused.
72 For baremetal deploys, PXE bridge is used for baremetal node provisioning,
73 while "mcpcontrol" is used to provision the infrastructure VMs only.
74 The default is 'pxebr'.
75 -d Dry-run - Produce deploy config files, but do not execute deploy
76 -e Do not launch environment deployment
77 -f Deploy on existing Salt master
78 -F Do only create a Salt master
79 -h Print this message and exit
80 -L Deployment log path and name, eg. -L /home/jenkins/job.log.tar.gz
81 -l Lab name as defined in the configuration directory, e.g. lf
82 -p POD name as defined in the configuration directory, e.g. pod2
83 -s Deployment-scenario, this points to a short deployment scenario name, which
84 has to be defined in config directory (e.g. os-odl-nofeature-ha).
85 -S Storage dir for VM images, default is mcp/deploy/images
87 $(notify "[NOTE] sudo & virsh priviledges are needed for this script to run" 3)
91 $(notify "sudo $(basename "$0") \\
92 -b file:///home/jenkins/securedlab \\
94 -s os-odl-nofeature-ha" 2)
99 # END of usage description
100 ##############################################################################
102 ##############################################################################
103 # BEGIN of colored notification wrapper
106 tput setaf "${2:-1}" || true
107 echo -en "${1:-"[WARN] Unsupported opt arg: $3\\n"}"
111 # END of colored notification wrapper
112 ##############################################################################
114 ##############################################################################
115 # BEGIN of deployment clean-up
118 echo "Cleaning up deploy tmp directories"
121 # END of deployment clean-up
122 ##############################################################################
124 ##############################################################################
125 # BEGIN of variables to customize
127 REPO_ROOT_PATH=$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")
128 DEPLOY_DIR=$(cd "${REPO_ROOT_PATH}/mcp/scripts"; pwd)
129 STORAGE_DIR=$(cd "${REPO_ROOT_PATH}/mcp/deploy/images"; pwd)
130 RECLASS_CLUSTER_DIR=$(cd "${REPO_ROOT_PATH}/mcp/reclass/classes/cluster"; pwd)
131 DEPLOY_TYPE='baremetal'
132 OPNFV_BRIDGES=('pxebr' 'mgmt' 'internal' 'public')
133 URI_REGEXP='(file|https?|ftp)://.*'
134 BASE_CONFIG_URI="file://${REPO_ROOT_PATH}/mcp/config"
136 # Customize deploy workflow
137 DRY_RUN=${DRY_RUN:-0}
138 USE_EXISTING_INFRA=${USE_EXISTING_INFRA:-0}
139 INFRA_CREATION_ONLY=${INFRA_CREATION_ONLY:-0}
140 NO_DEPLOY_ENVIRONMENT=${NO_DEPLOY_ENVIRONMENT:-0}
142 source "${DEPLOY_DIR}/globals.sh"
145 # END of variables to customize
146 ##############################################################################
148 ##############################################################################
153 while getopts "b:B:dfFl:L:p:s:S:he" OPTION
157 BASE_CONFIG_URI=${OPTARG}
158 if [[ ! $BASE_CONFIG_URI =~ ${URI_REGEXP} ]]; then
159 notify "[ERROR] -b $BASE_CONFIG_URI - invalid URI\n"
167 OPT_BRIDGES=($OPTARG)
168 for bridge in "${OPT_BRIDGES[@]}"; do
169 if [ -n "${bridge}" ]; then
170 OPNFV_BRIDGES[${OPNFV_BRIDGE_IDX}]="${bridge}"
172 OPNFV_BRIDGE_IDX=$((OPNFV_BRIDGE_IDX + 1))
183 INFRA_CREATION_ONLY=1
186 NO_DEPLOY_ENVIRONMENT=1
192 DEPLOY_LOG="${OPTARG}"
196 if [[ "${TARGET_POD}" =~ "virtual" ]]; then
197 DEPLOY_TYPE='virtual'
201 DEPLOY_SCENARIO=${OPTARG}
204 if [[ ${OPTARG} ]]; then
205 STORAGE_DIR="${OPTARG}"
213 notify "[ERROR] Arguments not according to new argument style\n"
219 if [[ "$(sudo whoami)" != 'root' ]]; then
220 notify "[ERROR] This script requires sudo rights\n" 1>&2
224 if ! virsh list >/dev/null 2>&1; then
225 notify "[ERROR] This script requires hypervisor access\n" 1>&2
229 # Validate mandatory arguments are set
230 if [ -z "${TARGET_LAB}" ] || [ -z "${TARGET_POD}" ] || \
231 [ -z "${DEPLOY_SCENARIO}" ]; then
232 notify "[ERROR] At least one of the mandatory args is missing!\n" 1>&2
239 # Enable the automatic exit trap
240 trap do_exit SIGINT SIGTERM EXIT
242 # Set no restrictive umask so that Jenkins can remove any residuals
247 pushd "${DEPLOY_DIR}" > /dev/null
248 # Prepare the deploy config files based on lab/pod information, deployment
251 # Install required packages
252 [ -n "$(command -v apt-get)" ] && sudo apt-get install -y \
253 git make rsync mkisofs curl virtinst cpu-checker qemu-kvm
254 [ -n "$(command -v yum)" ] && sudo yum install -y --skip-broken \
255 git make rsync genisoimage curl virt-install qemu-kvm
257 if [ "$(uname -i)" = "aarch64" ]; then
258 [ -n "$(command -v apt-get)" ] && sudo apt-get install -y vgabios && \
259 sudo ln -sf /usr/share/vgabios/vgabios.bin /usr/share/qemu/vgabios-stdvga.bin
260 [ -n "$(command -v yum)" ] && sudo yum install -y --skip-broken vgabios
263 # Clone git submodules and apply our patches
264 make -C "${REPO_ROOT_PATH}/mcp/patches" deepclean patches-import
266 # Convert Pharos-compatible POD Descriptor File (PDF) to reclass model input
267 PHAROS_GEN_CONFIG_SCRIPT="./pharos/config/utils/generate_config.py"
268 PHAROS_INSTALLER_ADAPTER="./pharos/config/installers/fuel/pod_config.yml.j2"
269 BASE_CONFIG_PDF="${BASE_CONFIG_URI}/labs/${TARGET_LAB}/${TARGET_POD}.yaml"
270 BASE_CONFIG_IDF="${BASE_CONFIG_URI}/labs/${TARGET_LAB}/idf-${TARGET_POD}.yaml"
271 LOCAL_PDF="${STORAGE_DIR}/$(basename "${BASE_CONFIG_PDF}")"
272 LOCAL_IDF="${STORAGE_DIR}/$(basename "${BASE_CONFIG_IDF}")"
273 LOCAL_PDF_RECLASS="${STORAGE_DIR}/pod_config.yml"
274 if ! curl --create-dirs -o "${LOCAL_PDF}" "${BASE_CONFIG_PDF}"; then
275 if [ "${DEPLOY_TYPE}" = 'baremetal' ]; then
276 notify "[ERROR] Could not retrieve PDF (Pod Descriptor File)!\n" 1>&2
279 notify "[WARN] Could not retrieve PDF (Pod Descriptor File)!\n" 3
281 elif ! curl -o "${LOCAL_IDF}" "${BASE_CONFIG_IDF}"; then
282 notify "[WARN] POD has no IDF (Installer Descriptor File)!\n" 3
283 elif ! "${PHAROS_GEN_CONFIG_SCRIPT}" -y "${LOCAL_PDF}" \
284 -j "${PHAROS_INSTALLER_ADAPTER}" > "${LOCAL_PDF_RECLASS}"; then
285 notify "[ERROR] Could not convert PDF to reclass model input!\n" 1>&2
289 # Check scenario file existence
290 SCENARIO_DIR="../config/scenario"
291 if [ ! -f "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml" ]; then
292 notify "[WARN] ${DEPLOY_SCENARIO}.yaml not found! \
293 Setting simplest scenario (os-nosdn-nofeature-noha)\n" 3
294 DEPLOY_SCENARIO='os-nosdn-nofeature-noha'
295 if [ ! -f "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml" ]; then
296 notify "[ERROR] Scenario definition file is missing!\n" 1>&2
301 # Check defaults file existence
302 if [ ! -f "${SCENARIO_DIR}/defaults-$(uname -i).yaml" ]; then
303 notify "[ERROR] Scenario defaults file is missing!\n" 1>&2
307 # Get required infra deployment data
310 eval "$(parse_yaml "${SCENARIO_DIR}/defaults-$(uname -i).yaml")"
311 eval "$(parse_yaml "${SCENARIO_DIR}/${DEPLOY_TYPE}/${DEPLOY_SCENARIO}.yaml")"
312 eval "$(parse_yaml "${LOCAL_PDF_RECLASS}")"
315 export CLUSTER_DOMAIN=${cluster_domain}
317 declare -A virtual_nodes_ram virtual_nodes_vcpus
318 for node in "${virtual_nodes[@]}"; do
319 virtual_custom_ram="virtual_${node}_ram"
320 virtual_custom_vcpus="virtual_${node}_vcpus"
321 virtual_nodes_ram[$node]=${!virtual_custom_ram:-$virtual_default_ram}
322 virtual_nodes_vcpus[$node]=${!virtual_custom_vcpus:-$virtual_default_vcpus}
325 # Expand reclass and virsh network templates
326 for tp in "${RECLASS_CLUSTER_DIR}/all-mcp-ocata-common/opnfv/"*.template \
330 EOF" 2> /dev/null > "${tp%.template}"
333 # Map PDF networks 'admin', 'mgmt', 'private' and 'public' to bridge names
334 BR_NAMES=('admin' 'mgmt' 'private' 'public')
336 "${parameters__param_opnfv_maas_pxe_address}" \
337 "${parameters__param_opnfv_infra_config_address}" \
338 "${parameters__param_opnfv_openstack_compute_node01_tenant_address}" \
339 "${parameters__param_opnfv_openstack_compute_node01_external_address}" \
341 for ((i = 0; i < ${#BR_NETS[@]}; i++)); do
342 br_jump=$(eval echo "\$parameters__param_opnfv_jump_bridge_${BR_NAMES[i]}")
343 if [ -n "${br_jump}" ] && [ "${br_jump}" != 'None' ] && \
344 [ -d "/sys/class/net/${br_jump}/bridge" ]; then
345 notify "[OK] Bridge found for '${BR_NAMES[i]}': ${br_jump}\n" 2
346 OPNFV_BRIDGES[${i}]="${br_jump}"
347 elif [ -n "${BR_NETS[i]}" ]; then
348 bridge=$(ip addr | awk "/${BR_NETS[i]%.*}./ {print \$NF; exit}")
349 if [ -n "${bridge}" ] && [ -d "/sys/class/net/${bridge}/bridge" ]; then
350 notify "[OK] Bridge found for net ${BR_NETS[i]%.*}.0: ${bridge}\n" 2
351 OPNFV_BRIDGES[${i}]="${bridge}"
355 notify "[NOTE] Using bridges: ${OPNFV_BRIDGES[*]}\n" 2
358 if [ ${DRY_RUN} -eq 1 ]; then
359 notify "[NOTE] Dry run, skipping all deployment tasks\n" 2 1>&2
361 elif [ ${USE_EXISTING_INFRA} -eq 1 ]; then
362 notify "[NOTE] Use existing infra\n" 2 1>&2
366 prepare_vms virtual_nodes "${base_image}" "${STORAGE_DIR}"
367 create_networks OPNFV_BRIDGES
368 create_vms virtual_nodes virtual_nodes_ram virtual_nodes_vcpus \
369 OPNFV_BRIDGES "${STORAGE_DIR}"
370 update_mcpcontrol_network
371 start_vms virtual_nodes
373 ./salt.sh "${LOCAL_PDF_RECLASS}"
376 # Openstack cluster setup
378 if [ ${INFRA_CREATION_ONLY} -eq 1 ] || [ ${NO_DEPLOY_ENVIRONMENT} -eq 1 ]; then
379 notify "[NOTE] Skip openstack cluster setup\n" 2
381 for state in "${cluster_states[@]}"; do
382 notify "[STATE] Applying state: ${state}\n" 2
383 # shellcheck disable=SC2086,2029
384 ssh ${SSH_OPTS} "${SSH_SALT}" \
385 sudo "/root/fuel/mcp/config/states/${state} || true"
389 ./log.sh "${DEPLOY_LOG}"
393 notify "\n[DONE] MCP: Openstack installation finished succesfully!\n\n" 2
397 ##############################################################################