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