diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | build/subst.inc | 1 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | packaging/installer/functions.sh | 221 | ||||
-rw-r--r-- | system/Makefile.am | 14 | ||||
-rwxr-xr-x | system/install-service.sh.in | 699 |
6 files changed, 863 insertions, 75 deletions
diff --git a/.gitignore b/.gitignore index 275b5d0076..b90428a14f 100644 --- a/.gitignore +++ b/.gitignore @@ -128,6 +128,7 @@ system/netdata.plist system/netdata-freebsd system/edit-config system/netdata.crontab +system/install-service.sh daemon/anonymous-statistics.sh daemon/get-kubernetes-labels.sh diff --git a/build/subst.inc b/build/subst.inc index cc8825e247..f51f47074d 100644 --- a/build/subst.inc +++ b/build/subst.inc @@ -10,6 +10,7 @@ -e 's#[@]registrydir_POST@#$(registrydir)#g' \ -e 's#[@]varlibdir_POST@#$(varlibdir)#g' \ -e 's#[@]webdir_POST@#$(webdir)#g' \ + -e 's#[@]libsysdir_POST@#$(libsysdir)#g' \ -e 's#[@]enable_aclk_POST@#$(enable_aclk)#g' \ -e 's#[@]enable_cloud_POST@#$(enable_cloud)#g' \ $< > $@.tmp; then \ diff --git a/configure.ac b/configure.ac index ef060a91f8..e2c73e28b2 100644 --- a/configure.ac +++ b/configure.ac @@ -1540,6 +1540,7 @@ configdir="${sysconfdir}/netdata" libconfigdir="${libdir}/netdata/conf.d" logdir="${localstatedir}/log/netdata" pluginsdir="${libexecdir}/netdata/plugins.d" +libsysdir="${libdir}/netdata/system" AC_SUBST([varlibdir]) AC_SUBST([registrydir]) @@ -1551,6 +1552,7 @@ AC_SUBST([libconfigdir]) AC_SUBST([logdir]) AC_SUBST([pluginsdir]) AC_SUBST([webdir]) +AC_SUBST([libsysdir]) CFLAGS="${originalCFLAGS} ${OPTIONAL_LTO_CFLAGS} ${OPTIONAL_PROTOBUF_CFLAGS} ${OPTIONAL_MATH_CFLAGS} ${OPTIONAL_NFACCT_CFLAGS} \ ${OPTIONAL_ZLIB_CFLAGS} ${OPTIONAL_UUID_CFLAGS} \ diff --git a/packaging/installer/functions.sh b/packaging/installer/functions.sh index 8bf7fafcfa..c3fb25bcea 100644 --- a/packaging/installer/functions.sh +++ b/packaging/installer/functions.sh @@ -475,92 +475,149 @@ install_non_systemd_init() { return 1 } -# This is used by netdata-installer.sh -# shellcheck disable=SC2034 -NETDATA_STOP_CMD="netdatacli shutdown-agent" +run_install_service_script() { + # shellcheck disable=SC2154 + save_path="${tmpdir}/netdata-service-cmds" + # shellcheck disable=SC2068 + run "${NETDATA_PREFIX}/usr/libexec/netdata/install-service.sh" --save-cmds "${save_path}" ${@} + + case $? in + 0) + if [ -r "${save_path}" ]; then + # shellcheck disable=SC1090 + . "${save_path}" + fi -NETDATA_START_CMD="netdata" -NETDATA_INSTALLER_START_CMD="" + if [ -z "${NETDATA_INSTALLER_START_CMD}" ]; then + if [ -n "${NETDATA_START_CMD}" ]; then + NETDATA_INSTALLER_START_CMD="${NETDATA_START_CMD}" + else + NETDATA_INSTALLER_START_CMD="netdata" + fi + fi + ;; + 1) + if [ -z "${NETDATA_SERVICE_WARNED_1}" ]; then + warning "Intenral error encountered while attempting to install or manage Netdata as a system service. This is probably a bug." + NETDATA_SERVICE_WARNED_1=1 + fi + ;; + 2) + if [ -z "${NETDATA_SERVICE_WARNED_2}" ]; then + warning "Failed to detect system service manager type. Cannot cleanly install or manage Netdata as a system service. If you are running this script in a container, this is expected and can safely be ignored." + NETDATA_SERVICE_WARNED_2=1 + fi + ;; + 3) + if [ -z "${NETDATA_SERVICE_WARNED_3}" ]; then + warning "Detected an unsupported system service manager. Manual setup will be required to manage Netdata as a system service." + NETDATA_SERVICE_WARNED_3=1 + fi + ;; + 4) + if [ -z "${NETDATA_SERVICE_WARNED_4}" ]; then + warning "Detected a supported system service manager, but failed to install Netdata as a system service. Usually this is a result of incorrect permissions. Manually running ${NETDATA_PREFIX}/usr/libexec/netdata/install-service.sh may provide more information about the exact issue." + NETDATA_SERVICE_WARNED_4=1 + fi + ;; + 5) + if [ -z "${NETDATA_SERVICE_WARNED_5}" ]; then + warning "We do not support managing Netdata as a system service on this platform. Manual setup will be required." + NETDATA_SERVICE_WARNED_5=1 + fi + ;; + esac +} install_netdata_service() { - uname="$(uname 2> /dev/null)" - if [ "${UID}" -eq 0 ]; then - if [ "${uname}" = "Darwin" ]; then - - if [ -f "/Library/LaunchDaemons/com.github.netdata.plist" ]; then - echo >&2 "file '/Library/LaunchDaemons/com.github.netdata.plist' already exists." - return 0 - else - echo >&2 "Installing MacOS X plist file..." - # This is used by netdata-installer.sh - # shellcheck disable=SC2034 - run cp system/netdata.plist /Library/LaunchDaemons/com.github.netdata.plist && - run launchctl load /Library/LaunchDaemons/com.github.netdata.plist && - NETDATA_START_CMD="launchctl start com.github.netdata" && - NETDATA_STOP_CMD="launchctl stop com.github.netdata" - return 0 - fi - - elif [ "${uname}" = "FreeBSD" ]; then - # This is used by netdata-installer.sh - # shellcheck disable=SC2034 - run cp system/netdata-freebsd /etc/rc.d/netdata && NETDATA_START_CMD="service netdata start" && - NETDATA_STOP_CMD="service netdata stop" && - NETDATA_INSTALLER_START_CMD="service netdata onestart" && - myret=$? - - echo >&2 "Note: To explicitly enable netdata automatic start, set 'netdata_enable' to 'YES' in /etc/rc.conf" - echo >&2 "" - - return ${myret} - - elif issystemd; then - # systemd is running on this system - NETDATA_START_CMD="systemctl start netdata" + if [ -x "${NETDATA_PREFIX}/usr/libexec/netdata/install-service.sh" ]; then + run_install_service_script + else # This is used by netdata-installer.sh # shellcheck disable=SC2034 - NETDATA_STOP_CMD="systemctl stop netdata" - NETDATA_INSTALLER_START_CMD="${NETDATA_START_CMD}" + NETDATA_STOP_CMD="netdatacli shutdown-agent" - SYSTEMD_DIRECTORY="$(get_systemd_service_dir)" + NETDATA_START_CMD="netdata" + NETDATA_INSTALLER_START_CMD="" - if [ "${SYSTEMD_DIRECTORY}x" != "x" ]; then - ENABLE_NETDATA_IF_PREVIOUSLY_ENABLED="run systemctl enable netdata" - IS_NETDATA_ENABLED="$(systemctl is-enabled netdata 2> /dev/null || echo "Netdata not there")" - if [ "${IS_NETDATA_ENABLED}" = "disabled" ]; then - echo >&2 "Netdata was there and disabled, make sure we don't re-enable it ourselves" - ENABLE_NETDATA_IF_PREVIOUSLY_ENABLED="true" - fi + uname="$(uname 2> /dev/null)" - echo >&2 "Installing systemd service..." - run cp system/netdata.service "${SYSTEMD_DIRECTORY}/netdata.service" && - run systemctl daemon-reload && - ${ENABLE_NETDATA_IF_PREVIOUSLY_ENABLED} && + if [ "${uname}" = "Darwin" ]; then + if [ -f "/Library/LaunchDaemons/com.github.netdata.plist" ]; then + echo >&2 "file '/Library/LaunchDaemons/com.github.netdata.plist' already exists." return 0 - else - warning "Could not find a systemd service directory, unable to install Netdata systemd service." - fi - else - install_non_systemd_init - ret=$? - - if [ ${ret} -eq 0 ]; then - if [ -n "${service_cmd}" ]; then - NETDATA_START_CMD="service netdata start" - # This is used by netdata-installer.sh - # shellcheck disable=SC2034 - NETDATA_STOP_CMD="service netdata stop" - elif [ -n "${rcservice_cmd}" ]; then - NETDATA_START_CMD="rc-service netdata start" + else + echo >&2 "Installing MacOS X plist file..." # This is used by netdata-installer.sh # shellcheck disable=SC2034 - NETDATA_STOP_CMD="rc-service netdata stop" + run cp system/netdata.plist /Library/LaunchDaemons/com.github.netdata.plist && + run launchctl load /Library/LaunchDaemons/com.github.netdata.plist && + NETDATA_START_CMD="launchctl start com.github.netdata" && + NETDATA_STOP_CMD="launchctl stop com.github.netdata" + return 0 fi + + elif [ "${uname}" = "FreeBSD" ]; then + # This is used by netdata-installer.sh + # shellcheck disable=SC2034 + run cp system/netdata-freebsd /etc/rc.d/netdata && NETDATA_START_CMD="service netdata start" && + NETDATA_STOP_CMD="service netdata stop" && + NETDATA_INSTALLER_START_CMD="service netdata onestart" && + myret=$? + + echo >&2 "Note: To explicitly enable netdata automatic start, set 'netdata_enable' to 'YES' in /etc/rc.conf" + echo >&2 "" + + return ${myret} + + elif issystemd; then + # systemd is running on this system + NETDATA_START_CMD="systemctl start netdata" + # This is used by netdata-installer.sh + # shellcheck disable=SC2034 + NETDATA_STOP_CMD="systemctl stop netdata" NETDATA_INSTALLER_START_CMD="${NETDATA_START_CMD}" - fi - return ${ret} + SYSTEMD_DIRECTORY="$(get_systemd_service_dir)" + + if [ "${SYSTEMD_DIRECTORY}x" != "x" ]; then + ENABLE_NETDATA_IF_PREVIOUSLY_ENABLED="run systemctl enable netdata" + IS_NETDATA_ENABLED="$(systemctl is-enabled netdata 2> /dev/null || echo "Netdata not there")" + if [ "${IS_NETDATA_ENABLED}" = "disabled" ]; then + echo >&2 "Netdata was there and disabled, make sure we don't re-enable it ourselves" + ENABLE_NETDATA_IF_PREVIOUSLY_ENABLED="true" + fi + + echo >&2 "Installing systemd service..." + run cp system/netdata.service "${SYSTEMD_DIRECTORY}/netdata.service" && + run systemctl daemon-reload && + ${ENABLE_NETDATA_IF_PREVIOUSLY_ENABLED} && + return 0 + else + warning "Could not find a systemd service directory, unable to install Netdata systemd service." + fi + else + install_non_systemd_init + ret=$? + + if [ ${ret} -eq 0 ]; then + if [ -n "${service_cmd}" ]; then + NETDATA_START_CMD="service netdata start" + # This is used by netdata-installer.sh + # shellcheck disable=SC2034 + NETDATA_STOP_CMD="service netdata stop" + elif [ -n "${rcservice_cmd}" ]; then + NETDATA_START_CMD="rc-service netdata start" + # This is used by netdata-installer.sh + # shellcheck disable=SC2034 + NETDATA_STOP_CMD="rc-service netdata stop" + fi + NETDATA_INSTALLER_START_CMD="${NETDATA_START_CMD}" + fi + + return ${ret} + fi fi fi @@ -642,11 +699,21 @@ netdata_pids() { stop_all_netdata() { stop_success=0 + if [ -x "${NETDATA_PREFIX}/usr/libexec/netdata/install-service.sh" ]; then + run_install_service_script --cmds-only + fi + if [ "${UID}" -eq 0 ]; then + uname="$(uname 2>/dev/null)" # Any of these may fail, but we need to not bail if they do. - if issystemd; then + if [ -n "${NETDATA_STOP_CMD}" ]; then + if ${NETDATA_STOP_CMD}; then + stop_success=1 + sleep 5 + fi + elif issystemd; then if systemctl stop netdata; then stop_success=1 sleep 5 @@ -693,8 +760,16 @@ restart_netdata() { progress "Restarting netdata instance" + if [ -x "${NETDATA_PREFIX}/usr/libexec/netdata/install-service.sh" ]; then + run_install_service_script --cmds-only + fi + if [ -z "${NETDATA_INSTALLER_START_CMD}" ]; then - NETDATA_INSTALLER_START_CMD="${netdata}" + if [ -n "${NETDATA_START_CMD}" ]; then + NETDATA_INSTALLER_START_CMD="${NETDATA_START_CMD}" + else + NETDATA_INSTALLER_START_CMD="${netdata}" + fi fi if [ "${UID}" -eq 0 ]; then diff --git a/system/Makefile.am b/system/Makefile.am index a88ccab654..72d123daa3 100644 --- a/system/Makefile.am +++ b/system/Makefile.am @@ -30,8 +30,14 @@ dist_config_DATA = \ # Explicitly install directories to avoid permission issues due to umask install-exec-local: $(INSTALL) -d $(DESTDIR)$(configdir) + $(INSTALL) -d $(DESTDIR)$(libsysdir) -nodist_noinst_DATA = \ +libexecnetdatadir=$(libexecdir)/netdata +nodist_libexecnetdata_SCRIPTS = \ + install-service.sh \ + $(NULL) + +nodist_libsys_DATA = \ netdata-openrc \ netdata.logrotate \ netdata.service \ @@ -44,8 +50,13 @@ nodist_noinst_DATA = \ netdata-updater.service \ $(NULL) +dist_libsys_DATA = \ + netdata-updater.timer \ + $(NULL) + dist_noinst_DATA = \ edit-config.in \ + install-service.sh.in \ netdata-openrc.in \ netdata.logrotate.in \ netdata.service.in \ @@ -57,5 +68,4 @@ dist_noinst_DATA = \ netdata.conf \ netdata.crontab.in \ netdata-updater.service.in \ - netdata-updater.timer \ $(NULL) diff --git a/system/install-service.sh.in b/system/install-service.sh.in new file mode 100755 index 0000000000..6c7c018878 --- /dev/null +++ b/system/install-service.sh.in @@ -0,0 +1,699 @@ +#!/usr/bin/env sh + +# SPDX-License-Identifier: GPL-3.0-or-later + +# Handle installation of the Netdata agent as a system service. +# +# Exit codes: +# 0 - Successfully installed service. +# 1 - Invalid arguments or other internal error. +# 2 - Unable to detect system service type. +# 3 - Detected system service type, but type not supported. +# 4 - Detected system service type, but could not install due to other issues. +# 5 - Platform not supported. + +set -e + +SCRIPT_SOURCE="$( + self=${0} + while [ -L "${self}" ] + do + cd "${self%/*}" || exit 1 + self=$(readlink "${self}") + done + cd "${self%/*}" || exit 1 + echo "$(pwd -P)/${self##*/}" +)" + +DUMP_CMDS=0 +ENABLE="auto" +EXPORT_CMDS=0 +INSTALL=1 +LINUX_INIT_TYPES="wsl systemd openrc lsb initd runit" +PLATFORM="$(uname -s)" +SVC_SOURCE="@libsysdir_POST@" +SVC_TYPE="detect" + +# ===================================================================== +# Utility functions + +cleanup() { + ec="${?}" + + if [ -n "${NETDATA_SAVE_WARNINGS}" ]; then + if [ -n "${NETDATA_PROPAGATE_WARNINGS}" ]; then + export NETDATA_WARNINGS="${NETDATA_WARNINGS}${SAVED_WARNINGS}" + fi + fi + + trap - EXIT + + exit "${ec}" +} + +info() { + printf >&2 "%s\n" "${*}" +} + +warning() { + if [ -n "${NETDATA_SAVE_WARNINGS}" ]; then + SAVED_WARNINGS="${SAVED_WARNINGS}\n - ${*}" + fi + printf >&2 "WARNING: %s\n" "${*}" +} + +error() { + if [ -n "${NETDATA_SAVE_WARNINGS}" ]; then + SAVED_WARNINGS="${SAVED_WARNINGS}\n - ${*}" + fi + printf >&2 "ERROR: %s\n" "${*}" +} + +get_os_key() { + if [ -f /etc/os-release ]; then + # shellcheck disable=SC1091 + . /etc/os-release || return 1 + echo "${ID}-${VERSION_ID}" + + elif [ -f /etc/redhat-release ]; then + cat /etc/redhat-release + else + echo "unknown" + fi +} + +valid_types() { + case "${PLATFORM}" in + Linux) + echo "detect systemd openrc lsb initd" + ;; + FreeBSD) + echo "detect freebsd" + ;; + Darwin) + echo "detect launchd" + ;; + *) + echo "detect" + ;; + esac +} + +install_generic_service() { + svc_type="${1}" + svc_type_name="${2}" + svc_file="${3}" + svc_enable_hook="${4}" + svc_disable_hook="${5}" + + info "Installing ${svc_type_name} service file." + if [ ! -f "${svc_file}" ] && [ "${ENABLE}" = "auto" ]; then + ENABLE="enable" + fi + + if ! install -p -m 0755 -o 0 -g 0 "${SVC_SOURCE}/netdata-${svc_type}" /etc/init.d/netdata; then + error "Failed to install service file." + exit 4 + fi + + case "${ENABLE}" in + auto) true ;; + disable) + info "Disabling Netdata service." + ${svc_disable_hook} + ;; + enable) + info "Enabling Netdata service." + ${svc_enable_hook} + ;; + esac +} + +dump_cmds() { + [ -n "${NETDATA_START_CMD}" ] && echo "NETDATA_START_CMD='${NETDATA_START_CMD}'" + [ -n "${NETDATA_STOP_CMD}" ] && echo "NETDATA_STOP_CMD='${NETDATA_STOP_CMD}'" + [ -n "${NETDATA_INSTALLER_START_CMD}" ] && echo "NETDATA_INSTALLER_START_CMD='${NETDATA_INSTALLER_START_CMD}'" + return 0 +} + +export_cmds() { + [ -n "${NETDATA_START_CMD}" ] && export NETDATA_START_CMD="${NETDATA_START_CMD}" + [ -n "${NETDATA_STOP_CMD}" ] && export NETDATA_STOP_CMD="${NETDATA_STOP_CMD}" + [ -n "${NETDATA_INSTALLER_START_CMD}" ] && export NETDATA_INSTALLER_START_CMD="${NETDATA_INSTALLER_START_COMMAND}" + return 0 +} + +save_cmds() { + dump_cmds > "${SAVE_CMDS_PATH}" +} + +# ===================================================================== +# Help functions + +usage() { + cat << HEREDOC +USAGE: install-service.sh [options] + where options include: + + --source Specify where to find the service files to install (default ${SVC_SOURCE}). + --type Specify the type of service file to install. Specify a type of 'help' to get a list of valid types for your platform. + --cmds Additionally print a list of commands for starting and stopping the agent with the detected service type. + --export-cmds Export the variables that would be printed by the --cmds option. + --cmds-only Don't install, just handle the --cmds or --export-cmds option. + --enable Explicitly enable the service on install (default is to enable if not already installed). + --disable Explicitly disable the service on install. + --help Print this help information. +HEREDOC +} + +help_types() { + cat << HEREDOC +Valid service types for ${PLATFORM} are: +$(valid_types) +HEREDOC +} + +# ===================================================================== +# systemd support functions + +issystemd() { + pids='' + p='' + myns='' + ns='' + systemctl='' + + # if the directory /lib/systemd/system OR /usr/lib/systemd/system (SLES 12.x) does not exit, it is not systemd + if [ ! -d /lib/systemd/system ] && [ ! -d /usr/lib/systemd/system ]; then + return 1 + fi + + # if there is no systemctl command, it is not systemd + systemctl=$(command -v systemctl 2> /dev/null) + if [ -z "${systemctl}" ] || [ ! -x "${systemctl}" ]; then + return 1 + fi + + # if pid 1 is systemd, it is systemd + [ "$(basename "$(readlink /proc/1/exe)" 2> /dev/null)" = "systemd" ] && return 0 + + # if systemd is not running, it is not systemd + pids=$(safe_pidof systemd 2> /dev/null) + [ -z "${pids}" ] && return 1 + + # check if the running systemd processes are not in our namespace + myns="$(readlink /proc/self/ns/pid 2> /dev/null)" + for p in ${pids}; do + ns="$(readlink "/proc/${p}/ns/pid" 2> /dev/null)" + + # if pid of systemd is in our namespace, it is systemd + [ -n "${myns}" ] && [ "${myns}" = "${ns}" ] && return 0 + done + + # else, it is not systemd + return 1 +} + +check_systemd() { + if [ -z "${IS_SYSTEMD}" ]; then + issystemd + IS_SYSTEMD="$?" + fi + + return "${IS_SYSTEMD}" +} + +get_systemd_service_dir() { + if [ -w "/lib/systemd/system" ]; then + echo "/lib/systemd/system" + elif [ -w "/usr/lib/systemd/system" ]; then + echo "/usr/lib/systemd/system" + elif [ -w "/etc/systemd/system" ]; then + echo "/etc/systemd/system" + else + error "Unable to detect systemd service directory." + exit 4 + fi +} + +install_systemd_service() { + SRCFILE="${SVC_SOURCE}/netdata.service" + + if [ "$(systemctl --version | head -n 1 | cut -f 2 -d ' ')" -le 235 ]; then + SRCFILE="${SVC_SOURCE}/netdata.service.v235" + fi + + if [ "${ENABLE}" = "auto" ]; then + IS_NETDATA_ENABLED="$(systemctl is-enabled netdata 2> /dev/null || echo "Netdata not there")" + + if [ "${IS_NETDATA_ENABLED}" = "disabled" ]; then + ENABLE="disable" + else + ENABLE="enable" + fi + fi + + info "Installing systemd service..." + if ! install -p -m 0644 -o 0 -g 0 "${SRCFILE}" "$(get_systemd_service_dir)/netdata.service"; then + error "Failed to install systemd service file." + exit 4 + fi + + if ! systemctl daemon-reload; then + warning "Failed to reload systemd unit files." + fi + + if ! systemctl ${ENABLE} netdata; then + warning "Failed to ${ENABLE} Netdata service." + fi +} + +systemd_cmds() { + NETDATA_START_CMD='systemctl start netdata' + NETDATA_STOP_CMD='systemctl stop netdata' +} + +# ===================================================================== +# OpenRC support functions + +isopenrc() { + # if /lib/rc/sh/functions.sh does not exist, it's not OpenRC + [ ! -f /lib/rc/sh/functions.sh ] && return 1 + + # if there is no /etc/init.d, it's not OpenRC + [ ! -d /etc/init.d ] && return 1 + + # if PID 1 is openrc-init, it's OpenRC + [ "$(basename "$(readlink /proc/1/exe)" 2> /dev/null)" = "openrc-init" ] && return 0 + + # If /run/openrc/softlevel exists, it's OpenRC + [ -f /run/openrc/softlevel ] && return 0 + + # if there is an openrc command, it's OpenRC + command -v openrc > /dev/null 2>&1 && return 0 + + # Otherwise, it’s not OpenRC + return 1 +} + +check_openrc() { + if [ -z "${IS_OPENRC}" ]; then + isopenrc + IS_OPENRC="$?" + fi + + return "${IS_OPENRC}" +} + +enable_openrc() { + runlevel="$(rc-status -r)" + runlevel="${runlevel:-default}" + if ! rc-update add netdata "${runlevel}"; then + warning "Failed to enable Netdata service in runlevel ${runlevel}." + fi +} + +disable_openrc() { + for runlevel in /etc/runlevels/*; do + if [ -e "${runlevel}/netdata" ]; then + runlevel="$(basename "${runlevel}")" + if ! rc-update del netdata "${runlevel}"; then + warning "Failed to disable Netdata service in runlevel ${runlevel}." + fi + fi + done +} + +install_openrc_service() { + install_generic_service openrc OpenRC /etc/init.d/netdata enable_openrc disable_openrc +} + +openrc_cmds() { + NETDATA_START_CMD='rc-service netdata start' + NETDATA_STOP_CMD='rc-service netdata stop' +} + +# ===================================================================== +# LSB init script support functions + +islsb() { + # if there is no /etc/init.d directory, it’s not an LSB system + [ ! -d /etc/init.d ] && return 1 + + # If it's an OpenRC system, then it's not an LSB system + check_openrc && return 1 + + # If /lib/lsb/init-functions exists, it’s an LSB system + [ -f /lib/lsb/init-functions ] && return 0 + + return 1 +} + +check_lsb() { + if [ -z "${IS_LSB}" ]; then + islsb + IS_LSB="$?" + fi + + return "${IS_LSB}" +} + +enable_lsb() { + if ! update-rc.d netdata defaults; then + warning "Failed to enable Netdata service." + elif ! update-rc.d netdata defaults-disable; then + warning "Failed to fully enable Netdata service." + fi +} + +disable_lsb() { + if ! update-rc.d netdata remove; then + warning "Failed to disable Netdata service." + fi +} + +install_lsb_service() { + install_generic_service lsb LSB /etc/init.d/netdata enable_lsb disable_lsb +} + +lsb_cmds() { + if command -v service >/dev/null 2>&1; then + NETDATA_START_CMD='service netdata start' + NETDATA_STOP_CMD='service netdata stop' + else + NETDATA_START_CMD='/etc/init.d/netdata start' + NETDATA_STOP_CMD='/etc/init.d/netdata stop' + fi +} + +# ===================================================================== +# init.d init script support functions + +isinitd() { + # if there is no /etc/init.d directory, it’s not an init.d system + [ ! -d /etc/init.d ] && return 1 + + # if there is no chkconfig command, it's not a (usable) init.d system + command -v chkconfig >/dev/null 2>&1 || return 1 + + # if it's not an LSB setup, it’s init.d + check_initd || return 0 + + return 1 +} + +check_initd() { + if [ -z "${IS_INITD}" ]; then + isinitd + IS_INITD="$?" + fi + + return "${IS_INITD}" +} + +enable_initd() { + if ! chkconfig netdata on; then + warning "Failed to enable Netdata service." + fi +} + +disable_initd() { + if ! chkconfig netdata off; then + warning "Failed to disable Netdata service." + fi +} + +install_initd_service() { + install_generic_service init-d init.d /etc/init.d/netdata enable_initd disable_initd +} + +initd_cmds() { + if command -v service >/dev/null 2>&1; then + NETDATA_START_CMD='service netdata start' + NETDATA_STOP_CMD='service netdata stop' + else + NETDATA_START_CMD='/etc/init.d/netdata start' + NETDATA_STOP_CMD='/etc/init.d/netdata stop' + fi +} + +# ===================================================================== +# runit support functions +# +# Currently not supported, this exists to provide useful error messages. + +isrunit() { + # if there is no /lib/rc/sv.d, then it's not runit + [ ! -d /lib/rc/sv.d ] && return 1 + + # if there is no runit command, then it's not runit + command -v runit >/dev/null 2>&1 || return 1 + + # if /run/runit exists, then it's runit + [ -d /run/runit ] && return 0 + + # if /etc/runit/1 exists and is executable, then it's runit + [ -x /etc/runit/1 ] && return 0 + + return 1 +} + +check_runit() { + if [ -z "${IS_RUNIT}" ]; then + isrunit + IS_RUNIT="$?" + fi + + return "${IS_RUNIT}" +} + +install_runit_service() { + error "Detected runit, which we do not currently support." + exit 3 +} + +runit_cmds() { + error "Detected runit, which we do not currently support." + exit 3 +} + +# ===================================================================== +# WSL support functions +# +# Cannot be supported, this exists to provide useful error messages. + +iswsl() { + # If uname -r contains the string WSL, then it's WSL. + uname -r | grep -q 'WSL' && return 0 + + # If uname -r contains the string Microsoft, then it's WSL. + # This probably throws a false positive on CBL-Mariner, but it's part of what MS officially recommends for + # detecting if you're running under WSL. + uname -r | grep -q "Microsoft" && return 0 + + return 1 +} + +check_wsl() { + if [ -z "${IS_WSL}" ]; then + iswsl + IS_WSL="$?" + fi + + return "${IS_WSL}" +} + +install_wsl_service() { + error "We appear to be running in WSL. Netdata cannot be automatically installed as a service under WSL." + exit 3 +} + +wsl_cmds() { + error "We appear to be running in WSL. Netdata cannot be automatically installed as a service under WSL." + exit 3 +} + +# ===================================================================== +# FreeBSD support functions + +enable_freebsd() { + if ! sysrc netdata_enable=YES; then + warning "Failed to enable netdata service." + fi +} + +disable_freebsd() { + if ! sysrc netdata_enable=NO; then + warning "Failed to disable netdata service." + fi +} + +install_freebsd_service() { + install_generic_service freebsd "FreeBSD rc.d" /usr/local/etc/rc.d/netdata enable_freebsd disable_freebsd +} + +freebsd_cmds() { + NETDATA_START_CMD='service netdata start' + NETDATA_STOP_CMD='service netdata stop' + NETDATA_INSTALLER_START_CMD='service netdata onestart' +} + +# ===================================================================== +# macOS support functions + +install_darwin_service() { + info "Installing macOS plist file for launchd." + if ! install -C -S -p -m 0644 -o 0 -g 0 system/netdata.plist /Library/LaunchDaemons/com.github.netdata.plist; then + error "Failed to copy plist file." + exit 4 + fi + + if ! launchctl load /Library/LaunchDaemons/com.github.netdata.plist; then + error "Failed to load plist file." + exit 4 + fi +} + +darwin_cmds() { + NETDATA_START_CMD='launchctl start com.github.netdata' + NETDATA_STOP_CMD='launchctl stop com.github.netdata' +} + +# ===================================================================== +# Linux support functions + +detect_linux_svc_type() { + if [ "${SVC_TYPE}" = "detect" ]; then + for t in ${LINUX_INIT_TYPES}; do + if "check_${t}"; then + SVC_TYPE="${t}" + break + fi + done + + if [ "${SVC_TYPE}" = "detect" ]; then + error "Failed to detect what type of service manager is in use." + else + echo "${SVC_TYPE}" + fi + else + echo "${SVC_TYPE}" + fi +} + +install_linux_service() { + t="$(detect_linux_svc_type)" + + if [ -z "${t}" ]; then + exit 2 + fi + + "install_${t}_service" +} + +linux_cmds() { + t="$(detect_linux_svc_type)" + + if [ -z "${t}" ]; then + exit 2 + fi + + "${t}_cmds" +} + +# ===================================================================== +# Argument handling + +parse_args() { + while [ -n "${1}" ]; do + case "${1}" in + "--source" | "-s") + SVC_SOURCE="${2}" + shift 1 + ;; + "--type" | "-t") + if [ "${2}" = "help" ]; then + help_types + exit 0 + else + SVC_TYPE="${2}" + shift 1 + fi + ;; + "--save-cmds") + if [ -z "${2}" ]; then + info "No path specified to save command variables." + exit 1 + else + SAVE_CMDS_PATH="${2}" + shift 1 + fi + ;; + "--cmds" | "-c") DUMP_CMDS=1 ;; + "--cmds-only") INSTALL=0 ;; + "--export-cmds") EXPORT_CMDS=1 ;; + "--enable" | "-e") ENABLE="enable" ;; + "--disable" | "-d") ENABLE="disable" ;; + "--help" | "-h") + usage + exit 0 + ;; + *) + info "Unrecognized option '${1}'." + exit 1 + ;; + esac + shift 1 + done + + if [ "${SVC_SOURCE#@}" = "libsysdir_POST@" ]; then + SVC_SOURCE="$(dirname "${SCRIPT_SOURCE}")/../../lib/netdata/system" + warning "SVC_SOURCE not templated, using ${SVC_SOURCE} as source directory." + fi + + if [ ! -d "${SVC_SOURCE}" ] && [ "${INSTALL}" -eq 1 ]; then + error "${SVC_SOURCE} does not appear to be a directory. Please specify a valid source for service files with the --source option." + exit 1 + fi + + if valid_types | grep -vw "${SVC_TYPE}"; then + error "${SVC_TYPE} is not supported on this platform." + help_types + exit 1 + fi +} + +# ===================================================================== +# Core logic + +main() { + trap "cleanup" EXIT + + parse_args "${@}" + + case "${PLATFORM}" in + FreeBSD) + [ "${INSTALL}" -eq 1 ] && install_freebsd_service + freebsd_cmds + ;; + Darwin) + [ "${INSTALL}" -eq 1 ] && install_darwin_service + darwin_cmds + ;; + Linux) + [ "${INSTALL}" -eq 1 ] && install_linux_service + linux_cmds + ;; + *) + error "${PLATFORM} is not supported by this script." + exit 5 + ;; + esac + + [ "${DUMP_CMDS}" -eq 1 ] && dump_cmds + [ "${EXPORT_CMDS}" -eq 1 ] && export_cmds + [ -n "${SAVE_CMDS_PATH}" ] && save_cmds + exit 0 +} + +main "${@}" |