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