netdata-updater.sh 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. #!/usr/bin/env bash
  2. # Netdata updater utility
  3. #
  4. # Variables needed by script:
  5. # - PATH
  6. # - CFLAGS
  7. # - LDFLAGS
  8. # - IS_NETDATA_STATIC_BINARY
  9. # - NETDATA_CONFIGURE_OPTIONS
  10. # - REINSTALL_OPTIONS
  11. # - NETDATA_TARBALL_URL
  12. # - NETDATA_TARBALL_CHECKSUM_URL
  13. # - NETDATA_TARBALL_CHECKSUM
  14. # - NETDATA_PREFIX / NETDATA_LIB_DIR (After 1.16.1 we will only depend on lib dir)
  15. #
  16. # Optional environment options:
  17. #
  18. # - TMPDIR (set to a usable temporary directory)
  19. # - NETDATA_NIGHTLIES_BASEURL (set the base url for downloading the dist tarball)
  20. #
  21. # Copyright: SPDX-License-Identifier: GPL-3.0-or-later
  22. #
  23. # Author: Paweł Krupa <paulfantom@gmail.com>
  24. # Author: Pavlos Emm. Katsoulakis <paul@netdata.cloud>
  25. set -e
  26. info() {
  27. echo >&3 "$(date) : INFO: " "${@}"
  28. }
  29. error() {
  30. echo >&3 "$(date) : ERROR: " "${@}"
  31. }
  32. safe_sha256sum() {
  33. # Within the contexct of the installer, we only use -c option that is common between the two commands
  34. # We will have to reconsider if we start non-common options
  35. if command -v sha256sum > /dev/null 2>&1; then
  36. sha256sum "$@"
  37. elif command -v shasum > /dev/null 2>&1; then
  38. shasum -a 256 "$@"
  39. else
  40. fatal "I could not find a suitable checksum binary to use"
  41. fi
  42. }
  43. # this is what we will do if it fails (head-less only)
  44. fatal() {
  45. error "FAILED TO UPDATE NETDATA : ${1}"
  46. exit 1
  47. }
  48. cleanup() {
  49. if [ -n "${logfile}" ]; then
  50. cat >&2 "${logfile}"
  51. rm "${logfile}"
  52. fi
  53. if [ -n "$ndtmpdir" ] && [ -d "$ndtmpdir" ]; then
  54. rm -rf "$ndtmpdir"
  55. fi
  56. }
  57. _cannot_use_tmpdir() {
  58. local testfile ret
  59. testfile="$(TMPDIR="${1}" mktemp -q -t netdata-test.XXXXXXXXXX)"
  60. ret=0
  61. if [ -z "${testfile}" ] ; then
  62. return "${ret}"
  63. fi
  64. if printf '#!/bin/sh\necho SUCCESS\n' > "${testfile}" ; then
  65. if chmod +x "${testfile}" ; then
  66. if [ "$("${testfile}")" = "SUCCESS" ] ; then
  67. ret=1
  68. fi
  69. fi
  70. fi
  71. rm -f "${testfile}"
  72. return "${ret}"
  73. }
  74. create_tmp_directory() {
  75. if [ -z "${TMPDIR}" ] || _cannot_use_tmpdir "${TMPDIR}" ; then
  76. if _cannot_use_tmpdir /tmp ; then
  77. if _cannot_use_tmpdir "${PWD}" ; then
  78. echo >&2
  79. echo >&2 "Unable to find a usable temprorary directory. Please set \$TMPDIR to a path that is both writable and allows execution of files and try again."
  80. exit 1
  81. else
  82. TMPDIR="${PWD}"
  83. fi
  84. else
  85. TMPDIR="/tmp"
  86. fi
  87. fi
  88. mktemp -d -t netdata-updater-XXXXXXXXXX
  89. }
  90. download() {
  91. url="${1}"
  92. dest="${2}"
  93. if command -v curl > /dev/null 2>&1; then
  94. curl -sSL --connect-timeout 10 --retry 3 "${url}" > "${dest}" || fatal "Cannot download ${url}"
  95. elif command -v wget > /dev/null 2>&1; then
  96. wget -T 15 -O - "${url}" > "${dest}" || fatal "Cannot download ${url}"
  97. else
  98. fatal "I need curl or wget to proceed, but neither is available on this system."
  99. fi
  100. }
  101. parse_version() {
  102. r="${1}"
  103. if echo "${r}" | grep -q '^v.*'; then
  104. # shellcheck disable=SC2001
  105. # XXX: Need a regex group subsitutation here.
  106. r="$(echo "${r}" | sed -e 's/^v\(.*\)/\1/')"
  107. fi
  108. read -r -a p <<< "$(echo "${r}" | tr '-' ' ')"
  109. v="${p[0]}"
  110. b="${p[1]}"
  111. _="${p[2]}" # ignore the SHA
  112. if [[ ! "${b}" =~ ^[0-9]+$ ]]; then
  113. b="0"
  114. fi
  115. read -r -a pp <<< "$(echo "${v}" | tr '.' ' ')"
  116. printf "%03d%03d%03d%05d" "${pp[0]}" "${pp[1]}" "${pp[2]}" "${b}"
  117. }
  118. get_latest_version() {
  119. local latest
  120. if [ "${RELEASE_CHANNEL}" == "stable" ]; then
  121. latest="$(download "https://api.github.com/repos/netdata/netdata/releases/latest" /dev/stdout | grep tag_name | cut -d'"' -f4)"
  122. else
  123. latest="$(download "$NETDATA_NIGHTLIES_BASEURL/latest-version.txt" /dev/stdout)"
  124. fi
  125. parse_version "$latest"
  126. }
  127. set_tarball_urls() {
  128. local extension="tar.gz"
  129. if [ "$2" == "yes" ]; then
  130. extension="gz.run"
  131. fi
  132. if [ "$1" = "stable" ]; then
  133. local latest
  134. # Simple version
  135. latest="$(download "https://api.github.com/repos/netdata/netdata/releases/latest" /dev/stdout | grep tag_name | cut -d'"' -f4)"
  136. export NETDATA_TARBALL_URL="https://github.com/netdata/netdata/releases/download/$latest/netdata-$latest.${extension}"
  137. export NETDATA_TARBALL_CHECKSUM_URL="https://github.com/netdata/netdata/releases/download/$latest/sha256sums.txt"
  138. else
  139. export NETDATA_TARBALL_URL="$NETDATA_NIGHTLIES_BASEURL/netdata-latest.${extension}"
  140. export NETDATA_TARBALL_CHECKSUM_URL="$NETDATA_NIGHTLIES_BASEURL/sha256sums.txt"
  141. fi
  142. }
  143. update() {
  144. [ -z "${logfile}" ] && info "Running on a terminal - (this script also supports running headless from crontab)"
  145. RUN_INSTALLER=0
  146. ndtmpdir=$(create_tmp_directory)
  147. cd "$ndtmpdir" || exit 1
  148. download "${NETDATA_TARBALL_CHECKSUM_URL}" "${ndtmpdir}/sha256sum.txt" >&3 2>&3
  149. current_version="$(command -v netdata > /dev/null && parse_version "$(netdata -v | cut -f 2 -d ' ')")"
  150. latest_version="$(get_latest_version)"
  151. # If we can't get the current version for some reason assume `0`
  152. current_version="${current_version:-0}"
  153. # If we can't get the latest version for some reason assume `0`
  154. latest_version="${latest_version:-0}"
  155. info "Current Version: ${current_version}"
  156. info "Latest Version: ${latest_version}"
  157. if [ "${latest_version}" -gt 0 ] && [ "${current_version}" -gt 0 ] && [ "${current_version}" -ge "${latest_version}" ]; then
  158. info "Newest version (current=${current_version} >= latest=${latest_version}) is already installed"
  159. elif [ -n "${NETDATA_TARBALL_CHECKSUM}" ] && grep "${NETDATA_TARBALL_CHECKSUM}" sha256sum.txt >&3 2>&3; then
  160. info "Newest version is already installed"
  161. else
  162. download "${NETDATA_TARBALL_URL}" "${ndtmpdir}/netdata-latest.tar.gz"
  163. if ! grep netdata-latest.tar.gz sha256sum.txt | safe_sha256sum -c - >&3 2>&3; then
  164. fatal "Tarball checksum validation failed. Stopping netdata upgrade and leaving tarball in ${ndtmpdir}"
  165. fi
  166. NEW_CHECKSUM="$(safe_sha256sum netdata-latest.tar.gz 2> /dev/null | cut -d' ' -f1)"
  167. tar -xf netdata-latest.tar.gz >&3 2>&3
  168. rm netdata-latest.tar.gz >&3 2>&3
  169. cd netdata-* || exit 1
  170. RUN_INSTALLER=1
  171. cd "${NETDATA_LOCAL_TARBAL_OVERRIDE}" || exit 1
  172. fi
  173. # We got the sources, run the update now
  174. if [ ${RUN_INSTALLER} -eq 1 ]; then
  175. # signal netdata to start saving its database
  176. # this is handy if your database is big
  177. possible_pids=$(pidof netdata)
  178. do_not_start=
  179. if [ -n "${possible_pids}" ]; then
  180. read -r -a pids_to_kill <<< "${possible_pids}"
  181. kill -USR1 "${pids_to_kill[@]}"
  182. else
  183. # netdata is currently not running, so do not start it after updating
  184. do_not_start="--dont-start-it"
  185. fi
  186. if [ -n "${NETDATA_SELECTED_DASHBOARD}" ]; then
  187. env="NETDATA_SELECTED_DASHBOARD=${NETDATA_SELECTED_DASHBOARD}"
  188. fi
  189. info "Re-installing netdata..."
  190. eval "${env} ./netdata-installer.sh ${REINSTALL_OPTIONS} --dont-wait ${do_not_start}" >&3 2>&3 || fatal "FAILED TO COMPILE/INSTALL NETDATA"
  191. # We no longer store checksum info here. but leave this so that we clean up all environment files upon next update.
  192. sed -i '/NETDATA_TARBALL/d' "${ENVIRONMENT_FILE}"
  193. info "Updating tarball checksum info"
  194. echo "${NEW_CHECKSUM}" > "${NETDATA_LIB_DIR}/netdata.tarball.checksum"
  195. fi
  196. rm -rf "${ndtmpdir}" >&3 2>&3
  197. [ -n "${logfile}" ] && rm "${logfile}" && logfile=
  198. return 0
  199. }
  200. logfile=
  201. ndtmpdir=
  202. trap cleanup EXIT
  203. while [ -n "${1}" ]; do
  204. if [ "${1}" = "--not-running-from-cron" ]; then
  205. NETDATA_NOT_RUNNING_FROM_CRON=1
  206. shift 1
  207. else
  208. break
  209. fi
  210. done
  211. # Random sleep to aileviate stampede effect of Agents upgrading
  212. # and disconnecting/reconnecting at the same time (or near to).
  213. # But only we're not a controlling terminal (tty)
  214. # Randomly sleep between 1s and 60m
  215. if [ ! -t 1 ] && [ -z "${NETDATA_NOT_RUNNING_FROM_CRON}" ]; then
  216. sleep $(((RANDOM % 3600) + 1))s
  217. fi
  218. # Usually stored in /etc/netdata/.environment
  219. : "${ENVIRONMENT_FILE:=THIS_SHOULD_BE_REPLACED_BY_INSTALLER_SCRIPT}"
  220. # shellcheck source=/dev/null
  221. source "${ENVIRONMENT_FILE}" || exit 1
  222. # We dont expect to find lib dir variable on older installations, so load this path if none found
  223. export NETDATA_LIB_DIR="${NETDATA_LIB_DIR:-${NETDATA_PREFIX}/var/lib/netdata}"
  224. # Source the tarbal checksum, if not already available from environment (for existing installations with the old logic)
  225. [[ -z "${NETDATA_TARBALL_CHECKSUM}" ]] && [[ -f ${NETDATA_LIB_DIR}/netdata.tarball.checksum ]] && NETDATA_TARBALL_CHECKSUM="$(cat "${NETDATA_LIB_DIR}/netdata.tarball.checksum")"
  226. # Grab the nightlies baseurl (defaulting to our Google Storage bucket)
  227. export NETDATA_NIGHTLIES_BASEURL="${NETDATA_NIGHTLIES_BASEURL:-https://storage.googleapis.com/netdata-nightlies}"
  228. if [ "${INSTALL_UID}" != "$(id -u)" ]; then
  229. fatal "You are running this script as user with uid $(id -u). We recommend to run this script as root (user with uid 0)"
  230. fi
  231. if [ -t 2 ]; then
  232. # we are running on a terminal
  233. # open fd 3 and send it to stderr
  234. exec 3>&2
  235. else
  236. # we are headless
  237. # create a temporary file for the log
  238. logfile="$(mktemp "${logfile}"/netdata-updater.log.XXXXXX)"
  239. # open fd 3 and send it to logfile
  240. exec 3> "${logfile}"
  241. fi
  242. set_tarball_urls "${RELEASE_CHANNEL}" "${IS_NETDATA_STATIC_BINARY}"
  243. if [ "${IS_NETDATA_STATIC_BINARY}" == "yes" ]; then
  244. ndtmpdir="$(create_tmp_directory)"
  245. PREVDIR="$(pwd)"
  246. echo >&2 "Entering ${ndtmpdir}"
  247. cd "${ndtmpdir}" || exit 1
  248. download "${NETDATA_TARBALL_CHECKSUM_URL}" "${ndtmpdir}/sha256sum.txt"
  249. download "${NETDATA_TARBALL_URL}" "${ndtmpdir}/netdata-latest.gz.run"
  250. if ! grep netdata-latest.gz.run "${ndtmpdir}/sha256sum.txt" | safe_sha256sum -c - > /dev/null 2>&1; then
  251. fatal "Static binary checksum validation failed. Stopping netdata installation and leaving binary in ${ndtmpdir}"
  252. fi
  253. # Do not pass any options other than the accept, for now
  254. # shellcheck disable=SC2086
  255. if sh "${ndtmpdir}/netdata-latest.gz.run" --accept -- ${REINSTALL_OPTIONS}; then
  256. rm -r "${ndtmpdir}"
  257. else
  258. echo >&2 "NOTE: did not remove: ${ndtmpdir}"
  259. fi
  260. echo >&2 "Switching back to ${PREVDIR}"
  261. cd "${PREVDIR}" || exit 1
  262. else
  263. # the installer updates this script - so we run and exit in a single line
  264. update && exit 0
  265. fi