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