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