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