1b8f36f062e624bcd38a7eb5ee1bdc32dafe6904
[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     elif [ "${deploy_options_array['vpn']}" == 'true' ]; then
805       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight_sdnvpn.yaml"
806     else
807       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight.yaml"
808     fi
809     SDN_IMAGE=opendaylight
810     if [ "${deploy_options_array['sfc']}" == 'true' ]; then
811       SDN_IMAGE+=-sfc
812       if [ ! -f $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 ]; then
813           echo "${red} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 is required to execute an SFC deployment."
814           echo "Please install the opnfv-apex-opendaylight-sfc package to provide this overcloud image for deployment.${reset}"
815           exit 1
816       fi
817     fi
818   elif [ "${deploy_options_array['sdn_controller']}" == 'opendaylight-external' ]; then
819     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight-external.yaml"
820     SDN_IMAGE=opendaylight
821   elif [ "${deploy_options_array['sdn_controller']}" == 'onos' ]; then
822     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/onos.yaml"
823     SDN_IMAGE=opendaylight
824   elif [ "${deploy_options_array['sdn_controller']}" == 'opencontrail' ]; then
825     echo -e "${red}ERROR: OpenContrail is currently unsupported...exiting${reset}"
826     exit 1
827   elif [[ -z "${deploy_options_array['sdn_controller']}" || "${deploy_options_array['sdn_controller']}" == 'false' ]]; then
828     echo -e "${blue}INFO: SDN Controller disabled...will deploy nosdn scenario${reset}"
829     SDN_IMAGE=opendaylight
830   else
831     echo "${red}Invalid sdn_controller: ${deploy_options_array['sdn_controller']}${reset}"
832     echo "${red}Valid choices are opendaylight, opendaylight-external, onos, opencontrail, false, or null${reset}"
833     exit 1
834   fi
835
836   # Make sure the correct overcloud image is available
837   if [ ! -f $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 ]; then
838       echo "${red} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 is required to execute your deployment."
839       echo "Both ONOS and OpenDaylight are currently deployed from this image."
840       echo "Please install the opnfv-apex package to provide this overcloud image for deployment.${reset}"
841       exit 1
842   fi
843
844   echo "Copying overcloud image to instack"
845   scp ${SSH_OPTIONS[@]} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 "stack@$UNDERCLOUD":overcloud-full.qcow2
846
847   # make sure ceph is installed
848   DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml"
849
850   # scale compute nodes according to inventory
851   total_nodes=$(ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "cat /home/stack/instackenv.json | grep -c memory")
852
853   # check if HA is enabled
854   if [[ "$ha_enabled" == "TRUE" || "$ha_enabled" == "true" ]]; then
855      DEPLOY_OPTIONS+=" --control-scale 3"
856      compute_nodes=$((total_nodes - 3))
857      DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/puppet-pacemaker.yaml"
858   else
859      compute_nodes=1
860   fi
861
862   if [ "$compute_nodes" -le 0 ]; then
863     echo -e "${red}ERROR: Invalid number of compute nodes: ${compute_nodes}. Check your inventory file.${reset}"
864     exit 1
865   else
866     echo -e "${blue}INFO: Number of compute nodes set for deployment: ${compute_nodes}${reset}"
867     DEPLOY_OPTIONS+=" --compute-scale ${compute_nodes}"
868   fi
869
870   if [[ "$net_isolation_enabled" == "TRUE" ]]; then
871      #DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/network-isolation.yaml"
872      DEPLOY_OPTIONS+=" -e network-environment.yaml"
873   fi
874
875   if [[ "$ha_enabled" == "TRUE" || "$ha_enabled" == "true"  ]] || [[ "$net_isolation_enabled" == "TRUE" ]]; then
876      DEPLOY_OPTIONS+=" --ntp-server $ntp_server"
877   fi
878
879   if [[ ! "$virtual" == "TRUE" ]]; then
880      DEPLOY_OPTIONS+=" --control-flavor control --compute-flavor compute"
881   fi
882
883   echo -e "${blue}INFO: Deploy options set:\n${DEPLOY_OPTIONS}${reset}"
884
885   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
886 if [ "$debug" == 'TRUE' ]; then
887     LIBGUESTFS_BACKEND=direct virt-customize -a overcloud-full.qcow2 --root-password password:opnfvapex
888 fi
889
890 source stackrc
891 set -o errexit
892 echo "Uploading overcloud glance images"
893 openstack overcloud image upload
894 echo "Configuring undercloud and discovering nodes"
895 openstack baremetal import --json instackenv.json
896 openstack baremetal configure boot
897 #if [[ -z "$virtual" ]]; then
898 #  openstack baremetal introspection bulk start
899 #fi
900 echo "Configuring flavors"
901 for flavor in baremetal control compute; do
902   echo -e "${blue}INFO: Updating flavor: \${flavor}${reset}"
903   if openstack flavor list | grep \${flavor}; then
904     openstack flavor delete \${flavor}
905   fi
906   openstack flavor create --id auto --ram 4096 --disk 39 --vcpus 1 \${flavor}
907   if ! openstack flavor list | grep \${flavor}; then
908     echo -e "${red}ERROR: Unable to create flavor \${flavor}${reset}"
909   fi
910 done
911 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" baremetal
912 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" --property "capabilities:profile"="control" control
913 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" --property "capabilities:profile"="compute" compute
914 echo "Configuring nameserver on ctlplane network"
915 neutron subnet-update \$(neutron subnet-list | grep -v id | grep -v \\\\-\\\\- | awk {'print \$2'}) --dns-nameserver 8.8.8.8
916 echo "Executing overcloud deployment, this should run for an extended period without output."
917 sleep 60 #wait for Hypervisor stats to check-in to nova
918 # save deploy command so it can be used for debugging
919 cat > deploy_command << EOF
920 openstack overcloud deploy --templates $DEPLOY_OPTIONS --timeout 90
921 EOF
922 EOI
923
924   if [ "$interactive" == "TRUE" ]; then
925     if ! prompt_user "Overcloud Deployment"; then
926       echo -e "${blue}INFO: User requests exit${reset}"
927       exit 0
928     fi
929   fi
930
931   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
932 source stackrc
933 set -o errexit
934 openstack overcloud deploy --templates $DEPLOY_OPTIONS --timeout 90
935 EOI
936
937   if [ "$debug" == 'TRUE' ]; then
938       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
939 source overcloudrc
940 echo "Keystone Endpoint List:"
941 keystone endpoint-list
942 echo "Keystone Service List"
943 keystone service-list
944 cinder quota-show \$(openstack project list | grep admin | awk {'print \$2'})
945 EOI
946   fi
947 }
948
949 ##Post configuration after install
950 ##params: none
951 function configure_post_install {
952   local opnfv_attach_networks ovs_ip ip_range net_cidr tmp_ip
953   opnfv_attach_networks="admin_network public_network"
954
955   echo -e "${blue}INFO: Post Install Configuration Running...${reset}"
956
957   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
958 source overcloudrc
959 set -o errexit
960 echo "Configuring Neutron external network"
961 neutron net-create external --router:external=True --tenant-id \$(keystone tenant-get service | grep id | awk '{ print \$4 }')
962 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}
963 EOI
964
965   echo -e "${blue}INFO: Checking if OVS bridges have IP addresses...${reset}"
966   for network in ${opnfv_attach_networks}; do
967     ovs_ip=$(find_ip ${NET_MAP[$network]})
968     tmp_ip=''
969     if [ -n "$ovs_ip" ]; then
970       echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} has IP address ${ovs_ip}${reset}"
971     else
972       echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} missing IP, will configure${reset}"
973       # use last IP of allocation pool
974       eval "ip_range=\${${network}_usable_ip_range}"
975       ovs_ip=${ip_range##*,}
976       eval "net_cidr=\${${network}_cidr}"
977       sudo ip addr add ${ovs_ip}/${net_cidr##*/} dev ${NET_MAP[$network]}
978       sudo ip link set up ${NET_MAP[$network]}
979       tmp_ip=$(find_ip ${NET_MAP[$network]})
980       if [ -n "$tmp_ip" ]; then
981         echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} IP set: ${tmp_ip}${reset}"
982         continue
983       else
984         echo -e "${red}ERROR: Unable to set OVS Bridge ${NET_MAP[$network]} with IP: ${ovs_ip}${reset}"
985         return 1
986       fi
987     fi
988   done
989
990   # for virtual, we NAT public network through instack
991   if [ "$virtual" == "TRUE" ]; then
992     if ! configure_undercloud_nat ${public_network_cidr}; then
993       echo -e "${red}ERROR: Unable to NAT undercloud with external net: ${public_network_cidr}${reset}"
994       exit 1
995     else
996       echo -e "${blue}INFO: Undercloud (instack VM) has been setup to NAT Overcloud public network${reset}"
997     fi
998   fi
999
1000   # for sfc deployments we need the vxlan workaround
1001   if [ "${deploy_options_array['sfc']}" == 'true' ]; then
1002       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1003 source stackrc
1004 set -o errexit
1005 for node in \$(nova list | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
1006 ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1007 sudo ifconfig br-int up
1008 sudo ip route add 123.123.123.0/24 dev br-int
1009 EOF
1010 done
1011 EOI
1012   fi
1013
1014   # Collect deployment logs
1015   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1016 mkdir -p ~/deploy_logs
1017 rm -rf deploy_logs/*
1018 source stackrc
1019 set -o errexit
1020 for node in \$(nova list | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
1021  ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1022  sudo cp /var/log/messages /home/heat-admin/messages.log
1023  sudo chown heat-admin /home/heat-admin/messages.log
1024 EOF
1025 scp ${SSH_OPTIONS[@]} heat-admin@\$node:/home/heat-admin/messages.log ~/deploy_logs/\$node.messages.log
1026 if [ "$debug" == "TRUE" ]; then
1027     nova list --ip \$node
1028     echo "---------------------------"
1029     echo "-----/var/log/messages-----"
1030     echo "---------------------------"
1031     cat ~/deploy_logs/\$node.messages.log
1032     echo "---------------------------"
1033     echo "----------END LOG----------"
1034     echo "---------------------------"
1035 fi
1036  ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1037  sudo rm -f /home/heat-admin/messages.log
1038 EOF
1039 done
1040
1041 # Print out the dashboard URL
1042 source stackrc
1043 echo "Overcloud dashboard available at http://\$(heat output-show overcloud PublicVip | sed 's/"//g')/dashboard"
1044 EOI
1045
1046 }
1047
1048 display_usage() {
1049   echo -e "Usage:\n$0 [arguments] \n"
1050   echo -e "   -c|--config : Directory to configuration files. Optional.  Defaults to /var/opt/opnfv/ \n"
1051   echo -e "   -d|--deploy-settings : Full path to deploy settings yaml file. Optional.  Defaults to null \n"
1052   echo -e "   -i|--inventory : Full path to inventory yaml file. Required only for baremetal \n"
1053   echo -e "   -n|--net-settings : Full path to network settings file. Optional. \n"
1054   echo -e "   -p|--ping-site : site to use to verify IP connectivity. Optional. Defaults to 8.8.8.8 \n"
1055   echo -e "   -r|--resources : Directory to deployment resources. Optional.  Defaults to /var/opt/opnfv/stack \n"
1056   echo -e "   -v|--virtual : Virtualize overcloud nodes instead of using baremetal. \n"
1057   echo -e "   --no-ha : disable High Availability deployment scheme, this assumes a single controller and single compute node \n"
1058   echo -e "   --flat : disable Network Isolation and use a single flat network for the underlay network.\n"
1059   echo -e "   --no-post-config : disable Post Install configuration."
1060   echo -e "   --debug : enable debug output."
1061   echo -e "   --interactive : enable interactive deployment mode which requires user to confirm steps of deployment."
1062 }
1063
1064 ##translates the command line parameters into variables
1065 ##params: $@ the entire command line is passed
1066 ##usage: parse_cmd_line() "$@"
1067 parse_cmdline() {
1068   echo -e "\n\n${blue}This script is used to deploy the Apex Installer and Provision OPNFV Target System${reset}\n\n"
1069   echo "Use -h to display help"
1070   sleep 2
1071
1072   while [ "${1:0:1}" = "-" ]
1073   do
1074     case "$1" in
1075         -h|--help)
1076                 display_usage
1077                 exit 0
1078             ;;
1079         -c|--config)
1080                 CONFIG=$2
1081                 echo "Deployment Configuration Directory Overridden to: $2"
1082                 shift 2
1083             ;;
1084         -d|--deploy-settings)
1085                 DEPLOY_SETTINGS_FILE=$2
1086                 echo "Deployment Configuration file: $2"
1087                 shift 2
1088             ;;
1089         -i|--inventory)
1090                 INVENTORY_FILE=$2
1091                 shift 2
1092             ;;
1093         -n|--net-settings)
1094                 NETSETS=$2
1095                 echo "Network Settings Configuration file: $2"
1096                 shift 2
1097             ;;
1098         -p|--ping-site)
1099                 ping_site=$2
1100                 echo "Using $2 as the ping site"
1101                 shift 2
1102             ;;
1103         -r|--resources)
1104                 RESOURCES=$2
1105                 echo "Deployment Resources Directory Overridden to: $2"
1106                 shift 2
1107             ;;
1108         -v|--virtual)
1109                 virtual="TRUE"
1110                 echo "Executing a Virtual Deployment"
1111                 shift 1
1112             ;;
1113         --no-ha )
1114                 ha_enabled="FALSE"
1115                 echo "HA Deployment Disabled"
1116                 shift 1
1117             ;;
1118         --flat )
1119                 net_isolation_enabled="FALSE"
1120                 echo "Underlay Network Isolation Disabled: using flat configuration"
1121                 shift 1
1122             ;;
1123         --no-post-config )
1124                 post_config="FALSE"
1125                 echo "Post install configuration disabled"
1126                 shift 1
1127             ;;
1128         --debug )
1129                 debug="TRUE"
1130                 echo "Enable debug output"
1131                 shift 1
1132             ;;
1133         --interactive )
1134                 interactive="TRUE"
1135                 echo "Interactive mode enabled"
1136                 shift 1
1137             ;;
1138         *)
1139                 display_usage
1140                 exit 1
1141             ;;
1142     esac
1143   done
1144
1145   if [[ ! -z "$NETSETS" && "$net_isolation_enabled" == "FALSE" ]]; then
1146     echo -e "${red}INFO: Single flat network requested. Ignoring any network settings!${reset}"
1147   elif [[ -z "$NETSETS" && "$net_isolation_enabled" == "TRUE" ]]; then
1148     echo -e "${red}ERROR: You must provide a network_settings file with -n or use --flat to force a single flat network${reset}"
1149     exit 1
1150   fi
1151
1152   if [[ -n "$virtual" && -n "$INVENTORY_FILE" ]]; then
1153     echo -e "${red}ERROR: You should not specify an inventory with virtual deployments${reset}"
1154     exit 1
1155   fi
1156
1157   if [[ -z "$DEPLOY_SETTINGS_FILE" || ! -f "$DEPLOY_SETTINGS_FILE" ]]; then
1158     echo -e "${red}ERROR: Deploy Settings: ${DEPLOY_SETTINGS_FILE} does not exist! Exiting...${reset}"
1159     exit 1
1160   fi
1161
1162   if [[ ! -z "$NETSETS" && ! -f "$NETSETS" ]]; then
1163     echo -e "${red}ERROR: Network Settings: ${NETSETS} does not exist! Exiting...${reset}"
1164     exit 1
1165   fi
1166
1167   if [[ ! -z "$INVENTORY_FILE" && ! -f "$INVENTORY_FILE" ]]; then
1168     echo -e "{$red}ERROR: Inventory File: ${INVENTORY_FILE} does not exist! Exiting...${reset}"
1169     exit 1
1170   fi
1171
1172   if [[ -z "$virtual" && -z "$INVENTORY_FILE" ]]; then
1173     echo -e "${red}ERROR: You must specify an inventory file for baremetal deployments! Exiting...${reset}"
1174     exit 1
1175   fi
1176
1177   if [[ "$net_isolation_enabled" == "FALSE" && "$post_config" == "TRUE" ]]; then
1178     echo -e "${blue}INFO: Post Install Configuration will be skipped.  It is not supported with --flat${reset}"
1179     post_config="FALSE"
1180   fi
1181
1182   ##LIBRARIES
1183   # Do this after cli parse so that $CONFIG is set properly
1184   source $CONFIG/lib/common-functions.sh
1185   source $CONFIG/lib/installer/onos/onos_gw_mac_update.sh
1186
1187 }
1188
1189 ##END FUNCTIONS
1190
1191 main() {
1192   parse_cmdline "$@"
1193   if [[ "$net_isolation_enabled" == "TRUE" ]]; then
1194     echo -e "${blue}INFO: Parsing network settings file...${reset}"
1195     parse_network_settings
1196   fi
1197   if ! configure_deps; then
1198     echo -e "${red}Dependency Validation Failed, Exiting.${reset}"
1199     exit 1
1200   fi
1201   if [ -n "$DEPLOY_SETTINGS_FILE" ]; then
1202     parse_deploy_settings
1203   fi
1204   setup_instack_vm
1205   if [ "$virtual" == "TRUE" ]; then
1206     setup_virtual_baremetal
1207   elif [ -n "$INVENTORY_FILE" ]; then
1208     parse_inventory_file
1209   fi
1210   configure_undercloud
1211   undercloud_prep_overcloud_deploy
1212   if [ "$post_config" == "TRUE" ]; then
1213     if ! configure_post_install; then
1214       echo -e "${red}ERROR:Post Install Configuration Failed, Exiting.${reset}"
1215       exit 1
1216     else
1217       echo -e "${blue}INFO: Post Install Configuration Complete${reset}"
1218     fi
1219   fi
1220   if [[ "${deploy_options_array['sdn_controller']}" == 'onos' ]]; then
1221     if ! onos_update_gw_mac ${public_network_cidr} ${public_network_gateway}; then
1222       echo -e "${red}ERROR:ONOS Post Install Configuration Failed, Exiting.${reset}"
1223       exit 1
1224     else
1225       echo -e "${blue}INFO: ONOS Post Install Configuration Complete${reset}"
1226     fi
1227   fi
1228 }
1229
1230 main "$@"