diff options
Diffstat (limited to 'packaging/installer/install-required-packages.sh')
-rwxr-xr-x | packaging/installer/install-required-packages.sh | 2112 |
1 files changed, 2112 insertions, 0 deletions
diff --git a/packaging/installer/install-required-packages.sh b/packaging/installer/install-required-packages.sh new file mode 100755 index 00000000..bdd52939 --- /dev/null +++ b/packaging/installer/install-required-packages.sh @@ -0,0 +1,2112 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2034 +# We use lots of computed variable names in here, so we need to disable shellcheck 2034 + +export PATH="${PATH}:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin" +export LC_ALL=C + +# Be nice on production environments +renice 19 $$ > /dev/null 2> /dev/null + +ME="${0}" + +if [ "${BASH_VERSINFO[0]}" -lt "4" ]; then + echo >&2 "Sorry! This script needs BASH version 4+, but you have BASH version ${BASH_VERSION}" + exit 1 +fi + +# These options control which packages we are going to install +# They can be pre-set, but also can be controlled with command line options +PACKAGES_NETDATA=${PACKAGES_NETDATA-1} +PACKAGES_NETDATA_PYTHON=${PACKAGES_NETDATA_PYTHON-0} +PACKAGES_NETDATA_PYTHON3=${PACKAGES_NETDATA_PYTHON3-1} +PACKAGES_DEBUG=${PACKAGES_DEBUG-0} +PACKAGES_IPRANGE=${PACKAGES_IPRANGE-0} +PACKAGES_FIREHOL=${PACKAGES_FIREHOL-0} +PACKAGES_FIREQOS=${PACKAGES_FIREQOS-0} +PACKAGES_UPDATE_IPSETS=${PACKAGES_UPDATE_IPSETS-0} +PACKAGES_NETDATA_DEMO_SITE=${PACKAGES_NETDATA_DEMO_SITE-0} +PACKAGES_NETDATA_SENSORS=${PACKAGES_NETDATA_SENSORS-0} +PACKAGES_NETDATA_DATABASE=${PACKAGES_NETDATA_DATABASE-1} +PACKAGES_NETDATA_STREAMING_COMPRESSION=${PACKAGES_NETDATA_STREAMING_COMPRESSION-0} +PACKAGES_NETDATA_EBPF=${PACKAGES_NETDATA_EBPF-1} + +# needed commands +lsb_release=$(command -v lsb_release 2> /dev/null) + +# Check which package managers are available +apk=$(command -v apk 2> /dev/null) +apt_get=$(command -v apt-get 2> /dev/null) +brew=$(command -v brew 2> /dev/null) +pkg=$(command -v pkg 2> /dev/null) +dnf=$(command -v dnf 2> /dev/null) +emerge=$(command -v emerge 2> /dev/null) +equo=$(command -v equo 2> /dev/null) +pacman=$(command -v pacman 2> /dev/null) +swupd=$(command -v swupd 2> /dev/null) +yum=$(command -v yum 2> /dev/null) +zypper=$(command -v zypper 2> /dev/null) + +distribution= +release= +version= +codename= +package_installer= +tree= +detection= +NAME= +ID= +ID_LIKE= +VERSION= +VERSION_ID= + +usage() { + cat << EOF +OPTIONS: + +${ME} [--dont-wait] [--non-interactive] \\ + [distribution DD [version VV] [codename CN]] [installer IN] [packages] + +Supported distributions (DD): + + - arch (all Arch Linux derivatives) + - centos (all CentOS derivatives) + - gentoo (all Gentoo Linux derivatives) + - sabayon (all Sabayon Linux derivatives) + - debian, ubuntu (all Debian and Ubuntu derivatives) + - redhat, fedora (all Red Hat and Fedora derivatives) + - suse, opensuse (all SUSE and openSUSE derivatives) + - clearlinux (all Clear Linux derivatives) + - macos (Apple's macOS) + +Supported installers (IN): + + - apt-get all Debian / Ubuntu Linux derivatives + - dnf newer Red Hat / Fedora Linux + - emerge all Gentoo Linux derivatives + - equo all Sabayon Linux derivatives + - pacman all Arch Linux derivatives + - yum all Red Hat / Fedora / CentOS Linux derivatives + - zypper all SUSE Linux derivatives + - apk all Alpine derivatives + - swupd all Clear Linux derivatives + - brew macOS Homebrew + - pkg FreeBSD Ports + +Supported packages (you can append many of them): + + - netdata-all all packages required to install netdata + including python, sensors, etc + + - netdata minimum packages required to install netdata + (includes python) + + - python install python + + - python3 install python3 + + - sensors install lm_sensors for monitoring h/w sensors + + - firehol-all packages required for FireHOL, FireQOS, update-ipsets + - firehol packages required for FireHOL + - fireqos packages required for FireQOS + - update-ipsets packages required for update-ipsets + + - demo packages required for running a netdata demo site + (includes nginx and various debugging tools) + + +If you don't supply the --dont-wait option, the program +will ask you before touching your system. + +EOF +} + +release2lsb_release() { + # loads the given /etc/x-release file + # this file is normally a single line containing something like + # + # X Linux release 1.2.3 (release-name) + # + # It attempts to parse it + # If it succeeds, it returns 0 + # otherwise it returns 1 + + local file="${1}" x DISTRIB_ID="" DISTRIB_RELEASE="" DISTRIB_CODENAME="" + echo >&2 "Loading ${file} ..." + + x="$(grep -v "^$" "${file}" | head -n 1)" + + if [[ "${x}" =~ ^.*[[:space:]]+Linux[[:space:]]+release[[:space:]]+.*[[:space:]]+(.*)[[:space:]]*$ ]]; then + eval "$(echo "${x}" | sed "s|^\(.*\)[[:space:]]\+Linux[[:space:]]\+release[[:space:]]\+\(.*\)[[:space:]]\+(\(.*\))[[:space:]]*$|DISTRIB_ID=\"\1\"\nDISTRIB_RELEASE=\"\2\"\nDISTRIB_CODENAME=\"\3\"|g" | grep "^DISTRIB")" + elif [[ "${x}" =~ ^.*[[:space:]]+Linux[[:space:]]+release[[:space:]]+.*[[:space:]]+$ ]]; then + eval "$(echo "${x}" | sed "s|^\(.*\)[[:space:]]\+Linux[[:space:]]\+release[[:space:]]\+\(.*\)[[:space:]]*$|DISTRIB_ID=\"\1\"\nDISTRIB_RELEASE=\"\2\"|g" | grep "^DISTRIB")" + elif [[ "${x}" =~ ^.*[[:space:]]+release[[:space:]]+.*[[:space:]]+(.*)[[:space:]]*$ ]]; then + eval "$(echo "${x}" | sed "s|^\(.*\)[[:space:]]\+release[[:space:]]\+\(.*\)[[:space:]]\+(\(.*\))[[:space:]]*$|DISTRIB_ID=\"\1\"\nDISTRIB_RELEASE=\"\2\"\nDISTRIB_CODENAME=\"\3\"|g" | grep "^DISTRIB")" + elif [[ "${x}" =~ ^.*[[:space:]]+release[[:space:]]+.*[[:space:]]+$ ]]; then + eval "$(echo "${x}" | sed "s|^\(.*\)[[:space:]]\+release[[:space:]]\+\(.*\)[[:space:]]*$|DISTRIB_ID=\"\1\"\nDISTRIB_RELEASE=\"\2\"|g" | grep "^DISTRIB")" + fi + + distribution="${DISTRIB_ID}" + version="${DISTRIB_RELEASE}" + codename="${DISTRIB_CODENAME}" + + [ -z "${distribution}" ] && echo >&2 "Cannot parse this lsb-release: ${x}" && return 1 + detection="${file}" + return 0 +} + +get_os_release() { + # Loads the /etc/os-release or /usr/lib/os-release file(s) + # Only the required fields are loaded + # + # If it manages to load a valid os-release, it returns 0 + # otherwise it returns 1 + # + # It searches the ID_LIKE field for a compatible distribution + + os_release_file= + if [ -s "/etc/os-release" ]; then + os_release_file="/etc/os-release" + elif [ -s "/usr/lib/os-release" ]; then + os_release_file="/usr/lib/os-release" + else + echo >&2 "Cannot find an os-release file ..." + return 1 + fi + + local x + echo >&2 "Loading ${os_release_file} ..." + + eval "$(grep -E "^(NAME|ID|ID_LIKE|VERSION|VERSION_ID)=" "${os_release_file}")" + for x in "${ID}" ${ID_LIKE}; do + case "${x,,}" in + almalinux | alpine | arch | centos | clear-linux-os | debian | fedora | gentoo | manjaro | opensuse-leap | opensuse-tumbleweed | ol | rhel | rocky | sabayon | sles | suse | ubuntu) + distribution="${x}" + if [[ "${ID}" = "opensuse-tumbleweed" ]]; then + version="tumbleweed" + codename="tumbleweed" + else + version="${VERSION_ID}" + codename="${VERSION}" + fi + detection="${os_release_file}" + break + ;; + *) + echo >&2 "Unknown distribution ID: ${x}" + ;; + esac + done + [[ -z "${distribution}" ]] && echo >&2 "Cannot find valid distribution in: \ +${ID} ${ID_LIKE}" && return 1 + + [[ -z "${distribution}" ]] && return 1 + return 0 +} + +get_lsb_release() { + # Loads the /etc/lsb-release file + # If it fails, it attempts to run the command: lsb_release -a + # and parse its output + # + # If it manages to find the lsb-release, it returns 0 + # otherwise it returns 1 + + if [ -f "/etc/lsb-release" ]; then + echo >&2 "Loading /etc/lsb-release ..." + local DISTRIB_ID="" DISTRIB_RELEASE="" DISTRIB_CODENAME="" + eval "$(grep -E "^(DISTRIB_ID|DISTRIB_RELEASE|DISTRIB_CODENAME)=" /etc/lsb-release)" + distribution="${DISTRIB_ID}" + version="${DISTRIB_RELEASE}" + codename="${DISTRIB_CODENAME}" + detection="/etc/lsb-release" + fi + + if [ -z "${distribution}" ] && [ -n "${lsb_release}" ]; then + echo >&2 "Cannot find distribution with /etc/lsb-release" + echo >&2 "Running command: lsb_release ..." + eval "declare -A release=( $(lsb_release -a 2> /dev/null | sed -e "s|^\(.*\):[[:space:]]*\(.*\)$|[\1]=\"\2\"|g") )" + distribution="${release["Distributor ID"]}" + version="${release[Release]}" + codename="${release[Codename]}" + detection="lsb_release" + fi + + [ -z "${distribution}" ] && echo >&2 "Cannot find valid distribution with lsb-release" && return 1 + return 0 +} + +find_etc_any_release() { + # Check for any of the known /etc/x-release files + # If it finds one, it loads it and returns 0 + # otherwise it returns 1 + + if [ -f "/etc/arch-release" ]; then + release2lsb_release "/etc/arch-release" && return 0 + fi + + if [ -f "/etc/centos-release" ]; then + release2lsb_release "/etc/centos-release" && return 0 + fi + + if [ -f "/etc/redhat-release" ]; then + release2lsb_release "/etc/redhat-release" && return 0 + fi + + if [ -f "/etc/SuSe-release" ]; then + release2lsb_release "/etc/SuSe-release" && return 0 + fi + + return 1 +} + +autodetect_distribution() { + # autodetection of distribution/OS + case "$(uname -s)" in + "Linux") + get_os_release || get_lsb_release || find_etc_any_release + ;; + "FreeBSD") + distribution="freebsd" + version="$(uname -r)" + detection="uname" + ;; + "Darwin") + distribution="macos" + version="$(uname -r)" + detection="uname" + + if [ ${EUID} -eq 0 ]; then + echo >&2 "This script does not support running as EUID 0 on macOS. Please run it as a regular user." + exit 1 + fi + ;; + *) + return 1 + ;; + esac +} + +user_picks_distribution() { + # let the user pick a distribution + + echo >&2 + echo >&2 "I NEED YOUR HELP" + echo >&2 "It seems I cannot detect your system automatically." + + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + echo >&2 " > Bailing out..." + exit 1 + fi + + if [ -z "${equo}" ] && [ -z "${emerge}" ] && [ -z "${apt_get}" ] && [ -z "${yum}" ] && [ -z "${dnf}" ] && [ -z "${pacman}" ] && [ -z "${apk}" ] && [ -z "${swupd}" ]; then + echo >&2 "And it seems I cannot find a known package manager in this system." + echo >&2 "Please open a github issue to help us support your system too." + exit 1 + fi + + local opts= + echo >&2 "I found though that the following installers are available:" + echo >&2 + [ -n "${apt_get}" ] && echo >&2 " - Debian/Ubuntu based (installer is: apt-get)" && opts="apt-get ${opts}" + [ -n "${yum}" ] && echo >&2 " - Red Hat/Fedora/CentOS based (installer is: yum)" && opts="yum ${opts}" + [ -n "${dnf}" ] && echo >&2 " - Red Hat/Fedora/CentOS based (installer is: dnf)" && opts="dnf ${opts}" + [ -n "${zypper}" ] && echo >&2 " - SuSe based (installer is: zypper)" && opts="zypper ${opts}" + [ -n "${pacman}" ] && echo >&2 " - Arch Linux based (installer is: pacman)" && opts="pacman ${opts}" + [ -n "${emerge}" ] && echo >&2 " - Gentoo based (installer is: emerge)" && opts="emerge ${opts}" + [ -n "${equo}" ] && echo >&2 " - Sabayon based (installer is: equo)" && opts="equo ${opts}" + [ -n "${apk}" ] && echo >&2 " - Alpine Linux based (installer is: apk)" && opts="apk ${opts}" + [ -n "${swupd}" ] && echo >&2 " - Clear Linux based (installer is: swupd)" && opts="swupd ${opts}" + [ -n "${brew}" ] && echo >&2 " - macOS based (installer is: brew)" && opts="brew ${opts}" + # XXX: This is being removed in another PR. + echo >&2 + + REPLY= + while [ -z "${REPLY}" ]; do + echo "To proceed please write one of these:" + echo "${opts// /, }" + if ! read -r -p ">" REPLY; then + continue + fi + + if [ "${REPLY}" = "yum" ] && [ -z "${distribution}" ]; then + REPLY= + while [ -z "${REPLY}" ]; do + if ! read -r -p "yum in centos, rhel, ol or fedora? > "; then + continue + fi + + case "${REPLY,,}" in + fedora | rhel) + distribution="rhel" + ;; + ol) + distribution="ol" + ;; + centos) + distribution="centos" + ;; + *) + echo >&2 "Please enter 'centos', 'fedora', 'ol' or 'rhel'." + REPLY= + ;; + esac + done + REPLY="yum" + fi + check_package_manager "${REPLY}" || REPLY= + done +} + +detect_package_manager_from_distribution() { + case "${1,,}" in + arch* | manjaro*) + package_installer="install_pacman" + tree="arch" + if [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${pacman}" ]; then + echo >&2 "command 'pacman' is required to install packages on a '${distribution} ${version}' system." + exit 1 + fi + ;; + + sabayon*) + package_installer="install_equo" + tree="sabayon" + if [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${equo}" ]; then + echo >&2 "command 'equo' is required to install packages on a '${distribution} ${version}' system." + # Maybe offer to fall back on emerge? Both installers exist in Sabayon... + exit 1 + fi + ;; + + alpine*) + package_installer="install_apk" + tree="alpine" + if [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${apk}" ]; then + echo >&2 "command 'apk' is required to install packages on a '${distribution} ${version}' system." + exit 1 + fi + ;; + + gentoo*) + package_installer="install_emerge" + tree="gentoo" + if [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${emerge}" ]; then + echo >&2 "command 'emerge' is required to install packages on a '${distribution} ${version}' system." + exit 1 + fi + ;; + + debian* | ubuntu*) + package_installer="install_apt_get" + tree="debian" + if [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${apt_get}" ]; then + echo >&2 "command 'apt-get' is required to install packages on a '${distribution} ${version}' system." + exit 1 + fi + ;; + + centos* | clearos* | rocky* | almalinux*) + package_installer="" + tree="centos" + [[ -n "${yum}" ]] && package_installer="install_yum" + [[ -n "${dnf}" ]] && package_installer="install_dnf" + if [[ "${IGNORE_INSTALLED}" -eq 0 ]] && [[ -z "${package_installer}" ]]; then + echo >&2 "command 'yum' or 'dnf' is required to install packages on a '${distribution} ${version}' system." + exit 1 + fi + ;; + + fedora* | redhat* | red\ hat* | rhel*) + package_installer= + tree="rhel" + [[ -n "${yum}" ]] && package_installer="install_yum" + [[ -n "${dnf}" ]] && package_installer="install_dnf" + if [[ "${IGNORE_INSTALLED}" -eq 0 ]] && [[ -z "${package_installer}" ]]; then + echo >&2 "command 'yum' or 'dnf' is required to install packages on a '${distribution} ${version}' system." + exit 1 + fi + ;; + + ol*) + package_installer= + tree="ol" + [ -n "${yum}" ] && package_installer="install_yum" + [ -n "${dnf}" ] && package_installer="install_dnf" + if [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${package_installer}" ]; then + echo >&2 "command 'yum' or 'dnf' is required to install packages on a '${distribution} ${version}' system." + exit 1 + fi + ;; + + suse* | opensuse* | sles*) + package_installer="install_zypper" + tree="suse" + if [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${zypper}" ]; then + echo >&2 "command 'zypper' is required to install packages on a '${distribution} ${version}' system." + exit 1 + fi + ;; + + clear-linux* | clearlinux*) + package_installer="install_swupd" + tree="clearlinux" + if [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${swupd}" ]; then + echo >&2 "command 'swupd' is required to install packages on a '${distribution} ${version}' system." + exit 1 + fi + ;; + + freebsd) + package_installer="install_pkg" + tree="freebsd" + if [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${pkg}" ]; then + echo >&2 "command 'pkg' is required to install packages on a '${distribution} ${version}' system." + exit 1 + fi + ;; + macos) + package_installer="install_brew" + tree="macos" + if [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${brew}" ]; then + echo >&2 "command 'brew' is required to install packages on a '${distribution} ${version}' system." + exit 1 + fi + ;; + + *) + # oops! unknown system + user_picks_distribution + ;; + esac +} + +# XXX: This is being removed in another PR. +check_package_manager() { + # This is called only when the user is selecting a package manager + # It is used to verify the user selection is right + + echo >&2 "Checking package manager: ${1}" + + case "${1}" in + apt-get) + [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${apt_get}" ] && echo >&2 "${1} is not available." && return 1 + package_installer="install_apt_get" + tree="debian" + detection="user-input" + return 0 + ;; + + dnf) + [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${dnf}" ] && echo >&2 "${1} is not available." && return 1 + package_installer="install_dnf" + if [ "${distribution}" = "centos" ]; then + tree="centos" + elif [ "${distribution}" = "ol" ]; then + tree="ol" + else + tree="rhel" + fi + detection="user-input" + return 0 + ;; + + apk) + [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${apk}" ] && echo >&2 "${1} is not available." && return 1 + package_installer="install_apk" + tree="alpine" + detection="user-input" + return 0 + ;; + + equo) + [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${equo}" ] && echo >&2 "${1} is not available." && return 1 + package_installer="install_equo" + tree="sabayon" + detection="user-input" + return 0 + ;; + + emerge) + [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${emerge}" ] && echo >&2 "${1} is not available." && return 1 + package_installer="install_emerge" + tree="gentoo" + detection="user-input" + return 0 + ;; + + pacman) + [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${pacman}" ] && echo >&2 "${1} is not available." && return 1 + package_installer="install_pacman" + tree="arch" + detection="user-input" + + return 0 + ;; + + zypper) + [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${zypper}" ] && echo >&2 "${1} is not available." && return 1 + package_installer="install_zypper" + tree="suse" + detection="user-input" + return 0 + ;; + + yum) + [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${yum}" ] && echo >&2 "${1} is not available." && return 1 + package_installer="install_yum" + if [ "${distribution}" = "centos" ]; then + tree="centos" + elif [ "${distribution}" = "ol" ]; then + tree="ol" + else + tree="rhel" + fi + detection="user-input" + return 0 + ;; + + swupd) + [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${swupd}" ] && echo >&2 "${1} is not available." && return 1 + package_installer="install_swupd" + tree="clear-linux" + detection="user-input" + return 0 + ;; + + brew) + [ "${IGNORE_INSTALLED}" -eq 0 ] && [ -z "${brew}" ] && echo >&2 "${1} is not available." && return 1 + package_installer="install_brew" + tree="macos" + detection="user-input" + + return 0 + ;; + + *) + echo >&2 "Invalid package manager: '${1}'." + return 1 + ;; + esac +} + +require_cmd() { + # check if any of the commands given as argument + # are present on this system + # If any of them is available, it returns 0 + # otherwise 1 + + [ "${IGNORE_INSTALLED}" -eq 1 ] && return 1 + + local wanted found + for wanted in "${@}"; do + if command -v "${wanted}" > /dev/null 2>&1; then + found="$(command -v "$wanted" 2> /dev/null)" + fi + [ -n "${found}" ] && [ -x "${found}" ] && return 0 + done + return 1 +} + +declare -A pkg_find=( + ['gentoo']="sys-apps/findutils" + ['fedora']="findutils" + ['clearlinux']="findutils" + ['rhel']="findutils" + ['centos']="findutils" + ['macos']="NOTREQUIRED" + ['freebsd']="NOTREQUIRED" + ['default']="WARNING|" +) + +declare -A pkg_distro_sdk=( + ['alpine']="alpine-sdk" + ['default']="NOTREQUIRED" +) + +declare -A pkg_autoconf=( + ['gentoo']="sys-devel/autoconf" + ['clearlinux']="c-basic" + ['default']="autoconf" +) + +# required to compile netdata with --enable-sse +# https://github.com/firehol/netdata/pull/450 +declare -A pkg_autoconf_archive=( + ['gentoo']="sys-devel/autoconf-archive" + ['clearlinux']="c-basic" + ['alpine']="WARNING|" + ['default']="autoconf-archive" + + # exceptions + ['centos-6']="WARNING|" + ['rhel-6']="WARNING|" + ['rhel-7']="WARNING|" +) + +declare -A pkg_autogen=( + ['gentoo']="sys-devel/autogen" + ['clearlinux']="c-basic" + ['alpine']="WARNING|" + ['default']="autogen" + + # exceptions + ['centos-6']="WARNING|" + ['rhel-6']="WARNING|" + ['centos-9']="NOTREQUIRED|" + ['rhel-9']="NOTREQUIRED|" +) + +declare -A pkg_automake=( + ['gentoo']="sys-devel/automake" + ['clearlinux']="c-basic" + ['default']="automake" +) + +# Required to build libwebsockets and libmosquitto on some systems. +declare -A pkg_cmake=( + ['gentoo']="dev-util/cmake" + ['clearlinux']="c-basic" + ['default']="cmake" +) + +# bison and flex are required by Fluent-Bit +declare -A pkg_bison=( + ['default']="bison" +) + +declare -A pkg_flex=( + ['default']="flex" +) + +# fts-dev is required by Fluent-Bit on Alpine +declare -A pkg_fts_dev=( + ['default']="NOTREQUIRED" + ['alpine']="musl-fts-dev" + ['alpine-3.16.9']="fts-dev" +) + +# cmake3 is required by Fluent-Bit on CentOS 7 +declare -A pkg_cmake3=( + ['default']="NOTREQUIRED" + ['centos-7']="cmake3" +) + +declare -A pkg_json_c_dev=( + ['alpine']="json-c-dev" + ['arch']="json-c" + ['clearlinux']="devpkg-json-c" + ['debian']="libjson-c-dev" + ['gentoo']="dev-libs/json-c" + ['sabayon']="dev-libs/json-c" + ['suse']="libjson-c-devel" + ['freebsd']="json-c" + ['macos']="json-c" + ['default']="json-c-devel" +) + +#TODO:: clearlinux ? +declare -A pkg_libyaml_dev=( + ['alpine']="yaml-dev" + ['arch']="libyaml" + ['clearlinux']="yaml-dev" + ['debian']="libyaml-dev" + ['gentoo']="dev-libs/libyaml" + ['sabayon']="dev-libs/libyaml" + ['suse']="libyaml-devel" + ['freebsd']="libyaml" + ['macos']="libyaml" + ['default']="libyaml-devel" +) + +declare -A pkg_libatomic=( + ['arch']="NOTREQUIRED" + ['clearlinux']="NOTREQUIRED" + ['debian']="libatomic1" + ['freebsd']="NOTREQUIRED" + ['gentoo']="NOTREQUIRED" + ['macos']="NOTREQUIRED" + ['sabayon']="NOTREQUIRED" + ['suse']="libatomic1" + ['ubuntu']="libatomic1" + ['default']="libatomic" +) + +declare -A pkg_libsystemd_dev=( + ['alpine']="NOTREQUIRED" + ['arch']="NOTREQUIRED" # inherently present on systems actually using systemd + ['clearlinux']="system-os-dev" + ['debian']="libsystemd-dev" + ['freebsd']="NOTREQUIRED" + ['gentoo']="NOTREQUIRED" # inherently present on systems actually using systemd + ['macos']="NOTREQUIRED" + ['sabayon']="NOTREQUIRED" # inherently present on systems actually using systemd + ['ubuntu']="libsystemd-dev" + ['default']="systemd-devel" +) + +declare -A pkg_bridge_utils=( + ['gentoo']="net-misc/bridge-utils" + ['clearlinux']="network-basic" + ['macos']="WARNING|" + ['default']="bridge-utils" +) + +declare -A pkg_curl=( + ['gentoo']="net-misc/curl" + ['sabayon']="net-misc/curl" + ['default']="curl" +) + +declare -A pkg_gzip=( + ['gentoo']="app-arch/gzip" + ['macos']="NOTREQUIRED" + ['default']="gzip" +) + +declare -A pkg_tar=( + ['gentoo']="app-arch/tar" + ['clearlinux']="os-core-update" + ['macos']="NOTREQUIRED" + ['freebsd']="NOTREQUIRED" + ['default']="tar" +) + +declare -A pkg_git=( + ['gentoo']="dev-vcs/git" + ['default']="git" +) + +declare -A pkg_gcc=( + ['gentoo']="sys-devel/gcc" + ['clearlinux']="c-basic" + ['macos']="NOTREQUIRED" + ['default']="gcc" +) + +# g++, required for building protobuf +# All three cases of this not being required are systems that implicitly +# include g++ when installing gcc. +declare -A pkg_gxx=( + ['alpine']="g++" + ['arch']="NOTREQUIRED" + ['clearlinux']="c-basic" + ['debian']="g++" + ['gentoo']="NOTREQUIRED" + ['macos']="NOTREQUIRED" + ['ubuntu']="g++" + ['freebsd']="NOTREQUIRED" + ['default']="gcc-c++" +) + +declare -A pkg_gdb=( + ['gentoo']="sys-devel/gdb" + ['macos']="NOTREQUIRED" + ['default']="gdb" +) + +declare -A pkg_iotop=( + ['gentoo']="sys-process/iotop" + ['macos']="WARNING|" + ['default']="iotop" +) + +declare -A pkg_iproute2=( + ['alpine']="iproute2" + ['debian']="iproute2" + ['gentoo']="sys-apps/iproute2" + ['sabayon']="sys-apps/iproute2" + ['clearlinux']="iproute2" + ['macos']="WARNING|" + ['default']="iproute" + + # exceptions + ['ubuntu-12.04']="iproute" +) + +declare -A pkg_ipset=( + ['gentoo']="net-firewall/ipset" + ['clearlinux']="network-basic" + ['macos']="WARNING|" + ['default']="ipset" +) + +declare -A pkg_jq=( + ['gentoo']="app-misc/jq" + ['default']="jq" +) + +declare -A pkg_iptables=( + ['gentoo']="net-firewall/iptables" + ['macos']="WARNING|" + ['default']="iptables" +) + +declare -A pkg_libz_dev=( + ['alpine']="zlib-dev" + ['arch']="zlib" + ['centos']="zlib-devel" + ['debian']="zlib1g-dev" + ['gentoo']="sys-libs/zlib" + ['sabayon']="sys-libs/zlib" + ['rhel']="zlib-devel" + ['ol']="zlib-devel" + ['suse']="zlib-devel" + ['clearlinux']="devpkg-zlib" + ['macos']="NOTREQUIRED" + ['freebsd']="lzlib" + ['default']="" +) + +declare -A pkg_libuuid_dev=( + ['alpine']="util-linux-dev" + ['arch']="util-linux" + ['centos']="libuuid-devel" + ['clearlinux']="devpkg-util-linux" + ['debian']="uuid-dev" + ['gentoo']="sys-apps/util-linux" + ['sabayon']="sys-apps/util-linux" + ['rhel']="libuuid-devel" + ['ol']="libuuid-devel" + ['suse']="libuuid-devel" + ['macos']="ossp-uuid" + ['freebsd']="e2fsprogs-libuuid" + ['default']="" +) + +declare -A pkg_libmnl_dev=( + ['alpine']="libmnl-dev" + ['arch']="libmnl" + ['centos']="libmnl-devel" + ['debian']="libmnl-dev" + ['gentoo']="net-libs/libmnl" + ['sabayon']="net-libs/libmnl" + ['rhel']="libmnl-devel" + ['ol']="libmnl-devel" + ['suse']="libmnl-devel" + ['clearlinux']="devpkg-libmnl" + ['macos']="NOTREQUIRED" + ['default']="" +) + +declare -A pkg_lm_sensors=( + ['alpine']="lm_sensors" + ['arch']="lm_sensors" + ['centos']="lm_sensors" + ['debian']="lm-sensors" + ['gentoo']="sys-apps/lm-sensors" + ['sabayon']="sys-apps/lm_sensors" + ['rhel']="lm_sensors" + ['suse']="sensors" + ['clearlinux']="lm-sensors" + ['macos']="WARNING|" + ['freebsd']="NOTREQUIRED" + ['default']="lm_sensors" +) + +declare -A pkg_logwatch=( + ['gentoo']="sys-apps/logwatch" + ['clearlinux']="WARNING|" + ['macos']="WARNING|" + ['default']="logwatch" +) + +declare -A pkg_lxc=( + ['gentoo']="app-emulation/lxc" + ['clearlinux']="WARNING|" + ['macos']="WARNING|" + ['default']="lxc" +) + +declare -A pkg_mailutils=( + ['gentoo']="net-mail/mailutils" + ['clearlinux']="WARNING|" + ['macos']="WARNING|" + ['default']="mailutils" +) + +declare -A pkg_make=( + ['gentoo']="sys-devel/make" + ['macos']="NOTREQUIRED" + ['freebsd']="gmake" + ['default']="make" +) + +declare -A pkg_nginx=( + ['gentoo']="www-servers/nginx" + ['default']="nginx" +) + +declare -A pkg_postfix=( + ['gentoo']="mail-mta/postfix" + ['macos']="WARNING|" + ['default']="postfix" +) + +declare -A pkg_pkg_config=( + ['alpine']="pkgconfig" + ['arch']="pkgconfig" + ['centos']="pkgconfig" + ['debian']="pkg-config" + ['gentoo']="virtual/pkgconfig" + ['sabayon']="virtual/pkgconfig" + ['rhel']="pkgconfig" + ['ol']="pkgconfig" + ['suse']="pkg-config" + ['freebsd']="pkgconf" + ['clearlinux']="c-basic" + ['default']="pkg-config" +) + +declare -A pkg_python=( + ['gentoo']="dev-lang/python" + ['sabayon']="dev-lang/python:2.7" + ['clearlinux']="python-basic" + ['default']="python" + + # Exceptions + ['macos']="WARNING|" + ['centos-8']="python2" +) + +declare -A pkg_python_pip=( + ['alpine']="py-pip" + ['gentoo']="dev-python/pip" + ['sabayon']="dev-python/pip" + ['clearlinux']="python-basic" + ['macos']="WARNING|" + ['default']="python-pip" +) + +declare -A pkg_python3_pip=( + ['alpine']="py3-pip" + ['arch']="python-pip" + ['gentoo']="dev-python/pip" + ['sabayon']="dev-python/pip" + ['clearlinux']="python3-basic" + ['macos']="NOTREQUIRED" + ['default']="python3-pip" +) + +declare -A pkg_python_requests=( + ['alpine']="py-requests" + ['arch']="python2-requests" + ['centos']="python-requests" + ['debian']="python-requests" + ['gentoo']="dev-python/requests" + ['sabayon']="dev-python/requests" + ['rhel']="python-requests" + ['suse']="python-requests" + ['clearlinux']="python-extras" + ['macos']="WARNING|" + ['default']="python-requests" + ['alpine-3.1.4']="WARNING|" + ['alpine-3.2.3']="WARNING|" +) + +declare -A pkg_python3_requests=( + ['alpine']="py3-requests" + ['arch']="python-requests" + ['centos']="WARNING|" + ['debian']="WARNING|" + ['gentoo']="dev-python/requests" + ['sabayon']="dev-python/requests" + ['rhel']="WARNING|" + ['suse']="WARNING|" + ['clearlinux']="python-extras" + ['macos']="WARNING|" + ['default']="WARNING|" + + ['centos-7']="python36-requests" + ['centos-8']="python3-requests" + ['rhel-7']="python36-requests" + ['rhel-8']="python3-requests" + ['ol-8']="python3-requests" +) + +declare -A pkg_lz4=( + ['alpine']="lz4-dev" + ['debian']="liblz4-dev" + ['ubuntu']="liblz4-dev" + ['suse']="liblz4-devel" + ['gentoo']="app-arch/lz4" + ['clearlinux']="devpkg-lz4" + ['arch']="lz4" + ['macos']="lz4" + ['freebsd']="liblz4" + ['default']="lz4-devel" +) + +declare -A pkg_zstd=( + ['alpine']="zstd-dev" + ['debian']="libzstd-dev" + ['ubuntu']="libzstd-dev" + ['gentoo']="app-arch/zstd" + ['clearlinux']="zstd-devel" + ['arch']="zstd" + ['macos']="zstd" + ['freebsd']="zstd" + ['default']="libzstd-devel" +) + +declare -A pkg_libuv=( + ['alpine']="libuv-dev" + ['debian']="libuv1-dev" + ['ubuntu']="libuv1-dev" + ['gentoo']="dev-libs/libuv" + ['arch']="libuv" + ['clearlinux']="devpkg-libuv" + ['macos']="libuv" + ['freebsd']="libuv" + ['default']="libuv-devel" +) + +declare -A pkg_openssl=( + ['alpine']="openssl-dev" + ['debian']="libssl-dev" + ['ubuntu']="libssl-dev" + ['suse']="libopenssl-devel" + ['clearlinux']="devpkg-openssl" + ['gentoo']="dev-libs/openssl" + ['arch']="openssl" + ['freebsd']="openssl" + ['macos']="openssl" + ['default']="openssl-devel" +) + +declare -A pkg_python3=( + ['gentoo']="dev-lang/python" + ['sabayon']="dev-lang/python:3.4" + ['clearlinux']="python3-basic" + ['macos']="python" + ['default']="python3" + + # exceptions + ['centos-6']="WARNING|" +) + +declare -A pkg_screen=( + ['gentoo']="app-misc/screen" + ['sabayon']="app-misc/screen" + ['clearlinux']="sysadmin-basic" + ['default']="screen" +) + +declare -A pkg_sudo=( + ['gentoo']="app-admin/sudo" + ['macos']="NOTREQUIRED" + ['default']="sudo" +) + +declare -A pkg_sysstat=( + ['gentoo']="app-admin/sysstat" + ['macos']="WARNING|" + ['default']="sysstat" +) + +declare -A pkg_tcpdump=( + ['gentoo']="net-analyzer/tcpdump" + ['clearlinux']="network-basic" + ['default']="tcpdump" +) + +declare -A pkg_traceroute=( + ['alpine']=" " + ['gentoo']="net-analyzer/traceroute" + ['clearlinux']="network-basic" + ['macos']="NOTREQUIRED" + ['default']="traceroute" +) + +declare -A pkg_valgrind=( + ['gentoo']="dev-util/valgrind" + ['default']="valgrind" +) + +declare -A pkg_ulogd=( + ['centos']="WARNING|" + ['rhel']="WARNING|" + ['ol']="WARNING|" + ['clearlinux']="WARNING|" + ['gentoo']="app-admin/ulogd" + ['arch']="ulogd" + ['macos']="WARNING|" + ['default']="ulogd2" +) + +declare -A pkg_unzip=( + ['gentoo']="app-arch/unzip" + ['macos']="NOTREQUIRED" + ['default']="unzip" +) + +declare -A pkg_zip=( + ['gentoo']="app-arch/zip" + ['macos']="NOTREQUIRED" + ['default']="zip" +) + +declare -A pkg_libelf=( + ['alpine']="elfutils-dev" + ['arch']="libelf" + ['gentoo']="virtual/libelf" + ['sabayon']="virtual/libelf" + ['debian']="libelf-dev" + ['ubuntu']="libelf-dev" + ['fedora']="elfutils-libelf-devel" + ['centos']="elfutils-libelf-devel" + ['rhel']="elfutils-libelf-devel" + ['ol']="elfutils-libelf-devel" + ['clearlinux']="devpkg-elfutils" + ['suse']="libelf-devel" + ['macos']="NOTREQUIRED" + ['freebsd']="NOTREQUIRED" + ['default']="libelf-devel" + + # exceptions + ['alpine-3.5']="libelf-dev" + ['alpine-3.4']="libelf-dev" + ['alpine-3.3']="libelf-dev" +) + +validate_package_trees() { + if type -t validate_tree_${tree} > /dev/null; then + validate_tree_${tree} + fi +} + +validate_installed_package() { + validate_${package_installer} "${p}" +} + +suitable_package() { + local package="${1//-/_}" p="" v="${version//.*/}" + + echo >&2 "Searching for ${package} ..." + + eval "p=\${pkg_${package}['${distribution,,}-${version,,}']}" + [ -z "${p}" ] && eval "p=\${pkg_${package}['${distribution,,}-${v,,}']}" + [ -z "${p}" ] && eval "p=\${pkg_${package}['${distribution,,}']}" + [ -z "${p}" ] && eval "p=\${pkg_${package}['${tree}-${version}']}" + [ -z "${p}" ] && eval "p=\${pkg_${package}['${tree}-${v}']}" + [ -z "${p}" ] && eval "p=\${pkg_${package}['${tree}']}" + [ -z "${p}" ] && eval "p=\${pkg_${package}['default']}" + + if [[ "${p/|*/}" =~ ^(ERROR|WARNING|INFO)$ ]]; then + echo >&2 "${p/|*/}" + echo >&2 "package ${1} is not available in this system." + if [ -z "${p/*|/}" ]; then + echo >&2 "You may try to install without it." + else + echo >&2 "${p/*|/}" + fi + echo >&2 + return 1 + elif [ "${p}" = "NOTREQUIRED" ]; then + return 0 + elif [ -z "${p}" ]; then + echo >&2 "WARNING" + echo >&2 "package ${1} is not available in this system." + echo >&2 + return 1 + else + if [ "${IGNORE_INSTALLED}" -eq 0 ]; then + validate_installed_package "${p}" + else + echo "${p}" + fi + return 0 + fi +} + +packages() { + # detect the packages we need to install on this system + + # ------------------------------------------------------------------------- + # basic build environment + + suitable_package distro-sdk + suitable_package libatomic + + require_cmd git || suitable_package git + require_cmd find || suitable_package find + + require_cmd gcc || require_cmd clang || + require_cmd gcc-multilib || suitable_package gcc + require_cmd g++ || require_cmd clang++ || suitable_package gxx + + require_cmd make || suitable_package make + require_cmd autoconf || suitable_package autoconf + suitable_package autoconf-archive + require_cmd autogen || suitable_package autogen + require_cmd automake || suitable_package automake + require_cmd pkg-config || suitable_package pkg-config + require_cmd cmake || suitable_package cmake + require_cmd cmake3 || suitable_package cmake3 + + # ------------------------------------------------------------------------- + # debugging tools for development + + if [ "${PACKAGES_DEBUG}" -ne 0 ]; then + require_cmd traceroute || suitable_package traceroute + require_cmd tcpdump || suitable_package tcpdump + require_cmd screen || suitable_package screen + + if [ "${PACKAGES_NETDATA}" -ne 0 ]; then + require_cmd gdb || suitable_package gdb + require_cmd valgrind || suitable_package valgrind + fi + fi + + # ------------------------------------------------------------------------- + # common command line tools + + if [ "${PACKAGES_NETDATA}" -ne 0 ]; then + require_cmd tar || suitable_package tar + require_cmd curl || suitable_package curl + require_cmd gzip || suitable_package gzip + require_cmd bison || suitable_package bison + require_cmd flex || suitable_package flex + fi + + # ------------------------------------------------------------------------- + # firehol/fireqos/update-ipsets command line tools + + if [ "${PACKAGES_FIREQOS}" -ne 0 ]; then + require_cmd ip || suitable_package iproute2 + fi + + if [ "${PACKAGES_FIREHOL}" -ne 0 ]; then + require_cmd iptables || suitable_package iptables + require_cmd ipset || suitable_package ipset + require_cmd ulogd ulogd2 || suitable_package ulogd + require_cmd traceroute || suitable_package traceroute + require_cmd bridge || suitable_package bridge-utils + fi + + if [ "${PACKAGES_UPDATE_IPSETS}" -ne 0 ]; then + require_cmd ipset || suitable_package ipset + require_cmd zip || suitable_package zip + require_cmd funzip || suitable_package unzip + fi + + # ------------------------------------------------------------------------- + # netdata libraries + + if [ "${PACKAGES_NETDATA}" -ne 0 ]; then + suitable_package libz-dev + suitable_package libuuid-dev + suitable_package libmnl-dev + suitable_package json-c-dev + suitable_package fts-dev + suitable_package libyaml-dev + suitable_package libsystemd-dev + fi + + # ------------------------------------------------------------------------- + # sensors + + if [ "${PACKAGES_NETDATA_SENSORS}" -ne 0 ]; then + require_cmd sensors || suitable_package lm_sensors + fi + + # ------------------------------------------------------------------------- + # netdata database + if [ "${PACKAGES_NETDATA_DATABASE}" -ne 0 ]; then + suitable_package libuv + suitable_package lz4 + suitable_package openssl + fi + + if [ "${PACKAGES_NETDATA_STREAMING_COMPRESSION}" -ne 0 ]; then + suitable_package zstd + fi + + # ------------------------------------------------------------------------- + # ebpf plugin + if [ "${PACKAGES_NETDATA_EBPF}" -ne 0 ]; then + suitable_package libelf + fi + + # ------------------------------------------------------------------------- + # python2 + + if [ "${PACKAGES_NETDATA_PYTHON}" -ne 0 ]; then + require_cmd python || suitable_package python + + # suitable_package python-requests + # suitable_package python-pip + fi + + # ------------------------------------------------------------------------- + # python3 + + if [ "${PACKAGES_NETDATA_PYTHON3}" -ne 0 ]; then + require_cmd python3 || suitable_package python3 + + # suitable_package python3-requests + # suitable_package python3-pip + fi + + # ------------------------------------------------------------------------- + # applications needed for the netdata demo sites + + if [ "${PACKAGES_NETDATA_DEMO_SITE}" -ne 0 ]; then + require_cmd sudo || suitable_package sudo + require_cmd jq || suitable_package jq + require_cmd nginx || suitable_package nginx + require_cmd postconf || suitable_package postfix + require_cmd lxc-create || suitable_package lxc + require_cmd logwatch || suitable_package logwatch + require_cmd mail || suitable_package mailutils + require_cmd iostat || suitable_package sysstat + require_cmd iotop || suitable_package iotop + fi +} + +DRYRUN=0 +run() { + + printf >&2 "%q " "${@}" + printf >&2 "\n" + + if [ ! "${DRYRUN}" -eq 1 ]; then + "${@}" + return $? + fi + return 0 +} + +sudo= +if [ ${UID} -ne 0 ]; then + sudo="sudo" +fi + +# ----------------------------------------------------------------------------- +# debian / ubuntu + +validate_install_apt_get() { + echo >&2 " > Checking if package '${*}' is installed..." + [ "$(dpkg-query -W --showformat='${Status}\n' "${*}")" = "install ok installed" ] || echo "${*}" +} + +install_apt_get() { + local opts="" + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + # http://serverfault.com/questions/227190/how-do-i-ask-apt-get-to-skip-any-interactive-post-install-configuration-steps + export DEBIAN_FRONTEND="noninteractive" + opts="${opts} -yq" + fi + + read -r -a apt_opts <<< "$opts" + + # update apt repository caches + + echo >&2 "NOTE: Running apt-get update and updating your APT caches ..." + if [ "${version}" = 8 ]; then + echo >&2 "WARNING: You seem to be on Debian 8 (jessie) which is old enough we have to disable Check-Valid-Until checks" + if ! cat /etc/apt/sources.list /etc/apt/sources.list.d/* 2> /dev/null | grep -q jessie-backports; then + echo >&2 "We also have to enable the jessie-backports repository" + if prompt "Is this okay?"; then + ${sudo} /bin/sh -c 'echo "deb http://archive.debian.org/debian/ jessie-backports main contrib non-free" >> /etc/apt/sources.list.d/99-archived.list' + fi + fi + run ${sudo} apt-get "${apt_opts[@]}" -o Acquire::Check-Valid-Until=false update + else + run ${sudo} apt-get "${apt_opts[@]}" update + fi + + # install the required packages + run ${sudo} apt-get "${apt_opts[@]}" install "${@}" +} + +# ----------------------------------------------------------------------------- +# centos / rhel + +prompt() { + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode, assuming yes (y)" + echo >&2 " > Would have prompted for ${1} ..." + return 0 + fi + + while true; do + read -r -p "${1} [y/n] " yn + case $yn in + [Yy]*) return 0 ;; + [Nn]*) return 1 ;; + *) echo >&2 "Please answer with yes (y) or no (n)." ;; + esac + done +} + +validate_tree_freebsd() { + local opts= + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + opts="-y" + fi + + echo >&2 " > FreeBSD Version: ${version} ..." + + make="make" + echo >&2 " > Checking for gmake ..." + if ! pkg query %n-%v | grep -q gmake; then + if prompt "gmake is required to build on FreeBSD and is not installed. Shall I install it?"; then + # shellcheck disable=2086 + run ${sudo} pkg install ${opts} gmake + fi + fi +} + +validate_tree_ol() { + local opts= + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + opts="-y" + fi + + if [[ "${version}" =~ ^8(\..*)?$ ]]; then + echo " > Checking for CodeReady Builder ..." + if ! run ${sudo} dnf repolist | grep -q codeready; then + if prompt "CodeReady Builder not found, shall I install it?"; then + cat > /etc/yum.repos.d/ol8_codeready.repo <<-EOF + [ol8_codeready_builder] + name=Oracle Linux \$releasever CodeReady Builder (\$basearch) + baseurl=http://yum.oracle.com/repo/OracleLinux/OL8/codeready/builder/\$basearch + gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-oracle + gpgcheck=1 + enabled=1 + EOF + fi + fi + elif [[ "${version}" =~ ^9(\..*)?$ ]]; then + echo " > Checking for CodeReady Builder ..." + if ! run ${sudo} dnf repolist enabled | grep -q codeready; then + if prompt "CodeReady Builder not enabled, shall I enable it?"; then + run ${sudo} dnf config-manager --set-enabled ol9_codeready_builder + fi + fi + fi +} + +validate_tree_centos() { + local opts= + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + opts="-y" + fi + + echo >&2 " > CentOS Version: ${version} ..." + + if [[ "${version}" =~ ^9(\..*)?$ ]]; then + echo >&2 " > Checking for config-manager ..." + if ! run ${sudo} dnf config-manager --help; then + if prompt "config-manager not found, shall I install it?"; then + # shellcheck disable=2086 + run ${sudo} dnf ${opts} install 'dnf-command(config-manager)' + fi + fi + + echo >&2 " > Checking for CRB ..." + # shellcheck disable=2086 + if ! run dnf ${sudo} repolist | grep CRB; then + if prompt "CRB not found, shall I install it?"; then + # shellcheck disable=2086 + run ${sudo} dnf ${opts} config-manager --set-enabled crb + fi + fi + elif [[ "${version}" =~ ^8(\..*)?$ ]]; then + echo >&2 " > Checking for config-manager ..." + if ! run ${sudo} yum config-manager --help; then + if prompt "config-manager not found, shall I install it?"; then + # shellcheck disable=2086 + run ${sudo} yum ${opts} install 'dnf-command(config-manager)' + fi + fi + + echo >&2 " > Checking for PowerTools ..." + # shellcheck disable=2086 + if ! run yum ${sudo} repolist | grep PowerTools; then + if prompt "PowerTools not found, shall I install it?"; then + # shellcheck disable=2086 + run ${sudo} yum ${opts} config-manager --set-enabled powertools + fi + fi + + echo >&2 " > Updating libarchive ..." + # shellcheck disable=2086 + run ${sudo} yum ${opts} install libarchive + + elif [[ "${version}" =~ ^7(\..*)?$ ]]; then + echo >&2 " > Checking for EPEL ..." + if ! rpm -qa | grep epel-release > /dev/null; then + if prompt "EPEL not found, shall I install it?"; then + # shellcheck disable=2086 + run ${sudo} yum ${opts} install epel-release + fi + fi + elif [[ "${version}" =~ ^6\..*$ ]]; then + echo >&2 " > Detected CentOS 6.x ..." + echo >&2 " > Checking for Okay ..." + if ! rpm -qa | grep okay > /dev/null; then + if prompt "okay not found, shall I install it?"; then + # shellcheck disable=2086 + run ${sudo} yum ${opts} install http://repo.okay.com.mx/centos/6/x86_64/release/okay-release-1-3.el6.noarch.rpm + fi + fi + + fi +} + +validate_install_yum() { + echo >&2 " > Checking if package '${*}' is installed..." + yum list installed "${*}" > /dev/null 2>&1 || echo "${*}" +} + +install_yum() { + # download the latest package info + if [ "${DRYRUN}" -eq 1 ]; then + echo >&2 " >> IMPORTANT << " + echo >&2 " Please make sure your system is up to date" + echo >&2 " by running: ${sudo} yum update " + echo >&2 + fi + + local opts= + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + # http://unix.stackexchange.com/questions/87822/does-yum-have-an-equivalent-to-apt-aptitudes-debian-frontend-noninteractive + opts="-y" + fi + + read -r -a yum_opts <<< "${opts}" + + # install the required packages + run ${sudo} yum "${yum_opts[@]}" install "${@}" +} + +# ----------------------------------------------------------------------------- +# fedora + +validate_install_dnf() { + echo >&2 " > Checking if package '${*}' is installed..." + dnf list installed "${*}" > /dev/null 2>&1 || echo "${*}" +} + +install_dnf() { + # download the latest package info + if [ "${DRYRUN}" -eq 1 ]; then + echo >&2 " >> IMPORTANT << " + echo >&2 " Please make sure your system is up to date" + echo >&2 " by running: ${sudo} dnf update " + echo >&2 + fi + + local opts= + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + # man dnf + opts="-y" + fi + + # install the required packages + # --setopt=strict=0 allows dnf to proceed + # installing whatever is available + # even if a package is not found + opts="$opts --setopt=strict=0" + read -r -a dnf_opts <<< "$opts" + run ${sudo} dnf "${dnf_opts[@]}" install "${@}" +} + +# ----------------------------------------------------------------------------- +# gentoo + +validate_install_emerge() { + echo "${*}" +} + +install_emerge() { + # download the latest package info + # we don't do this for emerge - it is very slow + # and most users are expected to do this daily + # emerge --sync + if [ "${DRYRUN}" -eq 1 ]; then + echo >&2 " >> IMPORTANT << " + echo >&2 " Please make sure your system is up to date" + echo >&2 " by running: ${sudo} emerge --sync or ${sudo} eix-sync " + echo >&2 + fi + + local opts="--ask" + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + opts="" + fi + + read -r -a emerge_opts <<< "$opts" + + # install the required packages + run ${sudo} emerge "${emerge_opts[@]}" -v --noreplace "${@}" +} + +# ----------------------------------------------------------------------------- +# alpine + +validate_install_apk() { + echo "${*}" +} + +install_apk() { + # download the latest package info + if [ "${DRYRUN}" -eq 1 ]; then + echo >&2 " >> IMPORTANT << " + echo >&2 " Please make sure your system is up to date" + echo >&2 " by running: ${sudo} apk update " + echo >&2 + fi + + local opts="--force-broken-world" + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + else + opts="${opts} -i" + fi + + read -r -a apk_opts <<< "$opts" + + # install the required packages + run ${sudo} apk add "${apk_opts[@]}" "${@}" +} + +# ----------------------------------------------------------------------------- +# sabayon + +validate_install_equo() { + echo >&2 " > Checking if package '${*}' is installed..." + equo s --installed "${*}" > /dev/null 2>&1 || echo "${*}" +} + +install_equo() { + # download the latest package info + if [ "${DRYRUN}" -eq 1 ]; then + echo >&2 " >> IMPORTANT << " + echo >&2 " Please make sure your system is up to date" + echo >&2 " by running: ${sudo} equo up " + echo >&2 + fi + + local opts="-av" + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + opts="-v" + fi + + read -r -a equo_opts <<< "$opts" + + # install the required packages + run ${sudo} equo i "${equo_opts[@]}" "${@}" +} + +# ----------------------------------------------------------------------------- +# arch + +PACMAN_DB_SYNCED=0 +validate_install_pacman() { + + if [ "${PACMAN_DB_SYNCED}" -eq 0 ]; then + echo >&2 " > Running pacman -Sy to sync the database" + local x + x=$(pacman -Sy) + [ -z "${x}" ] && echo "${*}" + PACMAN_DB_SYNCED=1 + fi + echo >&2 " > Checking if package '${*}' is installed..." + + # In pacman, you can utilize alternative flags to exactly match package names, + # but is highly likely we require pattern matching too in this so we keep -s and match + # the exceptional cases like so + local x="" + case "${package}" in + "gcc") + # Temporary workaround: In archlinux, default installation includes runtime libs under package "gcc" + # These are not sufficient for netdata install, so we need to make sure that the appropriate libraries are there + # by ensuring devel libs are available + x=$(pacman -Qs "${*}" | grep "base-devel") + ;; + "tar") + x=$(pacman -Qs "${*}" | grep "local/tar") + ;; + "make") + x=$(pacman -Qs "${*}" | grep "local/make ") + ;; + *) + x=$(pacman -Qs "${*}") + ;; + esac + + [ -z "${x}" ] && echo "${*}" +} + +install_pacman() { + # download the latest package info + if [ "${DRYRUN}" -eq 1 ]; then + echo >&2 " >> IMPORTANT << " + echo >&2 " Please make sure your system is up to date" + echo >&2 " by running: ${sudo} pacman -Syu " + echo >&2 + fi + + # install the required packages + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + # http://unix.stackexchange.com/questions/52277/pacman-option-to-assume-yes-to-every-question/52278 + # Try the noconfirm option, if that fails, go with the legacy way for non-interactive + run ${sudo} pacman --noconfirm --needed -S "${@}" || yes | run ${sudo} pacman --needed -S "${@}" + else + run ${sudo} pacman --needed -S "${@}" + fi +} + +# ----------------------------------------------------------------------------- +# suse / opensuse + +validate_install_zypper() { + rpm -q "${*}" > /dev/null 2>&1 || echo "${*}" +} + +install_zypper() { + # download the latest package info + if [ "${DRYRUN}" -eq 1 ]; then + echo >&2 " >> IMPORTANT << " + echo >&2 " Please make sure your system is up to date" + echo >&2 " by running: ${sudo} zypper update " + echo >&2 + fi + + local opts="--ignore-unknown" + local install_opts="--allow-downgrade" + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + # http://unix.stackexchange.com/questions/82016/how-to-use-zypper-in-bash-scripts-for-someone-coming-from-apt-get + opts="${opts} --non-interactive" + fi + + read -r -a zypper_opts <<< "$opts" + # install the required packages + run ${sudo} zypper "${zypper_opts[@]}" install "${install_opts}" "${@}" +} + +# ----------------------------------------------------------------------------- +# clearlinux + +validate_install_swupd() { + swupd bundle-list | grep -q "${*}" || echo "${*}" +} + +install_swupd() { + # download the latest package info + if [ "${DRYRUN}" -eq 1 ]; then + echo >&2 " >> IMPORTANT << " + echo >&2 " Please make sure your system is up to date" + echo >&2 " by running: ${sudo} swupd update " + echo >&2 + fi + + run ${sudo} swupd bundle-add "${@}" +} + +# ----------------------------------------------------------------------------- +# macOS + +validate_install_pkg() { + pkg query %n-%v | grep -q "${*}" || echo "${*}" +} + +validate_install_brew() { + brew list | grep -q "${*}" || echo "${*}" +} + +install_pkg() { + # download the latest package info + if [ "${DRYRUN}" -eq 1 ]; then + echo >&2 " >> IMPORTANT << " + echo >&2 " Please make sure your system is up to date" + echo >&2 " by running: pkg update " + echo >&2 + fi + + local opts= + if [ "${NON_INTERACTIVE}" -eq 1 ]; then + echo >&2 "Running in non-interactive mode" + opts="-y" + fi + + read -r -a pkg_opts <<< "${opts}" + + run ${sudo} pkg install "${pkg_opts[@]}" "${@}" +} + +install_brew() { + # download the latest package info + if [ "${DRYRUN}" -eq 1 ]; then + echo >&2 " >> IMPORTANT << " + echo >&2 " Please make sure your system is up to date" + echo >&2 " by running: brew upgrade " + echo >&2 + fi + + run brew install "${@}" +} + +# ----------------------------------------------------------------------------- + +install_failed() { + local ret="${1}" + cat << EOF + + + +We are very sorry! + +Installation of required packages failed. + +What to do now: + + 1. Make sure your system is updated. + Most of the times, updating your system will resolve the issue. + + 2. If the error message is about a specific package, try removing + that package from the command and run it again. + Depending on the broken package, you may be able to continue. + + 3. Let us know. We may be able to help. + Open a github issue with the above log, at: + + https://github.com/netdata/netdata/issues + + +EOF + remote_log "FAILED" "${ret}" + exit 1 +} + +remote_log() { + # log success or failure on our system + # to help us solve installation issues + curl > /dev/null 2>&1 -Ss --max-time 3 "https://registry.my-netdata.io/log/installer?status=${1}&error=${2}&distribution=${distribution}&version=${version}&installer=${package_installer}&tree=${tree}&detection=${detection}&netdata=${PACKAGES_NETDATA}&python=${PACKAGES_NETDATA_PYTHON}&python3=${PACKAGES_NETDATA_PYTHON3}&sensors=${PACKAGES_NETDATA_SENSORS}&database=${PACKAGES_NETDATA_DATABASE}&ebpf=${PACKAGES_NETDATA_EBPF}&firehol=${PACKAGES_FIREHOL}&fireqos=${PACKAGES_FIREQOS}&iprange=${PACKAGES_IPRANGE}&update_ipsets=${PACKAGES_UPDATE_IPSETS}&demo=${PACKAGES_NETDATA_DEMO_SITE}" +} + +if [ -z "${1}" ]; then + usage + exit 1 +fi + +pv=$(python --version 2>&1) +if [ "${tree}" = macos ]; then + pv=3 +elif [[ "${pv}" =~ ^Python\ 2.* ]]; then + pv=2 +elif [[ "${pv}" =~ ^Python\ 3.* ]]; then + pv=3 +elif [[ "${tree}" == "centos" ]] && [ "${version}" -lt 8 ]; then + pv=2 +else + pv=3 +fi + +# parse command line arguments +DONT_WAIT=0 +NON_INTERACTIVE=0 +IGNORE_INSTALLED=0 +while [ -n "${1}" ]; do + case "${1}" in + distribution) + distribution="${2}" + shift + ;; + + version) + version="${2}" + shift + ;; + + codename) + codename="${2}" + shift + ;; + + installer) + check_package_manager "${2}" || exit 1 + shift + ;; + + dont-wait | --dont-wait | -n) + DONT_WAIT=1 + ;; + + non-interactive | --non-interactive | -y) + NON_INTERACTIVE=1 + ;; + + ignore-installed | --ignore-installed | -i) + IGNORE_INSTALLED=1 + ;; + + netdata-all) + PACKAGES_NETDATA=1 + if [ "${pv}" -eq 2 ]; then + PACKAGES_NETDATA_PYTHON=1 + else + PACKAGES_NETDATA_PYTHON3=1 + fi + PACKAGES_NETDATA_SENSORS=1 + PACKAGES_NETDATA_DATABASE=1 + PACKAGES_NETDATA_EBPF=1 + PACKAGES_NETDATA_STREAMING_COMPRESSION=1 + ;; + + netdata) + PACKAGES_NETDATA=1 + PACKAGES_NETDATA_PYTHON3=1 + PACKAGES_NETDATA_DATABASE=1 + PACKAGES_NETDATA_EBPF=1 + PACKAGES_NETDATA_STREAMING_COMPRESSION=1 + ;; + + python | netdata-python) + PACKAGES_NETDATA_PYTHON=1 + ;; + + python3 | netdata-python3) + PACKAGES_NETDATA_PYTHON3=1 + ;; + + sensors | netdata-sensors) + PACKAGES_NETDATA=1 + PACKAGES_NETDATA_PYTHON3=1 + PACKAGES_NETDATA_SENSORS=1 + PACKAGES_NETDATA_DATABASE=1 + ;; + + firehol | update-ipsets | firehol-all | fireqos) + PACKAGES_IPRANGE=1 + PACKAGES_FIREHOL=1 + PACKAGES_FIREQOS=1 + PACKAGES_IPRANGE=1 + PACKAGES_UPDATE_IPSETS=1 + ;; + + demo | all) + PACKAGES_NETDATA=1 + if [ "${pv}" -eq 2 ]; then + PACKAGES_NETDATA_PYTHON=1 + else + PACKAGES_NETDATA_PYTHON3=1 + fi + PACKAGES_DEBUG=1 + PACKAGES_IPRANGE=1 + PACKAGES_FIREHOL=1 + PACKAGES_FIREQOS=1 + PACKAGES_UPDATE_IPSETS=1 + PACKAGES_NETDATA_DEMO_SITE=1 + PACKAGES_NETDATA_DATABASE=1 + PACKAGES_NETDATA_EBPF=1 + ;; + + help | -h | --help) + usage + exit 1 + ;; + + *) + echo >&2 "ERROR: Cannot understand option '${1}'" + echo >&2 + usage + exit 1 + ;; + esac + shift +done + +# Check for missing core commands like grep, warn the user to install it and bail out cleanly +if ! command -v grep > /dev/null 2>&1; then + echo >&2 + echo >&2 "ERROR: 'grep' is required for the install to run correctly and was not found on the system." + echo >&2 "Please install grep and run the installer again." + echo >&2 + exit 1 +fi + +if [ -z "${package_installer}" ] || [ -z "${tree}" ]; then + if [ -z "${distribution}" ]; then + # we dont know the distribution + autodetect_distribution || user_picks_distribution + fi + + # When no package installer is detected, try again from distro info if any + if [ -z "${package_installer}" ]; then + detect_package_manager_from_distribution "${distribution}" + fi + + # Validate package manager trees + validate_package_trees +fi + +[ "${detection}" = "/etc/os-release" ] && cat << EOF + +/etc/os-release information: +NAME : ${NAME} +VERSION : ${VERSION} +ID : ${ID} +ID_LIKE : ${ID_LIKE} +VERSION_ID : ${VERSION_ID} +EOF + +cat << EOF + +We detected these: +Distribution : ${distribution} +Version : ${version} +Codename : ${codename} +Package Manager : ${package_installer} +Packages Tree : ${tree} +Detection Method: ${detection} +Default Python v: ${pv} $([ ${pv} -eq 2 ] && [ "${PACKAGES_NETDATA_PYTHON3}" -eq 1 ] && echo "(will install python3 too)") + +EOF + +mapfile -t PACKAGES_TO_INSTALL < <(packages | sort -u) + +if [ ${#PACKAGES_TO_INSTALL[@]} -gt 0 ]; then + echo >&2 + echo >&2 "The following command will be run:" + echo >&2 + DRYRUN=1 + "${package_installer}" "${PACKAGES_TO_INSTALL[@]}" + DRYRUN=0 + echo >&2 + echo >&2 + + if [ "${DONT_WAIT}" -eq 0 ] && [ "${NON_INTERACTIVE}" -eq 0 ]; then + read -r -p "Press ENTER to run it > " || exit 1 + fi + + "${package_installer}" "${PACKAGES_TO_INSTALL[@]}" || install_failed $? + + echo >&2 + echo >&2 "All Done! - Now proceed to the next step." + echo >&2 + +else + echo >&2 + echo >&2 "All required packages are already installed. Now proceed to the next step." + echo >&2 +fi + +remote_log "OK" + +exit 0 |