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