netdata-updater.sh 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  1. #!/bin/sh
  2. # Netdata updater utility
  3. #
  4. # Variables needed by script:
  5. # - PATH
  6. # - CFLAGS
  7. # - LDFLAGS
  8. # - MAKEOPTS
  9. # - IS_NETDATA_STATIC_BINARY
  10. # - NETDATA_CONFIGURE_OPTIONS
  11. # - REINSTALL_OPTIONS
  12. # - NETDATA_TARBALL_URL
  13. # - NETDATA_TARBALL_CHECKSUM_URL
  14. # - NETDATA_TARBALL_CHECKSUM
  15. # - NETDATA_PREFIX
  16. # - NETDATA_LIB_DIR
  17. #
  18. # Optional environment options:
  19. #
  20. # - TMPDIR (set to a usable temporary directory)
  21. # - NETDATA_NIGHTLIES_BASEURL (set the base url for downloading the dist tarball)
  22. #
  23. # Copyright: 2018-2023 Netdata Inc.
  24. # SPDX-License-Identifier: GPL-3.0-or-later
  25. #
  26. # Author: Paweł Krupa <paulfantom@gmail.com>
  27. # Author: Pavlos Emm. Katsoulakis <paul@netdata.cloud>
  28. # Author: Austin S. Hemmelgarn <austin@netdata.cloud>
  29. # Next unused error code: U001B
  30. set -e
  31. PACKAGES_SCRIPT="https://raw.githubusercontent.com/netdata/netdata/master/packaging/installer/install-required-packages.sh"
  32. NETDATA_STABLE_BASE_URL="${NETDATA_BASE_URL:-https://github.com/netdata/netdata/releases}"
  33. NETDATA_NIGHTLY_BASE_URL="${NETDATA_BASE_URL:-https://github.com/netdata/netdata-nightlies/releases}"
  34. NETDATA_UPDATER_JITTER=3600
  35. script_dir="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd -P)"
  36. if [ -x "${script_dir}/netdata-updater" ]; then
  37. script_source="${script_dir}/netdata-updater"
  38. else
  39. script_source="${script_dir}/netdata-updater.sh"
  40. fi
  41. PATH="${PATH}:/usr/local/bin:/usr/local/sbin"
  42. if [ ! -t 1 ]; then
  43. INTERACTIVE=0
  44. else
  45. INTERACTIVE=1
  46. fi
  47. if [ -n "${script_source}" ]; then
  48. script_name="$(basename "${script_source}")"
  49. else
  50. script_name="netdata-updater.sh"
  51. fi
  52. info() {
  53. echo >&3 "$(date) : INFO: ${script_name}: " "${1}"
  54. }
  55. warning() {
  56. echo >&3 "$(date) : WARNING: ${script_name}: " "${@}"
  57. }
  58. error() {
  59. echo >&3 "$(date) : ERROR: ${script_name}: " "${1}"
  60. if [ -n "${NETDATA_SAVE_WARNINGS}" ]; then
  61. NETDATA_WARNINGS="${NETDATA_WARNINGS}\n - ${1}"
  62. fi
  63. }
  64. fatal() {
  65. echo >&3 "$(date) : FATAL: ${script_name}: FAILED TO UPDATE NETDATA: " "${1}"
  66. if [ -n "${NETDATA_SAVE_WARNINGS}" ]; then
  67. NETDATA_WARNINGS="${NETDATA_WARNINGS}\n - ${1}"
  68. fi
  69. exit_reason "${1}" "${2}"
  70. exit 1
  71. }
  72. exit_reason() {
  73. if [ -n "${NETDATA_SAVE_WARNINGS}" ]; then
  74. EXIT_REASON="${1}"
  75. EXIT_CODE="${2}"
  76. if [ -n "${NETDATA_PROPAGATE_WARNINGS}" ]; then
  77. if [ -n "${NETDATA_SCRIPT_STATUS_PATH}" ]; then
  78. {
  79. echo "EXIT_REASON=\"${EXIT_REASON}\""
  80. echo "EXIT_CODE=\"${EXIT_CODE}\""
  81. echo "NETDATA_WARNINGS=\"${NETDATA_WARNINGS}\""
  82. } >> "${NETDATA_SCRIPT_STATUS_PATH}"
  83. else
  84. export EXIT_REASON
  85. export EXIT_CODE
  86. export NETDATA_WARNINGS
  87. fi
  88. fi
  89. fi
  90. }
  91. is_integer () {
  92. case "${1#[+-]}" in
  93. *[!0123456789]*) return 1 ;;
  94. '') return 1 ;;
  95. *) return 0 ;;
  96. esac
  97. }
  98. issystemd() {
  99. # if the directory /lib/systemd/system OR /usr/lib/systemd/system (SLES 12.x) does not exit, it is not systemd
  100. if [ ! -d /lib/systemd/system ] && [ ! -d /usr/lib/systemd/system ]; then
  101. return 1
  102. fi
  103. # if there is no systemctl command, it is not systemd
  104. systemctl=$(command -v systemctl 2> /dev/null)
  105. if [ -z "${systemctl}" ] || [ ! -x "${systemctl}" ]; then
  106. return 1
  107. fi
  108. # if pid 1 is systemd, it is systemd
  109. [ "$(basename "$(readlink /proc/1/exe)" 2> /dev/null)" = "systemd" ] && return 0
  110. # if systemd is not running, it is not systemd
  111. pids=$(safe_pidof systemd 2> /dev/null)
  112. [ -z "${pids}" ] && return 1
  113. # check if the running systemd processes are not in our namespace
  114. myns="$(readlink /proc/self/ns/pid 2> /dev/null)"
  115. for p in ${pids}; do
  116. ns="$(readlink "/proc/${p}/ns/pid" 2> /dev/null)"
  117. # if pid of systemd is in our namespace, it is systemd
  118. [ -n "${myns}" ] && [ "${myns}" = "${ns}" ] && return 0
  119. done
  120. # else, it is not systemd
  121. return 1
  122. }
  123. _get_intervaldir() {
  124. if [ -d /etc/cron.daily ]; then
  125. echo /etc/cron.daily
  126. elif [ -d /etc/periodic/daily ]; then
  127. echo /etc/periodic/daily
  128. else
  129. return 1
  130. fi
  131. return 0
  132. }
  133. _get_scheduler_type() {
  134. if _get_intervaldir > /dev/null ; then
  135. echo 'interval'
  136. elif issystemd ; then
  137. echo 'systemd'
  138. elif [ -d /etc/cron.d ] ; then
  139. echo 'crontab'
  140. else
  141. echo 'none'
  142. fi
  143. }
  144. install_build_dependencies() {
  145. bash="$(command -v bash 2> /dev/null)"
  146. if [ -z "${bash}" ] || [ ! -x "${bash}" ]; then
  147. error "Unable to find a usable version of \`bash\` (required for local build)."
  148. return 1
  149. fi
  150. info "Fetching dependency handling script..."
  151. download "${PACKAGES_SCRIPT}" "./install-required-packages.sh" || true
  152. if [ ! -s "./install-required-packages.sh" ]; then
  153. error "Downloaded dependency installation script is empty."
  154. else
  155. info "Running dependency handling script..."
  156. opts="--dont-wait --non-interactive"
  157. # shellcheck disable=SC2086
  158. if ! "${bash}" "./install-required-packages.sh" ${opts} netdata >&3 2>&3; then
  159. error "Installing build dependencies failed. The update should still work, but you might be missing some features."
  160. fi
  161. fi
  162. }
  163. enable_netdata_updater() {
  164. updater_type="$(echo "${1}" | tr '[:upper:]' '[:lower:]')"
  165. case "${updater_type}" in
  166. systemd|interval|crontab)
  167. updater_type="${1}"
  168. ;;
  169. "")
  170. updater_type="$(_get_scheduler_type)"
  171. ;;
  172. *)
  173. fatal "Unrecognized updater type ${updater_type} requested. Supported types are 'systemd', 'interval', and 'crontab'." U0001
  174. ;;
  175. esac
  176. case "${updater_type}" in
  177. "systemd")
  178. if issystemd; then
  179. systemctl enable netdata-updater.timer
  180. info "Auto-updating has been ENABLED using a systemd timer unit.\n"
  181. info "If the update process fails, the failure will be logged to the systemd journal just like a regular service failure."
  182. info "Successful updates should produce empty logs."
  183. else
  184. error "Systemd-based auto-update scheduling requested, but this does not appear to be a systemd system. Auto-updates have NOT been enabled."
  185. return 1
  186. fi
  187. ;;
  188. "interval")
  189. if _get_intervaldir > /dev/null; then
  190. ln -sf "${NETDATA_PREFIX}/usr/libexec/netdata/netdata-updater.sh" "$(_get_intervaldir)/netdata-updater"
  191. info "Auto-updating has been ENABLED through cron, updater script linked to $(_get_intervaldir)/netdata-updater\n"
  192. 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."
  193. info "Successful updates will not send an email."
  194. else
  195. error "Interval-based auto-update scheduling requested, but I could not find an interval scheduling directory. Auto-updates have NOT been enabled."
  196. return 1
  197. fi
  198. ;;
  199. "crontab")
  200. if [ -d "/etc/cron.d" ]; then
  201. [ -f "/etc/cron.d/netdata-updater" ] && rm -f "/etc/cron.d/netdata-updater"
  202. install -p -m 0644 -o 0 -g 0 "${NETDATA_PREFIX}/usr/lib/system/cron/netdata-updater-daily" "/etc/cron.d/netdata-updater-daily"
  203. info "Auto-updating has been ENABLED through cron, using a crontab at /etc/cron.d/netdata-updater\n"
  204. 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."
  205. info "Successful updates will not send an email."
  206. else
  207. error "Crontab-based auto-update scheduling requested, but there is no '/etc/cron.d'. Auto-updates have NOT been enabled."
  208. return 1
  209. fi
  210. ;;
  211. *)
  212. error "Unable to determine what type of auto-update scheduling to use. Auto-updates have NOT been enabled."
  213. return 1
  214. esac
  215. return 0
  216. }
  217. disable_netdata_updater() {
  218. if issystemd && ( systemctl list-units --full -all | grep -Fq "netdata-updater.timer" ) ; then
  219. systemctl disable netdata-updater.timer
  220. fi
  221. if [ -d /etc/cron.daily ]; then
  222. rm -f /etc/cron.daily/netdata-updater.sh
  223. rm -f /etc/cron.daily/netdata-updater
  224. fi
  225. if [ -d /etc/periodic/daily ]; then
  226. rm -f /etc/periodic/daily/netdata-updater.sh
  227. rm -f /etc/periodic/daily/netdata-updater
  228. fi
  229. if [ -d /etc/cron.d ]; then
  230. rm -f /etc/cron.d/netdata-updater
  231. rm -f /etc/cron.d/netdata-updater-daily
  232. fi
  233. info "Auto-updates have been DISABLED."
  234. return 0
  235. }
  236. str_in_list() {
  237. printf "%s\n" "${2}" | tr ' ' "\n" | grep -qE "^${1}\$"
  238. return $?
  239. }
  240. safe_sha256sum() {
  241. # Within the context of the installer, we only use -c option that is common between the two commands
  242. # We will have to reconsider if we start non-common options
  243. if command -v shasum > /dev/null 2>&1; then
  244. shasum -a 256 "$@"
  245. elif command -v sha256sum > /dev/null 2>&1; then
  246. sha256sum "$@"
  247. else
  248. fatal "I could not find a suitable checksum binary to use" U0002
  249. fi
  250. }
  251. cleanup() {
  252. if [ -n "${logfile}" ]; then
  253. cat >&2 "${logfile}"
  254. rm "${logfile}"
  255. fi
  256. if [ -n "$ndtmpdir" ] && [ -d "$ndtmpdir" ]; then
  257. rm -rf "$ndtmpdir"
  258. fi
  259. }
  260. _cannot_use_tmpdir() {
  261. testfile="$(TMPDIR="${1}" mktemp -q -t netdata-test.XXXXXXXXXX)"
  262. ret=0
  263. if [ -z "${testfile}" ] ; then
  264. return "${ret}"
  265. fi
  266. if printf '#!/bin/sh\necho SUCCESS\n' > "${testfile}" ; then
  267. if chmod +x "${testfile}" ; then
  268. if [ "$("${testfile}" 2>/dev/null)" = "SUCCESS" ] ; then
  269. ret=1
  270. fi
  271. fi
  272. fi
  273. rm -f "${testfile}"
  274. return "${ret}"
  275. }
  276. create_tmp_directory() {
  277. if [ -n "${NETDATA_TMPDIR_PATH}" ]; then
  278. echo "${NETDATA_TMPDIR_PATH}"
  279. else
  280. if [ -z "${NETDATA_TMPDIR}" ] || _cannot_use_tmpdir "${NETDATA_TMPDIR}" ; then
  281. if [ -z "${TMPDIR}" ] || _cannot_use_tmpdir "${TMPDIR}" ; then
  282. if _cannot_use_tmpdir /tmp ; then
  283. if _cannot_use_tmpdir "${PWD}" ; then
  284. fatal "Unable to find a usable temporary directory. Please set \$TMPDIR to a path that is both writable and allows execution of files and try again." U0003
  285. else
  286. TMPDIR="${PWD}"
  287. fi
  288. else
  289. TMPDIR="/tmp"
  290. fi
  291. fi
  292. else
  293. TMPDIR="${NETDATA_TMPDIR}"
  294. fi
  295. mktemp -d -t netdata-updater-XXXXXXXXXX
  296. fi
  297. }
  298. check_for_curl() {
  299. if [ -z "${curl}" ]; then
  300. curl="$(PATH="${PATH}:/opt/netdata/bin" command -v curl 2>/dev/null && true)"
  301. fi
  302. }
  303. _safe_download() {
  304. url="${1}"
  305. dest="${2}"
  306. check_for_curl
  307. if [ -n "${curl}" ]; then
  308. "${curl}" -sSL --connect-timeout 10 --retry 3 "${url}" > "${dest}"
  309. return $?
  310. elif command -v wget > /dev/null 2>&1; then
  311. wget -T 15 -O - "${url}" > "${dest}"
  312. return $?
  313. else
  314. return 255
  315. fi
  316. }
  317. download() {
  318. url="${1}"
  319. dest="${2}"
  320. _safe_download "${url}" "${dest}"
  321. ret=$?
  322. if [ ${ret} -eq 0 ]; then
  323. return 0
  324. elif [ ${ret} -eq 255 ]; then
  325. fatal "I need curl or wget to proceed, but neither is available on this system." U0004
  326. else
  327. fatal "Cannot download ${url}" U0005
  328. fi
  329. }
  330. get_netdata_latest_tag() {
  331. url="${1}/latest"
  332. dest="${2}"
  333. check_for_curl
  334. if [ -n "${curl}" ]; then
  335. tag=$("${curl}" "${url}" -s -L -I -o /dev/null -w '%{url_effective}' | grep -m 1 -o '[^/]*$')
  336. elif command -v wget >/dev/null 2>&1; then
  337. tag=$(wget -S -O /dev/null "${url}" 2>&1 | grep -m 1 Location | grep -o '[^/]*$')
  338. else
  339. fatal "I need curl or wget to proceed, but neither of them are available on this system." U0006
  340. fi
  341. echo "${tag}" >"${dest}"
  342. }
  343. newer_commit_date() {
  344. info "Checking if a newer version of the updater script is available."
  345. commit_check_url="https://api.github.com/repos/netdata/netdata/commits?path=packaging%2Finstaller%2Fnetdata-updater.sh&page=1&per_page=1"
  346. python_version_check="from __future__ import print_function;import sys,json;data = json.load(sys.stdin);print(data[0]['commit']['committer']['date'] if isinstance(data, list) else '')"
  347. if command -v jq > /dev/null 2>&1; then
  348. commit_date="$(_safe_download "${commit_check_url}" /dev/stdout | jq '.[0].commit.committer.date' 2>/dev/null | tr -d '"')"
  349. elif command -v python > /dev/null 2>&1;then
  350. commit_date="$(_safe_download "${commit_check_url}" /dev/stdout | python -c "${python_version_check}")"
  351. elif command -v python3 > /dev/null 2>&1;then
  352. commit_date="$(_safe_download "${commit_check_url}" /dev/stdout | python3 -c "${python_version_check}")"
  353. fi
  354. if [ -z "${commit_date}" ] ; then
  355. return 0
  356. elif [ "$(uname)" = "Linux" ]; then
  357. commit_date="$(date -d "${commit_date}" +%s)"
  358. else # assume BSD-style `date` if we are not on Linux
  359. commit_date="$(/bin/date -j -f "%Y-%m-%dT%H:%M:%SZ" "${commit_date}" +%s 2>/dev/null)"
  360. if [ -z "${commit_date}" ]; then
  361. return 0
  362. fi
  363. fi
  364. if [ -e "${script_source}" ]; then
  365. script_date="$(date -r "${script_source}" +%s)"
  366. else
  367. script_date="$(date +%s)"
  368. fi
  369. [ "${commit_date}" -ge "${script_date}" ]
  370. }
  371. self_update() {
  372. if [ -z "${NETDATA_NO_UPDATER_SELF_UPDATE}" ] && newer_commit_date; then
  373. info "Downloading newest version of updater script."
  374. ndtmpdir=$(create_tmp_directory)
  375. cd "$ndtmpdir" || exit 1
  376. if _safe_download "https://raw.githubusercontent.com/netdata/netdata/master/packaging/installer/netdata-updater.sh" ./netdata-updater.sh; then
  377. chmod +x ./netdata-updater.sh || exit 1
  378. export ENVIRONMENT_FILE="${ENVIRONMENT_FILE}"
  379. force_update=""
  380. [ "$NETDATA_FORCE_UPDATE" = "1" ] && force_update="--force-update"
  381. exec ./netdata-updater.sh --not-running-from-cron --no-updater-self-update "$force_update" --tmpdir-path "$(pwd)"
  382. else
  383. error "Failed to download newest version of updater script, continuing with current version."
  384. fi
  385. fi
  386. }
  387. parse_version() {
  388. r="${1}"
  389. if [ "${r}" = "latest" ]; then
  390. # If we get ‘latest’ as a version, return the largest possible
  391. # version value.
  392. printf "99999999999999"
  393. return 0
  394. elif echo "${r}" | grep -q '^v.*'; then
  395. # shellcheck disable=SC2001
  396. # XXX: Need a regex group substitution here.
  397. r="$(echo "${r}" | sed -e 's/^v\(.*\)/\1/')"
  398. fi
  399. tmpfile="$(mktemp)"
  400. echo "${r}" | tr '-' ' ' > "${tmpfile}"
  401. read -r v b _ < "${tmpfile}"
  402. if echo "${b}" | grep -vEq "^[0-9]+$"; then
  403. b="0"
  404. fi
  405. echo "${v}" | tr '.' ' ' > "${tmpfile}"
  406. read -r maj min patch _ < "${tmpfile}"
  407. rm -f "${tmpfile}"
  408. printf "%03d%03d%03d%05d" "${maj}" "${min}" "${patch}" "${b}"
  409. }
  410. get_latest_version() {
  411. if [ "${RELEASE_CHANNEL}" = "stable" ]; then
  412. get_netdata_latest_tag "${NETDATA_STABLE_BASE_URL}" /dev/stdout
  413. else
  414. get_netdata_latest_tag "${NETDATA_NIGHTLY_BASE_URL}" /dev/stdout
  415. fi
  416. }
  417. validate_environment_file() {
  418. if [ -n "${NETDATA_PREFIX+SET_BUT_NULL}" ] && [ -n "${REINSTALL_OPTIONS+SET_BUT_NULL}" ]; then
  419. return 0
  420. else
  421. fatal "Environment file located at ${ENVIRONMENT_FILE} is not valid, unable to update." U0007
  422. fi
  423. }
  424. update_available() {
  425. if [ "$NETDATA_FORCE_UPDATE" = "1" ]; then
  426. info "Force update requested"
  427. return 0
  428. fi
  429. basepath="$(dirname "$(dirname "$(dirname "${NETDATA_LIB_DIR}")")")"
  430. searchpath="${basepath}/bin:${basepath}/sbin:${basepath}/usr/bin:${basepath}/usr/sbin:${PATH}"
  431. searchpath="${basepath}/netdata/bin:${basepath}/netdata/sbin:${basepath}/netdata/usr/bin:${basepath}/netdata/usr/sbin:${searchpath}"
  432. ndbinary="$(PATH="${searchpath}" command -v netdata 2>/dev/null)"
  433. if [ -z "${ndbinary}" ]; then
  434. current_version=0
  435. else
  436. current_version="$(parse_version "$(${ndbinary} -v | cut -f 2 -d ' ')")"
  437. fi
  438. latest_tag="$(get_latest_version)"
  439. latest_version="$(parse_version "${latest_tag}")"
  440. path_version="$(echo "${latest_tag}" | cut -f 1 -d "-")"
  441. # If we can't get the current version for some reason assume `0`
  442. current_version="${current_version:-0}"
  443. # If we can't get the latest version for some reason assume `0`
  444. latest_version="${latest_version:-0}"
  445. info "Current Version: ${current_version}"
  446. info "Latest Version: ${latest_version}"
  447. if [ "${latest_version}" -gt 0 ] && [ "${current_version}" -gt 0 ] && [ "${current_version}" -ge "${latest_version}" ]; then
  448. info "Newest version (current=${current_version} >= latest=${latest_version}) is already installed"
  449. return 1
  450. else
  451. info "Update available"
  452. return 0
  453. fi
  454. }
  455. set_tarball_urls() {
  456. filename="netdata-latest.tar.gz"
  457. if [ "$2" = "yes" ]; then
  458. if [ -e /opt/netdata/etc/netdata/.install-type ]; then
  459. # shellcheck disable=SC1091
  460. . /opt/netdata/etc/netdata/.install-type
  461. filename="netdata-${PREBUILT_ARCH}-latest.gz.run"
  462. else
  463. filename="netdata-x86_64-latest.gz.run"
  464. fi
  465. fi
  466. if [ "$1" = "stable" ]; then
  467. latest="$(get_netdata_latest_tag "${NETDATA_STABLE_BASE_URL}" /dev/stdout)"
  468. export NETDATA_TARBALL_URL="${NETDATA_STABLE_BASE_URL}/download/$latest/${filename}"
  469. export NETDATA_TARBALL_CHECKSUM_URL="${NETDATA_STABLE_BASE_URL}/download/$latest/sha256sums.txt"
  470. else
  471. tag="$(get_netdata_latest_tag "${NETDATA_NIGHTLY_BASE_URL}" /dev/stdout)"
  472. export NETDATA_TARBALL_URL="${NETDATA_NIGHTLY_BASE_URL}/download/${tag}/${filename}"
  473. export NETDATA_TARBALL_CHECKSUM_URL="${NETDATA_NIGHTLY_BASE_URL}/download/${tag}/sha256sums.txt"
  474. fi
  475. }
  476. update_build() {
  477. [ -z "${logfile}" ] && info "Running on a terminal - (this script also supports running headless from crontab)"
  478. RUN_INSTALLER=0
  479. ndtmpdir=$(create_tmp_directory)
  480. cd "$ndtmpdir" || fatal "Failed to change current working directory to ${ndtmpdir}" U0016
  481. install_build_dependencies
  482. if update_available; then
  483. download "${NETDATA_TARBALL_CHECKSUM_URL}" "${ndtmpdir}/sha256sum.txt" >&3 2>&3
  484. download "${NETDATA_TARBALL_URL}" "${ndtmpdir}/netdata-latest.tar.gz"
  485. if [ -n "${NETDATA_TARBALL_CHECKSUM}" ] &&
  486. grep "${NETDATA_TARBALL_CHECKSUM}" sha256sum.txt >&3 2>&3 &&
  487. [ "$NETDATA_FORCE_UPDATE" != "1" ]; then
  488. info "Newest version is already installed"
  489. else
  490. if ! grep netdata-latest.tar.gz sha256sum.txt | safe_sha256sum -c - >&3 2>&3; then
  491. fatal "Tarball checksum validation failed. Stopping netdata upgrade and leaving tarball in ${ndtmpdir}\nUsually this is a result of an older copy of the tarball or checksum file being cached somewhere upstream and can be resolved by retrying in an hour." U0008
  492. fi
  493. NEW_CHECKSUM="$(safe_sha256sum netdata-latest.tar.gz 2> /dev/null | cut -d' ' -f1)"
  494. tar -xf netdata-latest.tar.gz >&3 2>&3
  495. rm netdata-latest.tar.gz >&3 2>&3
  496. if [ -z "$path_version" ]; then
  497. latest_tag="$(get_latest_version)"
  498. path_version="$(echo "${latest_tag}" | cut -f 1 -d "-")"
  499. fi
  500. cd "$(find . -maxdepth 1 -type d -name "netdata-${path_version}*" | head -n 1)" || fatal "Failed to switch to build directory" U0017
  501. RUN_INSTALLER=1
  502. fi
  503. fi
  504. # We got the sources, run the update now
  505. if [ ${RUN_INSTALLER} -eq 1 ]; then
  506. # signal netdata to start saving its database
  507. # this is handy if your database is big
  508. possible_pids=$(pidof netdata)
  509. do_not_start=
  510. if [ -n "${possible_pids}" ]; then
  511. # shellcheck disable=SC2086
  512. kill -USR1 ${possible_pids}
  513. else
  514. # netdata is currently not running, so do not start it after updating
  515. do_not_start="--dont-start-it"
  516. fi
  517. env="env TMPDIR=${TMPDIR}"
  518. if [ -n "${NETDATA_SELECTED_DASHBOARD}" ]; then
  519. env="${env} NETDATA_SELECTED_DASHBOARD=${NETDATA_SELECTED_DASHBOARD}"
  520. fi
  521. if [ ! -x ./netdata-installer.sh ]; then
  522. if [ "$(find . -mindepth 1 -maxdepth 1 -type d | wc -l)" -eq 1 ] && [ -x "$(find . -mindepth 1 -maxdepth 1 -type d)/netdata-installer.sh" ]; then
  523. cd "$(find . -mindepth 1 -maxdepth 1 -type d)" || fatal "Failed to switch to build directory" U0018
  524. fi
  525. fi
  526. if [ -e "${NETDATA_PREFIX}/etc/netdata/.install-type" ] ; then
  527. install_type="$(cat "${NETDATA_PREFIX}"/etc/netdata/.install-type)"
  528. else
  529. install_type="INSTALL_TYPE='legacy-build'"
  530. fi
  531. if [ "${INSTALL_TYPE}" = "custom" ] && [ -f "${NETDATA_PREFIX}" ]; then
  532. install_type="INSTALL_TYPE='legacy-build'"
  533. fi
  534. info "Re-installing netdata..."
  535. export NETDATA_SAVE_WARNINGS=1
  536. export NETDATA_PROPAGATE_WARNINGS=1
  537. export NETDATA_WARNINGS="${NETDATA_WARNINGS}"
  538. export NETDATA_SCRIPT_STATUS_PATH="${NETDATA_SCRIPT_STATUS_PATH}"
  539. # shellcheck disable=SC2086
  540. if ! ${env} ./netdata-installer.sh ${REINSTALL_OPTIONS} --dont-wait ${do_not_start} >&3 2>&3; then
  541. if [ -r "${NETDATA_SCRIPT_STATUS_PATH}" ]; then
  542. # shellcheck disable=SC1090
  543. . "${NETDATA_SCRIPT_STATUS_PATH}"
  544. rm -f "${NETDATA_SCRIPT_STATUS_PATH}"
  545. fi
  546. if [ -n "${EXIT_REASON}" ]; then
  547. fatal "Failed to rebuild existing netdata install: ${EXIT_REASON}" "U${EXIT_CODE}"
  548. else
  549. fatal "Failed to rebuild existing netdata reinstall." UI0000
  550. fi
  551. fi
  552. # We no longer store checksum info here. but leave this so that we clean up all environment files upon next update.
  553. sed -i '/NETDATA_TARBALL/d' "${ENVIRONMENT_FILE}"
  554. info "Updating tarball checksum info"
  555. echo "${NEW_CHECKSUM}" > "${NETDATA_LIB_DIR}/netdata.tarball.checksum"
  556. echo "${install_type}" > "${NETDATA_PREFIX}/etc/netdata/.install-type"
  557. fi
  558. rm -rf "${ndtmpdir}" >&3 2>&3
  559. [ -n "${logfile}" ] && rm "${logfile}" && logfile=
  560. return 0
  561. }
  562. update_static() {
  563. ndtmpdir="$(create_tmp_directory)"
  564. PREVDIR="$(pwd)"
  565. info "Entering ${ndtmpdir}"
  566. cd "${ndtmpdir}" || fatal "Failed to change current working directory to ${ndtmpdir}" U0019
  567. if update_available; then
  568. sysarch="${PREBUILT_ARCH}"
  569. [ -z "$sysarch" ] && sysarch="$(uname -m)"
  570. download "${NETDATA_TARBALL_CHECKSUM_URL}" "${ndtmpdir}/sha256sum.txt"
  571. download "${NETDATA_TARBALL_URL}" "${ndtmpdir}/netdata-${sysarch}-latest.gz.run"
  572. if ! grep "netdata-${sysarch}-latest.gz.run" "${ndtmpdir}/sha256sum.txt" | safe_sha256sum -c - > /dev/null 2>&1; then
  573. fatal "Static binary checksum validation failed. Stopping netdata installation and leaving binary in ${ndtmpdir}\nUsually this is a result of an older copy of the file being cached somewhere and can be resolved by simply retrying in an hour." U000A
  574. fi
  575. if [ -e /opt/netdata/etc/netdata/.install-type ] ; then
  576. install_type="$(cat /opt/netdata/etc/netdata/.install-type)"
  577. else
  578. install_type="INSTALL_TYPE='legacy-static'"
  579. fi
  580. # Do not pass any options other than the accept, for now
  581. # shellcheck disable=SC2086
  582. if sh "${ndtmpdir}/netdata-${sysarch}-latest.gz.run" --accept -- ${REINSTALL_OPTIONS} >&3 2>&3; then
  583. rm -r "${ndtmpdir}"
  584. else
  585. info "NOTE: did not remove: ${ndtmpdir}"
  586. fi
  587. echo "${install_type}" > /opt/netdata/etc/netdata/.install-type
  588. fi
  589. if [ -e "${PREVDIR}" ]; then
  590. info "Switching back to ${PREVDIR}"
  591. cd "${PREVDIR}"
  592. fi
  593. [ -n "${logfile}" ] && rm "${logfile}" && logfile=
  594. exit 0
  595. }
  596. update_binpkg() {
  597. os_release_file=
  598. if [ -s "/etc/os-release" ] && [ -r "/etc/os-release" ]; then
  599. os_release_file="/etc/os-release"
  600. elif [ -s "/usr/lib/os-release" ] && [ -r "/usr/lib/os-release" ]; then
  601. os_release_file="/usr/lib/os-release"
  602. else
  603. fatal "Cannot find an os-release file ..." U000B
  604. fi
  605. # shellcheck disable=SC1090
  606. . "${os_release_file}"
  607. DISTRO="${ID}"
  608. supported_compat_names="debian ubuntu centos fedora opensuse ol amzn"
  609. if str_in_list "${DISTRO}" "${supported_compat_names}"; then
  610. DISTRO_COMPAT_NAME="${DISTRO}"
  611. else
  612. case "${DISTRO}" in
  613. opensuse-leap|opensuse-tumbleweed)
  614. DISTRO_COMPAT_NAME="opensuse"
  615. ;;
  616. cloudlinux|almalinux|rocky|rhel)
  617. DISTRO_COMPAT_NAME="centos"
  618. ;;
  619. *)
  620. DISTRO_COMPAT_NAME="unknown"
  621. ;;
  622. esac
  623. fi
  624. if [ "${INTERACTIVE}" = "0" ]; then
  625. interactive_opts="-y"
  626. env="DEBIAN_FRONTEND=noninteractive"
  627. else
  628. interactive_opts=""
  629. env=""
  630. fi
  631. case "${DISTRO_COMPAT_NAME}" in
  632. debian|ubuntu)
  633. pm_cmd="apt-get"
  634. repo_subcmd="update"
  635. upgrade_cmd="--only-upgrade install"
  636. pkg_install_opts="${interactive_opts}"
  637. repo_update_opts="${interactive_opts}"
  638. pkg_installed_check="dpkg -s"
  639. INSTALL_TYPE="binpkg-deb"
  640. ;;
  641. centos|fedora|ol|amzn)
  642. if command -v dnf > /dev/null; then
  643. pm_cmd="dnf"
  644. repo_subcmd="makecache"
  645. else
  646. pm_cmd="yum"
  647. fi
  648. upgrade_cmd="upgrade"
  649. pkg_install_opts="${interactive_opts}"
  650. repo_update_opts="${interactive_opts}"
  651. pkg_installed_check="rpm -q"
  652. INSTALL_TYPE="binpkg-rpm"
  653. ;;
  654. opensuse)
  655. pm_cmd="zypper"
  656. repo_subcmd="--gpg-auto-import-keys refresh"
  657. upgrade_cmd="update"
  658. pkg_install_opts="${interactive_opts}"
  659. repo_update_opts=""
  660. pkg_installed_check="rpm -q"
  661. INSTALL_TYPE="binpkg-rpm"
  662. ;;
  663. *)
  664. warning "We do not provide native packages for ${DISTRO}."
  665. return 2
  666. ;;
  667. esac
  668. if [ -n "${repo_subcmd}" ]; then
  669. # shellcheck disable=SC2086
  670. env ${env} ${pm_cmd} ${repo_subcmd} ${repo_update_opts} >&3 2>&3 || fatal "Failed to update repository metadata." U000C
  671. fi
  672. for repopkg in netdata-repo netdata-repo-edge; do
  673. if ${pkg_installed_check} ${repopkg} > /dev/null 2>&1; then
  674. # shellcheck disable=SC2086
  675. env ${env} ${pm_cmd} ${upgrade_cmd} ${pkg_install_opts} ${repopkg} >&3 2>&3 || fatal "Failed to update Netdata repository config." U000D
  676. # shellcheck disable=SC2086
  677. if [ -n "${repo_subcmd}" ]; then
  678. env ${env} ${pm_cmd} ${repo_subcmd} ${repo_update_opts} >&3 2>&3 || fatal "Failed to update repository metadata." U000E
  679. fi
  680. fi
  681. done
  682. # shellcheck disable=SC2086
  683. env ${env} ${pm_cmd} ${upgrade_cmd} ${pkg_install_opts} netdata >&3 2>&3 || fatal "Failed to update Netdata package." U000F
  684. [ -n "${logfile}" ] && rm "${logfile}" && logfile=
  685. return 0
  686. }
  687. # Simple function to encapsulate original updater behavior.
  688. update_legacy() {
  689. set_tarball_urls "${RELEASE_CHANNEL}" "${IS_NETDATA_STATIC_BINARY}"
  690. case "${IS_NETDATA_STATIC_BINARY}" in
  691. yes) update_static && exit 0 ;;
  692. *) update_build && exit 0 ;;
  693. esac
  694. }
  695. logfile=
  696. ndtmpdir=
  697. trap cleanup EXIT
  698. if [ -t 2 ] || [ "${GITHUB_ACTIONS}" ]; then
  699. # we are running on a terminal or under CI
  700. # open fd 3 and send it to stderr
  701. exec 3>&2
  702. else
  703. # we are headless
  704. # create a temporary file for the log
  705. logfile="$(mktemp -t netdata-updater.log.XXXXXX)"
  706. # open fd 3 and send it to logfile
  707. exec 3> "${logfile}"
  708. fi
  709. : "${ENVIRONMENT_FILE:=THIS_SHOULD_BE_REPLACED_BY_INSTALLER_SCRIPT}"
  710. if [ "${ENVIRONMENT_FILE}" = "THIS_SHOULD_BE_REPLACED_BY_INSTALLER_SCRIPT" ]; then
  711. if [ -r "${script_dir}/../../../etc/netdata/.environment" ] || [ -r "${script_dir}/../../../etc/netdata/.install-type" ]; then
  712. ENVIRONMENT_FILE="${script_dir}/../../../etc/netdata/.environment"
  713. elif [ -r "/etc/netdata/.environment" ] || [ -r "/etc/netdata/.install-type" ]; then
  714. ENVIRONMENT_FILE="/etc/netdata/.environment"
  715. elif [ -r "/opt/netdata/etc/netdata/.environment" ] || [ -r "/opt/netdata/etc/netdata/.install-type" ]; then
  716. ENVIRONMENT_FILE="/opt/netdata/etc/netdata/.environment"
  717. else
  718. envpath="$(find / -type d \( -path /sys -o -path /proc -o -path /dev \) -prune -false -o -path '*netdata/.environment' -type f 2> /dev/null | head -n 1)"
  719. itpath="$(find / -type d \( -path /sys -o -path /proc -o -path /dev \) -prune -false -o -path '*netdata/.install-type' -type f 2> /dev/null | head -n 1)"
  720. if [ -r "${envpath}" ]; then
  721. ENVIRONMENT_FILE="${envpath}"
  722. elif [ -r "${itpath}" ]; then
  723. ENVIRONMENT_FILE="$(dirname "${itpath}")/.environment"
  724. else
  725. fatal "Cannot find environment file or install type file, unable to update." U0010
  726. fi
  727. fi
  728. fi
  729. if [ -r "${ENVIRONMENT_FILE}" ] ; then
  730. # shellcheck source=/dev/null
  731. . "${ENVIRONMENT_FILE}" || fatal "Failed to source ${ENVIRONMENT_FILE}" U0014
  732. fi
  733. if [ -r "$(dirname "${ENVIRONMENT_FILE}")/.install-type" ]; then
  734. # shellcheck source=/dev/null
  735. . "$(dirname "${ENVIRONMENT_FILE}")/.install-type" || fatal "Failed to source $(dirname "${ENVIRONMENT_FILE}")/.install-type" U0015
  736. fi
  737. if [ -r "$(dirname "${ENVIRONMENT_FILE}")/netdata-updater.conf" ]; then
  738. # shellcheck source=/dev/null
  739. . "$(dirname "${ENVIRONMENT_FILE}")/netdata-updater.conf"
  740. fi
  741. while [ -n "${1}" ]; do
  742. case "${1}" in
  743. --not-running-from-cron) NETDATA_NOT_RUNNING_FROM_CRON=1 ;;
  744. --no-updater-self-update) NETDATA_NO_UPDATER_SELF_UPDATE=1 ;;
  745. --force-update) NETDATA_FORCE_UPDATE=1 ;;
  746. --non-interactive) INTERACTIVE=0 ;;
  747. --interactive) INTERACTIVE=1 ;;
  748. --tmpdir-path)
  749. NETDATA_TMPDIR_PATH="${2}"
  750. shift 1
  751. ;;
  752. --enable-auto-updates)
  753. enable_netdata_updater "${2}"
  754. exit $?
  755. ;;
  756. --disable-auto-updates)
  757. disable_netdata_updater
  758. exit $?
  759. ;;
  760. *) fatal "Unrecognized option ${1}" U001A ;;
  761. esac
  762. shift 1
  763. done
  764. # Random sleep to alleviate stampede effect of Agents upgrading
  765. # and disconnecting/reconnecting at the same time (or near to).
  766. # But only we're not a controlling terminal (tty)
  767. # Randomly sleep between 1s and 60m
  768. if [ ! -t 1 ] && \
  769. [ -z "${GITHUB_ACTIONS}" ] && \
  770. [ -z "${NETDATA_NOT_RUNNING_FROM_CRON}" ] && \
  771. is_integer "${NETDATA_UPDATER_JITTER}" && \
  772. [ "${NETDATA_UPDATER_JITTER}" -gt 1 ]; then
  773. rnd="$(awk "
  774. BEGIN { srand()
  775. printf(\"%d\\n\", ${NETDATA_UPDATER_JITTER} * rand())
  776. }")"
  777. sleep $(((rnd % NETDATA_UPDATER_JITTER) + 1))
  778. fi
  779. # We dont expect to find lib dir variable on older installations, so load this path if none found
  780. export NETDATA_LIB_DIR="${NETDATA_LIB_DIR:-${NETDATA_PREFIX}/var/lib/netdata}"
  781. # Source the tarball checksum, if not already available from environment (for existing installations with the old logic)
  782. [ -z "${NETDATA_TARBALL_CHECKSUM}" ] && [ -f "${NETDATA_LIB_DIR}/netdata.tarball.checksum" ] && NETDATA_TARBALL_CHECKSUM="$(cat "${NETDATA_LIB_DIR}/netdata.tarball.checksum")"
  783. if echo "$INSTALL_TYPE" | grep -qv ^binpkg && [ "${INSTALL_UID}" != "$(id -u)" ]; then
  784. fatal "You are running this script as user with uid $(id -u). We recommend to run this script as root (user with uid 0)" U0011
  785. fi
  786. self_update
  787. # shellcheck disable=SC2153
  788. case "${INSTALL_TYPE}" in
  789. *-build)
  790. validate_environment_file
  791. set_tarball_urls "${RELEASE_CHANNEL}" "${IS_NETDATA_STATIC_BINARY}"
  792. update_build && exit 0
  793. ;;
  794. *-static*)
  795. validate_environment_file
  796. set_tarball_urls "${RELEASE_CHANNEL}" "${IS_NETDATA_STATIC_BINARY}"
  797. update_static && exit 0
  798. ;;
  799. *binpkg*) update_binpkg && exit 0 ;;
  800. "") # Fallback case for no `.install-type` file. This just works like the old install type detection.
  801. validate_environment_file
  802. update_legacy
  803. ;;
  804. custom)
  805. # At this point, we _should_ have a valid `.environment` file, but it's best to just check.
  806. # If we do, then behave like the legacy updater.
  807. if validate_environment_file && [ -n "${IS_NETDATA_STATIC_BINARY}" ]; then
  808. update_legacy
  809. else
  810. fatal "This script does not support updating custom installations without valid environment files." U0012
  811. fi
  812. ;;
  813. oci) fatal "This script does not support updating Netdata inside our official Docker containers, please instead update the container itself." U0013 ;;
  814. *) fatal "Unrecognized installation type (${INSTALL_TYPE}), unable to update." U0014 ;;
  815. esac