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