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