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