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