Fixes nic template missing in spec and error catching
[apex.git] / ci / deploy.sh
1 #!/bin/bash
2 ##############################################################################
3 # Copyright (c) 2015 Tim Rozet (Red Hat), Dan Radez (Red Hat) and others.
4 #
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 ##############################################################################
10
11 # Deploy script to install provisioning server for OPNFV Apex
12 # author: Dan Radez (dradez@redhat.com)
13 # author: Tim Rozet (trozet@redhat.com)
14 #
15 # Based on RDO Manager http://www.rdoproject.org
16
17 set -e
18
19 ##VARIABLES
20 reset=$(tput sgr0 || echo "")
21 blue=$(tput setaf 4 || echo "")
22 red=$(tput setaf 1 || echo "")
23 green=$(tput setaf 2 || echo "")
24
25 vm_index=4
26 interactive="FALSE"
27 ping_site="8.8.8.8"
28 ntp_server="pool.ntp.org"
29 net_isolation_enabled="TRUE"
30 post_config="TRUE"
31 debug="FALSE"
32
33 declare -i CNT
34 declare UNDERCLOUD
35 declare -A deploy_options_array
36 declare -a performance_options
37 declare -A NET_MAP
38
39 SSH_OPTIONS=(-o StrictHostKeyChecking=no -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null -o LogLevel=error)
40 DEPLOY_OPTIONS=""
41 RESOURCES=${RESOURCES:-'/var/opt/opnfv/images'}
42 CONFIG=${CONFIG:-'/var/opt/opnfv'}
43 OPNFV_NETWORK_TYPES="admin_network private_network public_network storage_network"
44 VM_CPUS=4
45 VM_RAM=8
46 # Netmap used to map networks to OVS bridge names
47 NET_MAP['admin_network']="br-admin"
48 NET_MAP['private_network']="br-private"
49 NET_MAP['public_network']="br-public"
50 NET_MAP['storage_network']="br-storage"
51 ext_net_type="interface"
52 ip_address_family=4
53
54 ##FUNCTIONS
55 ##translates yaml into variables
56 ##params: filename, prefix (ex. "config_")
57 ##usage: parse_yaml opnfv_ksgen_settings.yml "config_"
58 parse_yaml() {
59    local prefix=$2
60    local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
61    sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
62         -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p"  $1 |
63    awk -F$fs '{
64       indent = length($1)/2;
65       vname[indent] = $2;
66       for (i in vname) {if (i > indent) {delete vname[i]}}
67       if (length($3) > 0) {
68          vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
69          printf("%s%s%s=%s\n", "'$prefix'",vn, $2, $3);
70       }
71    }'
72 }
73
74 ##checks if prefix exists in string
75 ##params: string, prefix
76 ##usage: contains_prefix "deploy_setting_launcher=1" "deploy_setting"
77 contains_prefix() {
78   local mystr=$1
79   local prefix=$2
80   if echo $mystr | grep -E "^$prefix.*$" > /dev/null; then
81     return 0
82   else
83     return 1
84   fi
85 }
86 ##parses variable from a string with '='
87 ##and removes global prefix
88 ##params: string, prefix
89 ##usage: parse_setting_var 'deploy_myvar=2' 'deploy_'
90 parse_setting_var() {
91   local mystr=$1
92   local prefix=$2
93   if echo $mystr | grep -E "^.+\=" > /dev/null; then
94     echo $(echo $mystr | grep -Eo "^.+\=" | tr -d '=' |  sed 's/^'"$prefix"'//')
95   else
96     return 1
97   fi
98 }
99 ##parses value from a string with '='
100 ##params: string
101 ##usage: parse_setting_value
102 parse_setting_value() {
103   local mystr=$1
104   echo $(echo $mystr | grep -Eo "\=.*$" | tr -d '=')
105 }
106
107 ##parses network settings yaml into globals
108 parse_network_settings() {
109   if local output=$(python3.4 -B $CONFIG/lib/python/apex-python-utils.py parse_net_settings -n $NETSETS -i $net_isolation_enabled); then
110       echo -e "${blue}${output}${reset}"
111       eval "$output"
112   else
113       echo -e "${red}ERROR: Failed to parse network settings file $NETSETS ${reset}"
114       exit 1
115   fi
116 }
117
118 ##parses deploy settings yaml into globals
119 parse_deploy_settings() {
120   if local output=$(python3.4 -B $CONFIG/lib/python/apex-python-utils.py parse-deploy-settings -f $DEPLOY_SETTINGS_FILE); then
121       echo -e "${blue}${output}${reset}"
122       eval "$output"
123   else
124       echo -e "${red}ERROR: Failed to parse deploy settings file $DEPLOY_SETTINGS_FILE ${reset}"
125       exit 1
126   fi
127 }
128
129 ##parses baremetal yaml settings into compatible json
130 ##writes the json to $CONFIG/instackenv_tmp.json
131 ##params: none
132 ##usage: parse_inventory_file
133 parse_inventory_file() {
134   local inventory=$(parse_yaml $INVENTORY_FILE)
135   local node_list
136   local node_prefix="node"
137   local node_count=0
138   local node_total
139   local inventory_list
140
141   # detect number of nodes
142   for entry in $inventory; do
143     if echo $entry | grep -Eo "^nodes_node[0-9]+_" > /dev/null; then
144       this_node=$(echo $entry | grep -Eo "^nodes_node[0-9]+_")
145       if [[ "$inventory_list" != *"$this_node"* ]]; then
146         inventory_list+="$this_node "
147       fi
148     fi
149   done
150
151   inventory_list=$(echo $inventory_list | sed 's/ $//')
152
153   for node in $inventory_list; do
154     ((node_count+=1))
155   done
156
157   node_total=$node_count
158
159   if [[ "$node_total" -lt 5 && ( ha_enabled == "TRUE" || "$ha_enabled" == "true" ) ]]; then
160     echo -e "${red}ERROR: You must provide at least 5 nodes for HA baremetal deployment${reset}"
161     exit 1
162   elif [[ "$node_total" -lt 2 ]]; then
163     echo -e "${red}ERROR: You must provide at least 2 nodes for non-HA baremetal deployment${reset}"
164     exit 1
165   fi
166
167   eval $(parse_yaml $INVENTORY_FILE) || {
168     echo "${red}Failed to parse inventory.yaml. Aborting.${reset}"
169     exit 1
170   }
171
172   instackenv_output="
173 {
174  \"nodes\" : [
175
176 "
177   node_count=0
178   for node in $inventory_list; do
179     ((node_count+=1))
180     node_output="
181         {
182           \"pm_password\": \"$(eval echo \${${node}ipmi_pass})\",
183           \"pm_type\": \"$(eval echo \${${node}pm_type})\",
184           \"mac\": [
185             \"$(eval echo \${${node}mac_address})\"
186           ],
187           \"cpu\": \"$(eval echo \${${node}cpus})\",
188           \"memory\": \"$(eval echo \${${node}memory})\",
189           \"disk\": \"$(eval echo \${${node}disk})\",
190           \"arch\": \"$(eval echo \${${node}arch})\",
191           \"pm_user\": \"$(eval echo \${${node}ipmi_user})\",
192           \"pm_addr\": \"$(eval echo \${${node}ipmi_ip})\",
193           \"capabilities\": \"$(eval echo \${${node}capabilities})\"
194 "
195     instackenv_output+=${node_output}
196     if [ $node_count -lt $node_total ]; then
197       instackenv_output+="        },"
198     else
199       instackenv_output+="        }"
200     fi
201   done
202
203   instackenv_output+='
204   ]
205 }
206 '
207   #Copy instackenv.json to undercloud for baremetal
208   echo -e "{blue}Parsed instackenv JSON:\n${instackenv_output}${reset}"
209   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
210 cat > instackenv.json << EOF
211 $instackenv_output
212 EOF
213 EOI
214
215 }
216 ##verify internet connectivity
217 #params: none
218 function verify_internet {
219   if ping -c 2 $ping_site > /dev/null; then
220     if ping -c 2 www.google.com > /dev/null; then
221       echo "${blue}Internet connectivity detected${reset}"
222       return 0
223     else
224       echo "${red}Internet connectivity detected, but DNS lookup failed${reset}"
225       return 1
226     fi
227   else
228     echo "${red}No internet connectivity detected${reset}"
229     return 1
230   fi
231 }
232
233 ##download dependencies if missing and configure host
234 #params: none
235 function configure_deps {
236   if ! verify_internet; then
237     echo "${red}Will not download dependencies${reset}"
238     internet=false
239   fi
240
241   # verify ip forwarding
242   if sysctl net.ipv4.ip_forward | grep 0; then
243     sudo sysctl -w net.ipv4.ip_forward=1
244     sudo sh -c "echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf"
245   fi
246
247   # ensure no dhcp server is running on jumphost
248   if ! sudo systemctl status dhcpd | grep dead; then
249     echo "${red}WARN: DHCP Server detected on jumphost, disabling...${reset}"
250     sudo systemctl stop dhcpd
251     sudo systemctl disable dhcpd
252   fi
253
254   # ensure networks are configured
255   systemctl status libvirtd || systemctl start libvirtd
256   systemctl status openvswitch || systemctl start openvswitch
257
258   # If flat we only use admin network
259   if [[ "$net_isolation_enabled" == "FALSE" ]]; then
260     virsh_enabled_networks="admin_network"
261     enabled_network_list="admin_network"
262   # For baremetal we only need to create/attach Undercloud to admin and public
263   elif [ "$virtual" == "FALSE" ]; then
264     virsh_enabled_networks="admin_network public_network"
265   else
266     virsh_enabled_networks=$enabled_network_list
267   fi
268
269   # ensure default network is configured correctly
270   libvirt_dir="/usr/share/libvirt/networks"
271   virsh net-list --all | grep default || virsh net-define ${libvirt_dir}/default.xml
272   virsh net-list --all | grep -E "default\s+active" > /dev/null || virsh net-start default
273   virsh net-list --all | grep -E "default\s+active\s+yes" > /dev/null || virsh net-autostart --network default
274
275   for network in ${OPNFV_NETWORK_TYPES}; do
276     echo "${blue}INFO: Creating Virsh Network: $network & OVS Bridge: ${NET_MAP[$network]}${reset}"
277     ovs-vsctl list-br | grep "^${NET_MAP[$network]}$" > /dev/null || ovs-vsctl add-br ${NET_MAP[$network]}
278     virsh net-list --all | grep $network > /dev/null || (cat > ${libvirt_dir}/apex-virsh-net.xml && virsh net-define ${libvirt_dir}/apex-virsh-net.xml) << EOF
279 <network>
280   <name>$network</name>
281   <forward mode='bridge'/>
282   <bridge name='${NET_MAP[$network]}'/>
283   <virtualport type='openvswitch'/>
284 </network>
285 EOF
286     if ! (virsh net-list --all | grep $network > /dev/null); then
287         echo "${red}ERROR: unable to create network: ${network}${reset}"
288         exit 1;
289     fi
290     rm -f ${libvirt_dir}/apex-virsh-net.xml &> /dev/null;
291     virsh net-list | grep -E "$network\s+active" > /dev/null || virsh net-start $network
292     virsh net-list | grep -E "$network\s+active\s+yes" > /dev/null || virsh net-autostart --network $network
293   done
294
295   echo -e "${blue}INFO: Bridges set: ${reset}"
296   ovs-vsctl list-br
297   echo -e "${blue}INFO: virsh networks set: ${reset}"
298   virsh net-list
299
300   if [[ -z "$virtual" || "$virtual" == "FALSE" ]]; then
301     # bridge interfaces to correct OVS instances for baremetal deployment
302     for network in ${enabled_network_list}; do
303       if [[ "$network" != "admin_network" && "$network" != "public_network" ]]; then
304         continue
305       fi
306       this_interface=$(eval echo \${${network}_bridged_interface})
307       # check if this a bridged interface for this network
308       if [[ ! -z "$this_interface" || "$this_interface" != "none" ]]; then
309         if ! attach_interface_to_ovs ${NET_MAP[$network]} ${this_interface} ${network}; then
310           echo -e "${red}ERROR: Unable to bridge interface ${this_interface} to bridge ${NET_MAP[$network]} for enabled network: ${network}${reset}"
311           exit 1
312         else
313           echo -e "${blue}INFO: Interface ${this_interface} bridged to bridge ${NET_MAP[$network]} for enabled network: ${network}${reset}"
314         fi
315       else
316         echo "${red}ERROR: Unable to determine interface to bridge to for enabled network: ${network}${reset}"
317         exit 1
318       fi
319     done
320   fi
321
322   # ensure storage pool exists and is started
323   virsh pool-list --all | grep default > /dev/null || virsh pool-define-as --name default dir --target /var/lib/libvirt/images
324   virsh pool-list | grep -Eo "default\s+active" > /dev/null || (virsh pool-autostart default; virsh pool-start default)
325
326   if ! egrep '^flags.*(vmx|svm)' /proc/cpuinfo > /dev/null; then
327     echo "${red}virtualization extensions not found, kvm kernel module insertion may fail.\n  \
328 Are you sure you have enabled vmx in your bios or hypervisor?${reset}"
329   fi
330
331   if ! lsmod | grep kvm > /dev/null; then modprobe kvm; fi
332   if ! lsmod | grep kvm_intel > /dev/null; then modprobe kvm_intel; fi
333
334   if ! lsmod | grep kvm > /dev/null; then
335     echo "${red}kvm kernel modules not loaded!${reset}"
336     return 1
337   fi
338
339   ##sshkeygen for root
340   if [ ! -e ~/.ssh/id_rsa.pub ]; then
341     ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
342   fi
343
344   echo "${blue}All dependencies installed and running${reset}"
345 }
346
347 ##verify vm exists, an has a dhcp lease assigned to it
348 ##params: none
349 function setup_undercloud_vm {
350   if ! virsh list --all | grep undercloud > /dev/null; then
351       undercloud_nets="default admin_network"
352       if [[ $enabled_network_list =~ "public_network" ]]; then
353         undercloud_nets+=" public_network"
354       fi
355       define_vm undercloud hd 30 "$undercloud_nets" 4 12288
356
357       ### this doesn't work for some reason I was getting hangup events so using cp instead
358       #virsh vol-upload --pool default --vol undercloud.qcow2 --file $CONFIG/stack/undercloud.qcow2
359       #2015-12-05 12:57:20.569+0000: 8755: info : libvirt version: 1.2.8, package: 16.el7_1.5 (CentOS BuildSystem <http://bugs.centos.org>, 2015-11-03-13:56:46, worker1.bsys.centos.org)
360       #2015-12-05 12:57:20.569+0000: 8755: warning : virKeepAliveTimerInternal:143 : No response from client 0x7ff1e231e630 after 6 keepalive messages in 35 seconds
361       #2015-12-05 12:57:20.569+0000: 8756: warning : virKeepAliveTimerInternal:143 : No response from client 0x7ff1e231e630 after 6 keepalive messages in 35 seconds
362       #error: cannot close volume undercloud.qcow2
363       #error: internal error: received hangup / error event on socket
364       #error: Reconnected to the hypervisor
365
366       local undercloud_dst=/var/lib/libvirt/images/undercloud.qcow2
367       cp -f $RESOURCES/undercloud.qcow2 $undercloud_dst
368
369       # resize Undercloud machine
370       echo "Checking if Undercloud needs to be resized..."
371       undercloud_size=$(LIBGUESTFS_BACKEND=direct virt-filesystems --long -h --all -a $undercloud_dst |grep device | grep -Eo "[0-9\.]+G" | sed -n 's/\([0-9][0-9]*\).*/\1/p')
372       if [ "$undercloud_size" -lt 30 ]; then
373         qemu-img resize /var/lib/libvirt/images/undercloud.qcow2 +25G
374         LIBGUESTFS_BACKEND=direct virt-resize --expand /dev/sda1 $RESOURCES/undercloud.qcow2 $undercloud_dst
375         LIBGUESTFS_BACKEND=direct virt-customize -a $undercloud_dst --run-command 'xfs_growfs -d /dev/sda1 || true'
376         new_size=$(LIBGUESTFS_BACKEND=direct virt-filesystems --long -h --all -a $undercloud_dst |grep filesystem | grep -Eo "[0-9\.]+G" | sed -n 's/\([0-9][0-9]*\).*/\1/p')
377         if [ "$new_size" -lt 30 ]; then
378           echo "Error resizing Undercloud machine, disk size is ${new_size}"
379           exit 1
380         else
381           echo "Undercloud successfully resized"
382         fi
383       else
384         echo "Skipped Undercloud resize, upstream is large enough"
385       fi
386
387   else
388       echo "Found Undercloud VM, using existing VM"
389   fi
390
391   # if the VM is not running update the authkeys and start it
392   if ! virsh list | grep undercloud > /dev/null; then
393     echo "Injecting ssh key to Undercloud VM"
394     LIBGUESTFS_BACKEND=direct virt-customize -a $undercloud_dst --run-command "mkdir -p /root/.ssh/" \
395         --upload ~/.ssh/id_rsa.pub:/root/.ssh/authorized_keys \
396         --run-command "chmod 600 /root/.ssh/authorized_keys && restorecon /root/.ssh/authorized_keys" \
397         --run-command "cp /root/.ssh/authorized_keys /home/stack/.ssh/" \
398         --run-command "chown stack:stack /home/stack/.ssh/authorized_keys && chmod 600 /home/stack/.ssh/authorized_keys"
399     virsh start undercloud
400   fi
401
402   sleep 10 # let undercloud get started up
403
404   # get the undercloud VM IP
405   CNT=10
406   echo -n "${blue}Waiting for Undercloud's dhcp address${reset}"
407   undercloud_mac=$(virsh domiflist undercloud | grep default | awk '{ print $5 }')
408   while ! $(arp -e | grep ${undercloud_mac} > /dev/null) && [ $CNT -gt 0 ]; do
409       echo -n "."
410       sleep 10
411       CNT=$((CNT-1))
412   done
413   UNDERCLOUD=$(arp -e | grep ${undercloud_mac} | awk {'print $1'})
414
415   if [ -z "$UNDERCLOUD" ]; then
416     echo "\n\nCan't get IP for Undercloud. Can Not Continue."
417     exit 1
418   else
419      echo -e "${blue}\rUndercloud VM has IP $UNDERCLOUD${reset}"
420   fi
421
422   CNT=10
423   echo -en "${blue}\rValidating Undercloud VM connectivity${reset}"
424   while ! ping -c 1 $UNDERCLOUD > /dev/null && [ $CNT -gt 0 ]; do
425       echo -n "."
426       sleep 3
427       CNT=$((CNT-1))
428   done
429   if [ "$CNT" -eq 0 ]; then
430       echo "Failed to contact Undercloud. Can Not Continue"
431       exit 1
432   fi
433   CNT=10
434   while ! ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "echo ''" 2>&1> /dev/null && [ $CNT -gt 0 ]; do
435       echo -n "."
436       sleep 3
437       CNT=$((CNT-1))
438   done
439   if [ "$CNT" -eq 0 ]; then
440       echo "Failed to connect to Undercloud. Can Not Continue"
441       exit 1
442   fi
443
444   # extra space to overwrite the previous connectivity output
445   echo -e "${blue}\r                                                                 ${reset}"
446   sleep 1
447   ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "if ! ip a s eth2 | grep ${public_network_provisioner_ip} > /dev/null; then ip a a ${public_network_provisioner_ip}/${public_network_cidr##*/} dev eth2; ip link set up dev eth2; fi"
448
449   # ssh key fix for stack user
450   ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "restorecon -r /home/stack"
451 }
452
453 ##Create virtual nodes in virsh
454 ##params: vcpus, ramsize
455 function setup_virtual_baremetal {
456   local vcpus ramsize
457   if [ -z "$1" ]; then
458     vcpus=4
459     ramsize=8192
460   elif [ -z "$2" ]; then
461     vcpus=$1
462     ramsize=8192
463   else
464     vcpus=$1
465     ramsize=$(($2*1024))
466   fi
467   #start by generating the opening json for instackenv.json
468   cat > $CONFIG/instackenv-virt.json << EOF
469 {
470   "nodes": [
471 EOF
472
473   # next create the virtual machines and add their definitions to the file
474   for i in $(seq 0 $vm_index); do
475     if ! virsh list --all | grep baremetal${i} > /dev/null; then
476       define_vm baremetal${i} network 41 'admin_network' $vcpus $ramsize
477       for n in private_network public_network storage_network; do
478         if [[ $enabled_network_list =~ $n ]]; then
479           echo -n "$n "
480           virsh attach-interface --domain baremetal${i} --type network --source $n --model rtl8139 --config
481         fi
482       done
483     else
484       echo "Found Baremetal ${i} VM, using existing VM"
485     fi
486     #virsh vol-list default | grep baremetal${i} 2>&1> /dev/null || virsh vol-create-as default baremetal${i}.qcow2 41G --format qcow2
487     mac=$(virsh domiflist baremetal${i} | grep admin_network | awk '{ print $5 }')
488
489     cat >> $CONFIG/instackenv-virt.json << EOF
490     {
491       "pm_addr": "192.168.122.1",
492       "pm_user": "root",
493       "pm_password": "INSERT_STACK_USER_PRIV_KEY",
494       "pm_type": "pxe_ssh",
495       "mac": [
496         "$mac"
497       ],
498       "cpu": "$vcpus",
499       "memory": "$ramsize",
500       "disk": "41",
501       "arch": "x86_64"
502     },
503 EOF
504   done
505
506   #truncate the last line to remove the comma behind the bracket
507   tail -n 1 $CONFIG/instackenv-virt.json | wc -c | xargs -I {} truncate $CONFIG/instackenv-virt.json -s -{}
508
509   #finally reclose the bracket and close the instackenv.json file
510   cat >> $CONFIG/instackenv-virt.json << EOF
511     }
512   ],
513   "arch": "x86_64",
514   "host-ip": "192.168.122.1",
515   "power_manager": "nova.virt.baremetal.virtual_power_driver.VirtualPowerManager",
516   "seed-ip": "",
517   "ssh-key": "INSERT_STACK_USER_PRIV_KEY",
518   "ssh-user": "root"
519 }
520 EOF
521 }
522
523 ##Create virtual nodes in virsh
524 ##params: name - String: libvirt name for VM
525 ##        bootdev - String: boot device for the VM
526 ##        disksize - Number: size of the disk in GB
527 ##        ovs_bridges: - List: list of ovs bridges
528 ##        vcpus - Number of VCPUs to use (defaults to 4)
529 ##        ramsize - Size of RAM for VM in MB (defaults to 8192)
530 function define_vm () {
531   local vcpus ramsize
532
533   if [ -z "$5" ]; then
534     vcpus=4
535     ramsize=8388608
536   elif [ -z "$6" ]; then
537     vcpus=$5
538     ramsize=8388608
539   else
540     vcpus=$5
541     ramsize=$(($6*1024))
542   fi
543
544   # Create the libvirt storage volume
545   if virsh vol-list default | grep ${1}.qcow2 2>&1> /dev/null; then
546     volume_path=$(virsh vol-path --pool default ${1}.qcow2 || echo "/var/lib/libvirt/images/${1}.qcow2")
547     echo "Volume ${1} exists. Deleting Existing Volume $volume_path"
548     virsh vol-dumpxml ${1}.qcow2 --pool default > /dev/null || echo '' #ok for this to fail
549     touch $volume_path
550     virsh vol-delete ${1}.qcow2 --pool default
551   fi
552   virsh vol-create-as default ${1}.qcow2 ${3}G --format qcow2
553   volume_path=$(virsh vol-path --pool default ${1}.qcow2)
554   if [ ! -f $volume_path ]; then
555       echo "$volume_path Not created successfully... Aborting"
556       exit 1
557   fi
558
559   # create the VM
560   /usr/libexec/openstack-tripleo/configure-vm --name $1 \
561                                               --bootdev $2 \
562                                               --image "$volume_path" \
563                                               --diskbus sata \
564                                               --arch x86_64 \
565                                               --cpus $vcpus \
566                                               --memory $ramsize \
567                                               --libvirt-nic-driver virtio \
568                                               --baremetal-interface $4
569 }
570
571 ##Set network-environment settings
572 ##params: network-environment file to edit
573 function configure_network_environment {
574   local tht_dir
575   tht_dir=/usr/share/openstack-tripleo-heat-templates/network
576
577   sed -i '/ControlPlaneSubnetCidr/c\\  ControlPlaneSubnetCidr: "'${admin_network_cidr##*/}'"' $1
578   sed -i '/ControlPlaneDefaultRoute/c\\  ControlPlaneDefaultRoute: '${admin_network_provisioner_ip}'' $1
579   sed -i '/ExternalNetCidr/c\\  ExternalNetCidr: '${public_network_cidr}'' $1
580   sed -i "/ExternalAllocationPools/c\\  ExternalAllocationPools: [{'start': '${public_network_usable_ip_range%%,*}', 'end': '${public_network_usable_ip_range##*,}'}]" $1
581   sed -i '/ExternalInterfaceDefaultRoute/c\\  ExternalInterfaceDefaultRoute: '${public_network_gateway}'' $1
582   sed -i '/EC2MetadataIp/c\\  EC2MetadataIp: '${admin_network_provisioner_ip}'' $1
583
584   # check for private network
585   if [[ ! -z "$private_network_enabled" && "$private_network_enabled" == "True" ]]; then
586       sed -i 's#^.*Network::Tenant.*$#  OS::TripleO::Network::Tenant: '${tht_dir}'/tenant.yaml#' $1
587       sed -i 's#^.*Controller::Ports::TenantPort:.*$#  OS::TripleO::Controller::Ports::TenantPort: '${tht_dir}'/ports/tenant.yaml#' $1
588       sed -i 's#^.*Compute::Ports::TenantPort:.*$#  OS::TripleO::Compute::Ports::TenantPort: '${tht_dir}'/ports/tenant.yaml#' $1
589       sed -i "/TenantAllocationPools/c\\  TenantAllocationPools: [{'start': '${private_network_usable_ip_range%%,*}', 'end': '${private_network_usable_ip_range##*,}'}]" $1
590       sed -i '/TenantNetCidr/c\\  TenantNetCidr: '${private_network_cidr}'' $1
591   else
592       sed -i 's#^.*Network::Tenant.*$#  OS::TripleO::Network::Tenant: '${tht_dir}'/noop.yaml#' $1
593       sed -i 's#^.*Controller::Ports::TenantPort:.*$#  OS::TripleO::Controller::Ports::TenantPort: '${tht_dir}'/ports/noop.yaml#' $1
594       sed -i 's#^.*Compute::Ports::TenantPort:.*$#  OS::TripleO::Compute::Ports::TenantPort: '${tht_dir}'/ports/noop.yaml#' $1
595   fi
596
597   # check for storage network
598   if [[ ! -z "$storage_network_enabled" && "$storage_network_enabled" == "True" ]]; then
599       sed -i 's#^.*Network::Storage:.*$#  OS::TripleO::Network::Storage: '${tht_dir}'/storage.yaml#' $1
600       sed -i 's#^.*Network::Ports::StorageVipPort:.*$#  OS::TripleO::Network::Ports::StorageVipPort: '${tht_dir}'/ports/storage.yaml#' $1
601       sed -i 's#^.*Controller::Ports::StoragePort:.*$#  OS::TripleO::Controller::Ports::StoragePort: '${tht_dir}'/ports/storage.yaml#' $1
602       sed -i 's#^.*Compute::Ports::StoragePort:.*$#  OS::TripleO::Compute::Ports::StoragePort: '${tht_dir}'/ports/storage.yaml#' $1
603       sed -i "/StorageAllocationPools/c\\  StorageAllocationPools: [{'start': '${storage_network_usable_ip_range%%,*}', 'end': '${storage_network_usable_ip_range##*,}'}]" $1
604       sed -i '/StorageNetCidr/c\\  StorageNetCidr: '${storage_network_cidr}'' $1
605   else
606       sed -i 's#^.*Network::Storage:.*$#  OS::TripleO::Network::Storage: '${tht_dir}'/noop.yaml#' $1
607       sed -i 's#^.*Network::Ports::StorageVipPort:.*$#  OS::TripleO::Network::Ports::StorageVipPort: '${tht_dir}'/ports/noop.yaml#' $1
608       sed -i 's#^.*Controller::Ports::StoragePort:.*$#  OS::TripleO::Controller::Ports::StoragePort: '${tht_dir}'/ports/noop.yaml#' $1
609       sed -i 's#^.*Compute::Ports::StoragePort:.*$#  OS::TripleO::Compute::Ports::StoragePort: '${tht_dir}'/ports/noop.yaml#' $1
610   fi
611
612   # check for ODL L3
613   if [ "${deploy_options_array['sdn_l3']}" == 'true' ]; then
614       ext_net_type=br-ex
615   fi
616
617 }
618 ##Copy over the glance images and instackenv json file
619 ##params: none
620 function configure_undercloud {
621   local controller_nic_template compute_nic_template
622   echo
623   echo "Copying configuration files to Undercloud"
624   if [[ "$net_isolation_enabled" == "TRUE" ]]; then
625     configure_network_environment $CONFIG/network-environment.yaml
626     echo -e "${blue}Network Environment set for Deployment: ${reset}"
627     cat $CONFIG/network-environment.yaml
628     scp ${SSH_OPTIONS[@]} $CONFIG/network-environment.yaml "stack@$UNDERCLOUD":
629     if ! controller_nic_template=$(python3.4 -B $CONFIG/lib/python/apex-python-utils.py nic_template -d $CONFIG -f nics-controller.yaml.jinja2 -n "$enabled_network_list" -e $ext_net_type -af $ip_addr_family); then
630       echo -e "${red}ERROR: Failed to generate controller NIC heat template ${reset}"
631       exit 1
632     fi
633
634     if ! compute_nic_template=$(python3.4 -B $CONFIG/lib/python/apex-python-utils.py nic_template -d $CONFIG -f nics-compute.yaml.jinja2 -n "$enabled_network_list" -e $ext_net_type -af $ip_addr_family); then
635       echo -e "${red}ERROR: Failed to generate compute NIC heat template ${reset}"
636       exit 1
637     fi
638     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" << EOI
639 mkdir nics/
640 cat > nics/controller.yaml << EOF
641 $controller_nic_template
642 EOF
643 cat > nics/compute.yaml << EOF
644 $compute_nic_template
645 EOF
646 EOI
647   fi
648
649   # ensure stack user on Undercloud machine has an ssh key
650   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "if [ ! -e ~/.ssh/id_rsa.pub ]; then ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa; fi"
651
652   if [ "$virtual" == "TRUE" ]; then
653
654       # copy the Undercloud VM's stack user's pub key to
655       # root's auth keys so that Undercloud can control
656       # vm power on the hypervisor
657       ssh ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "cat /home/stack/.ssh/id_rsa.pub" >> /root/.ssh/authorized_keys
658
659       DEPLOY_OPTIONS+=" --libvirt-type qemu"
660       INSTACKENV=$CONFIG/instackenv-virt.json
661
662       # upload instackenv file to Undercloud for virtual deployment
663       scp ${SSH_OPTIONS[@]} $INSTACKENV "stack@$UNDERCLOUD":instackenv.json
664   fi
665
666   # allow stack to control power management on the hypervisor via sshkey
667   # only if this is a virtual deployment
668   if [ "$virtual" == "TRUE" ]; then
669       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
670 while read -r line; do
671   stack_key=\${stack_key}\\\\\\\\n\${line}
672 done < <(cat ~/.ssh/id_rsa)
673 stack_key=\$(echo \$stack_key | sed 's/\\\\\\\\n//')
674 sed -i 's~INSERT_STACK_USER_PRIV_KEY~'"\$stack_key"'~' instackenv.json
675 EOI
676   fi
677
678   # copy stack's ssh key to this users authorized keys
679   ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "cat /home/stack/.ssh/id_rsa.pub" >> ~/.ssh/authorized_keys
680
681   # disable requiretty for sudo
682   ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "sed -i 's/Defaults\s*requiretty//'" /etc/sudoers
683
684   # configure undercloud on Undercloud VM
685   echo "Running undercloud configuration."
686   echo "Logging undercloud configuration to undercloud:/home/stack/apex-undercloud-install.log"
687   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" << EOI
688 if [[ "$net_isolation_enabled" == "TRUE" ]]; then
689   sed -i 's/#local_ip/local_ip/' undercloud.conf
690   sed -i 's/#network_gateway/network_gateway/' undercloud.conf
691   sed -i 's/#network_cidr/network_cidr/' undercloud.conf
692   sed -i 's/#dhcp_start/dhcp_start/' undercloud.conf
693   sed -i 's/#dhcp_end/dhcp_end/' undercloud.conf
694   sed -i 's/#inspection_iprange/inspection_iprange/' undercloud.conf
695   sed -i 's/#undercloud_debug/undercloud_debug/' undercloud.conf
696
697   openstack-config --set undercloud.conf DEFAULT local_ip ${admin_network_provisioner_ip}/${admin_network_cidr##*/}
698   openstack-config --set undercloud.conf DEFAULT network_gateway ${admin_network_provisioner_ip}
699   openstack-config --set undercloud.conf DEFAULT network_cidr ${admin_network_cidr}
700   openstack-config --set undercloud.conf DEFAULT dhcp_start ${admin_network_dhcp_range%%,*}
701   openstack-config --set undercloud.conf DEFAULT dhcp_end ${admin_network_dhcp_range##*,}
702   openstack-config --set undercloud.conf DEFAULT inspection_iprange ${admin_network_introspection_range}
703   openstack-config --set undercloud.conf DEFAULT undercloud_debug false
704
705 fi
706
707 sudo sed -i '/CephClusterFSID:/c\\  CephClusterFSID: \\x27$(cat /proc/sys/kernel/random/uuid)\\x27' /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml
708 sudo sed -i '/CephMonKey:/c\\  CephMonKey: \\x27'"\$(ceph-authtool --gen-print-key)"'\\x27' /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml
709 sudo sed -i '/CephAdminKey:/c\\  CephAdminKey: \\x27'"\$(ceph-authtool --gen-print-key)"'\\x27' /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml
710
711 # we assume that packages will not need to be updated with undercloud install
712 # and that it will be used only to configure the undercloud
713 # packages updates would need to be handled manually with yum update
714 sudo cp -f /usr/share/diskimage-builder/elements/yum/bin/install-packages /usr/share/diskimage-builder/elements/yum/bin/install-packages.bak
715 cat << 'EOF' | sudo tee /usr/share/diskimage-builder/elements/yum/bin/install-packages > /dev/null
716 #!/bin/sh
717 exit 0
718 EOF
719
720 openstack undercloud install &> apex-undercloud-install.log || {
721     # cat the undercloud install log incase it fails
722     echo "ERROR: openstack undercloud install has failed. Dumping Log:"
723     cat apex-undercloud-install.log
724     exit 1
725 }
726
727 sleep 30
728 sudo systemctl restart openstack-glance-api
729 sudo systemctl restart openstack-nova-conductor
730 sudo systemctl restart openstack-nova-compute
731
732 sudo sed -i '/num_engine_workers/c\num_engine_workers = 2' /etc/heat/heat.conf
733 sudo sed -i '/#workers\s=/c\workers = 2' /etc/heat/heat.conf
734 sudo systemctl restart openstack-heat-engine
735 sudo systemctl restart openstack-heat-api
736 EOI
737 # WORKAROUND: must restart the above services to fix sync problem with nova compute manager
738 # TODO: revisit and file a bug if necessary. This should eventually be removed
739 # as well as glance api problem
740 echo -e "${blue}INFO: Sleeping 15 seconds while services come back from restart${reset}"
741 sleep 15
742
743 }
744
745 ##preping it for deployment and launch the deploy
746 ##params: none
747 function undercloud_prep_overcloud_deploy {
748   if [[ "${#deploy_options_array[@]}" -eq 0 || "${deploy_options_array['sdn_controller']}" == 'opendaylight' ]]; then
749     if [ "${deploy_options_array['sdn_l3']}" == 'true' ]; then
750       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight_l3.yaml"
751     elif [ "${deploy_options_array['sfc']}" == 'true' ]; then
752       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight_sfc.yaml"
753     elif [ "${deploy_options_array['vpn']}" == 'true' ]; then
754       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight_sdnvpn.yaml"
755     else
756       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight.yaml"
757     fi
758     SDN_IMAGE=opendaylight
759     if [ "${deploy_options_array['sfc']}" == 'true' ]; then
760       SDN_IMAGE+=-sfc
761       if [ ! -f $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 ]; then
762           echo "${red} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 is required to execute an SFC deployment."
763           echo "Please install the opnfv-apex-opendaylight-sfc package to provide this overcloud image for deployment.${reset}"
764           exit 1
765       fi
766     fi
767   elif [ "${deploy_options_array['sdn_controller']}" == 'opendaylight-external' ]; then
768     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight-external.yaml"
769     SDN_IMAGE=opendaylight
770   elif [ "${deploy_options_array['sdn_controller']}" == 'onos' ]; then
771     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/onos.yaml"
772     SDN_IMAGE=onos
773   elif [ "${deploy_options_array['sdn_controller']}" == 'opencontrail' ]; then
774     echo -e "${red}ERROR: OpenContrail is currently unsupported...exiting${reset}"
775     exit 1
776   elif [[ -z "${deploy_options_array['sdn_controller']}" || "${deploy_options_array['sdn_controller']}" == 'False' ]]; then
777     echo -e "${blue}INFO: SDN Controller disabled...will deploy nosdn scenario${reset}"
778     SDN_IMAGE=opendaylight
779   else
780     echo "${red}Invalid sdn_controller: ${deploy_options_array['sdn_controller']}${reset}"
781     echo "${red}Valid choices are opendaylight, opendaylight-external, onos, opencontrail, False, or null${reset}"
782     exit 1
783   fi
784
785   # Make sure the correct overcloud image is available
786   if [ ! -f $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 ]; then
787       echo "${red} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 is required to execute your deployment."
788       echo "Both ONOS and OpenDaylight are currently deployed from this image."
789       echo "Please install the opnfv-apex package to provide this overcloud image for deployment.${reset}"
790       exit 1
791   fi
792
793   echo "Copying overcloud image to Undercloud"
794   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "rm -f overcloud-full.qcow2"
795   scp ${SSH_OPTIONS[@]} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 "stack@$UNDERCLOUD":overcloud-full.qcow2
796
797   # Push performance options to subscript to modify per-role images as needed
798   for option in "${performance_options[@]}" ; do
799     echo -e "${blue}Setting performance option $option${reset}"
800     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "bash build_perf_image.sh $option"
801   done
802
803   # Add performance deploy options if they have been set
804   if [ ! -z "${deploy_options_array['performance']}" ]; then
805     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/numa.yaml"
806   fi
807
808   # make sure ceph is installed
809   DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml"
810
811   # scale compute nodes according to inventory
812   total_nodes=$(ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "cat /home/stack/instackenv.json | grep -c memory")
813
814   # check if HA is enabled
815   if [[ "$ha_enabled" == "TRUE" || "$ha_enabled" == "true" ]]; then
816      DEPLOY_OPTIONS+=" --control-scale 3"
817      compute_nodes=$((total_nodes - 3))
818      DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/puppet-pacemaker.yaml"
819   else
820      compute_nodes=$((total_nodes - 1))
821   fi
822
823   if [ "$compute_nodes" -le 0 ]; then
824     echo -e "${red}ERROR: Invalid number of compute nodes: ${compute_nodes}. Check your inventory file.${reset}"
825     exit 1
826   else
827     echo -e "${blue}INFO: Number of compute nodes set for deployment: ${compute_nodes}${reset}"
828     DEPLOY_OPTIONS+=" --compute-scale ${compute_nodes}"
829   fi
830
831   if [[ "$net_isolation_enabled" == "TRUE" ]]; then
832      #DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/network-isolation.yaml"
833      DEPLOY_OPTIONS+=" -e network-environment.yaml"
834   fi
835
836   if [[ "$ha_enabled" == "TRUE" || "$ha_enabled" == "true"  ]] || [[ "$net_isolation_enabled" == "TRUE" ]]; then
837      DEPLOY_OPTIONS+=" --ntp-server $ntp_server"
838   fi
839
840   if [[ ! "$virtual" == "TRUE" ]]; then
841      DEPLOY_OPTIONS+=" --control-flavor control --compute-flavor compute"
842   else
843      DEPLOY_OPTIONS+=" -e virtual-environment.yaml"
844   fi
845
846   DEPLOY_OPTIONS+=" -e opnfv-environment.yaml"
847
848   echo -e "${blue}INFO: Deploy options set:\n${DEPLOY_OPTIONS}${reset}"
849
850   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
851 if [ "$debug" == 'TRUE' ]; then
852     LIBGUESTFS_BACKEND=direct virt-customize -a overcloud-full.qcow2 --root-password password:opnfvapex
853 fi
854
855 source stackrc
856 set -o errexit
857 echo "Uploading overcloud glance images"
858 openstack overcloud image upload
859
860 bash -x set_perf_images.sh ${performance_roles}
861
862 echo "Configuring undercloud and discovering nodes"
863 openstack baremetal import --json instackenv.json
864 openstack baremetal configure boot
865 #if [[ -z "$virtual" ]]; then
866 #  openstack baremetal introspection bulk start
867 #fi
868 echo "Configuring flavors"
869 for flavor in baremetal control compute; do
870   echo -e "${blue}INFO: Updating flavor: \${flavor}${reset}"
871   if openstack flavor list | grep \${flavor}; then
872     openstack flavor delete \${flavor}
873   fi
874   openstack flavor create --id auto --ram 4096 --disk 39 --vcpus 1 \${flavor}
875   if ! openstack flavor list | grep \${flavor}; then
876     echo -e "${red}ERROR: Unable to create flavor \${flavor}${reset}"
877   fi
878 done
879 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" baremetal
880 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" --property "capabilities:profile"="control" control
881 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" --property "capabilities:profile"="compute" compute
882 echo "Configuring nameserver on ctlplane network"
883 neutron subnet-update \$(neutron subnet-list | grep -v id | grep -v \\\\-\\\\- | awk {'print \$2'}) --dns-nameserver 8.8.8.8
884 echo "Executing overcloud deployment, this should run for an extended period without output."
885 sleep 60 #wait for Hypervisor stats to check-in to nova
886 # save deploy command so it can be used for debugging
887 cat > deploy_command << EOF
888 openstack overcloud deploy --templates $DEPLOY_OPTIONS --timeout 90
889 EOF
890 EOI
891
892   if [ "$interactive" == "TRUE" ]; then
893     if ! prompt_user "Overcloud Deployment"; then
894       echo -e "${blue}INFO: User requests exit${reset}"
895       exit 0
896     fi
897   fi
898
899   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
900 source stackrc
901 openstack overcloud deploy --templates $DEPLOY_OPTIONS --timeout 90
902 if ! heat stack-list | grep CREATE_COMPLETE 1>/dev/null; then
903   $(typeset -f debug_stack)
904   debug_stack
905   exit 1
906 fi
907 EOI
908
909   if [ "$debug" == 'TRUE' ]; then
910       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
911 source overcloudrc
912 echo "Keystone Endpoint List:"
913 keystone endpoint-list
914 echo "Keystone Service List"
915 keystone service-list
916 cinder quota-show \$(openstack project list | grep admin | awk {'print \$2'})
917 EOI
918   fi
919 }
920
921 ##Post configuration after install
922 ##params: none
923 function configure_post_install {
924   local opnfv_attach_networks ovs_ip ip_range net_cidr tmp_ip
925   opnfv_attach_networks="admin_network public_network"
926
927   echo -e "${blue}INFO: Post Install Configuration Running...${reset}"
928
929   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
930 source overcloudrc
931 set -o errexit
932 echo "Configuring Neutron external network"
933 neutron net-create external --router:external=True --tenant-id \$(keystone tenant-get service | grep id | awk '{ print \$4 }')
934 neutron subnet-create --name external-net --tenant-id \$(keystone tenant-get service | grep id | awk '{ print \$4 }') --disable-dhcp external --gateway ${public_network_gateway} --allocation-pool start=${public_network_floating_ip_range%%,*},end=${public_network_floating_ip_range##*,} ${public_network_cidr}
935 EOI
936
937   echo -e "${blue}INFO: Checking if OVS bridges have IP addresses...${reset}"
938   for network in ${opnfv_attach_networks}; do
939     ovs_ip=$(find_ip ${NET_MAP[$network]})
940     tmp_ip=''
941     if [ -n "$ovs_ip" ]; then
942       echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} has IP address ${ovs_ip}${reset}"
943     else
944       echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} missing IP, will configure${reset}"
945       # use last IP of allocation pool
946       eval "ip_range=\${${network}_usable_ip_range}"
947       ovs_ip=${ip_range##*,}
948       eval "net_cidr=\${${network}_cidr}"
949       sudo ip addr add ${ovs_ip}/${net_cidr##*/} dev ${NET_MAP[$network]}
950       sudo ip link set up ${NET_MAP[$network]}
951       tmp_ip=$(find_ip ${NET_MAP[$network]})
952       if [ -n "$tmp_ip" ]; then
953         echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} IP set: ${tmp_ip}${reset}"
954         continue
955       else
956         echo -e "${red}ERROR: Unable to set OVS Bridge ${NET_MAP[$network]} with IP: ${ovs_ip}${reset}"
957         return 1
958       fi
959     fi
960   done
961
962   # for virtual, we NAT public network through Undercloud
963   if [ "$virtual" == "TRUE" ]; then
964     if ! configure_undercloud_nat ${public_network_cidr}; then
965       echo -e "${red}ERROR: Unable to NAT undercloud with external net: ${public_network_cidr}${reset}"
966       exit 1
967     else
968       echo -e "${blue}INFO: Undercloud VM has been setup to NAT Overcloud public network${reset}"
969     fi
970   fi
971
972   # for sfc deployments we need the vxlan workaround
973   if [ "${deploy_options_array['sfc']}" == 'true' ]; then
974       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
975 source stackrc
976 set -o errexit
977 for node in \$(nova list | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
978 ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
979 sudo ifconfig br-int up
980 sudo ip route add 123.123.123.0/24 dev br-int
981 EOF
982 done
983 EOI
984   fi
985
986   # Collect deployment logs
987   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
988 mkdir -p ~/deploy_logs
989 rm -rf deploy_logs/*
990 source stackrc
991 set -o errexit
992 for node in \$(nova list | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
993  ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
994  sudo cp /var/log/messages /home/heat-admin/messages.log
995  sudo chown heat-admin /home/heat-admin/messages.log
996 EOF
997 scp ${SSH_OPTIONS[@]} heat-admin@\$node:/home/heat-admin/messages.log ~/deploy_logs/\$node.messages.log
998 if [ "$debug" == "TRUE" ]; then
999     nova list --ip \$node
1000     echo "---------------------------"
1001     echo "-----/var/log/messages-----"
1002     echo "---------------------------"
1003     cat ~/deploy_logs/\$node.messages.log
1004     echo "---------------------------"
1005     echo "----------END LOG----------"
1006     echo "---------------------------"
1007 fi
1008  ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1009  sudo rm -f /home/heat-admin/messages.log
1010 EOF
1011 done
1012
1013 # Print out the dashboard URL
1014 source stackrc
1015 echo "Overcloud dashboard available at http://\$(heat output-show overcloud PublicVip | sed 's/"//g')/dashboard"
1016 EOI
1017
1018 }
1019
1020 display_usage() {
1021   echo -e "Usage:\n$0 [arguments] \n"
1022   echo -e "   -c|--config : Directory to configuration files. Optional.  Defaults to /var/opt/opnfv/ \n"
1023   echo -e "   -d|--deploy-settings : Full path to deploy settings yaml file. Optional.  Defaults to null \n"
1024   echo -e "   -i|--inventory : Full path to inventory yaml file. Required only for baremetal \n"
1025   echo -e "   -n|--net-settings : Full path to network settings file. Optional. \n"
1026   echo -e "   -p|--ping-site : site to use to verify IP connectivity. Optional. Defaults to 8.8.8.8 \n"
1027   echo -e "   -r|--resources : Directory to deployment resources. Optional.  Defaults to /var/opt/opnfv/stack \n"
1028   echo -e "   -v|--virtual : Virtualize overcloud nodes instead of using baremetal. \n"
1029   echo -e "   --no-ha : disable High Availability deployment scheme, this assumes a single controller and single compute node \n"
1030   echo -e "   --flat : disable Network Isolation and use a single flat network for the underlay network.\n"
1031   echo -e "   --no-post-config : disable Post Install configuration."
1032   echo -e "   --debug : enable debug output."
1033   echo -e "   --interactive : enable interactive deployment mode which requires user to confirm steps of deployment."
1034   echo -e "   --virtual-cpus : Number of CPUs to use per Overcloud VM in a virtual deployment (defaults to 4)."
1035   echo -e "   --virtual-ram : Amount of RAM to use per Overcloud VM in GB (defaults to 8)."
1036 }
1037
1038 ##translates the command line parameters into variables
1039 ##params: $@ the entire command line is passed
1040 ##usage: parse_cmd_line() "$@"
1041 parse_cmdline() {
1042   echo -e "\n\n${blue}This script is used to deploy the Apex Installer and Provision OPNFV Target System${reset}\n\n"
1043   echo "Use -h to display help"
1044   sleep 2
1045
1046   while [ "${1:0:1}" = "-" ]
1047   do
1048     case "$1" in
1049         -h|--help)
1050                 display_usage
1051                 exit 0
1052             ;;
1053         -c|--config)
1054                 CONFIG=$2
1055                 echo "Deployment Configuration Directory Overridden to: $2"
1056                 shift 2
1057             ;;
1058         -d|--deploy-settings)
1059                 DEPLOY_SETTINGS_FILE=$2
1060                 echo "Deployment Configuration file: $2"
1061                 shift 2
1062             ;;
1063         -i|--inventory)
1064                 INVENTORY_FILE=$2
1065                 shift 2
1066             ;;
1067         -n|--net-settings)
1068                 NETSETS=$2
1069                 echo "Network Settings Configuration file: $2"
1070                 shift 2
1071             ;;
1072         -p|--ping-site)
1073                 ping_site=$2
1074                 echo "Using $2 as the ping site"
1075                 shift 2
1076             ;;
1077         -r|--resources)
1078                 RESOURCES=$2
1079                 echo "Deployment Resources Directory Overridden to: $2"
1080                 shift 2
1081             ;;
1082         -v|--virtual)
1083                 virtual="TRUE"
1084                 echo "Executing a Virtual Deployment"
1085                 shift 1
1086             ;;
1087         --no-ha )
1088                 ha_enabled="FALSE"
1089                 vm_index=1
1090                 echo "HA Deployment Disabled"
1091                 shift 1
1092             ;;
1093         --flat )
1094                 net_isolation_enabled="FALSE"
1095                 echo "Underlay Network Isolation Disabled: using flat configuration"
1096                 shift 1
1097             ;;
1098         --no-post-config )
1099                 post_config="FALSE"
1100                 echo "Post install configuration disabled"
1101                 shift 1
1102             ;;
1103         --debug )
1104                 debug="TRUE"
1105                 echo "Enable debug output"
1106                 shift 1
1107             ;;
1108         --interactive )
1109                 interactive="TRUE"
1110                 echo "Interactive mode enabled"
1111                 shift 1
1112             ;;
1113         --virtual-cpus )
1114                 VM_CPUS=$2
1115                 echo "Number of CPUs per VM set to $VM_CPUS"
1116                 shift 2
1117             ;;
1118         --virtual-ram )
1119                 VM_RAM=$2
1120                 echo "Amount of RAM per VM set to $VM_RAM"
1121                 shift 2
1122             ;;
1123         *)
1124                 display_usage
1125                 exit 1
1126             ;;
1127     esac
1128   done
1129
1130   if [[ ! -z "$NETSETS" && "$net_isolation_enabled" == "FALSE" ]]; then
1131     echo -e "${red}INFO: Single flat network requested. Only admin_network settings will be used!${reset}"
1132   elif [[ -z "$NETSETS" ]]; then
1133     echo -e "${red}ERROR: You must provide a network_settings file with -n.${reset}"
1134     exit 1
1135   fi
1136
1137   if [[ -n "$virtual" && -n "$INVENTORY_FILE" ]]; then
1138     echo -e "${red}ERROR: You should not specify an inventory with virtual deployments${reset}"
1139     exit 1
1140   fi
1141
1142   if [[ -z "$DEPLOY_SETTINGS_FILE" || ! -f "$DEPLOY_SETTINGS_FILE" ]]; then
1143     echo -e "${red}ERROR: Deploy Settings: ${DEPLOY_SETTINGS_FILE} does not exist! Exiting...${reset}"
1144     exit 1
1145   fi
1146
1147   if [[ ! -z "$NETSETS" && ! -f "$NETSETS" ]]; then
1148     echo -e "${red}ERROR: Network Settings: ${NETSETS} does not exist! Exiting...${reset}"
1149     exit 1
1150   fi
1151
1152   if [[ ! -z "$INVENTORY_FILE" && ! -f "$INVENTORY_FILE" ]]; then
1153     echo -e "{$red}ERROR: Inventory File: ${INVENTORY_FILE} does not exist! Exiting...${reset}"
1154     exit 1
1155   fi
1156
1157   if [[ -z "$virtual" && -z "$INVENTORY_FILE" ]]; then
1158     echo -e "${red}ERROR: You must specify an inventory file for baremetal deployments! Exiting...${reset}"
1159     exit 1
1160   fi
1161
1162   if [[ "$net_isolation_enabled" == "FALSE" && "$post_config" == "TRUE" ]]; then
1163     echo -e "${blue}INFO: Post Install Configuration will be skipped.  It is not supported with --flat${reset}"
1164     post_config="FALSE"
1165   fi
1166
1167   ##LIBRARIES
1168   # Do this after cli parse so that $CONFIG is set properly
1169   source $CONFIG/lib/common-functions.sh
1170   source $CONFIG/lib/utility-functions.sh
1171   source $CONFIG/lib/installer/onos/onos_gw_mac_update.sh
1172
1173 }
1174
1175 ##END FUNCTIONS
1176
1177 main() {
1178   # Make sure jinja2 is installed
1179   easy_install-3.4 jinja2 > /dev/null
1180   parse_cmdline "$@"
1181   echo -e "${blue}INFO: Parsing network settings file...${reset}"
1182   parse_network_settings
1183   if ! configure_deps; then
1184     echo -e "${red}Dependency Validation Failed, Exiting.${reset}"
1185     exit 1
1186   fi
1187   if [ -n "$DEPLOY_SETTINGS_FILE" ]; then
1188     echo -e "${blue}INFO: Parsing deploy settings file...${reset}"
1189     parse_deploy_settings
1190   fi
1191   setup_undercloud_vm
1192   if [ "$virtual" == "TRUE" ]; then
1193     setup_virtual_baremetal $VM_CPUS $VM_RAM
1194   elif [ -n "$INVENTORY_FILE" ]; then
1195     parse_inventory_file
1196   fi
1197   configure_undercloud
1198   undercloud_prep_overcloud_deploy
1199   if [ "$post_config" == "TRUE" ]; then
1200     if ! configure_post_install; then
1201       echo -e "${red}ERROR:Post Install Configuration Failed, Exiting.${reset}"
1202       exit 1
1203     else
1204       echo -e "${blue}INFO: Post Install Configuration Complete${reset}"
1205     fi
1206   fi
1207   if [[ "${deploy_options_array['sdn_controller']}" == 'onos' ]]; then
1208     if ! onos_update_gw_mac ${public_network_cidr} ${public_network_gateway}; then
1209       echo -e "${red}ERROR:ONOS Post Install Configuration Failed, Exiting.${reset}"
1210       exit 1
1211     else
1212       echo -e "${blue}INFO: ONOS Post Install Configuration Complete${reset}"
1213     fi
1214   fi
1215 }
1216
1217 main "$@"