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