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