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