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