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