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