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