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