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