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