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