fuel-virtualbox/functions/product.sh

288 lines
10 KiB
Bash
Executable File

#!/bin/bash
# Copyright 2013 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# This file contains the functions for connecting to Fuel VM, checking if the installation process completed
# and Fuel became operational, and also enabling outbound network/internet access for this VM through the
# host system
source ./functions/shell.sh
ssh_options='-oConnectTimeout=5 -oStrictHostKeyChecking=no -oCheckHostIP=no -oUserKnownHostsFile=/dev/null -oRSAAuthentication=no -oPubkeyAuthentication=no'
wait_for_line_in_puppet_bootstrap() {
ip=$1
username=$2
password=$3
prompt=$4
goodline=$5
badline=$6
# Log in into the VM, see if Puppet has completed its run
# Looks a bit ugly, but 'end of expect' has to be in the very beginning of the line
result=$(
execute expect << ENDOFEXPECT
spawn ssh $ssh_options $username@$ip
expect "connect to host" exit
expect "*?assword:*"
send "$password\r"
expect "$prompt"
send "egrep --color=none -e '$goodline' -e '$badline' /var/log/puppet/bootstrap_admin_node.log\r"
expect "$prompt"
send "logout\r"
expect "$prompt"
ENDOFEXPECT
)
echo "$result" | egrep "$badline" >&2 && return 1
echo "$result" | egrep -q "$goodline" && return 0
return 1
}
is_product_vm_operational() {
wait_for_line_in_puppet_bootstrap "$@" "^Fuel.*complete" "^Fuel.*FAILED"
}
wait_for_product_vm_to_download() {
ip=$1
username=$2
password=$3
prompt=$4
echo "Waiting for product VM to download files. Please do NOT abort the script..."
# Loop until master node gets successfully installed
maxdelay=3000
while ! wait_for_line_in_puppet_bootstrap $ip $username $password "$prompt" "build docker containers finished.|^Fuel.*complete" "^Fuel.*FAILED"; do
sleep 5
((waited += 5))
if (( waited >= maxdelay )); then
echo "Installation timed out! ($maxdelay seconds)" 1>&2
exit 1
fi
done
}
wait_for_product_vm_to_install() {
ip=$1
username=$2
password=$3
prompt=$4
echo "Waiting for product VM to install. Please do NOT abort the script..."
# Loop until master node gets successfully installed
maxdelay=3000
while ! is_product_vm_operational $ip $username $password "$prompt"; do
sleep 5
((waited += 5))
if (( waited >= maxdelay )); then
echo "Installation timed out! ($maxdelay seconds)" 1>&2
exit 1
fi
done
}
check_internet_connection() {
line=$1
OIFS="${IFS}"
NIFS=$' '
IFS="${NIFS}"
for i in $line; do
if [[ "$i" == *% && "$i" != 100* ]]; then
return 0
fi
done
IFS="${OIFS}"
return 1
}
enable_outbound_network_for_product_vm() {
ip=$1
username=$2
password=$3
prompt=$4
interface_id=$(($5-1)) # Subtract one to get ethX index (0-based) from the VirtualBox index (from 1 to 4)
gateway_ip=$6
# Check for internet access on the host system
echo -n "Checking for internet connectivity on the host system... "
check_hosts=`echo google.com wikipedia.com | tr ' ' '\n'`
case $(execute uname) in
Linux | Darwin)
for i in ${check_hosts} ; do
ping_host=`execute ping -c 2 ${i} | grep %`
ping_host_result+=$ping_host
done
;;
CYGWIN*)
if [ ! -z "`execute type ping | grep system32`" ]; then
for i in ${check_hosts} ; do
ping_host=`execute ping -n 5 ${i} | grep %`
ping_host_result+=$ping_host
done
elif [ ! -z "`execute type ping | grep bin`" ]; then
for i in ${check_hosts} ; do
ping_host=`execute ping ${i} count 5 | grep %`
ping_host_result+=$ping_host
done
else
print_no_internet_connectivity_banner
fi
;;
*)
print_no_internet_connectivity_banner
;;
esac
check_internet_connection "$ping_host_result"
if [[ $? -eq 0 ]]; then
echo "OK"
else
print_no_internet_connectivity_banner
fi
# Check host nameserver configuration
echo -n "Checking local DNS configuration... "
if execute test -f /etc/resolv.conf ; then
nameserver="$(execute grep '^nameserver' /etc/resolv.conf | grep -v 'nameserver\s\s*127.' | head -3)"
fi
if [ -z "$nameserver" ] && execute test -x /usr/bin/nmcli; then
# Get DNS from network manager
if [ -n "`execute LANG=C nmcli nm | grep \"running\s\+connected\"`" ]; then
nameserver="$(execute nmcli dev list | grep 'IP[46].DNS' | sed -e 's/IP[46]\.DNS\[[0-9]\+\]:\s\+/nameserver /'| grep -v 'nameserver\s\s*127.' | head -3)"
fi
fi
if [ -z "$nameserver" ]; then
echo "/etc/resolv.conf does not contain a nameserver. Using 8.8.8.8 for DNS."
nameserver="nameserver 8.8.8.8"
else
echo "OK"
fi
# Enable internet access on inside the VMs
echo -n "Enabling outbound network/internet access for the product VM... "
# Get network settings (ip address and ip network) for eth1 interface of the master node
local master_ip_pub_net=$(echo $fuel_master_ips | cut -f2 -d ' ')
master_ip_pub_net="${master_ip_pub_net%.*}"".1"
local master_pub_net="${master_ip_pub_net%.*}"".0"
# Log in into the VM, configure and bring up the NAT interface, set default gateway, check internet connectivity
# Looks a bit ugly, but 'end of expect' has to be in the very beginning of the line
result=$(
execute expect << ENDOFEXPECT
spawn ssh $ssh_options $username@$ip
expect "connect to host" exit
expect "*?assword:*"
send "$password\r"
expect "$prompt"
send "file=/etc/sysconfig/network-scripts/ifcfg-eth$interface_id\r"
expect "$prompt"
send "hwaddr=\\\$(grep HWADDR \\\$file)\r"
expect "$prompt"
send "uuid=\\\$(grep UUID \\\$file)\r"
expect "$prompt"
send "echo -e \"\\\$hwaddr\\n\\\$uuid\\nDEVICE=eth$interface_id\\nTYPE=Ethernet\\nONBOOT=yes\\nNM_CONTROLLED=no\\nBOOTPROTO=dhcp\\nPEERDNS=no\" > \\\$file\r"
expect "$prompt"
send "sed \"s/GATEWAY=.*/GATEWAY=\"$gateway_ip\"/g\" -i /etc/sysconfig/network\r"
expect "$prompt"
send "echo -e \"$nameserver\" > /etc/dnsmasq.upstream\r"
expect "$prompt"
send "sed \"s/DNS_UPSTREAM:.*/DNS_UPSTREAM: \\\$(grep \'^nameserver\' /etc/dnsmasq.upstream | cut -d \' \' -f2)/g\" -i /etc/fuel/astute.yaml\r"
expect "$prompt"
send "sed -i 's/ONBOOT=no/ONBOOT=yes/g' /etc/sysconfig/network-scripts/ifcfg-eth1\r"
expect "$prompt"
send "sed -i 's/NM_CONTROLLED=yes/NM_CONTROLLED=no/g' /etc/sysconfig/network-scripts/ifcfg-eth1\r"
expect "$prompt"
send "sed -i 's/BOOTPROTO=dhcp/BOOTPROTO=static/g' /etc/sysconfig/network-scripts/ifcfg-eth1\r"
expect "$prompt"
send " echo \"IPADDR=$master_ip_pub_net\" >> /etc/sysconfig/network-scripts/ifcfg-eth1\r"
expect "$prompt"
send " echo \"NETMASK=$mask\" >> /etc/sysconfig/network-scripts/ifcfg-eth1\r"
expect "$prompt"
send "/sbin/iptables -t nat -A POSTROUTING -s $master_pub_net/24 \! -d $master_pub_net/24 -j MASQUERADE\r"
expect "$prompt"
send "/sbin/iptables -I FORWARD 1 --dst $master_pub_net/24 -j ACCEPT\r"
expect "$prompt"
send "/sbin/iptables -I FORWARD 1 --src $master_pub_net/24 -j ACCEPT\r"
expect "$prompt"
send "service iptables save >/dev/null 2>&1\r"
expect "$prompt"
send "dockerctl restart cobbler >/dev/null 2>&1\r"
expect "$prompt"
send "service network restart >/dev/null 2>&1\r"
expect "*OK*"
expect "$prompt"
send "dockerctl restart cobbler >/dev/null 2>&1\r"
expect "$prompt"
send "dockerctl check cobbler >/dev/null 2>&1\r"
expect "*ready*"
expect "$prompt"
send "logout\r"
expect "$prompt"
ENDOFEXPECT
)
# Waiting until the network services are restarted.
# 5 seconds is optimal time for different operating systems.
echo -e "\nWaiting until the network services are restarted..."
sleep 5s
result_inet=$(
execute expect << ENDOFEXPECT
spawn ssh $ssh_options $username@$ip
expect "connect to host" exit
expect "*?assword:*"
send "$password\r"
expect "$prompt"
send "for i in {1..5}; do ping -c 2 google.com || ping -c 2 wikipedia.com || sleep 2; done\r"
expect "*icmp*"
expect "$prompt"
send "logout\r"
expect "$prompt"
ENDOFEXPECT
)
# When you are launching command in a sub-shell, there are issues with IFS (internal field separator)
# and parsing output as a set of strings. So, we are saving original IFS, replacing it, iterating over lines,
# and changing it back to normal
#
# http://blog.edwards-research.com/2010/01/quick-bash-trick-looping-through-output-lines/
OIFS="${IFS}"
NIFS=$'\n'
IFS="${NIFS}"
for line in $result_inet; do
IFS="${OIFS}"
if [[ $line == *icmp_seq* ]]; then
IFS="${NIFS}"
echo "OK"
return 0;
fi
IFS="${NIFS}"
done
print_no_internet_connectivity_banner
return 1
}
print_no_internet_connectivity_banner() {
echo "FAIL"
echo "############################################################"
echo "# WARNING: some of the Fuel features will not be supported #"
echo "# because there is no Internet connectivity #"
echo "############################################################"
}