83dc422247982bc63021db91e584800c41bbd0c8
[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 -s $NETSETS -i $net_isolation_enabled -e $CONFIG/network-environment.yaml); 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     if [ "$VM_COMPUTES" -gt 0 ]; then
539       capability="profile:compute"
540       VM_COMPUTES=$((VM_COMPUTES - 1))
541     else
542       capability="profile:control"
543     fi
544
545     cat >> $CONFIG/instackenv-virt.json << EOF
546     {
547       "pm_addr": "192.168.122.1",
548       "pm_user": "root",
549       "pm_password": "INSERT_STACK_USER_PRIV_KEY",
550       "pm_type": "pxe_ssh",
551       "mac": [
552         "$mac"
553       ],
554       "cpu": "$vcpus",
555       "memory": "$ramsize",
556       "disk": "41",
557       "arch": "x86_64",
558       "capabilities": "$capability"
559     },
560 EOF
561   done
562
563   #truncate the last line to remove the comma behind the bracket
564   tail -n 1 $CONFIG/instackenv-virt.json | wc -c | xargs -I {} truncate $CONFIG/instackenv-virt.json -s -{}
565
566   #finally reclose the bracket and close the instackenv.json file
567   cat >> $CONFIG/instackenv-virt.json << EOF
568     }
569   ],
570   "arch": "x86_64",
571   "host-ip": "192.168.122.1",
572   "power_manager": "nova.virt.baremetal.virtual_power_driver.VirtualPowerManager",
573   "seed-ip": "",
574   "ssh-key": "INSERT_STACK_USER_PRIV_KEY",
575   "ssh-user": "root"
576 }
577 EOF
578 }
579
580 ##Create virtual nodes in virsh
581 ##params: name - String: libvirt name for VM
582 ##        bootdev - String: boot device for the VM
583 ##        disksize - Number: size of the disk in GB
584 ##        ovs_bridges: - List: list of ovs bridges
585 ##        vcpus - Number of VCPUs to use (defaults to 4)
586 ##        ramsize - Size of RAM for VM in MB (defaults to 8192)
587 function define_vm () {
588   local vcpus ramsize
589
590   if [ -z "$5" ]; then
591     vcpus=4
592     ramsize=8388608
593   elif [ -z "$6" ]; then
594     vcpus=$5
595     ramsize=8388608
596   else
597     vcpus=$5
598     ramsize=$(($6*1024))
599   fi
600
601   # Create the libvirt storage volume
602   if virsh vol-list default | grep ${1}.qcow2 2>&1> /dev/null; then
603     volume_path=$(virsh vol-path --pool default ${1}.qcow2 || echo "/var/lib/libvirt/images/${1}.qcow2")
604     echo "Volume ${1} exists. Deleting Existing Volume $volume_path"
605     virsh vol-dumpxml ${1}.qcow2 --pool default > /dev/null || echo '' #ok for this to fail
606     touch $volume_path
607     virsh vol-delete ${1}.qcow2 --pool default
608   fi
609   virsh vol-create-as default ${1}.qcow2 ${3}G --format qcow2
610   volume_path=$(virsh vol-path --pool default ${1}.qcow2)
611   if [ ! -f $volume_path ]; then
612       echo "$volume_path Not created successfully... Aborting"
613       exit 1
614   fi
615
616   # create the VM
617   /usr/libexec/openstack-tripleo/configure-vm --name $1 \
618                                               --bootdev $2 \
619                                               --image "$volume_path" \
620                                               --diskbus sata \
621                                               --arch x86_64 \
622                                               --cpus $vcpus \
623                                               --memory $ramsize \
624                                               --libvirt-nic-driver virtio \
625                                               --baremetal-interface $4
626 }
627
628 ##Copy over the glance images and instackenv json file
629 ##params: none
630 function configure_undercloud {
631   local controller_nic_template compute_nic_template
632   echo
633   echo "Copying configuration files to Undercloud"
634   if [[ "$net_isolation_enabled" == "TRUE" ]]; then
635     echo -e "${blue}Network Environment set for Deployment: ${reset}"
636     cat /tmp/network-environment.yaml
637     scp ${SSH_OPTIONS[@]} /tmp/network-environment.yaml "stack@$UNDERCLOUD":
638
639     # check for ODL L3/ONOS
640     if [ "${deploy_options_array['sdn_l3']}" == 'True' ]; then
641       ext_net_type=br-ex
642     fi
643
644     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
645       echo -e "${red}ERROR: Failed to generate controller NIC heat template ${reset}"
646       exit 1
647     fi
648
649     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
650       echo -e "${red}ERROR: Failed to generate compute NIC heat template ${reset}"
651       exit 1
652     fi
653     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" << EOI
654 mkdir nics/
655 cat > nics/controller.yaml << EOF
656 $controller_nic_template
657 EOF
658 cat > nics/compute.yaml << EOF
659 $compute_nic_template
660 EOF
661 EOI
662   fi
663
664   # ensure stack user on Undercloud machine has an ssh key
665   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "if [ ! -e ~/.ssh/id_rsa.pub ]; then ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa; fi"
666
667   if [ "$virtual" == "TRUE" ]; then
668
669       # copy the Undercloud VM's stack user's pub key to
670       # root's auth keys so that Undercloud can control
671       # vm power on the hypervisor
672       ssh ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "cat /home/stack/.ssh/id_rsa.pub" >> /root/.ssh/authorized_keys
673
674       DEPLOY_OPTIONS+=" --libvirt-type qemu"
675       INSTACKENV=$CONFIG/instackenv-virt.json
676
677       # upload instackenv file to Undercloud for virtual deployment
678       scp ${SSH_OPTIONS[@]} $INSTACKENV "stack@$UNDERCLOUD":instackenv.json
679   fi
680
681   # allow stack to control power management on the hypervisor via sshkey
682   # only if this is a virtual deployment
683   if [ "$virtual" == "TRUE" ]; then
684       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
685 while read -r line; do
686   stack_key=\${stack_key}\\\\\\\\n\${line}
687 done < <(cat ~/.ssh/id_rsa)
688 stack_key=\$(echo \$stack_key | sed 's/\\\\\\\\n//')
689 sed -i 's~INSERT_STACK_USER_PRIV_KEY~'"\$stack_key"'~' instackenv.json
690 EOI
691   fi
692
693   # copy stack's ssh key to this users authorized keys
694   ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "cat /home/stack/.ssh/id_rsa.pub" >> ~/.ssh/authorized_keys
695
696   # disable requiretty for sudo
697   ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "sed -i 's/Defaults\s*requiretty//'" /etc/sudoers
698
699   # configure undercloud on Undercloud VM
700   echo "Running undercloud configuration."
701   echo "Logging undercloud configuration to undercloud:/home/stack/apex-undercloud-install.log"
702   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" << EOI
703 if [[ "$net_isolation_enabled" == "TRUE" ]]; then
704   sed -i 's/#local_ip/local_ip/' undercloud.conf
705   sed -i 's/#network_gateway/network_gateway/' undercloud.conf
706   sed -i 's/#network_cidr/network_cidr/' undercloud.conf
707   sed -i 's/#dhcp_start/dhcp_start/' undercloud.conf
708   sed -i 's/#dhcp_end/dhcp_end/' undercloud.conf
709   sed -i 's/#inspection_iprange/inspection_iprange/' undercloud.conf
710   sed -i 's/#undercloud_debug/undercloud_debug/' undercloud.conf
711
712   openstack-config --set undercloud.conf DEFAULT local_ip ${admin_network_provisioner_ip}/${admin_network_cidr##*/}
713   openstack-config --set undercloud.conf DEFAULT network_gateway ${admin_network_provisioner_ip}
714   openstack-config --set undercloud.conf DEFAULT network_cidr ${admin_network_cidr}
715   openstack-config --set undercloud.conf DEFAULT dhcp_start ${admin_network_dhcp_range%%,*}
716   openstack-config --set undercloud.conf DEFAULT dhcp_end ${admin_network_dhcp_range##*,}
717   openstack-config --set undercloud.conf DEFAULT inspection_iprange ${admin_network_introspection_range}
718   openstack-config --set undercloud.conf DEFAULT undercloud_debug false
719
720 fi
721
722 sudo sed -i '/CephClusterFSID:/c\\  CephClusterFSID: \\x27$(cat /proc/sys/kernel/random/uuid)\\x27' /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml
723 sudo sed -i '/CephMonKey:/c\\  CephMonKey: \\x27'"\$(ceph-authtool --gen-print-key)"'\\x27' /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml
724 sudo sed -i '/CephAdminKey:/c\\  CephAdminKey: \\x27'"\$(ceph-authtool --gen-print-key)"'\\x27' /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml
725
726 # we assume that packages will not need to be updated with undercloud install
727 # and that it will be used only to configure the undercloud
728 # packages updates would need to be handled manually with yum update
729 sudo cp -f /usr/share/diskimage-builder/elements/yum/bin/install-packages /usr/share/diskimage-builder/elements/yum/bin/install-packages.bak
730 cat << 'EOF' | sudo tee /usr/share/diskimage-builder/elements/yum/bin/install-packages > /dev/null
731 #!/bin/sh
732 exit 0
733 EOF
734
735 openstack undercloud install &> apex-undercloud-install.log || {
736     # cat the undercloud install log incase it fails
737     echo "ERROR: openstack undercloud install has failed. Dumping Log:"
738     cat apex-undercloud-install.log
739     exit 1
740 }
741
742 sleep 30
743 sudo systemctl restart openstack-glance-api
744 sudo systemctl restart openstack-nova-conductor
745 sudo systemctl restart openstack-nova-compute
746
747 sudo sed -i '/num_engine_workers/c\num_engine_workers = 2' /etc/heat/heat.conf
748 sudo sed -i '/#workers\s=/c\workers = 2' /etc/heat/heat.conf
749 sudo systemctl restart openstack-heat-engine
750 sudo systemctl restart openstack-heat-api
751 EOI
752 # WORKAROUND: must restart the above services to fix sync problem with nova compute manager
753 # TODO: revisit and file a bug if necessary. This should eventually be removed
754 # as well as glance api problem
755 echo -e "${blue}INFO: Sleeping 15 seconds while services come back from restart${reset}"
756 sleep 15
757
758 }
759
760 ##preping it for deployment and launch the deploy
761 ##params: none
762 function undercloud_prep_overcloud_deploy {
763   if [[ "${#deploy_options_array[@]}" -eq 0 || "${deploy_options_array['sdn_controller']}" == 'opendaylight' ]]; then
764     if [ "${deploy_options_array['sdn_l3']}" == 'True' ]; then
765       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight_l3.yaml"
766     elif [ "${deploy_options_array['sfc']}" == 'True' ]; then
767       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight_sfc.yaml"
768     elif [ "${deploy_options_array['vpn']}" == 'True' ]; then
769       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight_sdnvpn.yaml"
770     else
771       DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight.yaml"
772     fi
773     SDN_IMAGE=opendaylight
774     if [ "${deploy_options_array['sfc']}" == 'True' ]; then
775       SDN_IMAGE+=-sfc
776       if [ ! -f $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 ]; then
777           echo "${red} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 is required to execute an SFC deployment."
778           echo "Please install the opnfv-apex-opendaylight-sfc package to provide this overcloud image for deployment.${reset}"
779           exit 1
780       fi
781     fi
782   elif [ "${deploy_options_array['sdn_controller']}" == 'opendaylight-external' ]; then
783     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/opendaylight-external.yaml"
784     SDN_IMAGE=opendaylight
785   elif [ "${deploy_options_array['sdn_controller']}" == 'onos' ]; then
786     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/onos.yaml"
787     SDN_IMAGE=onos
788   elif [ "${deploy_options_array['sdn_controller']}" == 'opencontrail' ]; then
789     echo -e "${red}ERROR: OpenContrail is currently unsupported...exiting${reset}"
790     exit 1
791   elif [[ -z "${deploy_options_array['sdn_controller']}" || "${deploy_options_array['sdn_controller']}" == 'False' ]]; then
792     echo -e "${blue}INFO: SDN Controller disabled...will deploy nosdn scenario${reset}"
793     SDN_IMAGE=opendaylight
794   else
795     echo "${red}Invalid sdn_controller: ${deploy_options_array['sdn_controller']}${reset}"
796     echo "${red}Valid choices are opendaylight, opendaylight-external, onos, opencontrail, False, or null${reset}"
797     exit 1
798   fi
799
800   # Handle different dataplanes
801   if [ "${deploy_options_array['dataplane']}" != 'ovs']; then
802     echo "${red}ovs is the only currently available dataplane. ${deploy_options_array['dataplane']} not implemented${reset}"
803     exit 1
804   fi
805
806   # Make sure the correct overcloud image is available
807   if [ ! -f $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 ]; then
808       echo "${red} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 is required to execute your deployment."
809       echo "Both ONOS and OpenDaylight are currently deployed from this image."
810       echo "Please install the opnfv-apex package to provide this overcloud image for deployment.${reset}"
811       exit 1
812   fi
813
814   echo "Copying overcloud image to Undercloud"
815   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "rm -f overcloud-full.qcow2"
816   scp ${SSH_OPTIONS[@]} $RESOURCES/overcloud-full-${SDN_IMAGE}.qcow2 "stack@$UNDERCLOUD":overcloud-full.qcow2
817
818   # Add performance deploy options if they have been set
819   if [ ! -z "${deploy_options_array['performance']}" ]; then
820
821     # Remove previous kernel args files per role
822     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "rm -f Compute-kernel_params.txt"
823     ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "rm -f Controller-kernel_params.txt"
824
825     # Push performance options to subscript to modify per-role images as needed
826     for option in "${performance_options[@]}" ; do
827       echo -e "${blue}Setting performance option $option${reset}"
828       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" "bash build_perf_image.sh $option"
829     done
830
831     # Build IPA kernel option ramdisks
832     ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" <<EOI
833 /bin/cp -f /home/stack/ironic-python-agent.initramfs /root/
834 mkdir -p ipa/
835 pushd ipa
836 gunzip -c ../ironic-python-agent.initramfs | cpio -i
837 if [ ! -f /home/stack/Compute-kernel_params.txt ]; then
838   touch /home/stack/Compute-kernel_params.txt
839   chown stack /home/stack/Compute-kernel_params.txt
840 fi
841 /bin/cp -f /home/stack/Compute-kernel_params.txt tmp/kernel_params.txt
842 echo "Compute params set: "
843 cat tmp/kernel_params.txt
844 /bin/cp -f /root/image.py usr/lib/python2.7/site-packages/ironic_python_agent/extensions/image.py
845 /bin/cp -f /root/image.pyc usr/lib/python2.7/site-packages/ironic_python_agent/extensions/image.pyc
846 find . | cpio -o -H newc | gzip > /home/stack/Compute-ironic-python-agent.initramfs
847 chown stack /home/stack/Compute-ironic-python-agent.initramfs
848 if [ ! -f /home/stack/Controller-kernel_params.txt ]; then
849   touch /home/stack/Controller-kernel_params.txt
850   chown stack /home/stack/Controller-kernel_params.txt
851 fi
852 /bin/cp -f /home/stack/Controller-kernel_params.txt tmp/kernel_params.txt
853 echo "Controller params set: "
854 cat tmp/kernel_params.txt
855 find . | cpio -o -H newc | gzip > /home/stack/Controller-ironic-python-agent.initramfs
856 chown stack /home/stack/Controller-ironic-python-agent.initramfs
857 popd
858 /bin/rm -rf ipa/
859 EOI
860
861     DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/numa.yaml"
862   fi
863
864   # make sure ceph is installed
865   DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/storage-environment.yaml"
866
867   # scale compute nodes according to inventory
868   total_nodes=$(ssh -T ${SSH_OPTIONS[@]} "root@$UNDERCLOUD" "cat /home/stack/instackenv.json | grep -c memory")
869
870   # check if HA is enabled
871   if [[ "$ha_enabled" == "True" ]]; then
872      DEPLOY_OPTIONS+=" --control-scale 3"
873      compute_nodes=$((total_nodes - 3))
874      DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/puppet-pacemaker.yaml"
875   else
876      compute_nodes=$((total_nodes - 1))
877   fi
878
879   if [ "$compute_nodes" -le 0 ]; then
880     echo -e "${red}ERROR: Invalid number of compute nodes: ${compute_nodes}. Check your inventory file.${reset}"
881     exit 1
882   else
883     echo -e "${blue}INFO: Number of compute nodes set for deployment: ${compute_nodes}${reset}"
884     DEPLOY_OPTIONS+=" --compute-scale ${compute_nodes}"
885   fi
886
887   if [[ "$net_isolation_enabled" == "TRUE" ]]; then
888      #DEPLOY_OPTIONS+=" -e /usr/share/openstack-tripleo-heat-templates/environments/network-isolation.yaml"
889      DEPLOY_OPTIONS+=" -e network-environment.yaml"
890   fi
891
892   if [[ "$ha_enabled" == "True" ]] || [[ "$net_isolation_enabled" == "TRUE" ]]; then
893      DEPLOY_OPTIONS+=" --ntp-server $ntp_server"
894   fi
895
896   if [[ ! "$virtual" == "TRUE" ]]; then
897      DEPLOY_OPTIONS+=" --control-flavor control --compute-flavor compute"
898   else
899      DEPLOY_OPTIONS+=" -e virtual-environment.yaml"
900   fi
901
902   DEPLOY_OPTIONS+=" -e opnfv-environment.yaml"
903
904   echo -e "${blue}INFO: Deploy options set:\n${DEPLOY_OPTIONS}${reset}"
905
906   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
907 if [ "$debug" == 'TRUE' ]; then
908     LIBGUESTFS_BACKEND=direct virt-customize -a overcloud-full.qcow2 --root-password password:opnfvapex
909 fi
910
911 source stackrc
912 set -o errexit
913 echo "Uploading overcloud glance images"
914 openstack overcloud image upload
915
916 echo "Configuring undercloud and discovering nodes"
917 openstack baremetal import --json instackenv.json
918 openstack baremetal configure boot
919 bash -x set_perf_images.sh ${performance_roles[@]}
920 #if [[ -z "$virtual" ]]; then
921 #  openstack baremetal introspection bulk start
922 #fi
923 echo "Configuring flavors"
924 for flavor in baremetal control compute; do
925   echo -e "${blue}INFO: Updating flavor: \${flavor}${reset}"
926   if openstack flavor list | grep \${flavor}; then
927     openstack flavor delete \${flavor}
928   fi
929   openstack flavor create --id auto --ram 4096 --disk 39 --vcpus 1 \${flavor}
930   if ! openstack flavor list | grep \${flavor}; then
931     echo -e "${red}ERROR: Unable to create flavor \${flavor}${reset}"
932   fi
933 done
934 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" baremetal
935 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" --property "capabilities:profile"="control" control
936 openstack flavor set --property "cpu_arch"="x86_64" --property "capabilities:boot_option"="local" --property "capabilities:profile"="compute" compute
937 echo "Configuring nameserver on ctlplane network"
938 neutron subnet-update \$(neutron subnet-list | grep -v id | grep -v \\\\-\\\\- | awk {'print \$2'}) --dns-nameserver 8.8.8.8
939 echo "Executing overcloud deployment, this should run for an extended period without output."
940 sleep 60 #wait for Hypervisor stats to check-in to nova
941 # save deploy command so it can be used for debugging
942 cat > deploy_command << EOF
943 openstack overcloud deploy --templates $DEPLOY_OPTIONS --timeout 90
944 EOF
945 EOI
946
947   if [ "$interactive" == "TRUE" ]; then
948     if ! prompt_user "Overcloud Deployment"; then
949       echo -e "${blue}INFO: User requests exit${reset}"
950       exit 0
951     fi
952   fi
953
954   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
955 source stackrc
956 openstack overcloud deploy --templates $DEPLOY_OPTIONS --timeout 90
957 if ! heat stack-list | grep CREATE_COMPLETE 1>/dev/null; then
958   $(typeset -f debug_stack)
959   debug_stack
960   exit 1
961 fi
962 EOI
963
964   if [ "$debug" == 'TRUE' ]; then
965       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
966 source overcloudrc
967 echo "Keystone Endpoint List:"
968 keystone endpoint-list
969 echo "Keystone Service List"
970 keystone service-list
971 cinder quota-show \$(openstack project list | grep admin | awk {'print \$2'})
972 EOI
973   fi
974 }
975
976 ##Post configuration after install
977 ##params: none
978 function configure_post_install {
979   local opnfv_attach_networks ovs_ip ip_range net_cidr tmp_ip
980   opnfv_attach_networks="admin_network public_network"
981
982   echo -e "${blue}INFO: Post Install Configuration Running...${reset}"
983
984   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
985 source overcloudrc
986 set -o errexit
987 echo "Configuring Neutron external network"
988 neutron net-create external --router:external=True --tenant-id \$(keystone tenant-get service | grep id | awk '{ print \$4 }')
989 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}
990 EOI
991
992   echo -e "${blue}INFO: Checking if OVS bridges have IP addresses...${reset}"
993   for network in ${opnfv_attach_networks}; do
994     ovs_ip=$(find_ip ${NET_MAP[$network]})
995     tmp_ip=''
996     if [ -n "$ovs_ip" ]; then
997       echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} has IP address ${ovs_ip}${reset}"
998     else
999       echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} missing IP, will configure${reset}"
1000       # use last IP of allocation pool
1001       eval "ip_range=\${${network}_usable_ip_range}"
1002       ovs_ip=${ip_range##*,}
1003       eval "net_cidr=\${${network}_cidr}"
1004       sudo ip addr add ${ovs_ip}/${net_cidr##*/} dev ${NET_MAP[$network]}
1005       sudo ip link set up ${NET_MAP[$network]}
1006       tmp_ip=$(find_ip ${NET_MAP[$network]})
1007       if [ -n "$tmp_ip" ]; then
1008         echo -e "${blue}INFO: OVS Bridge ${NET_MAP[$network]} IP set: ${tmp_ip}${reset}"
1009         continue
1010       else
1011         echo -e "${red}ERROR: Unable to set OVS Bridge ${NET_MAP[$network]} with IP: ${ovs_ip}${reset}"
1012         return 1
1013       fi
1014     fi
1015   done
1016
1017   # for virtual, we NAT public network through Undercloud
1018   if [ "$virtual" == "TRUE" ]; then
1019     if ! configure_undercloud_nat ${public_network_cidr}; then
1020       echo -e "${red}ERROR: Unable to NAT undercloud with external net: ${public_network_cidr}${reset}"
1021       exit 1
1022     else
1023       echo -e "${blue}INFO: Undercloud VM has been setup to NAT Overcloud public network${reset}"
1024     fi
1025   fi
1026
1027   # for sfc deployments we need the vxlan workaround
1028   if [ "${deploy_options_array['sfc']}" == 'True' ]; then
1029       ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1030 source stackrc
1031 set -o errexit
1032 for node in \$(nova list | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
1033 ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1034 sudo ifconfig br-int up
1035 sudo ip route add 123.123.123.0/24 dev br-int
1036 EOF
1037 done
1038 EOI
1039   fi
1040
1041   # Collect deployment logs
1042   ssh -T ${SSH_OPTIONS[@]} "stack@$UNDERCLOUD" <<EOI
1043 mkdir -p ~/deploy_logs
1044 rm -rf deploy_logs/*
1045 source stackrc
1046 set -o errexit
1047 for node in \$(nova list | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"); do
1048  ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1049  sudo cp /var/log/messages /home/heat-admin/messages.log
1050  sudo chown heat-admin /home/heat-admin/messages.log
1051 EOF
1052 scp ${SSH_OPTIONS[@]} heat-admin@\$node:/home/heat-admin/messages.log ~/deploy_logs/\$node.messages.log
1053 if [ "$debug" == "TRUE" ]; then
1054     nova list --ip \$node
1055     echo "---------------------------"
1056     echo "-----/var/log/messages-----"
1057     echo "---------------------------"
1058     cat ~/deploy_logs/\$node.messages.log
1059     echo "---------------------------"
1060     echo "----------END LOG----------"
1061     echo "---------------------------"
1062 fi
1063  ssh -T ${SSH_OPTIONS[@]} "heat-admin@\$node" <<EOF
1064  sudo rm -f /home/heat-admin/messages.log
1065 EOF
1066 done
1067
1068 # Print out the dashboard URL
1069 source stackrc
1070 echo "Overcloud dashboard available at http://\$(heat output-show overcloud PublicVip | sed 's/"//g')/dashboard"
1071 EOI
1072
1073 }
1074
1075 display_usage() {
1076   echo -e "Usage:\n$0 [arguments] \n"
1077   echo -e "   -d|--deploy-settings : Full path to deploy settings yaml file. Optional.  Defaults to null"
1078   echo -e "   -i|--inventory : Full path to inventory yaml file. Required only for baremetal"
1079   echo -e "   -n|--net-settings : Full path to network settings file. Optional."
1080   echo -e "   -p|--ping-site : site to use to verify IP connectivity. Optional. Defaults to 8.8.8.8"
1081   echo -e "   -v|--virtual : Virtualize overcloud nodes instead of using baremetal."
1082   echo -e "   --flat : disable Network Isolation and use a single flat network for the underlay network."
1083   echo -e "   --no-post-config : disable Post Install configuration."
1084   echo -e "   --debug : enable debug output."
1085   echo -e "   --interactive : enable interactive deployment mode which requires user to confirm steps of deployment."
1086   echo -e "   --virtual-cpus : Number of CPUs to use per Overcloud VM in a virtual deployment (defaults to 4)."
1087   echo -e "   --virtual-ram : Amount of RAM to use per Overcloud VM in GB (defaults to 8)."
1088 }
1089
1090 ##translates the command line parameters into variables
1091 ##params: $@ the entire command line is passed
1092 ##usage: parse_cmd_line() "$@"
1093 parse_cmdline() {
1094   echo -e "\n\n${blue}This script is used to deploy the Apex Installer and Provision OPNFV Target System${reset}\n\n"
1095   echo "Use -h to display help"
1096   sleep 2
1097
1098   while [ "${1:0:1}" = "-" ]
1099   do
1100     case "$1" in
1101         -h|--help)
1102                 display_usage
1103                 exit 0
1104             ;;
1105         -d|--deploy-settings)
1106                 DEPLOY_SETTINGS_FILE=$2
1107                 echo "Deployment Configuration file: $2"
1108                 shift 2
1109             ;;
1110         -i|--inventory)
1111                 INVENTORY_FILE=$2
1112                 shift 2
1113             ;;
1114         -n|--net-settings)
1115                 NETSETS=$2
1116                 echo "Network Settings Configuration file: $2"
1117                 shift 2
1118             ;;
1119         -p|--ping-site)
1120                 ping_site=$2
1121                 echo "Using $2 as the ping site"
1122                 shift 2
1123             ;;
1124         -v|--virtual)
1125                 virtual="TRUE"
1126                 echo "Executing a Virtual Deployment"
1127                 shift 1
1128             ;;
1129         --flat )
1130                 net_isolation_enabled="FALSE"
1131                 echo "Underlay Network Isolation Disabled: using flat configuration"
1132                 shift 1
1133             ;;
1134         --no-post-config )
1135                 post_config="FALSE"
1136                 echo "Post install configuration disabled"
1137                 shift 1
1138             ;;
1139         --debug )
1140                 debug="TRUE"
1141                 echo "Enable debug output"
1142                 shift 1
1143             ;;
1144         --interactive )
1145                 interactive="TRUE"
1146                 echo "Interactive mode enabled"
1147                 shift 1
1148             ;;
1149         --virtual-cpus )
1150                 VM_CPUS=$2
1151                 echo "Number of CPUs per VM set to $VM_CPUS"
1152                 shift 2
1153             ;;
1154         --virtual-ram )
1155                 VM_RAM=$2
1156                 echo "Amount of RAM per VM set to $VM_RAM"
1157                 shift 2
1158             ;;
1159         --virtual-computes )
1160                 VM_COMPUTES=$2
1161                 echo "Virtual Compute nodes set to $VM_COMPUTES"
1162                 shift 2
1163             ;;
1164         *)
1165                 display_usage
1166                 exit 1
1167             ;;
1168     esac
1169   done
1170
1171   if [[ ! -z "$NETSETS" && "$net_isolation_enabled" == "FALSE" ]]; then
1172     echo -e "${red}INFO: Single flat network requested. Only admin_network settings will be used!${reset}"
1173   elif [[ -z "$NETSETS" ]]; then
1174     echo -e "${red}ERROR: You must provide a network_settings file with -n.${reset}"
1175     exit 1
1176   fi
1177
1178   if [[ -n "$virtual" && -n "$INVENTORY_FILE" ]]; then
1179     echo -e "${red}ERROR: You should not specify an inventory with virtual deployments${reset}"
1180     exit 1
1181   fi
1182
1183   if [[ -z "$DEPLOY_SETTINGS_FILE" || ! -f "$DEPLOY_SETTINGS_FILE" ]]; then
1184     echo -e "${red}ERROR: Deploy Settings: ${DEPLOY_SETTINGS_FILE} does not exist! Exiting...${reset}"
1185     exit 1
1186   fi
1187
1188   if [[ ! -z "$NETSETS" && ! -f "$NETSETS" ]]; then
1189     echo -e "${red}ERROR: Network Settings: ${NETSETS} does not exist! Exiting...${reset}"
1190     exit 1
1191   fi
1192
1193   if [[ ! -z "$INVENTORY_FILE" && ! -f "$INVENTORY_FILE" ]]; then
1194     echo -e "{$red}ERROR: Inventory File: ${INVENTORY_FILE} does not exist! Exiting...${reset}"
1195     exit 1
1196   fi
1197
1198   if [[ -z "$virtual" && -z "$INVENTORY_FILE" ]]; then
1199     echo -e "${red}ERROR: You must specify an inventory file for baremetal deployments! Exiting...${reset}"
1200     exit 1
1201   fi
1202
1203   if [[ "$net_isolation_enabled" == "FALSE" && "$post_config" == "TRUE" ]]; then
1204     echo -e "${blue}INFO: Post Install Configuration will be skipped.  It is not supported with --flat${reset}"
1205     post_config="FALSE"
1206   fi
1207
1208 }
1209
1210 ##END FUNCTIONS
1211
1212 main() {
1213   # Make sure jinja2 is installed
1214   easy_install-3.4 jinja2 > /dev/null
1215   parse_cmdline "$@"
1216   echo -e "${blue}INFO: Parsing network settings file...${reset}"
1217   parse_network_settings
1218   if ! configure_deps; then
1219     echo -e "${red}Dependency Validation Failed, Exiting.${reset}"
1220     exit 1
1221   fi
1222   if [ -n "$DEPLOY_SETTINGS_FILE" ]; then
1223     echo -e "${blue}INFO: Parsing deploy settings file...${reset}"
1224     parse_deploy_settings
1225   fi
1226   setup_undercloud_vm
1227   if [ "$virtual" == "TRUE" ]; then
1228     setup_virtual_baremetal $VM_CPUS $VM_RAM
1229   elif [ -n "$INVENTORY_FILE" ]; then
1230     parse_inventory_file
1231   fi
1232   configure_undercloud
1233   undercloud_prep_overcloud_deploy
1234   if [ "$post_config" == "TRUE" ]; then
1235     if ! configure_post_install; then
1236       echo -e "${red}ERROR:Post Install Configuration Failed, Exiting.${reset}"
1237       exit 1
1238     else
1239       echo -e "${blue}INFO: Post Install Configuration Complete${reset}"
1240     fi
1241   fi
1242   if [[ "${deploy_options_array['sdn_controller']}" == 'onos' ]]; then
1243     if ! onos_update_gw_mac ${public_network_cidr} ${public_network_gateway}; then
1244       echo -e "${red}ERROR:ONOS Post Install Configuration Failed, Exiting.${reset}"
1245       exit 1
1246     else
1247       echo -e "${blue}INFO: ONOS Post Install Configuration Complete${reset}"
1248     fi
1249   fi
1250 }
1251
1252 main "$@"