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