Merge "Fixes nic templates for ovs dpdk"
[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 neutron subnet-update \$(neutron subnet-list | grep -v id | grep -v \\\\-\\\\- | awk {'print \$2'}) --dns-nameserver 8.8.8.8
985 echo "Executing overcloud deployment, this should run for an extended period without output."
986 sleep 60 #wait for Hypervisor stats to check-in to nova
987 # save deploy command so it can be used for debugging
988 cat > deploy_command << EOF
989 openstack overcloud deploy --templates $DEPLOY_OPTIONS --timeout 90
990 EOF
991 EOI
992
993   if [ "$interactive" == "TRUE" ]; then
994     if ! prompt_user "Overcloud Deployment"; then
995       echo -e "${blue}INFO: User requests exit${reset}"
996       exit 0
997     fi
998   fi
999
1000   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1001 source stackrc
1002 openstack overcloud deploy --templates $DEPLOY_OPTIONS --timeout 90
1003 if ! heat stack-list | grep CREATE_COMPLETE 1>/dev/null; then
1004   $(typeset -f debug_stack)
1005   debug_stack
1006   exit 1
1007 fi
1008 EOI
1009
1010   # Configure DPDK
1011   if [ "${deploy_options_array['dataplane']}" == 'ovs_dpdk' ]; then
1012     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI || (echo "DPDK config failed, exiting..."; exit 1)
1013 source stackrc
1014 set -o errexit
1015 for node in \$(nova list | grep novacompute | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
1016 echo "Running DPDK test app on \$node"
1017 ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1018 set -o errexit
1019 sudo dpdk_helloworld --no-pci
1020 sudo dpdk_nic_bind -s
1021 EOF
1022 done
1023 EOI
1024   fi
1025
1026   if [ "$debug" == 'TRUE' ]; then
1027       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1028 source overcloudrc
1029 echo "Keystone Endpoint List:"
1030 openstack endpoint list
1031 echo "Keystone Service List"
1032 openstack service list
1033 cinder quota-show \$(openstack project list | grep admin | awk {'print \$2'})
1034 EOI
1035   fi
1036 }
1037
1038 ##Post configuration after install
1039 ##params: none
1040 function configure_post_install {
1041   local opnfv_attach_networks ovs_ip ip_range net_cidr tmp_ip
1042   opnfv_attach_networks="admin_network public_network"
1043
1044   echo -e "${blue}INFO: Post Install Configuration Running...${reset}"
1045
1046   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1047 source overcloudrc
1048 set -o errexit
1049 echo "Configuring Neutron external network"
1050 neutron net-create external --router:external=True --tenant-id \$(openstack project show service | grep id | awk '{ print \$4 }')
1051 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}
1052
1053 echo "Removing swift endpoint and service"
1054 swift_service_id=\$(openstack service list | grep swift | cut -d ' ' -f 2)
1055 swift_endpoint_id=\$(openstack endpoint list | grep swift | cut -d ' ' -f 2)
1056 openstack endpoint delete \$swift_endpoint_id
1057 openstack service delete \$swift_service_id
1058 EOI
1059
1060   echo -e "${blue}INFO: Checking if OVS bridges have IP addresses...${reset}"
1061   for network in ${opnfv_attach_networks}; do
1062     ovs_ip=$(find_ip ${NET_MAP[$network]})
1063     tmp_ip=''
1064     if [ -n "$ovs_ip" ]; then
1065       echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} has IP address ${ovs_ip}${reset}"
1066     else
1067       echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} missing IP, will configure${reset}"
1068       # use last IP of allocation pool
1069       eval "ip_range=\${${network}_usable_ip_range}"
1070       ovs_ip=${ip_range##*,}
1071       eval "net_cidr=\${${network}_cidr}"
1072       sudo ip addr add ${ovs_ip}/${net_cidr##*/} dev ${NET_MAP[$network]}
1073       sudo ip link set up ${NET_MAP[$network]}
1074       tmp_ip=$(find_ip ${NET_MAP[$network]})
1075       if [ -n "$tmp_ip" ]; then
1076         echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} IP set: ${tmp_ip}${reset}"
1077         continue
1078       else
1079         echo -e "${red}ERROR: Unable to set OVS Bridge ${NET_MAP[$network]} with IP: ${ovs_ip}${reset}"
1080         return 1
1081       fi
1082     fi
1083   done
1084
1085   # for virtual, we NAT public network through Undercloud
1086   if [ "$virtual" == "TRUE" ]; then
1087     if ! configure_undercloud_nat ${public_network_cidr}; then
1088       echo -e "${red}ERROR: Unable to NAT undercloud with external net: ${public_network_cidr}${reset}"
1089       exit 1
1090     else
1091       echo -e "${blue}INFO: Undercloud VM has been setup to NAT Overcloud public network${reset}"
1092     fi
1093   fi
1094
1095   # for sfc deployments we need the vxlan workaround
1096   if [ "${deploy_options_array['sfc']}" == 'True' ]; then
1097       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1098 source stackrc
1099 set -o errexit
1100 for node in \$(nova list | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
1101 ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1102 sudo ifconfig br-int up
1103 sudo ip route add 123.123.123.0/24 dev br-int
1104 EOF
1105 done
1106 EOI
1107   fi
1108
1109   # Collect deployment logs
1110   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1111 mkdir -p ~/deploy_logs
1112 rm -rf deploy_logs/*
1113 source stackrc
1114 set -o errexit
1115 for node in \$(nova list | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
1116  ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1117  sudo cp /var/log/messages /home/heat-admin/messages.log
1118  sudo chown heat-admin /home/heat-admin/messages.log
1119 EOF
1120 scp ${SSH_OPTIONS[@]} heat-admin@\$node:/home/heat-admin/messages.log ~/deploy_logs/\$node.messages.log
1121 if [ "$debug" == "TRUE" ]; then
1122     nova list --ip \$node
1123     echo "---------------------------"
1124     echo "-----/var/log/messages-----"
1125     echo "---------------------------"
1126     cat ~/deploy_logs/\$node.messages.log
1127     echo "---------------------------"
1128     echo "----------END LOG----------"
1129     echo "---------------------------"
1130 fi
1131  ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1132  sudo rm -f /home/heat-admin/messages.log
1133 EOF
1134 done
1135
1136 # Print out the undercloud IP and dashboard URL
1137 source stackrc
1138 echo "Undercloud IP: $UNDERCLOUD, please connect by doing 'opnfv-util undercloud'"
1139 echo "Overcloud dashboard available at http://\$(heat output-show overcloud PublicVip | sed 's/"//g')/dashboard"
1140 EOI
1141
1142 }
1143
1144 display_usage() {
1145   echo -e "Usage:\n$0 [arguments] \n"
1146   echo -e "   -d|--deploy-settings : Full path to deploy settings yaml file. Optional.  Defaults to null"
1147   echo -e "   -i|--inventory : Full path to inventory yaml file. Required only for baremetal"
1148   echo -e "   -n|--net-settings : Full path to network settings file. Optional."
1149   echo -e "   -p|--ping-site : site to use to verify IP connectivity. Optional. Defaults to 8.8.8.8"
1150   echo -e "   -v|--virtual : Virtualize overcloud nodes instead of using baremetal."
1151   echo -e "   --flat : disable Network Isolation and use a single flat network for the underlay network."
1152   echo -e "   --no-post-config : disable Post Install configuration."
1153   echo -e "   --debug : enable debug output."
1154   echo -e "   --interactive : enable interactive deployment mode which requires user to confirm steps of deployment."
1155   echo -e "   --virtual-cpus : Number of CPUs to use per Overcloud VM in a virtual deployment (defaults to 4)."
1156   echo -e "   --virtual-ram : Amount of RAM to use per Overcloud VM in GB (defaults to 8)."
1157 }
1158
1159 ##translates the command line parameters into variables
1160 ##params: $@ the entire command line is passed
1161 ##usage: parse_cmd_line() "$@"
1162 parse_cmdline() {
1163   echo -e "\n\n${blue}This script is used to deploy the Apex Installer and Provision OPNFV Target System${reset}\n\n"
1164   echo "Use -h to display help"
1165   sleep 2
1166
1167   while [ "${1:0:1}" = "-" ]
1168   do
1169     case "$1" in
1170         -h|--help)
1171                 display_usage
1172                 exit 0
1173             ;;
1174         -d|--deploy-settings)
1175                 DEPLOY_SETTINGS_FILE=$2
1176                 echo "Deployment Configuration file: $2"
1177                 shift 2
1178             ;;
1179         -i|--inventory)
1180                 INVENTORY_FILE=$2
1181                 shift 2
1182             ;;
1183         -n|--net-settings)
1184                 NETSETS=$2
1185                 echo "Network Settings Configuration file: $2"
1186                 shift 2
1187             ;;
1188         -p|--ping-site)
1189                 ping_site=$2
1190                 echo "Using $2 as the ping site"
1191                 shift 2
1192             ;;
1193         -v|--virtual)
1194                 virtual="TRUE"
1195                 echo "Executing a Virtual Deployment"
1196                 shift 1
1197             ;;
1198         --flat )
1199                 net_isolation_enabled="FALSE"
1200                 echo "Underlay Network Isolation Disabled: using flat configuration"
1201                 shift 1
1202             ;;
1203         --no-post-config )
1204                 post_config="FALSE"
1205                 echo "Post install configuration disabled"
1206                 shift 1
1207             ;;
1208         --debug )
1209                 debug="TRUE"
1210                 echo "Enable debug output"
1211                 shift 1
1212             ;;
1213         --interactive )
1214                 interactive="TRUE"
1215                 echo "Interactive mode enabled"
1216                 shift 1
1217             ;;
1218         --virtual-cpus )
1219                 VM_CPUS=$2
1220                 echo "Number of CPUs per VM set to $VM_CPUS"
1221                 shift 2
1222             ;;
1223         --virtual-ram )
1224                 VM_RAM=$2
1225                 echo "Amount of RAM per VM set to $VM_RAM"
1226                 shift 2
1227             ;;
1228         --virtual-computes )
1229                 VM_COMPUTES=$2
1230                 echo "Virtual Compute nodes set to $VM_COMPUTES"
1231                 shift 2
1232             ;;
1233         *)
1234                 display_usage
1235                 exit 1
1236             ;;
1237     esac
1238   done
1239
1240   if [[ ! -z "$NETSETS" && "$net_isolation_enabled" == "FALSE" ]]; then
1241     echo -e "${red}INFO: Single flat network requested. Only admin_network settings will be used!${reset}"
1242   elif [[ -z "$NETSETS" ]]; then
1243     echo -e "${red}ERROR: You must provide a network_settings file with -n.${reset}"
1244     exit 1
1245   fi
1246
1247   if [[ -n "$virtual" && -n "$INVENTORY_FILE" ]]; then
1248     echo -e "${red}ERROR: You should not specify an inventory with virtual deployments${reset}"
1249     exit 1
1250   fi
1251
1252   if [[ -z "$DEPLOY_SETTINGS_FILE" || ! -f "$DEPLOY_SETTINGS_FILE" ]]; then
1253     echo -e "${red}ERROR: Deploy Settings: ${DEPLOY_SETTINGS_FILE} does not exist! Exiting...${reset}"
1254     exit 1
1255   fi
1256
1257   if [[ ! -z "$NETSETS" && ! -f "$NETSETS" ]]; then
1258     echo -e "${red}ERROR: Network Settings: ${NETSETS} does not exist! Exiting...${reset}"
1259     exit 1
1260   fi
1261
1262   if [[ ! -z "$INVENTORY_FILE" && ! -f "$INVENTORY_FILE" ]]; then
1263     echo -e "{$red}ERROR: Inventory File: ${INVENTORY_FILE} does not exist! Exiting...${reset}"
1264     exit 1
1265   fi
1266
1267   if [[ -z "$virtual" && -z "$INVENTORY_FILE" ]]; then
1268     echo -e "${red}ERROR: You must specify an inventory file for baremetal deployments! Exiting...${reset}"
1269     exit 1
1270   fi
1271
1272   if [[ "$net_isolation_enabled" == "FALSE" && "$post_config" == "TRUE" ]]; then
1273     echo -e "${blue}INFO: Post Install Configuration will be skipped.  It is not supported with --flat${reset}"
1274     post_config="FALSE"
1275   fi
1276
1277 }
1278
1279 ##END FUNCTIONS
1280
1281 main() {
1282   parse_cmdline "$@"
1283   echo -e "${blue}INFO: Parsing network settings file...${reset}"
1284   parse_network_settings
1285   if ! configure_deps; then
1286     echo -e "${red}Dependency Validation Failed, Exiting.${reset}"
1287     exit 1
1288   fi
1289   if [ -n "$DEPLOY_SETTINGS_FILE" ]; then
1290     echo -e "${blue}INFO: Parsing deploy settings file...${reset}"
1291     parse_deploy_settings
1292   fi
1293   setup_undercloud_vm
1294   if [ "$virtual" == "TRUE" ]; then
1295     setup_virtual_baremetal $VM_CPUS $VM_RAM
1296   elif [ -n "$INVENTORY_FILE" ]; then
1297     parse_inventory_file
1298   fi
1299   configure_undercloud
1300   undercloud_prep_overcloud_deploy
1301   if [ "$post_config" == "TRUE" ]; then
1302     if ! configure_post_install; then
1303       echo -e "${red}ERROR:Post Install Configuration Failed, Exiting.${reset}"
1304       exit 1
1305     else
1306       echo -e "${blue}INFO: Post Install Configuration Complete${reset}"
1307     fi
1308   fi
1309   if [[ "${deploy_options_array['sdn_controller']}" == 'onos' ]]; then
1310     if ! onos_update_gw_mac ${public_network_cidr} ${public_network_gateway}; then
1311       echo -e "${red}ERROR:ONOS Post Install Configuration Failed, Exiting.${reset}"
1312       exit 1
1313     else
1314       echo -e "${blue}INFO: ONOS Post Install Configuration Complete${reset}"
1315     fi
1316   fi
1317 }
1318
1319 main "$@"