#!/bin/sh -e # # Install perfSONAR # STARTED=$(date +%Y-%m-%dT%H:%M:%S) usage() { cat <<'EOF' Usage: install-perfsonar [ OPTIONS ] BUNDLE [ URL ... ] BUNDLE is one of tools, core, testpoint, toolkit or archive. URL points to a pSConfig file that will be applied with 'psconfig remote add' if pSConfig is installed. OPTIONS: --add P Add package P to the installation. May be used repeatedly for multiple packages. --auto-updates Enable automatic updates --security Install security package --tunings Install system tunings --repo R Use repository R (production, staging, nightly-minor or nightly-patch). Defaults to production. --dry-run Don't do anything --no-log Don't write a log into $HOME --ps-repo-version V Use perfSONAR repo verion V on EL systems NOTE: The --security and --tunings switches are for the testpoint and toolkit bundles only. Example usage from GitHub: curl -s https://raw.githubusercontent.com/perfsonar/project/master/install-perfsonar \ | sh -s - --auto-updates --tunings testpoint EOF } # ----------------------------------------------------------------------------- # Utilities warn() { if [ $# -gt 0 ] then echo "$@" 1>&2 fi } die() { warn "$@" exit 1 } die_usage() { usage 1>&2 die } do_dry() { if ${DRY_RUN:-true} then echo "$@" else "$@" fi } narrate() { printf "\n#\n# " echo "$@" printf "#\n\n" } # ----------------------------------------------------------------------------- # OS Identification, adapted from Unibuild # This page has some useful information about figuring out what # distribution you're running: # http://linuxmafia.com/faq/Admin/release-files.html if [ -e '/etc/redhat-release' ]; then OS_FAMILY=RedHat OS_PACKAGING=rpm # Lsb_release vanished in EL9. Do this stuff the hard way. OS_DISTRO=$(source /etc/os-release && echo $ID) OS_RELEASE=$(sed -e 's/^.*release\s\+//i; s/\s.*$//' /etc/redhat-release) OS_CODENAME=$(sed -e 's/^.*[(]\([^)]\+\)[)].*$/\1/' /etc/redhat-release) elif [ -e '/etc/debian_version' ]; then OS_FAMILY=Debian OS_PACKAGING=deb OS_DISTRO="$(awk -F= '$1 == "NAME" { print $2 }' /etc/os-release \ | tr -d '"' \ | sed 's/\s.*$//')" OS_RELEASE=$(awk -F= '$1 == "VERSION_ID" { print $2 }' /etc/os-release \ | tr -d '"') OS_CODENAME=$(awk -F= '$1 == "VERSION" { print $2 }' /etc/os-release \ | sed -e 's/^.*[(]\(.*\)[)].*$/\1/') else die "Installation is not supported on this system." fi OS_MAJOR=$(echo "${OS_RELEASE}" | cut -d . -f 1) OS_MINOR=$(echo "${OS_RELEASE}" | cut -d . -f 2) OS_PATCH=$(echo "${OS_RELEASE}" | cut -d . -f 3) OS_ARCH=$(uname -m) # ----------------------------------------------------------------------------- # Temporary Storage TMPBASE=$(mktemp -d) cleanup() { rm -rf "${TMPBASE}" } trap cleanup EXIT chmod 700 "${TMPBASE}" # ----------------------------------------------------------------------------- # Parse the Options ADD_LIST="${TMPBASE}/add-list" AUTO_UPDATES=false DRY_RUN=false LOG="${HOME}/install-perfsonar-${STARTED}" PS_REPO_VERSION=0.11-1 REPO=production SECURITY=false TUNINGS=false while echo "$1" | egrep -q -e '^--' do case "$1" in --add) echo "$2" >> "${ADD_LIST}" shift 2 ;; --auto-updates) AUTO_UPDATES=true shift ;; --dry-run) DRY_RUN=true shift ;; --no-log) LOG=/dev/null shift ;; --ps-repo-version) PS_REPO_VERSION=$2 shift 2 ;; --repo) REPO=$2 shift 2 ;; --security) SECURITY=true shift ;; --tunings) TUNINGS=true shift ;; --help) usage exit 0 ;; --*) die "Unknown option $1" ;; *) # Anything not looking like an option is plain old # arguments. The end. break ;; esac done [ $# -ge 1 ] || die_usage PS_BUNDLE=$1 shift case "${REPO}" in production|staging|nightly-minor|nightly-patch) true ;; *) die "Unknown repository '${REPO}'." ;; esac case "${PS_BUNDLE}" in testpoint|toolkit) true # This is fine. ;; tools|core) $SECURITY && die "The --security switch is inappropriate for the ${PS_BUNDLE} bundle." $TUNINGS && die "The --tunings switch is inappropriate for the ${PS_BUNDLE} bundle." ;; archive) $SECURITY && die "The --security switch is inappropriate for the ${PS_BUNDLE} bundle." $TUNINGS && die "The --tunings switch is inappropriate for the ${PS_BUNDLE} bundle." [ \( "${OS_FAMILY}" = "RedHat" \) \ -o \( "${OS_DISTRO}" = "Debian" -a "${OS_MAJOR}" -ge 11 \) \ -o \( "${OS_DISTRO}" = "Ubuntu" -a "${OS_MAJOR}" -ge 22 \) \ ] || die "The archive bundle is not supported on ${OS_DISTRO} ${OS_MAJOR}." ;; *) die "Unknown bundle '${PS_BUNDLE}'." ;; esac # We need to set an environment variable for opensearch install. # The value has to pass opensearch security checks length and character mix, # but otherwise does not matter since it will be overwritten by # a random password by perfsoanr-archive package. INSTALL_ENV="" case "${PS_BUNDLE}" in core|toolkit|archive) INSTALL_ENV="env OPENSEARCH_INITIAL_ADMIN_PASSWORD=perfSONAR123! " ;; esac # ----------------------------------------------------------------------------- [ $(id -u) -eq 0 ] || die "This program must be run as root." cleanup() { case "$?" in 0) printf "\n\nInstallation completed successfully.\n\n" | tee -a "${LOG}" ;; *) printf "\n\nINSTALLATION FAILED\n\n" | tee -a "${LOG}" ;; esac if [ -f "${LOG}" ] then echo "Output logged to ${LOG}" fi } trap cleanup EXIT install_redhat() { case "${OS_DISTRO}" in ol) # The *only* version of EL8 we support is Oracle's. MAJOR_MIN=8 ;; *) # Anything else has to be 9+ MAJOR_MIN=9 ;; esac [ "${OS_MAJOR}" -ge "${MAJOR_MIN}" ] \ || die "perfSONAR can only be installed on ${OS_DISTRO} ${MAJOR_MIN} or later." narrate Installing repositories do_dry dnf -y install epel-release case "${OS_MAJOR}" in 8) do_dry dnf config-manager --set-enabled powertools ;; 9) do_dry dnf config-manager --set-enabled crb ;; *) true ;; esac do_dry dnf -y install "http://software.internet2.edu/rpms/el${OS_MAJOR}/${OS_ARCH}/latest/packages/perfsonar-repo-${PS_REPO_VERSION}.noarch.rpm" case "${REPO}" in staging|nightly-minor|nightly-patch) narrate "Installing ${REPO} repository" do_dry dnf -y install "perfsonar-repo-${REPO}" # Remove prod repo so we can test a clean setup from chosen repo do_dry dnf -y remove "perfsonar-repo" ;; *) # Nothing to do; production is the default true ;; esac do_dry dnf clean all narrate Updating System do_dry dnf -y update narrate "Installing perfSONAR ${PS_BUNDLE} bundle" do_dry ${INSTALL_ENV}dnf -y install "perfsonar-${PS_BUNDLE}" if $AUTO_UPDATES then narrate Configuring automatic updates if ! $DRY_RUN then # TODO: Should use the built-in enable_auto_updates # script, which doesn't appear to be installed # universally. do_dry dnf -y install dnf-automatic if [ -f "/etc/dnf/automatic.conf" ]; then sed -i "s/download_updates = .*/download_updates = yes/g" /etc/dnf/automatic.conf sed -i "s/apply_updates = .*/apply_updates = yes/g" /etc/dnf/automatic.conf systemctl enable --now dnf-automatic.timer else die "Unable to find DNF-automatic configuration." fi fi fi if $SECURITY then narrate Installing security package do_dry dnf -y install perfsonar-toolkit-security do_dry /usr/lib/perfsonar/scripts/configure_firewall install fi if $TUNINGS then narrate Installing system tunings do_dry dnf -y install perfsonar-toolkit-sysctl fi if [ -s "${ADD_LIST}" ] then narrate Installing additional packages: while read PACKAGE do printf "\n%s:\n\n" "${PACKAGE}" do_dry dnf -y install "${PACKAGE}" done < "${ADD_LIST}" fi } debian_add_key() { URL=$1 IMPORT_KEY="${TMPBASE}/key" curl -o "${IMPORT_KEY}" "${URL}" KEYRING="${TMPBASE}/keyring" gpg --no-default-keyring --keyring "${KEYRING}" --import "${IMPORT_KEY}" gpg --no-default-keyring --keyring "${KEYRING}" --export \ > "/etc/apt/trusted.gpg.d/$(basename -s .key "$1")" } install_debian() { case "${OS_DISTRO}" in Debian) MAJOR_MIN=11 ;; Ubuntu) MAJOR_MIN=20 ;; *) die "${OS_DISTRO} is not supported." ;; esac [ "${OS_MAJOR}" -ge "${MAJOR_MIN}" ] \ || die "perfSONAR can only be installed on ${OS_DISTRO} ${MAJOR_MIN} or later." export DEBIAN_FRONTEND=noninteractive narrate Installing prerequisites do_dry apt-get -y install software-properties-common curl narrate Importing package lists and keys case "${REPO}" in production) do_dry curl -o /etc/apt/sources.list.d/perfsonar-release.list \ http://downloads.perfsonar.net/debian/perfsonar-release.list if ! $DRY_RUN then debian_add_key http://downloads.perfsonar.net/debian/perfsonar-official.gpg.key else echo "(Not installing perfSONAR GPG key)" fi if [ "${OS_DISTRO}" = "Ubuntu" ] then do_dry add-apt-repository -y universe fi ;; staging) LIST=/etc/apt/sources.list.d/perfsonar-minor-staging.list do_dry rm -rf "${LIST}" do_dry curl -o "${LIST}" http://downloads.perfsonar.net/debian/perfsonar-minor-staging.list if ! $DRY_RUN then debian_add_key http://downloads.perfsonar.net/debian/perfsonar-snapshot.gpg.key else echo "(Not installing perfSONAR snapshot GPG key)" fi ;; nightly-minor) LIST=/etc/apt/sources.list.d/perfsonar-minor-snapshot.list do_dry rm -rf "${LIST}" do_dry curl -o "${LIST}" http://downloads.perfsonar.net/debian/perfsonar-minor-snapshot.list if ! $DRY_RUN then debian_add_key http://downloads.perfsonar.net/debian/perfsonar-snapshot.gpg.key else echo "(Not installing perfSONAR snapshot GPG key)" fi ;; nightly-minor|nightly-patch) printf "\n\nNOTE: Installing the Debian minor snapshot repository\n\n" ;; *) # TODO: Find out how to run nightly die "Repo ${REPO} is not supported yet on ${OS_DISTRO}." ;; esac narrate Updating repositories do_dry apt-get -y update narrate Upgrading system do_dry apt-get -y upgrade narrate "Installing perfSONAR ${PS_BUNDLE} bundle" do_dry ${INSTALL_ENV}apt-get -y install "perfsonar-${PS_BUNDLE}" if $AUTO_UPDATES then narrate Configuring automatic updates do_dry apt-get -y install unattended-upgrades FILE=/etc/apt/apt.conf.d/60unattended-upgrades-perfsonar if ! $DRY_RUN then echo 'APT::Periodic::Update-Package-Lists "1";' > "${FILE}" echo 'APT::Periodic::Unattended-Upgrade "1";' >> "${FILE}" echo 'APT::Periodic::AutocleanInterval "31";' >> "${FILE}" echo 'Unattended-Upgrade::Origins-Pattern:: "origin=perfSONAR";' >> "${FILE}" else echo "(Not writing ${FILE})" fi fi if $SECURITY then narrate Installing security package do_dry apt-get -y install perfsonar-toolkit-security fi if $TUNINGS then narrate Installing system tunings do_dry apt-get -y install perfsonar-toolkit-sysctl fi if [ -s "${ADD_LIST}" ] then narrate Installing additional packages: while read PACKAGE do printf "\n%s:\n\n" "${PACKAGE}" do_dry apt-get -y install "${PACKAGE}" done < "${ADD_LIST}" fi } main() { if $DRY_RUN then narrate "Starting dry-run perfSONAR installation ${STARTED}" else narrate "Starting perfSONAR installation ${STARTED}" fi case "${OS_FAMILY}" in RedHat) install_redhat ;; Debian) install_debian ;; *) die "Installation is not supported on ${OS_FAMILY}." ;; esac # pSConfig if type -p psconfig > /dev/null then if [ $# -gt 0 ] then narrate Setting up pSConfig remotes for URL in "$@" do echo "${URL}:" psconfig remote add "${URL}" echo done fi fi } # Run main(), preserving stdout and stderr while logging both to a # file and exiting with the appropriate status. (((( \ main "$@" 2>&1 ; \ echo $? >&3 \ ) \ | tee "${LOG}" >&4) 3>&1) \ | (read XS && exit $XS) \ ) 4>&1