multi-distro puppet install script
#!/bin/bash
# This script installs puppet on most linux distros.
# To run, simply execute as root.
# $ install_puppet.sh [ puppet_version ]
# e.g. $ install_puppet.sh 3.4.1
# Successfully run on Debian 6/7, Ubuntu 12.04 LTS and 14.04 LTS, Fedora 20, and arch.
# Not tested on OS X, Solaris, AIX, etc, simply because I lack test environments.
set -e
if [ -n "$1" ]; then
puppet_version="$1"
fi
require_root_access() {
if [[ $EUID -ne 0 ]]; then
echo "ERROR: This script requires root access"
exit 1
fi
}
# Check if a package is installed
is_installed() {
package="$1"
detect_os
case $DistroBasedOn in
redhat)
rpm -qi "$package" > /dev/null 2>&1 && return 0
;;
debian)
dpkg-query --status "$package" >/dev/null 2>&1 && return 0
;;
arch)
pacman -Qi "$package" >/dev/null 2>&1 && return 0
;;
*)
echo "unknown package management system"
;;
esac
return 1
}
# Check if the package is installed, and install it if not present
ensure_package_present() {
package="$1"
is_installed "$package" && return 0 # return if it's installed already
echo "installing $package and dependencies..."
detect_os
case $DistroBasedOn in
redhat)
yum -y --quiet install "$package"
;;
debian)
apt-get -qq update
apt-get -qq install -y "$package" > /dev/null
;;
arch)
# Update the pacman repositories
pacman -Sy
# Install Ruby (arch uses gem install of puppet)
pacman -S --noconfirm --needed "$package"
;;
*)
echo "Unable to install \"$package\": unknown package management system"
;;
esac
}
lowercase(){
#echo "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/"
echo "$1" | tr "[:upper:]" "[:lower:]"
}
# Figure out what distribution or OS we're running on
detect_os() {
# Inspired by http://stackoverflow.com/questions/394230/detect-the-os-from-a-bash-script
if [ -n "$DIST" ] ; then
# Avoid running these checks repeatedly even if called again
return
fi
# Identify major distro type
if [ -f /etc/redhat-release ] ; then
DistroBasedOn='RedHat'
elif [ -f /etc/debian_version ] ; then
DistroBasedOn='Debian'
elif [ -f /etc/arch-release ] ; then
DistroBasedOn='Arch'
fi
DistroBasedOn=$(lowercase $DistroBasedOn)
# Determine further distro details
# We take this approach to avoid forcing lsb-base package installs
case $DistroBasedOn in
redhat)
DIST=$(cat /etc/redhat-release |sed s/\ release.*//)
PSUEDONAME=$(cat /etc/redhat-release | sed s/.*\(// | sed s/\)//)
REV=$(cat /etc/redhat-release | sed s/.*release\ // | sed s/\ .*//)
;;
debian)
if hash lsb_release ; then
DIST=$(lsb_release --id --short)
PSUEDONAME=$(lsb_release --codename --short)
REV=$(lsb_release --release --short)
elif [ -f /etc/lsb-release ] ; then
DIST=$(grep '^DISTRIB_ID' /etc/lsb-release | awk -F= '{ print $2 }')
PSUEDONAME=$(grep '^DISTRIB_CODENAME' /etc/lsb-release | awk -F= '{ print $2 }')
REV=$(grep '^DISTRIB_RELEASE' /etc/lsb-release | awk -F= '{ print $2 }')
elif [ -f /etc/os-release ] ; then
DIST=$(grep '^ID' /etc/os-release | awk -F= '{ print $2 }')
PSUEDONAME=$(grep '^VERSION=' /etc/os-release | cut -d '(' -f 2 | cut -d ')' -f 1)
REV=$(grep '^VERSION_ID' /etc/os-release | awk -F= '{ print $2 }')
else
REV=$(cat /etc/debian_version)
fi
;;
arch)
# Arch is rolling release based so revision numbers don't apply
DIST=$DistroBasedOn
;;
*)
;;
esac
MACH=$(uname -m)
MAJOR_REV=$(echo $REV | cut -d '.' -f 1)
}
# Idempotent puppet and puppet repository installer
ensure_puppet() {
is_puppet_installed && echo "Puppet already installed" && return 0
ensure_package_present wget
detect_os
OS_DESCRIPTION="Detected ${DistroBasedOn}-based distro: $DIST $PSUEDONAME $REV for $MACH"
case $DistroBasedOn in
redhat)
echo "$OS_DESCRIPTION"
REPO_BASE_URL="https://yum.puppetlabs.com/el/${MAJOR_REV}/products/${MACH}"
if [ "$(lowercase $DIST)" == 'fedora' ]; then
REPO_BASE_URL="https://yum.puppetlabs.com/fedora/f${MAJOR_REV}/products/${MACH}"
ensure_package_present 'gnupg'
fi
# Figure out what the most recent puppetlabs-release rpm is
TEMPLIST=$(mktemp)
wget --convert-links --output-document="$TEMPLIST" "$REPO_BASE_URL"
REPO_URL="$(wget --spider --force-html -i "$TEMPLIST" 2>&1 | grep --only-matching 'https://yum.puppetlabs.com/.*/puppetlabs-release-[0-9]*-[0-9]*.noarch.rpm' | sort | head -n 1)"
#echo "wget --spider --force-html -i "$TEMPLIST" 2>&1 | grep --only-matching 'https://yum.puppetlabs.com/.*/puppetlabs-release-[0-9]*-[0-9]*.noarch.rpm' | sort | head -n 1"
rm "$TEMPLIST"
# Install GPG key
if ! rpm -qi gpg-pubkey-4bd6ec30-4ff1e4fa > /dev/null 2>&1 ; then
gpg_key=$(mktemp)
gpg --recv-key --trust-model direct --keyserver pool.sks-keyservers.net 4BD6EC30
gpg --export --armor 47B320EB4C7C375AA9DAE1A01054B7A24BD6EC30 > $gpg_key
echo "Installing puppetlabs GPG key"
rpm --import $gpg_key
rm $gpg_key
rpm -qi gpg-pubkey-4bd6ec30-4ff1e4fa > /dev/null 2>&1 && echo "Puppet GPG key installed successfully" || echo "Error: Puppet GPG key install failed"
fi
if ! is_installed puppetlabs-release ; then
# Install puppet yum repository
echo "installing puppetlabs yum repository from $REPO_URL"
repo_path="$(mktemp).rpm"
wget --quiet --output-document=${repo_path} ${REPO_URL}
yum -y --quiet install $repo_path
rm $repo_path
is_installed puppetlabs-release && echo "Puppetlabs yum repo installed sucessfully" || echo "Error: puppetlabs repo install failed"
fi
ensure_package_present 'ruby-devel' #needed for librarian-puppet and many others
# Install puppet itself
if [ -n "$puppet_version" ]; then
puppet_package_name="puppet-${puppet_version}"
else
puppet_package_name="puppet"
fi
ensure_package_present "$puppet_package_name"
;;
debian)
echo "$OS_DESCRIPTION"
# Ensure the puppet repository is available
if ! is_installed "puppetlabs-release" ; then
echo "Puppetlabs repository not detected. Installing..."
REPO_URL="https://apt.puppetlabs.com/puppetlabs-release-${PSUEDONAME}.deb"
repo_path=$(mktemp)
wget --quiet --output-document=${repo_path} ${REPO_URL}
dpkg --install ${repo_path}
apt-get -qq update
rm ${repo_path}
is_installed "puppetlabs-release" && echo "puppetlabs repository installed successfully"
else
echo "puppet repo already installed"
fi
# Install puppet
ensure_package_present 'ruby-dev' #needed for librarian-puppet and many others
if [ -n "$puppet_version" ]; then
puppet_package_name="puppet=${puppet_version}-1puppetlabs1"
puppet_common_package_name="puppet-common=${puppet_version}-1puppetlabs1"
else
puppet_package_name="puppet"
puppet_common_package_name="puppet-common"
fi
apt-get -qq update
apt-get -qq install -y ${puppet_package_name} ${puppet_common_package_name} > /dev/null
;;
arch)
echo "detected arch distro"
echo "always installs latest version of puppet - version parameter ignored"
# Install Puppet and Facter as ruby gems
ensure_gem puppet
ensure_gem facter
ensure_group puppet
;;
*)
echo "Unsupported OS - cannot install puppet"
return 1
;;
esac
}
is_gem_installed() {
gem list | grep -q "${gem} ("
}
ensure_gem() {
gem="$1"
ensure_package_present ruby
if ! is_gem_installed "$gem" ; then
gem install "$gem" --no-ri --no-rdoc --no-user-install
is_gem_installed "$gem" || exit 1
fi
}
ensure_group() {
[ -z "$1" ] && exit 1
group="$1"
if ! getent group "$group" > /dev/null 2>&1 ; then
groupadd "$group"
fi
}
# Both facter and puppet need to be available
is_puppet_installed() {
( hash puppet && hash facter ) > /dev/null 2>&1
}
require_root_access
# Install puppet if it's not installed already
if is_puppet_installed ; then
echo "Puppet and facter already installed"
exit 0
else
echo "No existing puppet install detected"
echo "Preparing to install puppet and facter"
ensure_puppet
fi
# Verify puppet install before telling user it's installed
echo "Verifying that puppet and facter installed successfully..."
if is_puppet_installed ; then
echo "Detected puppet version $(puppet -V)"
echo "Detected facter version $(facter --version)"
echo "Puppet and facter installed successfully"
else
echo "Error: puppet and/or facter not detected following install attempt"
exit 1
fi