anvil/smithy
Joshua Harlow 5db32bd180 Allow running on unknown distros
For unknown distros with no bootstrap file default to using
a specific unknown file when in force mode (which only sets up
the virtualenv for anvil).

This allows smithy to be ran on those unknown distros (although
most of the followup operations will still not succeed).

Change-Id: Iac36f1583e16f55ba34b5393c7096c750ee4990f
2014-04-13 10:27:08 -07:00

367 lines
9.5 KiB
Bash
Executable File

#!/bin/bash
locale -a | grep -q -e "^en_US$" && export LANG="en_US"
shopt -s nocasematch
SMITHY_NAME=$(readlink -f "$0")
cd "$(dirname "$0")"
VERBOSE="${VERBOSE:-0}"
YUM_OPTS="--assumeyes --nogpgcheck"
CURL_OPTS=""
# Give access to the system packages so that when clients get installed
# after installation that the virtualenv can access them to do things like
# install images, setup keystone...
VENV_OPTS="--system-site-packages"
VENV_DIR="$PWD/.venv"
VENV_ACTIVATE="$VENV_DIR/bin/activate"
PIP="$VENV_DIR/bin/pip"
YYOOM_CMD="$PWD/tools/yyoom"
if [ "$VERBOSE" == "0" ]; then
YUM_OPTS="$YUM_OPTS -q"
CURL_OPTS="-s"
VENV_OPTS="$VENV_OPTS -q"
fi
# Source in our variables (or overrides)
source ".anvilrc"
if [ -n "$SUDO_USER" ]; then
USER_HOME=$(getent passwd "$SUDO_USER" | cut -d: -f6)
if [ -n "$USER_HOME" ]; then
HOME_RC="${USER_HOME}/.anvilrc"
if [ -f "$HOME_RC" ]; then
source "$HOME_RC"
fi
fi
fi
dump_list()
{
for var in "$@"; do
for name in $var; do
echo " - $name"
done
done
}
yum_install()
{
local requires=$@
if [ "$VERBOSE" == "0" ]; then
yum install $YUM_OPTS $requires > /dev/null 2>&1
else
yum install $YUM_OPTS $requires
fi
return $?
}
yum_remove()
{
local remove=$@
if [ "$VERBOSE" == "0" ]; then
yum remove $YUM_OPTS $remove > /dev/null 2>&1
else
yum remove $YUM_OPTS $remove
fi
return $?
}
bootstrap_rpm_packages()
{
if [ -n "$REQUIRES" ]; then
echo -e "Installing system packages:"
dump_list $REQUIRES
echo "Please wait..."
yum_install $REQUIRES
if [ "$?" != "0" ]; then
echo -e "Failed installing!"
return 1
fi
fi
if [ -n "$CONFLICTS" ]; then
echo -e "Removing conflicting system packages:"
dump_list $CONFLICTS
echo "Please wait..."
yum_remove $CONFLICTS
if [ "$?" != "0" ]; then
echo -e "Failed removing!"
return 1
fi
fi
return 0
}
clean_pip()
{
# See: https://github.com/pypa/pip/issues/982
if [ -n "$SUDO_USER" ]; then
rm -rf "/tmp/pip-build-$SUDO_USER"
fi
}
bootstrap_epel()
{
# Installs the repository that will allow for installation of packages
# from epel, see https://fedoraproject.org/wiki/EPEL for information
# about what is epel.
[ -z "$EPEL_RPM_URL" ] && return 0
echo "Installing epel rpm from $EPEL_RPM_URL"
cache_and_install_rpm_url "$EPEL_RPM_URL"
return $?
}
bootstrap_repos()
{
# Installs other repositories that will allow for installation of packages
# from places other than epel. This allows for anvil to find dependencies
# from other places (so anvil can avoid building those dependencies in the
# first place).
[ -z "$REPO_URLS" ] && return 0
# If urls were provided but no directory, that's bad.
[ -z "$REPO_DIR" ] && return 1
for repo_url in $REPO_URLS; do
echo "Installing repo file from $repo_url -> $REPO_DIR"
local base_filename=$(basename $repo_url)
local output_filename="$REPO_DIR/$base_filename"
if [ "$VERBOSE" == "0" ]; then
wget -q "$repo_url" -O "$output_filename"
else
wget "$repo_url" -O "$output_filename"
fi
if [ "$?" != "0" ]; then
echo -e "Failed downloading $repo_url -> $output_filename"
return 1
fi
done
return 0
}
unsudo()
{
# If a sudo user is active the given files/directories will be changed to
# be owned by that user instead of the current root user, if no sudo user
# is active, then nothing changes.
if [ -n "$SUDO_UID" -a -n "$SUDO_GID" ]; then
if [ "$VERBOSE" == "0" ]; then
chown -R "$SUDO_UID:$SUDO_GID" $@
else
chown -R -c "$SUDO_UID:$SUDO_GID" $@
fi
fi
}
bootstrap_virtualenv()
{
# Creates a virtualenv and then installs anvils requirements in it.
echo "Setting up virtualenv in $VENV_DIR"
virtualenv $VENV_OPTS "$VENV_DIR" || return 1
unsudo $VENV_DIR
local deps=$(cat requirements.txt | grep -v '^$\|^\s*\#' | sort)
if [ -n "$deps" ]; then
echo "Installing anvil dependencies in $VENV_DIR"
dump_list $deps
echo "Please wait..."
if [ "$VERBOSE" == "0" ]; then
$PIP install -r requirements.txt > /dev/null 2>&1
else
$PIP install -v -r requirements.txt
fi
if [ "$?" != "0" ]; then
return 1
fi
fi
unsudo $VENV_DIR
}
bootstrap_selinux()
{
# See if selinux is on.
echo "Enabling selinux for yum like binaries."
if [ "$(getenforce)" == "Enforcing" ]; then
# Ensure all yum api interacting binaries are ok to be used.
chcon -h "system_u:object_r:rpm_exec_t:s0" "$YYOOM_CMD"
fi
}
run_smithy()
{
source "$VENV_ACTIVATE"
local python=$(which python)
exec "$python" anvil $ARGS
}
puke()
{
local cleaned_force=$(echo "$FORCE" | sed -e 's/\([A-Z]\)/\L\1/g;s/\s//g')
if [ "$cleaned_force" != "yes" ]; then
echo -e "To run anyway set FORCE=yes and rerun." >&2
exit 1
fi
}
needs_bootstrap()
{
# Checks if we need to perform the bootstrap phase.
if [ "$BOOTSTRAP" == "true" ]; then
return 0
fi
if [ ! -d "$VENV_DIR" -o ! -f "$VENV_ACTIVATE" -o ! -f "$PIP" ]; then
return 0
fi
return 1
}
rpm_is_installed()
{
# Checks if an rpm is already installed.
local name=$(basename "$1")
rpm -q "${name%.rpm}" &>/dev/null
return $?
}
cache_and_install_rpm_url()
{
# Downloads an rpm from a url and then installs it (if it's not already
# installed).
url=${1:?"Error: rpm url is undefined!"}
cachedir=${RPM_CACHEDIR:-'/tmp'}
rpm=$(basename "$url")
if rpm_is_installed "$rpm"; then
return 0
fi
if [ ! -f "$cachedir/$rpm" ]; then
echo -e "Downloading ${rpm} to ${cachedir}"
curl $CURL_OPTS "$url" -o "$cachedir/$rpm" || return 1
fi
echo -e "Installing $cachedir/$rpm"
yum_install "$cachedir/$rpm"
return $?
}
greatest_version()
{
for arg in "$@"; do
echo "$arg"
done | sort --version-sort --reverse | head -n1
}
## Identify which bootstrap configuration file to use: either set
## explicitly (BSCONF_FILE) or determined based on the os distribution:
BSCONF_DIR="${BSCONF_DIR:-$(dirname $(readlink -f "$0"))/tools/bootstrap}"
get_os_info()
{
if [ "$(uname)" = "Linux" ] ; then
if [ -f /etc/redhat-release ] ; then
PKG="rpm"
OSNAME=`cat /etc/redhat-release`
OSDIST=`cat /etc/redhat-release | sed -e 's/release.*$//g;s/\s//g'`
PSUEDONAME=`cat /etc/redhat-release | sed s/.*\(// | sed s/\)//`
RELEASE=`cat /etc/redhat-release | sed s/.*release\ // | sed s/\ .*//`
elif [ -f /etc/debian_version ] ; then
PKG="deb"
OSDIST=`cat /etc/lsb-release | grep '^DISTRIB_ID' | awk -F= '{ print $2 }'`
PSUEDONAME=`cat /etc/lsb-release | grep '^DISTRIB_CODENAME' | awk -F= '{ print $2 }'`
RELEASE=`cat /etc/lsb-release | grep '^DISTRIB_RELEASE' | awk -F= '{ print $2 }'`
OSNAME="$OSDIST $RELEASE ($PSUEDONAME)"
fi
fi
}
get_os_info
if [ -z "$BSCONF_FILE" ]; then
BSCONF_FILE="$BSCONF_DIR/$OSDIST"
fi
ARGS=""
BOOTSTRAP=false
# Ad-hoc getopt to handle long opts.
#
# Smithy opts are consumed while those to anvil are copied through.
while [ "$#" != 0 ]; do
case "$1" in
'--bootstrap')
BOOTSTRAP=true
shift
;;
'--force')
FORCE=yes
shift
;;
*)
ARGS="$ARGS $1"
shift
;;
esac
done
# Source immediately so that we can export the needed variables.
if [ -f "$BSCONF_FILE" ]; then
source "$BSCONF_FILE"
fi
if ! needs_bootstrap; then
clean_pip
run_smithy
fi
if [ "$BOOTSTRAP" == "false" ]; then
echo "This system needs to be updated in order to run anvil!" >&2
echo "Running 'sudo $SMITHY_NAME --bootstrap' will attempt to do so." >&2
puke
fi
## Bootstrap smithy
if [ "$(id -u)" != "0" ]; then
echo "You must run '$SMITHY_NAME --bootstrap' with root privileges!" >&2
exit 1
fi
if [ ! -f "$BSCONF_FILE" ]; then
echo "Anvil has not been tested on distribution '$OSNAME'" >&2
puke
else
MIN_RELEASE=${MIN_RELEASE:?"Error: MIN_RELEASE is undefined!"}
SHORTNAME=${SHORTNAME:?"Error: SHORTNAME is undefined!"}
if [ "$RELEASE" != "$(greatest_version "$RELEASE" "$MIN_RELEASE")" ]; then
echo "This script must be run on $SHORTNAME $MIN_RELEASE+ and not $SHORTNAME $RELEASE." >&2
puke
fi
fi
# If we got here then we must be in force mode, setup with the default configuration
# file for unknown distros...
if [ ! -f "$BSCONF_FILE" ]; then
BSCONF_FILE="$BSCONF_DIR/Unknown"
SHORTNAME="$OSDIST"
source "$BSCONF_FILE"
fi
echo "Bootstrapping $SHORTNAME $RELEASE"
echo "Please wait..."
clean_pip
for step in ${STEPS:?"Error: STEPS is undefined!"}; do
echo "--- Running bootstrap step $step ---"
"bootstrap_${step}"
if [ $? != 0 ]; then
echo "Bootstrapping $SHORTNAME $RELEASE failed." >&2
exit 1
fi
done
clean_pip
# Anvil writes configurations in these locations, make sure they are created
# and that the user running this script can actually access those files (even
# later if they are not running with sudo).
mkdir -p -v /etc/anvil /usr/share/anvil
touch /var/log/anvil.log
unsudo /etc/anvil /usr/share/anvil /var/log/anvil.log
echo "Bootstrapped for $SHORTNAME $RELEASE"
ARGS="-a moo"
run_smithy