Browse Source

Add support to the updater to toggle auto-updates on and off. (#12202)

* Add support to the updater to toggle auto-updates on and off.

This also adds the updater script to our native packages.

* Move argument handling logic to updater enabler function.

* Properly handle crontab case.
Austin S. Hemmelgarn 3 years ago
parent
commit
3dc314432e
4 changed files with 228 additions and 24 deletions
  1. 8 0
      contrib/debian/rules
  2. 6 0
      netdata.spec.in
  3. 53 15
      packaging/installer/UPDATE.md
  4. 161 9
      packaging/installer/netdata-updater.sh

+ 8 - 0
contrib/debian/rules

@@ -75,6 +75,10 @@ override_dh_install:
 	mkdir -p "$(TOP)/var/cache/netdata"
 	mkdir -p "$(TOP)/var/run/netdata"
 
+	# Copy the updater script
+	#
+	cp -v packaging/installer/netdata-updater.sh $(TOP)/usr/libexec/netdata/netdata-updater.sh
+
 	# Move files that local user shouldn't be editing to /usr/share/netdata
 	#
 	mkdir -p "$(TOP)/usr/share/netdata/www"
@@ -108,6 +112,10 @@ override_dh_installdocs:
 override_dh_fixperms:
 	dh_fixperms
 
+	# Updater script should be executable
+	#
+	chmod 0755 $(TOP)/usr/libexec/netdata/netdata-updater.sh
+
 	# apps.plugin should only be runnable by the netdata user. It will be
 	# given extra capabilities in the postinst script.
 	#

+ 6 - 0
netdata.spec.in

@@ -283,6 +283,10 @@ rm -rf "${RPM_BUILD_ROOT}"
 
 install -m 644 -p system/netdata.conf "${RPM_BUILD_ROOT}%{_sysconfdir}/%{name}"
 
+# ###########################################################
+# Install updater script
+install -m 755 -p packaging/installer/netdata-updater.sh "${RPM_BUILD_ROOT}%{_libexecdir}/%{name}/netdata-updater.sh"
+
 # ###########################################################
 # logrotate settings
 install -m 755 -d "${RPM_BUILD_ROOT}%{_sysconfdir}/logrotate.d"
@@ -557,6 +561,8 @@ are sensor monitoring, system event monitoring, power control, and serial-over-L
 %attr(4750,root,netdata) %{_libexecdir}/%{name}/plugins.d/freeipmi.plugin
 
 %changelog
+* Wed Feb 03 2022 Austin Hemmelgarn <austin@netdata.cloud> 0.0.0-16
+- Bundle updater script in native packages.
 * Mon Oct 11 2021 Austin Hemmelgarn <austin@netdata.cloud> 0.0.0-15
 - Remove support code for legacy ACLK implementation.
 * Wed Sep 16 2020 Austin Hemmelgarn <austin@netdata.cloud> 0.0.0-14

+ 53 - 15
packaging/installer/UPDATE.md

@@ -6,8 +6,9 @@ custom_edit_url: https://github.com/netdata/netdata/edit/master/packaging/instal
 
 # Update the Netdata Agent
 
-By default, the Netdata Agent automatically updates with the latest nightly version. If you opted out of automatic
-updates, you need to update your Netdata Agent to the latest nightly or stable version.
+By default, the Netdata Agent automatically updates with the latest nightly or stable version depending on which
+you installed. If you opted out of automatic updates, you need to update your Netdata Agent to the latest nightly
+or stable version. You can also [enable or disable automatic updates on an existing install](#control-automatic-updates).
 
 > 💡 Looking to reinstall the Netdata Agent to enable a feature, update an Agent that cannot update automatically, or
 > troubleshoot an error during the installation process? See our [reinstallation doc](/packaging/installer/REINSTALL.md)
@@ -20,28 +21,35 @@ icon in the local Agent dashboard's top navigation. This modal informs you wheth
 
 ## Determine which installation method you used
 
+Starting with netdata v1.33.0, you can use Netdata itself to determine the installation type by running:
+
+```bash
+netdata -W buildinfo | grep 'Install type:'
+```
+
+If this produces no output, you have an older install and will have to manually look in the Netdata config directory.
 If you are not sure where your Netdata config directory is, see the [configuration doc](/docs/configure/nodes.md). In
 most installations, this is `/etc/netdata`.
 
 Use `cd` to navigate to the Netdata config directory, then use `ls -a` to look for a file called `.install-type`.
 
 -   If the `.install-type` file doex not exist, look for a file in the same directory called `.environment`.
-    -   If the `.environment` file does not exist, you probably installed Netdata using your system package manager
-        and should update it the same way you would run updates on the system itself.
-    -   If the `.environment` file does exist, then our [regular update method](#updates-for-most-systems) should
-        work correctly.
+    -   If the `.environment` file does not exist, then you have a ‘custom’ install.
+    -   If the `.environment` file does exist, then you have either a ‘static’ or ‘build’ install.
 -   If the `.install-type` file does exist, check it’s contents with `cat .install-type`.
-    -   If the `INSTALL_TYPE` key has a value of `custom`, you probably installed Netdata using your system
-        package manager and should update it the same way you would run updates on the system itself.
-    -   If the `INSTALL_TYPE` key has a value of `oci`, the install is from a Docker image.
-    -   Otherwise, the install should work with our [regular update method](#updates-for-most-systems).
+    -   The value of the `INSTALL_TYPE` key indicates what type of install you have.
 
-Next, use the appropriate method to update the Netdata Agent:
+The exact update method to use depends on the install type:
 
--   [Updates for most systems](#updates-for-most-systems)
--   [Docker](#docker)
--   [macOS](#macos)
--   [Manual installation from Git](#manual-installation-from-git)
+-   Installs with an install type of 'custom' usually indicate installing a third-party package through the system
+    package manager. To update these installs, you should update the package just like you would any other package
+    on your system.
+-   Installs with an install type starting with `binpkg` or ending with `build` or `static` can be updated using
+    our [regular update method](#updates-for-most-systems).
+-   Installs with an install type of 'oci' were created from our official Docker images, and should be updated
+    using our [Docker](#docker) update procedure.
+-   macOS users should check [our update instructions for macOS](#macos).
+-   Manually built installs should check [our update instructions for manual builds](#manual-installation-from-git).
 
 ## Updates for most systems
 
@@ -95,6 +103,9 @@ Homebrew downloads the latest Netdata via the
 [formulae](https://github.com/Homebrew/homebrew-core/blob/master/Formula/netdata.rb), ensures all dependencies are met,
 and updates Netdata via reinstallation.
 
+If you instead installed Netdata using our one-line installation script, you can use our [regular update
+instructions](#updates-for-most-systems) to update Netdata.
+
 ## Manual installation from Git
 
 If you installed [Netdata manually from Git](/packaging/installer/methods/manual.md), you can run that installer again
@@ -117,4 +128,31 @@ sudo ./netdata-installer.sh
 > ⚠️ If you installed Netdata with any optional parameters, such as `--no-updates` to disable automatic updates, and
 > want to retain those settings, you need to set them again during this process.
 
+## Control automatic updates
+
+Starting with Netdata v1.34.0, you can easily enable or disable automatic updates on an existing installation
+using the updater script.
+
+For most installs on Linux, you can enable auto-updates with:
+
+```bash
+/usr/libexec/netdata/netdata-updater.sh --enable-auto-updates
+```
+
+and disable them with:
 
+```bash
+/usr/libexec/netdata/netdata-updater.sh --disable-auto-updates
+```
+
+For static installs, instead use:
+
+```bash
+/opt/netdata/usr/libexec/netdata/netdata-updater.sh --enable-auto-updates
+```
+
+and:
+
+```bash
+/opt/netdata/usr/libexec/netdata/netdata-updater.sh --disable-auto-updates
+```

+ 161 - 9
packaging/installer/netdata-updater.sh

@@ -73,6 +73,152 @@ if [ "${ENVIRONMENT_FILE}" = "THIS_SHOULD_BE_REPLACED_BY_INSTALLER_SCRIPT" ]; th
   fi
 fi
 
+issystemd() {
+  # 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
+}
+
+_get_scheduler_type() {
+  if _get_intervaldir > /dev/null ; then
+    echo 'interval'
+  elif issystemd ; then
+    echo 'systemd'
+  elif [ -d /etc/cron.d ] ; then
+    echo 'crontab'
+  else
+    echo 'none'
+  fi
+}
+
+_get_intervaldir() {
+  if [ -d /etc/cron.daily ]; then
+    echo /etc/cron.daily
+  elif [ -d /etc/periodic/daily ]; then
+    echo /etc/periodic/daily
+  else
+    return 1
+  fi
+
+  return 0
+}
+
+enable_netdata_updater() {
+  updater_type="$(echo "${1}" | tr '[:upper:]' '[:lower:]')"
+  case "${updater_type}" in
+    systemd|interval|crontab)
+      updater_type="${1}"
+      ;;
+    "")
+      updater_type="$(_get_scheduler_type)"
+      ;;
+    *)
+      error "Unrecognized updater type ${updater_type} requested. Supported types are 'systemd', 'interval', and 'crontab'."
+      exit 1
+      ;;
+  esac
+
+  case "${updater_type}" in
+    "systemd")
+      if issystemd; then
+        systemctl enable netdata-updater.timer
+
+        info "Auto-updating has been ENABLED using a systemd timer unit.\n"
+        info "If the update process fails, the failure will be logged to the systemd journal just like a regular service failure."
+        info "Successful updates should produce empty logs."
+      else
+        error "Systemd-based auto-update scheduling requested, but this does not appear to be a systemd system."
+        error "Auto-updates have NOT been enabled."
+        return 1
+      fi
+      ;;
+    "interval")
+      if _get_intervaldir > /dev/null; then
+        ln -sf "${NETDATA_PREFIX}/usr/libexec/netdata/netdata-updater.sh" "$(_get_intervaldir)/netdata-updater"
+
+        info "Auto-updating has been ENABLED through cron, updater script linked to $(_get_intervaldir)/netdata-updater\n"
+        info "If the update process fails and you have email notifications set up correctly for cron on this system, you should receive an email notification of the failure."
+        info "Successful updates will not send an email."
+      else
+        error "Interval-based auto-update scheduling requested, but I could not find an interval scheduling directory."
+        error "Auto-updates have NOT been enabled."
+        return 1
+      fi
+      ;;
+    "crontab")
+      if [ -d "/etc/cron.d" ]; then
+        cat > "/etc/cron.d/netdata-updater" <<-EOF
+	2 57 * * * root ${NETDATA_PREFIX}/netdata-updater.sh
+	EOF
+
+        info "Auto-updating has been ENABLED through cron, using a crontab at /etc/cron.d/netdata-updater\n"
+        info "If the update process fails and you have email notifications set up correctly for cron on this system, you should receive an email notification of the failure."
+        info "Successful updates will not send an email."
+      else
+        error "Crontab-based auto-update scheduling requested, but there is no '/etc/cron.d'."
+        error "Auto-updates have NOT been enabled."
+        return 1
+      fi
+      ;;
+    *)
+      error "Unable to determine what type of auto-update scheduling to use."
+      error "Auto-updates have NOT been enabled."
+      return 1
+  esac
+
+  return 0
+}
+
+disable_netdata_updater() {
+  if issystemd && ( systemctl list-units --full -all | grep -Fq "netdata-updater.timer" ) ; then
+    systemctl disable netdata-updater.timer
+  fi
+
+  if [ -d /etc/cron.daily ]; then
+    rm -f /etc/cron.daily/netdata-updater.sh
+    rm -f /etc/cron.daily/netdata-updater
+  fi
+
+  if [ -d /etc/periodic/daily ]; then
+    rm -f /etc/periodic/daily/netdata-updater.sh
+    rm -f /etc/periodic/daily/netdata-updater
+  fi
+
+  if [ -d /etc/cron.d ]; then
+    rm -f /etc/cron.d/netdata-updater
+  fi
+
+  info "Auto-updates have been DISABLED."
+
+  return 0
+}
+
 str_in_list() {
   printf "%s\n" "${2}" | tr ' ' "\n" | grep -qE "^${1}\$"
   return $?
@@ -574,6 +720,14 @@ ndtmpdir=
 
 trap cleanup EXIT
 
+# shellcheck source=/dev/null
+. "${ENVIRONMENT_FILE}" || exit 1
+
+if [ -f "$(dirname "${ENVIRONMENT_FILE}")/.install-type" ]; then
+  # shellcheck source=/dev/null
+  . "$(dirname "${ENVIRONMENT_FILE}")/.install-type" || exit 1
+fi
+
 while [ -n "${1}" ]; do
   if [ "${1}" = "--not-running-from-cron" ]; then
     NETDATA_NOT_RUNNING_FROM_CRON=1
@@ -584,6 +738,12 @@ while [ -n "${1}" ]; do
   elif [ "${1}" = "--tmpdir-path" ]; then
     NETDATA_TMPDIR_PATH="${2}"
     shift 2
+  elif [ "${1}" = "--enable-auto-updates" ]; then
+    enable_netdata_updater "${2}"
+    exit $?
+  elif [ "${1}" = "--disable-auto-updates" ]; then
+    disable_netdata_updater
+    exit $?
   else
     break
   fi
@@ -601,14 +761,6 @@ if [ ! -t 1 ] && [ -z "${NETDATA_NOT_RUNNING_FROM_CRON}" ]; then
     sleep $(((rnd % 3600) + 1))
 fi
 
-# shellcheck source=/dev/null
-. "${ENVIRONMENT_FILE}" || exit 1
-
-if [ -f "$(dirname "${ENVIRONMENT_FILE}")/.install-type" ]; then
-  # shellcheck source=/dev/null
-  . "$(dirname "${ENVIRONMENT_FILE}")/.install-type" || exit 1
-fi
-
 # We dont expect to find lib dir variable on older installations, so load this path if none found
 export NETDATA_LIB_DIR="${NETDATA_LIB_DIR:-${NETDATA_PREFIX}/var/lib/netdata}"
 
@@ -653,7 +805,7 @@ case "${INSTALL_TYPE}" in
       update_legacy
       ;;
     custom)
-      # At this point, we _should_ have a valid `.environment` file, but it0s best to just check.
+      # At this point, we _should_ have a valid `.environment` file, but it's best to just check.
       # If we do, then behave like the legacy updater.
       if [ -n "${RELEASE_CHANNEL}" ] && [ -n "${NETDATA_PREFIX}" ] && [ -n "${REINSTALL_OPTIONS}" ]; then
         update_legacy