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