Adds initial FDIO support
[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     elif [ "${deploy_options_array['vpp']}" == 'True' ]; then
784       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight_fdio.yaml"
785     else
786       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight.yaml"
787     fi
788     SDN_IMAGE=opendaylight
789     if [ "${deploy_options_array['sfc']}" == 'True' ]; then
790       SDN_IMAGE+=-sfc
791       if [ ! -f $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 ]; then
792           echo "${red} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 is required to execute an SFC deployment."
793           echo "Please install the opnfv-apex-opendaylight-sfc package to provide this overcloud image for deployment.${reset}"
794           exit 1
795       fi
796     fi
797   elif [ "${deploy_options_array['sdn_controller']}" == 'opendaylight-external' ]; then
798     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight-external.yaml"
799     SDN_IMAGE=opendaylight
800   elif [ "${deploy_options_array['sdn_controller']}" == 'onos' ]; then
801     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/onos.yaml"
802     SDN_IMAGE=onos
803   elif [ "${deploy_options_array['sdn_controller']}" == 'opencontrail' ]; then
804     echo -e "${red}ERROR: OpenContrail is currently unsupported...exiting${reset}"
805     exit 1
806   elif [[ -z "${deploy_options_array['sdn_controller']}" || "${deploy_options_array['sdn_controller']}" == 'False' ]]; then
807     echo -e "${blue}INFO: SDN Controller disabled...will deploy nosdn scenario${reset}"
808     SDN_IMAGE=opendaylight
809   else
810     echo "${red}Invalid sdn_controller: ${deploy_options_array['sdn_controller']}${reset}"
811     echo "${red}Valid choices are opendaylight, opendaylight-external, onos, opencontrail, False, or null${reset}"
812     exit 1
813   fi
814
815
816
817   # Make sure the correct overcloud image is available
818   if [ ! -f $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 ]; then
819       echo "${red} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 is required to execute your deployment."
820       echo "Both ONOS and OpenDaylight are currently deployed from this image."
821       echo "Please install the opnfv-apex package to provide this overcloud image for deployment.${reset}"
822       exit 1
823   fi
824
825   echo "Copying overcloud image to Undercloud"
826   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "rm -f overcloud-full.qcow2"
827   scp ${SSH_OPTIONS[@]} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 "stack@$UNDERCLOUD":overcloud-full.qcow2
828
829   # Install ovs-dpdk inside the overcloud image if it is enabled.
830   if [ "${deploy_options_array['dataplane']}" == 'ovs_dpdk' ]; then
831     # install dpdk packages before ovs
832     echo -e "${blue}INFO: Enabling kernel modules for dpdk inside overcloud image${reset}"
833
834     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
835       cat << EOF > vfio_pci.modules
836 #!/bin/bash
837 exec /sbin/modprobe vfio_pci >/dev/null 2>&1
838 EOF
839
840       cat << EOF > uio_pci_generic.modules
841 #!/bin/bash
842 exec /sbin/modprobe uio_pci_generic >/dev/null 2>&1
843 EOF
844
845       LIBGUESTFS_BACKEND=direct virt-customize --upload vfio_pci.modules:/etc/sysconfig/modules/ \
846                                                --upload uio_pci_generic.modules:/etc/sysconfig/modules/ \
847                                                --run-command "chmod 0755 /etc/sysconfig/modules/vfio_pci.modules" \
848                                                --run-command "chmod 0755 /etc/sysconfig/modules/uio_pci_generic.modules" \
849                                                --run-command "yum install -y /root/dpdk_rpms/*" \
850                                                -a overcloud-full.qcow2
851 EOI
852   elif [ "${deploy_options_array['dataplane']}" != 'ovs' ]; then
853     echo "${red}${deploy_options_array['dataplane']} not supported${reset}"
854     exit 1
855   fi
856
857   # Set ODL version accordingly
858   if [[ "${deploy_options_array['sdn_controller']}" == 'opendaylight' && "${deploy_options_array['odl_version']}" == 'boron' ]]; then
859     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
860       LIBGUESTFS_BACKEND=direct virt-customize --run-command "yum -y remove opendaylight" \
861                                                --run-command "yum -y install /root/boron/*" \
862                                                -a overcloud-full.qcow2
863 EOI
864   fi
865
866   # Add performance deploy options if they have been set
867   if [ ! -z "${deploy_options_array['performance']}" ]; then
868
869     # Remove previous kernel args files per role
870     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "rm -f Compute-kernel_params.txt"
871     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "rm -f Controller-kernel_params.txt"
872
873     # Push performance options to subscript to modify per-role images as needed
874     for option in "${performance_options[@]}" ; do
875       echo -e "${blue}Setting performance option $option${reset}"
876       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "bash build_perf_image.sh $option"
877     done
878
879     # Build IPA kernel option ramdisks
880     ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" <<EOI
881 /bin/cp -f /home/stack/ironic-python-agent.initramfs /root/
882 mkdir -p ipa/
883 pushd ipa
884 gunzip -c ../ironic-python-agent.initramfs | cpio -i
885 if [ ! -f /home/stack/Compute-kernel_params.txt ]; then
886   touch /home/stack/Compute-kernel_params.txt
887   chown stack /home/stack/Compute-kernel_params.txt
888 fi
889 /bin/cp -f /home/stack/Compute-kernel_params.txt tmp/kernel_params.txt
890 echo "Compute params set: "
891 cat tmp/kernel_params.txt
892 /bin/cp -f /root/image.py usr/lib/python2.7/site-packages/ironic_python_agent/extensions/image.py
893 /bin/cp -f /root/image.pyc usr/lib/python2.7/site-packages/ironic_python_agent/extensions/image.pyc
894 find . | cpio -o -H newc | gzip > /home/stack/Compute-ironic-python-agent.initramfs
895 chown stack /home/stack/Compute-ironic-python-agent.initramfs
896 if [ ! -f /home/stack/Controller-kernel_params.txt ]; then
897   touch /home/stack/Controller-kernel_params.txt
898   chown stack /home/stack/Controller-kernel_params.txt
899 fi
900 /bin/cp -f /home/stack/Controller-kernel_params.txt tmp/kernel_params.txt
901 echo "Controller params set: "
902 cat tmp/kernel_params.txt
903 find . | cpio -o -H newc | gzip > /home/stack/Controller-ironic-python-agent.initramfs
904 chown stack /home/stack/Controller-ironic-python-agent.initramfs
905 popd
906 /bin/rm -rf ipa/
907 EOI
908
909     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/numa.yaml"
910   fi
911
912   # make sure ceph is installed
913   DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml"
914
915   # scale compute nodes according to inventory
916   total_nodes=$(ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "cat /home/stack/instackenv.json | grep -c memory")
917
918   # check if HA is enabled
919   if [[ "$ha_enabled" == "True" ]]; then
920      DEPLOY_OPTIONS+=" --control-scale 3"
921      compute_nodes=$((total_nodes - 3))
922      DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/puppet-pacemaker.yaml"
923   else
924      compute_nodes=$((total_nodes - 1))
925   fi
926
927   if [ "$compute_nodes" -le 0 ]; then
928     echo -e "${red}ERROR: Invalid number of compute nodes: ${compute_nodes}. Check your inventory file.${reset}"
929     exit 1
930   else
931     echo -e "${blue}INFO: Number of compute nodes set for deployment: ${compute_nodes}${reset}"
932     DEPLOY_OPTIONS+=" --compute-scale ${compute_nodes}"
933   fi
934
935   if [[ "$net_isolation_enabled" == "TRUE" ]]; then
936      #DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/network-isolation.yaml"
937      DEPLOY_OPTIONS+=" -e network-environment.yaml"
938   fi
939
940   if [[ "$ha_enabled" == "True" ]] || [[ "$net_isolation_enabled" == "TRUE" ]]; then
941      DEPLOY_OPTIONS+=" --ntp-server $ntp_server"
942   fi
943
944   if [[ ! "$virtual" == "TRUE" ]]; then
945      DEPLOY_OPTIONS+=" --control-flavor control --compute-flavor compute"
946   else
947      DEPLOY_OPTIONS+=" -e virtual-environment.yaml"
948   fi
949
950   DEPLOY_OPTIONS+=" -e opnfv-environment.yaml"
951
952   echo -e "${blue}INFO: Deploy options set:\n${DEPLOY_OPTIONS}${reset}"
953
954   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
955 if [ "$debug" == 'TRUE' ]; then
956     LIBGUESTFS_BACKEND=direct virt-customize -a overcloud-full.qcow2 --root-password password:opnfvapex
957 fi
958
959 source stackrc
960 set -o errexit
961 echo "Uploading overcloud glance images"
962 openstack overcloud image upload
963
964 echo "Configuring undercloud and discovering nodes"
965 openstack baremetal import --json instackenv.json
966 openstack baremetal configure boot
967 bash -x set_perf_images.sh ${performance_roles[@]}
968 #if [[ -z "$virtual" ]]; then
969 #  openstack baremetal introspection bulk start
970 #fi
971 echo "Configuring flavors"
972 for flavor in baremetal control compute; do
973   echo -e "${blue}INFO: Updating flavor: \${flavor}${reset}"
974   if openstack flavor list | grep \${flavor}; then
975     openstack flavor delete \${flavor}
976   fi
977   openstack flavor create --id auto --ram 4096 --disk 39 --vcpus 1 \${flavor}
978   if ! openstack flavor list | grep \${flavor}; then
979     echo -e "${red}ERROR: Unable to create flavor \${flavor}${reset}"
980   fi
981 done
982 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" baremetal
983 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" --property "capabilities:profile"="control" control
984 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" --property "capabilities:profile"="compute" compute
985 echo "Configuring nameserver on ctlplane network"
986 dns_server_ext=''
987 for dns_server in ${dns_servers}; do
988   dns_server_ext="\${dns_server_ext} --dns-nameserver \${dns_server}"
989 done
990 neutron subnet-update \$(neutron subnet-list | grep -Ev "id|tenant|external|storage" | grep -v \\\\-\\\\- | awk {'print \$2'}) \${dns_server_ext}
991 echo "Executing overcloud deployment, this should run for an extended period without output."
992 sleep 60 #wait for Hypervisor stats to check-in to nova
993 # save deploy command so it can be used for debugging
994 cat > deploy_command << EOF
995 openstack overcloud deploy --templates $DEPLOY_OPTIONS --timeout 90
996 EOF
997 EOI
998
999   if [ "$interactive" == "TRUE" ]; then
1000     if ! prompt_user "Overcloud Deployment"; then
1001       echo -e "${blue}INFO: User requests exit${reset}"
1002       exit 0
1003     fi
1004   fi
1005
1006   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1007 source stackrc
1008 openstack overcloud deploy --templates $DEPLOY_OPTIONS --timeout 90
1009 if ! heat stack-list | grep CREATE_COMPLETE 1>/dev/null; then
1010   $(typeset -f debug_stack)
1011   debug_stack
1012   exit 1
1013 fi
1014 EOI
1015
1016   # Configure DPDK
1017   if [ "${deploy_options_array['dataplane']}" == 'ovs_dpdk' ]; then
1018     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI || (echo "DPDK config failed, exiting..."; exit 1)
1019 source stackrc
1020 set -o errexit
1021 for node in \$(nova list | grep novacompute | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
1022 echo "Running DPDK test app on \$node"
1023 ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1024 set -o errexit
1025 sudo dpdk_helloworld --no-pci
1026 sudo dpdk_nic_bind -s
1027 EOF
1028 done
1029 EOI
1030   fi
1031
1032   if [ "$debug" == 'TRUE' ]; then
1033       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1034 source overcloudrc
1035 echo "Keystone Endpoint List:"
1036 openstack endpoint list
1037 echo "Keystone Service List"
1038 openstack service list
1039 cinder quota-show \$(openstack project list | grep admin | awk {'print \$2'})
1040 EOI
1041   fi
1042 }
1043
1044 ##Post configuration after install
1045 ##params: none
1046 function configure_post_install {
1047   local opnfv_attach_networks ovs_ip ip_range net_cidr tmp_ip
1048   opnfv_attach_networks="admin_network public_network"
1049
1050   echo -e "${blue}INFO: Post Install Configuration Running...${reset}"
1051
1052   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1053 source overcloudrc
1054 set -o errexit
1055 echo "Configuring Neutron external network"
1056 neutron net-create external --router:external=True --tenant-id \$(openstack project show service | grep id | awk '{ print \$4 }')
1057 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}
1058
1059 echo "Removing swift endpoint and service"
1060 swift_service_id=\$(openstack service list | grep swift | cut -d ' ' -f 2)
1061 swift_endpoint_id=\$(openstack endpoint list | grep swift | cut -d ' ' -f 2)
1062 openstack endpoint delete \$swift_endpoint_id
1063 openstack service delete \$swift_service_id
1064 EOI
1065
1066   echo -e "${blue}INFO: Checking if OVS bridges have IP addresses...${reset}"
1067   for network in ${opnfv_attach_networks}; do
1068     ovs_ip=$(find_ip ${NET_MAP[$network]})
1069     tmp_ip=''
1070     if [ -n "$ovs_ip" ]; then
1071       echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} has IP address ${ovs_ip}${reset}"
1072     else
1073       echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} missing IP, will configure${reset}"
1074       # use last IP of allocation pool
1075       eval "ip_range=\${${network}_usable_ip_range}"
1076       ovs_ip=${ip_range##*,}
1077       eval "net_cidr=\${${network}_cidr}"
1078       sudo ip addr add ${ovs_ip}/${net_cidr##*/} dev ${NET_MAP[$network]}
1079       sudo ip link set up ${NET_MAP[$network]}
1080       tmp_ip=$(find_ip ${NET_MAP[$network]})
1081       if [ -n "$tmp_ip" ]; then
1082         echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} IP set: ${tmp_ip}${reset}"
1083         continue
1084       else
1085         echo -e "${red}ERROR: Unable to set OVS Bridge ${NET_MAP[$network]} with IP: ${ovs_ip}${reset}"
1086         return 1
1087       fi
1088     fi
1089   done
1090
1091   # for virtual, we NAT public network through Undercloud
1092   if [ "$virtual" == "TRUE" ]; then
1093     if ! configure_undercloud_nat ${public_network_cidr}; then
1094       echo -e "${red}ERROR: Unable to NAT undercloud with external net: ${public_network_cidr}${reset}"
1095       exit 1
1096     else
1097       echo -e "${blue}INFO: Undercloud VM has been setup to NAT Overcloud public network${reset}"
1098     fi
1099   fi
1100
1101   # for sfc deployments we need the vxlan workaround
1102   if [ "${deploy_options_array['sfc']}" == 'True' ]; then
1103       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1104 source stackrc
1105 set -o errexit
1106 for node in \$(nova list | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
1107 ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1108 sudo ifconfig br-int up
1109 sudo ip route add 123.123.123.0/24 dev br-int
1110 EOF
1111 done
1112 EOI
1113   fi
1114
1115   # Collect deployment logs
1116   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1117 mkdir -p ~/deploy_logs
1118 rm -rf deploy_logs/*
1119 source stackrc
1120 set -o errexit
1121 for node in \$(nova list | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
1122  ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1123  sudo cp /var/log/messages /home/heat-admin/messages.log
1124  sudo chown heat-admin /home/heat-admin/messages.log
1125 EOF
1126 scp ${SSH_OPTIONS[@]} heat-admin@\$node:/home/heat-admin/messages.log ~/deploy_logs/\$node.messages.log
1127 if [ "$debug" == "TRUE" ]; then
1128     nova list --ip \$node
1129     echo "---------------------------"
1130     echo "-----/var/log/messages-----"
1131     echo "---------------------------"
1132     cat ~/deploy_logs/\$node.messages.log
1133     echo "---------------------------"
1134     echo "----------END LOG----------"
1135     echo "---------------------------"
1136 fi
1137  ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1138  sudo rm -f /home/heat-admin/messages.log
1139 EOF
1140 done
1141
1142 # Print out the undercloud IP and dashboard URL
1143 source stackrc
1144 echo "Undercloud IP: $UNDERCLOUD, please connect by doing 'opnfv-util undercloud'"
1145 echo "Overcloud dashboard available at http://\$(heat output-show overcloud PublicVip | sed 's/"//g')/dashboard"
1146 EOI
1147
1148 }
1149
1150 display_usage() {
1151   echo -e "Usage:\n$0 [arguments] \n"
1152   echo -e "   -d|--deploy-settings : Full path to deploy settings yaml file. Optional.  Defaults to null"
1153   echo -e "   -i|--inventory : Full path to inventory yaml file. Required only for baremetal"
1154   echo -e "   -n|--net-settings : Full path to network settings file. Optional."
1155   echo -e "   -p|--ping-site : site to use to verify IP connectivity. Optional. Defaults to 8.8.8.8"
1156   echo -e "   -v|--virtual : Virtualize overcloud nodes instead of using baremetal."
1157   echo -e "   --flat : disable Network Isolation and use a single flat network for the underlay network."
1158   echo -e "   --no-post-config : disable Post Install configuration."
1159   echo -e "   --debug : enable debug output."
1160   echo -e "   --interactive : enable interactive deployment mode which requires user to confirm steps of deployment."
1161   echo -e "   --virtual-cpus : Number of CPUs to use per Overcloud VM in a virtual deployment (defaults to 4)."
1162   echo -e "   --virtual-ram : Amount of RAM to use per Overcloud VM in GB (defaults to 8)."
1163 }
1164
1165 ##translates the command line parameters into variables
1166 ##params: $@ the entire command line is passed
1167 ##usage: parse_cmd_line() "$@"
1168 parse_cmdline() {
1169   echo -e "\n\n${blue}This script is used to deploy the Apex Installer and Provision OPNFV Target System${reset}\n\n"
1170   echo "Use -h to display help"
1171   sleep 2
1172
1173   while [ "${1:0:1}" = "-" ]
1174   do
1175     case "$1" in
1176         -h|--help)
1177                 display_usage
1178                 exit 0
1179             ;;
1180         -d|--deploy-settings)
1181                 DEPLOY_SETTINGS_FILE=$2
1182                 echo "Deployment Configuration file: $2"
1183                 shift 2
1184             ;;
1185         -i|--inventory)
1186                 INVENTORY_FILE=$2
1187                 shift 2
1188             ;;
1189         -n|--net-settings)
1190                 NETSETS=$2
1191                 echo "Network Settings Configuration file: $2"
1192                 shift 2
1193             ;;
1194         -p|--ping-site)
1195                 ping_site=$2
1196                 echo "Using $2 as the ping site"
1197                 shift 2
1198             ;;
1199         -v|--virtual)
1200                 virtual="TRUE"
1201                 echo "Executing a Virtual Deployment"
1202                 shift 1
1203             ;;
1204         --flat )
1205                 net_isolation_enabled="FALSE"
1206                 echo "Underlay Network Isolation Disabled: using flat configuration"
1207                 shift 1
1208             ;;
1209         --no-post-config )
1210                 post_config="FALSE"
1211                 echo "Post install configuration disabled"
1212                 shift 1
1213             ;;
1214         --debug )
1215                 debug="TRUE"
1216                 echo "Enable debug output"
1217                 shift 1
1218             ;;
1219         --interactive )
1220                 interactive="TRUE"
1221                 echo "Interactive mode enabled"
1222                 shift 1
1223             ;;
1224         --virtual-cpus )
1225                 VM_CPUS=$2
1226                 echo "Number of CPUs per VM set to $VM_CPUS"
1227                 shift 2
1228             ;;
1229         --virtual-ram )
1230                 VM_RAM=$2
1231                 echo "Amount of RAM per VM set to $VM_RAM"
1232                 shift 2
1233             ;;
1234         --virtual-computes )
1235                 VM_COMPUTES=$2
1236                 echo "Virtual Compute nodes set to $VM_COMPUTES"
1237                 shift 2
1238             ;;
1239         *)
1240                 display_usage
1241                 exit 1
1242             ;;
1243     esac
1244   done
1245
1246   if [[ ! -z "$NETSETS" && "$net_isolation_enabled" == "FALSE" ]]; then
1247     echo -e "${red}INFO: Single flat network requested. Only admin_network settings will be used!${reset}"
1248   elif [[ -z "$NETSETS" ]]; then
1249     echo -e "${red}ERROR: You must provide a network_settings file with -n.${reset}"
1250     exit 1
1251   fi
1252
1253   if [[ -n "$virtual" && -n "$INVENTORY_FILE" ]]; then
1254     echo -e "${red}ERROR: You should not specify an inventory with virtual deployments${reset}"
1255     exit 1
1256   fi
1257
1258   if [[ -z "$DEPLOY_SETTINGS_FILE" || ! -f "$DEPLOY_SETTINGS_FILE" ]]; then
1259     echo -e "${red}ERROR: Deploy Settings: ${DEPLOY_SETTINGS_FILE} does not exist! Exiting...${reset}"
1260     exit 1
1261   fi
1262
1263   if [[ ! -z "$NETSETS" && ! -f "$NETSETS" ]]; then
1264     echo -e "${red}ERROR: Network Settings: ${NETSETS} does not exist! Exiting...${reset}"
1265     exit 1
1266   fi
1267
1268   if [[ ! -z "$INVENTORY_FILE" && ! -f "$INVENTORY_FILE" ]]; then
1269     echo -e "{$red}ERROR: Inventory File: ${INVENTORY_FILE} does not exist! Exiting...${reset}"
1270     exit 1
1271   fi
1272
1273   if [[ -z "$virtual" && -z "$INVENTORY_FILE" ]]; then
1274     echo -e "${red}ERROR: You must specify an inventory file for baremetal deployments! Exiting...${reset}"
1275     exit 1
1276   fi
1277
1278   if [[ "$net_isolation_enabled" == "FALSE" && "$post_config" == "TRUE" ]]; then
1279     echo -e "${blue}INFO: Post Install Configuration will be skipped.  It is not supported with --flat${reset}"
1280     post_config="FALSE"
1281   fi
1282
1283 }
1284
1285 ##END FUNCTIONS
1286
1287 main() {
1288   parse_cmdline "$@"
1289   echo -e "${blue}INFO: Parsing network settings file...${reset}"
1290   parse_network_settings
1291   if ! configure_deps; then
1292     echo -e "${red}Dependency Validation Failed, Exiting.${reset}"
1293     exit 1
1294   fi
1295   if [ -n "$DEPLOY_SETTINGS_FILE" ]; then
1296     echo -e "${blue}INFO: Parsing deploy settings file...${reset}"
1297     parse_deploy_settings
1298   fi
1299   setup_undercloud_vm
1300   if [ "$virtual" == "TRUE" ]; then
1301     setup_virtual_baremetal $VM_CPUS $VM_RAM
1302   elif [ -n "$INVENTORY_FILE" ]; then
1303     parse_inventory_file
1304   fi
1305   configure_undercloud
1306   undercloud_prep_overcloud_deploy
1307   if [ "$post_config" == "TRUE" ]; then
1308     if ! configure_post_install; then
1309       echo -e "${red}ERROR:Post Install Configuration Failed, Exiting.${reset}"
1310       exit 1
1311     else
1312       echo -e "${blue}INFO: Post Install Configuration Complete${reset}"
1313     fi
1314   fi
1315   if [[ "${deploy_options_array['sdn_controller']}" == 'onos' ]]; then
1316     if ! onos_update_gw_mac ${public_network_cidr} ${public_network_gateway}; then
1317       echo -e "${red}ERROR:ONOS Post Install Configuration Failed, Exiting.${reset}"
1318       exit 1
1319     else
1320       echo -e "${blue}INFO: ONOS Post Install Configuration Complete${reset}"
1321     fi
1322   fi
1323 }
1324
1325 main "$@"