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