d43960efb0135ac8ea197b8c7cb8cfe3696953e4
[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 reset=$(tput sgr0 || echo "")
21 blue=$(tput setaf 4 || echo "")
22 red=$(tput setaf 1 || echo "")
23 green=$(tput setaf 2 || echo "")
24
25 vm_index=4
26 interactive="FALSE"
27 ping_site="8.8.8.8"
28 ntp_server="pool.ntp.org"
29 net_isolation_enabled="TRUE"
30 post_config="TRUE"
31 debug="FALSE"
32
33 declare -i CNT
34 declare UNDERCLOUD
35 declare -A deploy_options_array
36 declare -a performance_options
37 declare -A NET_MAP
38
39 SSH_OPTIONS=(-o StrictHostKeyChecking=no -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null -o LogLevel=error)
40 DEPLOY_OPTIONS=""
41 RESOURCES=${RESOURCES:-'/var/opt/opnfv/images'}
42 CONFIG=${CONFIG:-'/var/opt/opnfv'}
43 OPNFV_NETWORK_TYPES="admin_network private_network public_network storage_network"
44 VM_CPUS=4
45 VM_RAM=8
46 # Netmap used to map networks to OVS bridge names
47 NET_MAP['admin_network']="br-admin"
48 NET_MAP['private_network']="br-private"
49 NET_MAP['public_network']="br-public"
50 NET_MAP['storage_network']="br-storage"
51 ext_net_type="interface"
52 ip_address_family=4
53
54 ##FUNCTIONS
55 ##translates yaml into variables
56 ##params: filename, prefix (ex. "config_")
57 ##usage: parse_yaml opnfv_ksgen_settings.yml "config_"
58 parse_yaml() {
59    local prefix=$2
60    local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
61    sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
62         -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p"  $1 |
63    awk -F$fs '{
64       indent = length($1)/2;
65       vname[indent] = $2;
66       for (i in vname) {if (i > indent) {delete vname[i]}}
67       if (length($3) > 0) {
68          vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
69          printf("%s%s%s=%s\n", "'$prefix'",vn, $2, $3);
70       }
71    }'
72 }
73
74 ##checks if prefix exists in string
75 ##params: string, prefix
76 ##usage: contains_prefix "deploy_setting_launcher=1" "deploy_setting"
77 contains_prefix() {
78   local mystr=$1
79   local prefix=$2
80   if echo $mystr | grep -E "^$prefix.*$" > /dev/null; then
81     return 0
82   else
83     return 1
84   fi
85 }
86 ##parses variable from a string with '='
87 ##and removes global prefix
88 ##params: string, prefix
89 ##usage: parse_setting_var 'deploy_myvar=2' 'deploy_'
90 parse_setting_var() {
91   local mystr=$1
92   local prefix=$2
93   if echo $mystr | grep -E "^.+\=" > /dev/null; then
94     echo $(echo $mystr | grep -Eo "^.+\=" | tr -d '=' |  sed 's/^'"$prefix"'//')
95   else
96     return 1
97   fi
98 }
99 ##parses value from a string with '='
100 ##params: string
101 ##usage: parse_setting_value
102 parse_setting_value() {
103   local mystr=$1
104   echo $(echo $mystr | grep -Eo "\=.*$" | tr -d '=')
105 }
106
107 ##parses network settings yaml into globals
108 parse_network_settings() {
109   if local output=$(python3.4 -B $CONFIG/lib/python/apex-python-utils.py parse_net_settings -n $NETSETS -i $net_isolation_enabled); then
110       echo -e "${blue}${output}${reset}"
111       eval "$output"
112   else
113       echo -e "${red}ERROR: Failed to parse network settings file $NETSETS ${reset}"
114       exit 1
115   fi
116 }
117
118 ##parses deploy settings yaml into globals
119 parse_deploy_settings() {
120   if local output=$(python3.4 -B $CONFIG/lib/python/apex-python-utils.py parse-deploy-settings -f $DEPLOY_SETTINGS_FILE); then
121       echo -e "${blue}${output}${reset}"
122       eval "$output"
123   else
124       echo -e "${red}ERROR: Failed to parse deploy settings file $DEPLOY_SETTINGS_FILE ${reset}"
125       exit 1
126   fi
127 }
128
129 ##parses baremetal yaml settings into compatible json
130 ##writes the json to $CONFIG/instackenv_tmp.json
131 ##params: none
132 ##usage: parse_inventory_file
133 parse_inventory_file() {
134   local inventory=$(parse_yaml $INVENTORY_FILE)
135   local node_list
136   local node_prefix="node"
137   local node_count=0
138   local node_total
139   local inventory_list
140
141   # detect number of nodes
142   for entry in $inventory; do
143     if echo $entry | grep -Eo "^nodes_node[0-9]+_" > /dev/null; then
144       this_node=$(echo $entry | grep -Eo "^nodes_node[0-9]+_")
145       if [[ "$inventory_list" != *"$this_node"* ]]; then
146         inventory_list+="$this_node "
147       fi
148     fi
149   done
150
151   inventory_list=$(echo $inventory_list | sed 's/ $//')
152
153   for node in $inventory_list; do
154     ((node_count+=1))
155   done
156
157   node_total=$node_count
158
159   if [[ "$node_total" -lt 5 && ( ha_enabled == "TRUE" || "$ha_enabled" == "true" ) ]]; then
160     echo -e "${red}ERROR: You must provide at least 5 nodes for HA baremetal deployment${reset}"
161     exit 1
162   elif [[ "$node_total" -lt 2 ]]; then
163     echo -e "${red}ERROR: You must provide at least 2 nodes for non-HA baremetal deployment${reset}"
164     exit 1
165   fi
166
167   eval $(parse_yaml $INVENTORY_FILE) || {
168     echo "${red}Failed to parse inventory.yaml. Aborting.${reset}"
169     exit 1
170   }
171
172   instackenv_output="
173 {
174  \"nodes\" : [
175
176 "
177   node_count=0
178   for node in $inventory_list; do
179     ((node_count+=1))
180     node_output="
181         {
182           \"pm_password\": \"$(eval echo \${${node}ipmi_pass})\",
183           \"pm_type\": \"$(eval echo \${${node}pm_type})\",
184           \"mac\": [
185             \"$(eval echo \${${node}mac_address})\"
186           ],
187           \"cpu\": \"$(eval echo \${${node}cpus})\",
188           \"memory\": \"$(eval echo \${${node}memory})\",
189           \"disk\": \"$(eval echo \${${node}disk})\",
190           \"arch\": \"$(eval echo \${${node}arch})\",
191           \"pm_user\": \"$(eval echo \${${node}ipmi_user})\",
192           \"pm_addr\": \"$(eval echo \${${node}ipmi_ip})\",
193           \"capabilities\": \"$(eval echo \${${node}capabilities})\"
194 "
195     instackenv_output+=${node_output}
196     if [ $node_count -lt $node_total ]; then
197       instackenv_output+="        },"
198     else
199       instackenv_output+="        }"
200     fi
201   done
202
203   instackenv_output+='
204   ]
205 }
206 '
207   #Copy instackenv.json to undercloud for baremetal
208   echo -e "{blue}Parsed instackenv JSON:\n${instackenv_output}${reset}"
209   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
210 cat > instackenv.json << EOF
211 $instackenv_output
212 EOF
213 EOI
214
215 }
216 ##verify internet connectivity
217 #params: none
218 function verify_internet {
219   if ping -c 2 $ping_site > /dev/null; then
220     if ping -c 2 www.google.com > /dev/null; then
221       echo "${blue}Internet connectivity detected${reset}"
222       return 0
223     else
224       echo "${red}Internet connectivity detected, but DNS lookup failed${reset}"
225       return 1
226     fi
227   else
228     echo "${red}No internet connectivity detected${reset}"
229     return 1
230   fi
231 }
232
233 ##download dependencies if missing and configure host
234 #params: none
235 function configure_deps {
236   if ! verify_internet; then
237     echo "${red}Will not download dependencies${reset}"
238     internet=false
239   fi
240
241   # verify ip forwarding
242   if sysctl net.ipv4.ip_forward | grep 0; then
243     sudo sysctl -w net.ipv4.ip_forward=1
244     sudo sh -c "echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf"
245   fi
246
247   # ensure no dhcp server is running on jumphost
248   if ! sudo systemctl status dhcpd | grep dead; then
249     echo "${red}WARN: DHCP Server detected on jumphost, disabling...${reset}"
250     sudo systemctl stop dhcpd
251     sudo systemctl disable dhcpd
252   fi
253
254   # ensure networks are configured
255   systemctl status libvirtd || systemctl start libvirtd
256   systemctl status openvswitch || systemctl start openvswitch
257
258   # If flat we only use admin network
259   if [[ "$net_isolation_enabled" == "FALSE" ]]; then
260     virsh_enabled_networks="admin_network"
261     enabled_network_list="admin_network"
262   # For baremetal we only need to create/attach Undercloud to admin and public
263   elif [ "$virtual" == "FALSE" ]; then
264     virsh_enabled_networks="admin_network public_network"
265   else
266     virsh_enabled_networks=$enabled_network_list
267   fi
268
269   # ensure default network is configured correctly
270   libvirt_dir="/usr/share/libvirt/networks"
271   virsh net-list --all | grep default || virsh net-define ${libvirt_dir}/default.xml
272   virsh net-list --all | grep -E "default\s+active" > /dev/null || virsh net-start default
273   virsh net-list --all | grep -E "default\s+active\s+yes" > /dev/null || virsh net-autostart --network default
274
275   if [[ -z "$virtual" || "$virtual" == "FALSE" ]]; then
276     for network in ${OPNFV_NETWORK_TYPES}; do
277       echo "${blue}INFO: Creating Virsh Network: $network & OVS Bridge: ${NET_MAP[$network]}${reset}"
278       ovs-vsctl list-br | grep "^${NET_MAP[$network]}$" > /dev/null || ovs-vsctl add-br ${NET_MAP[$network]}
279       virsh net-list --all | grep $network > /dev/null || (cat > ${libvirt_dir}/apex-virsh-net.xml && virsh net-define ${libvirt_dir}/apex-virsh-net.xml) << EOF
280 <network>
281   <name>$network</name>
282   <forward mode='bridge'/>
283   <bridge name='${NET_MAP[$network]}'/>
284   <virtualport type='openvswitch'/>
285 </network>
286 EOF
287       if ! (virsh net-list --all | grep $network > /dev/null); then
288           echo "${red}ERROR: unable to create network: ${network}${reset}"
289           exit 1;
290       fi
291       rm -f ${libvirt_dir}/apex-virsh-net.xml &> /dev/null;
292       virsh net-list | grep -E "$network\s+active" > /dev/null || virsh net-start $network
293       virsh net-list | grep -E "$network\s+active\s+yes" > /dev/null || virsh net-autostart --network $network
294     done
295
296     echo -e "${blue}INFO: Bridges set: ${reset}"
297     ovs-vsctl list-br
298
299     # bridge interfaces to correct OVS instances for baremetal deployment
300     for network in ${enabled_network_list}; do
301       if [[ "$network" != "admin_network" && "$network" != "public_network" ]]; then
302         continue
303       fi
304       this_interface=$(eval echo \${${network}_bridged_interface})
305       # check if this a bridged interface for this network
306       if [[ ! -z "$this_interface" || "$this_interface" != "none" ]]; then
307         if ! attach_interface_to_ovs ${NET_MAP[$network]} ${this_interface} ${network}; then
308           echo -e "${red}ERROR: Unable to bridge interface ${this_interface} to bridge ${NET_MAP[$network]} for enabled network: ${network}${reset}"
309           exit 1
310         else
311           echo -e "${blue}INFO: Interface ${this_interface} bridged to bridge ${NET_MAP[$network]} for enabled network: ${network}${reset}"
312         fi
313       else
314         echo "${red}ERROR: Unable to determine interface to bridge to for enabled network: ${network}${reset}"
315         exit 1
316       fi
317     done
318   else
319     for network in ${OPNFV_NETWORK_TYPES}; do
320       echo "${blue}INFO: Creating Virsh Network: $network${reset}"
321       virsh net-list --all | grep $network > /dev/null || (cat > ${libvirt_dir}/apex-virsh-net.xml && virsh net-define ${libvirt_dir}/apex-virsh-net.xml) << EOF
322 <network ipv6='yes'>
323 <name>$network</name>
324 <bridge name='${NET_MAP[$network]}'/>
325 </network>
326 EOF
327       if ! (virsh net-list --all | grep $network > /dev/null); then
328           echo "${red}ERROR: unable to create network: ${network}${reset}"
329           exit 1;
330       fi
331       rm -f ${libvirt_dir}/apex-virsh-net.xml &> /dev/null;
332       virsh net-list | grep -E "$network\s+active" > /dev/null || virsh net-start $network
333       virsh net-list | grep -E "$network\s+active\s+yes" > /dev/null || virsh net-autostart --network $network
334     done
335
336     echo -e "${blue}INFO: Bridges set: ${reset}"
337     brctl show
338   fi
339
340   echo -e "${blue}INFO: virsh networks set: ${reset}"
341   virsh net-list
342
343   # ensure storage pool exists and is started
344   virsh pool-list --all | grep default > /dev/null || virsh pool-define-as --name default dir --target /var/lib/libvirt/images
345   virsh pool-list | grep -Eo "default\s+active" > /dev/null || (virsh pool-autostart default; virsh pool-start default)
346
347   if ! egrep '^flags.*(vmx|svm)' /proc/cpuinfo > /dev/null; then
348     echo "${red}virtualization extensions not found, kvm kernel module insertion may fail.\n  \
349 Are you sure you have enabled vmx in your bios or hypervisor?${reset}"
350   fi
351
352   if ! lsmod | grep kvm > /dev/null; then modprobe kvm; fi
353   if ! lsmod | grep kvm_intel > /dev/null; then modprobe kvm_intel; fi
354
355   if ! lsmod | grep kvm > /dev/null; then
356     echo "${red}kvm kernel modules not loaded!${reset}"
357     return 1
358   fi
359
360   ##sshkeygen for root
361   if [ ! -e ~/.ssh/id_rsa.pub ]; then
362     ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
363   fi
364
365   echo "${blue}All dependencies installed and running${reset}"
366 }
367
368 ##verify vm exists, an has a dhcp lease assigned to it
369 ##params: none
370 function setup_undercloud_vm {
371   if ! virsh list --all | grep undercloud > /dev/null; then
372       undercloud_nets="default admin_network"
373       if [[ $enabled_network_list =~ "public_network" ]]; then
374         undercloud_nets+=" public_network"
375       fi
376       define_vm undercloud hd 30 "$undercloud_nets" 4 12288
377
378       ### this doesn't work for some reason I was getting hangup events so using cp instead
379       #virsh vol-upload --pool default --vol undercloud.qcow2 --file $CONFIG/stack/undercloud.qcow2
380       #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)
381       #2015-12-05 12:57:20.569+0000: 8755: warning : virKeepAliveTimerInternal:143 : No response from client 0x7ff1e231e630 after 6 keepalive messages in 35 seconds
382       #2015-12-05 12:57:20.569+0000: 8756: warning : virKeepAliveTimerInternal:143 : No response from client 0x7ff1e231e630 after 6 keepalive messages in 35 seconds
383       #error: cannot close volume undercloud.qcow2
384       #error: internal error: received hangup / error event on socket
385       #error: Reconnected to the hypervisor
386
387       local undercloud_dst=/var/lib/libvirt/images/undercloud.qcow2
388       cp -f $RESOURCES/undercloud.qcow2 $undercloud_dst
389
390       # resize Undercloud machine
391       echo "Checking if Undercloud needs to be resized..."
392       undercloud_size=$(LIBGUESTFS_BACKEND=direct virt-filesystems --long -h --all -a $undercloud_dst |grep device | grep -Eo "[0-9\.]+G" | sed -n 's/\([0-9][0-9]*\).*/\1/p')
393       if [ "$undercloud_size" -lt 30 ]; then
394         qemu-img resize /var/lib/libvirt/images/undercloud.qcow2 +25G
395         LIBGUESTFS_BACKEND=direct virt-resize --expand /dev/sda1 $RESOURCES/undercloud.qcow2 $undercloud_dst
396         LIBGUESTFS_BACKEND=direct virt-customize -a $undercloud_dst --run-command 'xfs_growfs -d /dev/sda1 || true'
397         new_size=$(LIBGUESTFS_BACKEND=direct virt-filesystems --long -h --all -a $undercloud_dst |grep filesystem | grep -Eo "[0-9\.]+G" | sed -n 's/\([0-9][0-9]*\).*/\1/p')
398         if [ "$new_size" -lt 30 ]; then
399           echo "Error resizing Undercloud machine, disk size is ${new_size}"
400           exit 1
401         else
402           echo "Undercloud successfully resized"
403         fi
404       else
405         echo "Skipped Undercloud resize, upstream is large enough"
406       fi
407
408   else
409       echo "Found Undercloud VM, using existing VM"
410   fi
411
412   # if the VM is not running update the authkeys and start it
413   if ! virsh list | grep undercloud > /dev/null; then
414     echo "Injecting ssh key to Undercloud VM"
415     LIBGUESTFS_BACKEND=direct virt-customize -a $undercloud_dst --run-command "mkdir -p /root/.ssh/" \
416         --upload ~/.ssh/id_rsa.pub:/root/.ssh/authorized_keys \
417         --run-command "chmod 600 /root/.ssh/authorized_keys && restorecon /root/.ssh/authorized_keys" \
418         --run-command "cp /root/.ssh/authorized_keys /home/stack/.ssh/" \
419         --run-command "chown stack:stack /home/stack/.ssh/authorized_keys && chmod 600 /home/stack/.ssh/authorized_keys"
420     virsh start undercloud
421   fi
422
423   sleep 10 # let undercloud get started up
424
425   # get the undercloud VM IP
426   CNT=10
427   echo -n "${blue}Waiting for Undercloud's dhcp address${reset}"
428   undercloud_mac=$(virsh domiflist undercloud | grep default | awk '{ print $5 }')
429   while ! $(arp -e | grep ${undercloud_mac} > /dev/null) && [ $CNT -gt 0 ]; do
430       echo -n "."
431       sleep 10
432       CNT=$((CNT-1))
433   done
434   UNDERCLOUD=$(arp -e | grep ${undercloud_mac} | awk {'print $1'})
435
436   if [ -z "$UNDERCLOUD" ]; then
437     echo "\n\nCan't get IP for Undercloud. Can Not Continue."
438     exit 1
439   else
440      echo -e "${blue}\rUndercloud VM has IP $UNDERCLOUD${reset}"
441   fi
442
443   CNT=10
444   echo -en "${blue}\rValidating Undercloud VM connectivity${reset}"
445   while ! ping -c 1 $UNDERCLOUD > /dev/null && [ $CNT -gt 0 ]; do
446       echo -n "."
447       sleep 3
448       CNT=$((CNT-1))
449   done
450   if [ "$CNT" -eq 0 ]; then
451       echo "Failed to contact Undercloud. Can Not Continue"
452       exit 1
453   fi
454   CNT=10
455   while ! ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "echo ''" 2>&1> /dev/null && [ $CNT -gt 0 ]; do
456       echo -n "."
457       sleep 3
458       CNT=$((CNT-1))
459   done
460   if [ "$CNT" -eq 0 ]; then
461       echo "Failed to connect to Undercloud. Can Not Continue"
462       exit 1
463   fi
464
465   # extra space to overwrite the previous connectivity output
466   echo -e "${blue}\r                                                                 ${reset}"
467   sleep 1
468   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"
469
470   # ssh key fix for stack user
471   ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "restorecon -r /home/stack"
472 }
473
474 ##Create virtual nodes in virsh
475 ##params: vcpus, ramsize
476 function setup_virtual_baremetal {
477   local vcpus ramsize
478   if [ -z "$1" ]; then
479     vcpus=4
480     ramsize=8192
481   elif [ -z "$2" ]; then
482     vcpus=$1
483     ramsize=8192
484   else
485     vcpus=$1
486     ramsize=$(($2*1024))
487   fi
488   #start by generating the opening json for instackenv.json
489   cat > $CONFIG/instackenv-virt.json << EOF
490 {
491   "nodes": [
492 EOF
493
494   # next create the virtual machines and add their definitions to the file
495   for i in $(seq 0 $vm_index); do
496     if ! virsh list --all | grep baremetal${i} > /dev/null; then
497       define_vm baremetal${i} network 41 'admin_network' $vcpus $ramsize
498       for n in private_network public_network storage_network; do
499         if [[ $enabled_network_list =~ $n ]]; then
500           echo -n "$n "
501           virsh attach-interface --domain baremetal${i} --type network --source $n --model rtl8139 --config
502         fi
503       done
504     else
505       echo "Found Baremetal ${i} VM, using existing VM"
506     fi
507     #virsh vol-list default | grep baremetal${i} 2>&1> /dev/null || virsh vol-create-as default baremetal${i}.qcow2 41G --format qcow2
508     mac=$(virsh domiflist baremetal${i} | grep admin_network | awk '{ print $5 }')
509
510     cat >> $CONFIG/instackenv-virt.json << EOF
511     {
512       "pm_addr": "192.168.122.1",
513       "pm_user": "root",
514       "pm_password": "INSERT_STACK_USER_PRIV_KEY",
515       "pm_type": "pxe_ssh",
516       "mac": [
517         "$mac"
518       ],
519       "cpu": "$vcpus",
520       "memory": "$ramsize",
521       "disk": "41",
522       "arch": "x86_64"
523     },
524 EOF
525   done
526
527   #truncate the last line to remove the comma behind the bracket
528   tail -n 1 $CONFIG/instackenv-virt.json | wc -c | xargs -I {} truncate $CONFIG/instackenv-virt.json -s -{}
529
530   #finally reclose the bracket and close the instackenv.json file
531   cat >> $CONFIG/instackenv-virt.json << EOF
532     }
533   ],
534   "arch": "x86_64",
535   "host-ip": "192.168.122.1",
536   "power_manager": "nova.virt.baremetal.virtual_power_driver.VirtualPowerManager",
537   "seed-ip": "",
538   "ssh-key": "INSERT_STACK_USER_PRIV_KEY",
539   "ssh-user": "root"
540 }
541 EOF
542 }
543
544 ##Create virtual nodes in virsh
545 ##params: name - String: libvirt name for VM
546 ##        bootdev - String: boot device for the VM
547 ##        disksize - Number: size of the disk in GB
548 ##        ovs_bridges: - List: list of ovs bridges
549 ##        vcpus - Number of VCPUs to use (defaults to 4)
550 ##        ramsize - Size of RAM for VM in MB (defaults to 8192)
551 function define_vm () {
552   local vcpus ramsize
553
554   if [ -z "$5" ]; then
555     vcpus=4
556     ramsize=8388608
557   elif [ -z "$6" ]; then
558     vcpus=$5
559     ramsize=8388608
560   else
561     vcpus=$5
562     ramsize=$(($6*1024))
563   fi
564
565   # Create the libvirt storage volume
566   if virsh vol-list default | grep ${1}.qcow2 2>&1> /dev/null; then
567     volume_path=$(virsh vol-path --pool default ${1}.qcow2 || echo "/var/lib/libvirt/images/${1}.qcow2")
568     echo "Volume ${1} exists. Deleting Existing Volume $volume_path"
569     virsh vol-dumpxml ${1}.qcow2 --pool default > /dev/null || echo '' #ok for this to fail
570     touch $volume_path
571     virsh vol-delete ${1}.qcow2 --pool default
572   fi
573   virsh vol-create-as default ${1}.qcow2 ${3}G --format qcow2
574   volume_path=$(virsh vol-path --pool default ${1}.qcow2)
575   if [ ! -f $volume_path ]; then
576       echo "$volume_path Not created successfully... Aborting"
577       exit 1
578   fi
579
580   # create the VM
581   /usr/libexec/openstack-tripleo/configure-vm --name $1 \
582                                               --bootdev $2 \
583                                               --image "$volume_path" \
584                                               --diskbus sata \
585                                               --arch x86_64 \
586                                               --cpus $vcpus \
587                                               --memory $ramsize \
588                                               --libvirt-nic-driver virtio \
589                                               --baremetal-interface $4
590 }
591
592 ##Set network-environment settings
593 ##params: network-environment file to edit
594 function configure_network_environment {
595   local tht_dir
596   tht_dir=/usr/share/openstack-tripleo-heat-templates/network
597
598   sed -i '/ControlPlaneSubnetCidr/c\\  ControlPlaneSubnetCidr: "'${admin_network_cidr##*/}'"' $1
599   sed -i '/ControlPlaneDefaultRoute/c\\  ControlPlaneDefaultRoute: '${admin_network_provisioner_ip}'' $1
600   sed -i '/ExternalNetCidr/c\\  ExternalNetCidr: '${public_network_cidr}'' $1
601   sed -i "/ExternalAllocationPools/c\\  ExternalAllocationPools: [{'start': '${public_network_usable_ip_range%%,*}', 'end': '${public_network_usable_ip_range##*,}'}]" $1
602   sed -i '/ExternalInterfaceDefaultRoute/c\\  ExternalInterfaceDefaultRoute: '${public_network_gateway}'' $1
603   sed -i '/EC2MetadataIp/c\\  EC2MetadataIp: '${admin_network_provisioner_ip}'' $1
604
605   # check for private network
606   if [[ ! -z "$private_network_enabled" && "$private_network_enabled" == "True" ]]; then
607       sed -i 's#^.*Network::Tenant.*$#  OS::TripleO::Network::Tenant: '${tht_dir}'/tenant.yaml#' $1
608       sed -i 's#^.*Controller::Ports::TenantPort:.*$#  OS::TripleO::Controller::Ports::TenantPort: '${tht_dir}'/ports/tenant.yaml#' $1
609       sed -i 's#^.*Compute::Ports::TenantPort:.*$#  OS::TripleO::Compute::Ports::TenantPort: '${tht_dir}'/ports/tenant.yaml#' $1
610       sed -i "/TenantAllocationPools/c\\  TenantAllocationPools: [{'start': '${private_network_usable_ip_range%%,*}', 'end': '${private_network_usable_ip_range##*,}'}]" $1
611       sed -i '/TenantNetCidr/c\\  TenantNetCidr: '${private_network_cidr}'' $1
612   else
613       sed -i 's#^.*Network::Tenant.*$#  OS::TripleO::Network::Tenant: '${tht_dir}'/noop.yaml#' $1
614       sed -i 's#^.*Controller::Ports::TenantPort:.*$#  OS::TripleO::Controller::Ports::TenantPort: '${tht_dir}'/ports/noop.yaml#' $1
615       sed -i 's#^.*Compute::Ports::TenantPort:.*$#  OS::TripleO::Compute::Ports::TenantPort: '${tht_dir}'/ports/noop.yaml#' $1
616   fi
617
618   # check for storage network
619   if [[ ! -z "$storage_network_enabled" && "$storage_network_enabled" == "True" ]]; then
620       sed -i 's#^.*Network::Storage:.*$#  OS::TripleO::Network::Storage: '${tht_dir}'/storage.yaml#' $1
621       sed -i 's#^.*Network::Ports::StorageVipPort:.*$#  OS::TripleO::Network::Ports::StorageVipPort: '${tht_dir}'/ports/storage.yaml#' $1
622       sed -i 's#^.*Controller::Ports::StoragePort:.*$#  OS::TripleO::Controller::Ports::StoragePort: '${tht_dir}'/ports/storage.yaml#' $1
623       sed -i 's#^.*Compute::Ports::StoragePort:.*$#  OS::TripleO::Compute::Ports::StoragePort: '${tht_dir}'/ports/storage.yaml#' $1
624       sed -i "/StorageAllocationPools/c\\  StorageAllocationPools: [{'start': '${storage_network_usable_ip_range%%,*}', 'end': '${storage_network_usable_ip_range##*,}'}]" $1
625       sed -i '/StorageNetCidr/c\\  StorageNetCidr: '${storage_network_cidr}'' $1
626   else
627       sed -i 's#^.*Network::Storage:.*$#  OS::TripleO::Network::Storage: '${tht_dir}'/noop.yaml#' $1
628       sed -i 's#^.*Network::Ports::StorageVipPort:.*$#  OS::TripleO::Network::Ports::StorageVipPort: '${tht_dir}'/ports/noop.yaml#' $1
629       sed -i 's#^.*Controller::Ports::StoragePort:.*$#  OS::TripleO::Controller::Ports::StoragePort: '${tht_dir}'/ports/noop.yaml#' $1
630       sed -i 's#^.*Compute::Ports::StoragePort:.*$#  OS::TripleO::Compute::Ports::StoragePort: '${tht_dir}'/ports/noop.yaml#' $1
631   fi
632
633   # check for ODL L3
634   if [ "${deploy_options_array['sdn_l3']}" == 'true' ]; then
635       ext_net_type=br-ex
636   fi
637
638 }
639 ##Copy over the glance images and instackenv json file
640 ##params: none
641 function configure_undercloud {
642
643   echo
644   echo "Copying configuration files to Undercloud"
645   if [[ "$net_isolation_enabled" == "TRUE" ]]; then
646     configure_network_environment $CONFIG/network-environment.yaml
647     echo -e "${blue}Network Environment set for Deployment: ${reset}"
648     cat $CONFIG/network-environment.yaml
649     scp ${SSH_OPTIONS[@]} $CONFIG/network-environment.yaml "stack@$UNDERCLOUD":
650     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" << EOI
651 mkdir nics/
652 cat > nics/controller.yaml << EOF
653 $(python3.4 -B $CONFIG/lib/python/apex-python-utils.py nic_template -d $CONFIG -f nics-controller.yaml.jinja2 -n "$enabled_network_list" -e $ext_net_type -af $ip_addr_family)
654 EOF
655 cat > nics/compute.yaml << EOF
656 $(python3.4 -B $CONFIG/lib/python/apex-python-utils.py nic_template -d $CONFIG -f nics-compute.yaml.jinja2 -n "$enabled_network_list" -e $ext_net_type -af $ip_addr_family)
657 EOF
658 EOI
659   fi
660
661   # ensure stack user on Undercloud machine has an ssh key
662   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "if [ ! -e ~/.ssh/id_rsa.pub ]; then ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa; fi"
663
664   if [ "$virtual" == "TRUE" ]; then
665
666       # copy the Undercloud VM's stack user's pub key to
667       # root's auth keys so that Undercloud can control
668       # vm power on the hypervisor
669       ssh ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "cat /home/stack/.ssh/id_rsa.pub" >> /root/.ssh/authorized_keys
670
671       DEPLOY_OPTIONS+=" --libvirt-type qemu"
672       INSTACKENV=$CONFIG/instackenv-virt.json
673
674       # upload instackenv file to Undercloud for virtual deployment
675       scp ${SSH_OPTIONS[@]} $INSTACKENV "stack@$UNDERCLOUD":instackenv.json
676   fi
677
678   # allow stack to control power management on the hypervisor via sshkey
679   # only if this is a virtual deployment
680   if [ "$virtual" == "TRUE" ]; then
681       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
682 while read -r line; do
683   stack_key=\${stack_key}\\\\\\\\n\${line}
684 done < <(cat ~/.ssh/id_rsa)
685 stack_key=\$(echo \$stack_key | sed 's/\\\\\\\\n//')
686 sed -i 's~INSERT_STACK_USER_PRIV_KEY~'"\$stack_key"'~' instackenv.json
687 EOI
688   fi
689
690   # copy stack's ssh key to this users authorized keys
691   ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "cat /home/stack/.ssh/id_rsa.pub" >> ~/.ssh/authorized_keys
692
693   # disable requiretty for sudo
694   ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "sed -i 's/Defaults\s*requiretty//'" /etc/sudoers
695
696   # configure undercloud on Undercloud VM
697   echo "Running undercloud configuration."
698   echo "Logging undercloud configuration to undercloud:/home/stack/apex-undercloud-install.log"
699   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" << EOI
700 if [[ "$net_isolation_enabled" == "TRUE" ]]; then
701   sed -i 's/#local_ip/local_ip/' undercloud.conf
702   sed -i 's/#network_gateway/network_gateway/' undercloud.conf
703   sed -i 's/#network_cidr/network_cidr/' undercloud.conf
704   sed -i 's/#dhcp_start/dhcp_start/' undercloud.conf
705   sed -i 's/#dhcp_end/dhcp_end/' undercloud.conf
706   sed -i 's/#inspection_iprange/inspection_iprange/' undercloud.conf
707   sed -i 's/#undercloud_debug/undercloud_debug/' undercloud.conf
708
709   openstack-config --set undercloud.conf DEFAULT local_ip ${admin_network_provisioner_ip}/${admin_network_cidr##*/}
710   openstack-config --set undercloud.conf DEFAULT network_gateway ${admin_network_provisioner_ip}
711   openstack-config --set undercloud.conf DEFAULT network_cidr ${admin_network_cidr}
712   openstack-config --set undercloud.conf DEFAULT dhcp_start ${admin_network_dhcp_range%%,*}
713   openstack-config --set undercloud.conf DEFAULT dhcp_end ${admin_network_dhcp_range##*,}
714   openstack-config --set undercloud.conf DEFAULT inspection_iprange ${admin_network_introspection_range}
715   openstack-config --set undercloud.conf DEFAULT undercloud_debug false
716
717 fi
718
719 sudo sed -i '/CephClusterFSID:/c\\  CephClusterFSID: \\x27$(cat /proc/sys/kernel/random/uuid)\\x27' /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml
720 sudo sed -i '/CephMonKey:/c\\  CephMonKey: \\x27'"\$(ceph-authtool --gen-print-key)"'\\x27' /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml
721 sudo sed -i '/CephAdminKey:/c\\  CephAdminKey: \\x27'"\$(ceph-authtool --gen-print-key)"'\\x27' /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml
722
723 # we assume that packages will not need to be updated with undercloud install
724 # and that it will be used only to configure the undercloud
725 # packages updates would need to be handled manually with yum update
726 sudo cp -f /usr/share/diskimage-builder/elements/yum/bin/install-packages /usr/share/diskimage-builder/elements/yum/bin/install-packages.bak
727 cat << 'EOF' | sudo tee /usr/share/diskimage-builder/elements/yum/bin/install-packages > /dev/null
728 #!/bin/sh
729 exit 0
730 EOF
731
732 openstack undercloud install &> apex-undercloud-install.log || {
733     # cat the undercloud install log incase it fails
734     echo "ERROR: openstack undercloud install has failed. Dumping Log:"
735     cat apex-undercloud-install.log
736     exit 1
737 }
738
739 sleep 30
740 sudo systemctl restart openstack-glance-api
741 sudo systemctl restart openstack-nova-conductor
742 sudo systemctl restart openstack-nova-compute
743
744 sudo sed -i '/num_engine_workers/c\num_engine_workers = 2' /etc/heat/heat.conf
745 sudo sed -i '/#workers\s=/c\workers = 2' /etc/heat/heat.conf
746 sudo systemctl restart openstack-heat-engine
747 sudo systemctl restart openstack-heat-api
748 EOI
749 # WORKAROUND: must restart the above services to fix sync problem with nova compute manager
750 # TODO: revisit and file a bug if necessary. This should eventually be removed
751 # as well as glance api problem
752 echo -e "${blue}INFO: Sleeping 15 seconds while services come back from restart${reset}"
753 sleep 15
754
755 }
756
757 ##preping it for deployment and launch the deploy
758 ##params: none
759 function undercloud_prep_overcloud_deploy {
760   if [[ "${#deploy_options_array[@]}" -eq 0 || "${deploy_options_array['sdn_controller']}" == 'opendaylight' ]]; then
761     if [ "${deploy_options_array['sdn_l3']}" == 'true' ]; then
762       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight_l3.yaml"
763     elif [ "${deploy_options_array['sfc']}" == 'true' ]; then
764       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight_sfc.yaml"
765     elif [ "${deploy_options_array['vpn']}" == 'true' ]; then
766       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight_sdnvpn.yaml"
767     else
768       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight.yaml"
769     fi
770     SDN_IMAGE=opendaylight
771     if [ "${deploy_options_array['sfc']}" == 'true' ]; then
772       SDN_IMAGE+=-sfc
773       if [ ! -f $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 ]; then
774           echo "${red} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 is required to execute an SFC deployment."
775           echo "Please install the opnfv-apex-opendaylight-sfc package to provide this overcloud image for deployment.${reset}"
776           exit 1
777       fi
778     fi
779   elif [ "${deploy_options_array['sdn_controller']}" == 'opendaylight-external' ]; then
780     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight-external.yaml"
781     SDN_IMAGE=opendaylight
782   elif [ "${deploy_options_array['sdn_controller']}" == 'onos' ]; then
783     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/onos.yaml"
784     SDN_IMAGE=onos
785   elif [ "${deploy_options_array['sdn_controller']}" == 'opencontrail' ]; then
786     echo -e "${red}ERROR: OpenContrail is currently unsupported...exiting${reset}"
787     exit 1
788   elif [[ -z "${deploy_options_array['sdn_controller']}" || "${deploy_options_array['sdn_controller']}" == 'False' ]]; then
789     echo -e "${blue}INFO: SDN Controller disabled...will deploy nosdn scenario${reset}"
790     SDN_IMAGE=opendaylight
791   else
792     echo "${red}Invalid sdn_controller: ${deploy_options_array['sdn_controller']}${reset}"
793     echo "${red}Valid choices are opendaylight, opendaylight-external, onos, opencontrail, False, or null${reset}"
794     exit 1
795   fi
796
797   # Make sure the correct overcloud image is available
798   if [ ! -f $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 ]; then
799       echo "${red} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 is required to execute your deployment."
800       echo "Both ONOS and OpenDaylight are currently deployed from this image."
801       echo "Please install the opnfv-apex package to provide this overcloud image for deployment.${reset}"
802       exit 1
803   fi
804
805   echo "Copying overcloud image to Undercloud"
806   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "rm -f overcloud-full.qcow2"
807   scp ${SSH_OPTIONS[@]} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 "stack@$UNDERCLOUD":overcloud-full.qcow2
808
809   # Push performance options to subscript to modify per-role images as needed
810   for option in "${performance_options[@]}" ; do
811     echo -e "${blue}Setting performance option $option${reset}"
812     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "bash build_perf_image.sh $option"
813   done
814
815   # Add performance deploy options if they have been set
816   if [ ! -z "${deploy_options_array['performance']}" ]; then
817     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/numa.yaml"
818   fi
819
820   # make sure ceph is installed
821   DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml"
822
823   # scale compute nodes according to inventory
824   total_nodes=$(ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "cat /home/stack/instackenv.json | grep -c memory")
825
826   # check if HA is enabled
827   if [[ "$ha_enabled" == "TRUE" || "$ha_enabled" == "true" ]]; then
828      DEPLOY_OPTIONS+=" --control-scale 3"
829      compute_nodes=$((total_nodes - 3))
830      DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/puppet-pacemaker.yaml"
831   else
832      compute_nodes=$((total_nodes - 1))
833   fi
834
835   if [ "$compute_nodes" -le 0 ]; then
836     echo -e "${red}ERROR: Invalid number of compute nodes: ${compute_nodes}. Check your inventory file.${reset}"
837     exit 1
838   else
839     echo -e "${blue}INFO: Number of compute nodes set for deployment: ${compute_nodes}${reset}"
840     DEPLOY_OPTIONS+=" --compute-scale ${compute_nodes}"
841   fi
842
843   if [[ "$net_isolation_enabled" == "TRUE" ]]; then
844      #DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/network-isolation.yaml"
845      DEPLOY_OPTIONS+=" -e network-environment.yaml"
846   fi
847
848   if [[ "$ha_enabled" == "TRUE" || "$ha_enabled" == "true"  ]] || [[ "$net_isolation_enabled" == "TRUE" ]]; then
849      DEPLOY_OPTIONS+=" --ntp-server $ntp_server"
850   fi
851
852   if [[ ! "$virtual" == "TRUE" ]]; then
853      DEPLOY_OPTIONS+=" --control-flavor control --compute-flavor compute"
854   else
855      DEPLOY_OPTIONS+=" -e virtual-environment.yaml"
856   fi
857
858   DEPLOY_OPTIONS+=" -e opnfv-environment.yaml"
859
860   echo -e "${blue}INFO: Deploy options set:\n${DEPLOY_OPTIONS}${reset}"
861
862   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
863 if [ "$debug" == 'TRUE' ]; then
864     LIBGUESTFS_BACKEND=direct virt-customize -a overcloud-full.qcow2 --root-password password:opnfvapex
865 fi
866
867 source stackrc
868 set -o errexit
869 echo "Uploading overcloud glance images"
870 openstack overcloud image upload
871
872 bash -x set_perf_images.sh ${performance_roles}
873
874 echo "Configuring undercloud and discovering nodes"
875 openstack baremetal import --json instackenv.json
876 openstack baremetal configure boot
877 #if [[ -z "$virtual" ]]; then
878 #  openstack baremetal introspection bulk start
879 #fi
880 echo "Configuring flavors"
881 for flavor in baremetal control compute; do
882   echo -e "${blue}INFO: Updating flavor: \${flavor}${reset}"
883   if openstack flavor list | grep \${flavor}; then
884     openstack flavor delete \${flavor}
885   fi
886   openstack flavor create --id auto --ram 4096 --disk 39 --vcpus 1 \${flavor}
887   if ! openstack flavor list | grep \${flavor}; then
888     echo -e "${red}ERROR: Unable to create flavor \${flavor}${reset}"
889   fi
890 done
891 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" baremetal
892 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" --property "capabilities:profile"="control" control
893 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" --property "capabilities:profile"="compute" compute
894 echo "Configuring nameserver on ctlplane network"
895 neutron subnet-update \$(neutron subnet-list | grep -v id | grep -v \\\\-\\\\- | awk {'print \$2'}) --dns-nameserver 8.8.8.8
896 echo "Executing overcloud deployment, this should run for an extended period without output."
897 sleep 60 #wait for Hypervisor stats to check-in to nova
898 # save deploy command so it can be used for debugging
899 cat > deploy_command << EOF
900 openstack overcloud deploy --templates $DEPLOY_OPTIONS --timeout 90
901 EOF
902 EOI
903
904   if [ "$interactive" == "TRUE" ]; then
905     if ! prompt_user "Overcloud Deployment"; then
906       echo -e "${blue}INFO: User requests exit${reset}"
907       exit 0
908     fi
909   fi
910
911   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
912 source stackrc
913 openstack overcloud deploy --templates $DEPLOY_OPTIONS --timeout 90
914 if ! heat stack-list | grep CREATE_COMPLETE 1>/dev/null; then
915   $(typeset -f debug_stack)
916   debug_stack
917   exit 1
918 fi
919 EOI
920
921   if [ "$debug" == 'TRUE' ]; then
922       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
923 source overcloudrc
924 echo "Keystone Endpoint List:"
925 keystone endpoint-list
926 echo "Keystone Service List"
927 keystone service-list
928 cinder quota-show \$(openstack project list | grep admin | awk {'print \$2'})
929 EOI
930   fi
931 }
932
933 ##Post configuration after install
934 ##params: none
935 function configure_post_install {
936   local opnfv_attach_networks ovs_ip ip_range net_cidr tmp_ip
937   opnfv_attach_networks="admin_network public_network"
938
939   echo -e "${blue}INFO: Post Install Configuration Running...${reset}"
940
941   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
942 source overcloudrc
943 set -o errexit
944 echo "Configuring Neutron external network"
945 neutron net-create external --router:external=True --tenant-id \$(keystone tenant-get service | grep id | awk '{ print \$4 }')
946 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}
947 EOI
948
949   echo -e "${blue}INFO: Checking if OVS bridges have IP addresses...${reset}"
950   for network in ${opnfv_attach_networks}; do
951     ovs_ip=$(find_ip ${NET_MAP[$network]})
952     tmp_ip=''
953     if [ -n "$ovs_ip" ]; then
954       echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} has IP address ${ovs_ip}${reset}"
955     else
956       echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} missing IP, will configure${reset}"
957       # use last IP of allocation pool
958       eval "ip_range=\${${network}_usable_ip_range}"
959       ovs_ip=${ip_range##*,}
960       eval "net_cidr=\${${network}_cidr}"
961       sudo ip addr add ${ovs_ip}/${net_cidr##*/} dev ${NET_MAP[$network]}
962       sudo ip link set up ${NET_MAP[$network]}
963       tmp_ip=$(find_ip ${NET_MAP[$network]})
964       if [ -n "$tmp_ip" ]; then
965         echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} IP set: ${tmp_ip}${reset}"
966         continue
967       else
968         echo -e "${red}ERROR: Unable to set OVS Bridge ${NET_MAP[$network]} with IP: ${ovs_ip}${reset}"
969         return 1
970       fi
971     fi
972   done
973
974   # for virtual, we NAT public network through Undercloud
975   if [ "$virtual" == "TRUE" ]; then
976     if ! configure_undercloud_nat ${public_network_cidr}; then
977       echo -e "${red}ERROR: Unable to NAT undercloud with external net: ${public_network_cidr}${reset}"
978       exit 1
979     else
980       echo -e "${blue}INFO: Undercloud VM has been setup to NAT Overcloud public network${reset}"
981     fi
982   fi
983
984   # for sfc deployments we need the vxlan workaround
985   if [ "${deploy_options_array['sfc']}" == 'true' ]; then
986       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
987 source stackrc
988 set -o errexit
989 for node in \$(nova list | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
990 ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
991 sudo ifconfig br-int up
992 sudo ip route add 123.123.123.0/24 dev br-int
993 EOF
994 done
995 EOI
996   fi
997
998   # Collect deployment logs
999   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1000 mkdir -p ~/deploy_logs
1001 rm -rf deploy_logs/*
1002 source stackrc
1003 set -o errexit
1004 for node in \$(nova list | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
1005  ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1006  sudo cp /var/log/messages /home/heat-admin/messages.log
1007  sudo chown heat-admin /home/heat-admin/messages.log
1008 EOF
1009 scp ${SSH_OPTIONS[@]} heat-admin@\$node:/home/heat-admin/messages.log ~/deploy_logs/\$node.messages.log
1010 if [ "$debug" == "TRUE" ]; then
1011     nova list --ip \$node
1012     echo "---------------------------"
1013     echo "-----/var/log/messages-----"
1014     echo "---------------------------"
1015     cat ~/deploy_logs/\$node.messages.log
1016     echo "---------------------------"
1017     echo "----------END LOG----------"
1018     echo "---------------------------"
1019 fi
1020  ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1021  sudo rm -f /home/heat-admin/messages.log
1022 EOF
1023 done
1024
1025 # Print out the dashboard URL
1026 source stackrc
1027 echo "Overcloud dashboard available at http://\$(heat output-show overcloud PublicVip | sed 's/"//g')/dashboard"
1028 EOI
1029
1030 }
1031
1032 display_usage() {
1033   echo -e "Usage:\n$0 [arguments] \n"
1034   echo -e "   -c|--config : Directory to configuration files. Optional.  Defaults to /var/opt/opnfv/ \n"
1035   echo -e "   -d|--deploy-settings : Full path to deploy settings yaml file. Optional.  Defaults to null \n"
1036   echo -e "   -i|--inventory : Full path to inventory yaml file. Required only for baremetal \n"
1037   echo -e "   -n|--net-settings : Full path to network settings file. Optional. \n"
1038   echo -e "   -p|--ping-site : site to use to verify IP connectivity. Optional. Defaults to 8.8.8.8 \n"
1039   echo -e "   -r|--resources : Directory to deployment resources. Optional.  Defaults to /var/opt/opnfv/stack \n"
1040   echo -e "   -v|--virtual : Virtualize overcloud nodes instead of using baremetal. \n"
1041   echo -e "   --no-ha : disable High Availability deployment scheme, this assumes a single controller and single compute node \n"
1042   echo -e "   --flat : disable Network Isolation and use a single flat network for the underlay network.\n"
1043   echo -e "   --no-post-config : disable Post Install configuration."
1044   echo -e "   --debug : enable debug output."
1045   echo -e "   --interactive : enable interactive deployment mode which requires user to confirm steps of deployment."
1046   echo -e "   --virtual-cpus : Number of CPUs to use per Overcloud VM in a virtual deployment (defaults to 4)."
1047   echo -e "   --virtual-ram : Amount of RAM to use per Overcloud VM in GB (defaults to 8)."
1048 }
1049
1050 ##translates the command line parameters into variables
1051 ##params: $@ the entire command line is passed
1052 ##usage: parse_cmd_line() "$@"
1053 parse_cmdline() {
1054   echo -e "\n\n${blue}This script is used to deploy the Apex Installer and Provision OPNFV Target System${reset}\n\n"
1055   echo "Use -h to display help"
1056   sleep 2
1057
1058   while [ "${1:0:1}" = "-" ]
1059   do
1060     case "$1" in
1061         -h|--help)
1062                 display_usage
1063                 exit 0
1064             ;;
1065         -c|--config)
1066                 CONFIG=$2
1067                 echo "Deployment Configuration Directory Overridden to: $2"
1068                 shift 2
1069             ;;
1070         -d|--deploy-settings)
1071                 DEPLOY_SETTINGS_FILE=$2
1072                 echo "Deployment Configuration file: $2"
1073                 shift 2
1074             ;;
1075         -i|--inventory)
1076                 INVENTORY_FILE=$2
1077                 shift 2
1078             ;;
1079         -n|--net-settings)
1080                 NETSETS=$2
1081                 echo "Network Settings Configuration file: $2"
1082                 shift 2
1083             ;;
1084         -p|--ping-site)
1085                 ping_site=$2
1086                 echo "Using $2 as the ping site"
1087                 shift 2
1088             ;;
1089         -r|--resources)
1090                 RESOURCES=$2
1091                 echo "Deployment Resources Directory Overridden to: $2"
1092                 shift 2
1093             ;;
1094         -v|--virtual)
1095                 virtual="TRUE"
1096                 echo "Executing a Virtual Deployment"
1097                 shift 1
1098             ;;
1099         --no-ha )
1100                 ha_enabled="FALSE"
1101                 vm_index=1
1102                 echo "HA Deployment Disabled"
1103                 shift 1
1104             ;;
1105         --flat )
1106                 net_isolation_enabled="FALSE"
1107                 echo "Underlay Network Isolation Disabled: using flat configuration"
1108                 shift 1
1109             ;;
1110         --no-post-config )
1111                 post_config="FALSE"
1112                 echo "Post install configuration disabled"
1113                 shift 1
1114             ;;
1115         --debug )
1116                 debug="TRUE"
1117                 echo "Enable debug output"
1118                 shift 1
1119             ;;
1120         --interactive )
1121                 interactive="TRUE"
1122                 echo "Interactive mode enabled"
1123                 shift 1
1124             ;;
1125         --virtual-cpus )
1126                 VM_CPUS=$2
1127                 echo "Number of CPUs per VM set to $VM_CPUS"
1128                 shift 2
1129             ;;
1130         --virtual-ram )
1131                 VM_RAM=$2
1132                 echo "Amount of RAM per VM set to $VM_RAM"
1133                 shift 2
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. Only admin_network settings will be used!${reset}"
1144   elif [[ -z "$NETSETS" ]]; then
1145     echo -e "${red}ERROR: You must provide a network_settings file with -n.${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/utility-functions.sh
1183   source $CONFIG/lib/installer/onos/onos_gw_mac_update.sh
1184
1185 }
1186
1187 ##END FUNCTIONS
1188
1189 main() {
1190   # Make sure jinja2 is installed
1191   easy_install-3.4 jinja2 > /dev/null
1192   parse_cmdline "$@"
1193   echo -e "${blue}INFO: Parsing network settings file...${reset}"
1194   parse_network_settings
1195   if ! configure_deps; then
1196     echo -e "${red}Dependency Validation Failed, Exiting.${reset}"
1197     exit 1
1198   fi
1199   if [ -n "$DEPLOY_SETTINGS_FILE" ]; then
1200     echo -e "${blue}INFO: Parsing deploy settings file...${reset}"
1201     parse_deploy_settings
1202   fi
1203   setup_undercloud_vm
1204   if [ "$virtual" == "TRUE" ]; then
1205     setup_virtual_baremetal $VM_CPUS $VM_RAM
1206   elif [ -n "$INVENTORY_FILE" ]; then
1207     parse_inventory_file
1208   fi
1209   configure_undercloud
1210   undercloud_prep_overcloud_deploy
1211   if [ "$post_config" == "TRUE" ]; then
1212     if ! configure_post_install; then
1213       echo -e "${red}ERROR:Post Install Configuration Failed, Exiting.${reset}"
1214       exit 1
1215     else
1216       echo -e "${blue}INFO: Post Install Configuration Complete${reset}"
1217     fi
1218   fi
1219   if [[ "${deploy_options_array['sdn_controller']}" == 'onos' ]]; then
1220     if ! onos_update_gw_mac ${public_network_cidr} ${public_network_gateway}; then
1221       echo -e "${red}ERROR:ONOS Post Install Configuration Failed, Exiting.${reset}"
1222       exit 1
1223     else
1224       echo -e "${blue}INFO: ONOS Post Install Configuration Complete${reset}"
1225     fi
1226   fi
1227 }
1228
1229 main "$@"