master
sh 1,535 lines 49.4 KB
Raw
1 #!/bin/sh
2 # SPDX-License-Identifier: GPL-3.0-or-later
3 #
4 # Netdata updater utility
5 #
6 # Variables needed by script:
7 # - PATH
8 # - CFLAGS
9 # - LDFLAGS
10 # - MAKEOPTS
11 # - IS_NETDATA_STATIC_BINARY
12 # - NETDATA_CONFIGURE_OPTIONS
13 # - REINSTALL_OPTIONS
14 # - NETDATA_TARBALL_URL
15 # - NETDATA_TARBALL_CHECKSUM_URL
16 # - NETDATA_TARBALL_CHECKSUM
17 # - NETDATA_PREFIX
18 # - NETDATA_LIB_DIR
19 #
20 # Optional environment options:
21 #
22 # - TMPDIR (set to a usable temporary directory)
23 # - NETDATA_NIGHTLIES_BASEURL (set the base url for downloading the dist tarball)
24
25 # Next unused error code: U0029
26
27 set -e
28
29 PACKAGES_SCRIPT="https://raw.githubusercontent.com/netdata/netdata/master/packaging/installer/install-required-packages.sh"
30
31 NETDATA_STABLE_BASE_URL="${NETDATA_BASE_URL:-https://github.com/netdata/netdata/releases}"
32 NETDATA_NIGHTLY_BASE_URL="${NETDATA_BASE_URL:-https://github.com/netdata/netdata-nightlies/releases}"
33 NETDATA_STABLE_REPO_URL="${NETDATA_BASE_URL:-https://repository.netdata.cloud/repos/stable}"
34 NETDATA_NIGHTLY_REPO_URL="${NETDATA_BASE_URL:-https://repository.netdata.cloud/repos/edge}"
35 NETDATA_DEFAULT_ACCEPT_MAJOR_VERSIONS="1 2"
36
37 # Following variables are intended to be overridden by the updater config file.
38 NETDATA_UPDATER_JITTER=3600
39 NETDATA_NO_SYSTEMD_JOURNAL=0
40 NETDATA_ACCEPT_MAJOR_VERSIONS=''
41
42 script_dir="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd -P)"
43
44 if [ -x "${script_dir}/netdata-updater" ]; then
45 script_source="${script_dir}/netdata-updater"
46 else
47 script_source="${script_dir}/netdata-updater.sh"
48 fi
49
50 PATH="${PATH}:/usr/local/bin:/usr/local/sbin"
51
52 if [ ! -t 1 ]; then
53 INTERACTIVE=0
54 else
55 INTERACTIVE=1
56 fi
57
58 if [ -n "${script_source}" ]; then
59 script_name="$(basename "${script_source}")"
60 else
61 script_name="netdata-updater.sh"
62 fi
63
64 info() {
65 echo >&3 "$(date) : INFO: ${script_name}: " "${1}"
66 }
67
68 warning() {
69 echo >&3 "$(date) : WARNING: ${script_name}: " "${@}"
70 }
71
72 error() {
73 echo >&3 "$(date) : ERROR: ${script_name}: " "${1}"
74 if [ -n "${NETDATA_SAVE_WARNINGS}" ]; then
75 NETDATA_WARNINGS="${NETDATA_WARNINGS}\n - ${1}"
76 fi
77 }
78
79 fatal() {
80 echo >&3 "$(date) : FATAL: ${script_name}: FAILED TO UPDATE NETDATA: " "${1}"
81 if [ -n "${NETDATA_SAVE_WARNINGS}" ]; then
82 NETDATA_WARNINGS="${NETDATA_WARNINGS}\n - ${1}"
83 fi
84 exit_reason "${1}" "${2}"
85 exit 1
86 }
87
88 exit_reason() {
89 if [ -n "${NETDATA_SAVE_WARNINGS}" ]; then
90 EXIT_REASON="${1}"
91 EXIT_CODE="${2}"
92 if [ -n "${NETDATA_PROPAGATE_WARNINGS}" ]; then
93 if [ -n "${NETDATA_SCRIPT_STATUS_PATH}" ]; then
94 {
95 echo "EXIT_REASON=\"${EXIT_REASON}\""
96 echo "EXIT_CODE=\"${EXIT_CODE}\""
97 echo "NETDATA_WARNINGS=\"${NETDATA_WARNINGS}\""
98 } >> "${NETDATA_SCRIPT_STATUS_PATH}"
99 else
100 export EXIT_REASON
101 export EXIT_CODE
102 export NETDATA_WARNINGS
103 fi
104 fi
105 fi
106 }
107
108 is_integer () {
109 case "${1#[+-]}" in
110 *[!0123456789]*) return 1 ;;
111 '') return 1 ;;
112 *) return 0 ;;
113 esac
114 }
115
116 safe_pidof() {
117 pidof_cmd="$(command -v pidof 2> /dev/null)"
118 if [ -n "${pidof_cmd}" ]; then
119 ${pidof_cmd} "${@}"
120 return $?
121 else
122 ps -acxo pid,comm |
123 sed "s/^ *//g" |
124 grep netdata |
125 cut -d ' ' -f 1
126 return $?
127 fi
128 }
129
130 issystemd() {
131 # if there is no systemctl command, it is not systemd
132 systemctl=$(command -v systemctl 2> /dev/null)
133 if [ -z "${systemctl}" ] || [ ! -x "${systemctl}" ]; then
134 return 1
135 fi
136
137 # Check the output of systemctl is-system-running.
138 # If this reports 'offline', it’s not systemd. If it reports 'unknown'
139 # or nothing at all (which indicates the command is not supported), it
140 # may or may not be systemd, so continue to other checks. If it reports
141 # anything else, it is systemd.
142 #
143 # This may return a non-zero exit status in cases when it actually
144 # succeeded for our purposes (notably, if the state is `degraded`),
145 # so we need to toggle set -e off here.
146 set +e
147 systemd_state="$(systemctl is-system-running)"
148 set -e
149
150 case "${systemd_state}" in
151 offline) return 1 ;;
152 unknown) : ;;
153 "") : ;;
154 *) return 0 ;;
155 esac
156
157 # if pid 1 is systemd, it is systemd
158 [ "$(basename "$(readlink /proc/1/exe)" 2> /dev/null)" = "systemd" ] && return 0
159
160 # if systemd is not running, it is not systemd
161 pids=$(safe_pidof systemd 2> /dev/null)
162 [ -z "${pids}" ] && return 1
163
164 # check if the running systemd processes are not in our namespace
165 myns="$(readlink /proc/self/ns/pid 2> /dev/null)"
166 for p in ${pids}; do
167 ns="$(readlink "/proc/${p}/ns/pid" 2> /dev/null)"
168
169 # if pid of systemd is in our namespace, it is systemd
170 [ -n "${myns}" ] && [ "${myns}" = "${ns}" ] && return 0
171 done
172
173 # else, it is not systemd
174 return 1
175 }
176
177 systemd_unit_exists() {
178 if systemctl list-unit-files "${1}" 2>&1 | tail -n 1 | grep -qv '^0 '; then
179 return 0
180 else
181 return 1
182 fi
183 }
184
185 # shellcheck disable=SC2009
186 running_under_anacron() {
187 pid="${1:-$$}"
188 iter="${2:-0}"
189
190 [ "${iter}" -gt 50 ] && return 1
191
192 if [ "$(uname -s)" = "Linux" ] && [ -r "/proc/${pid}/stat" ]; then
193 ppid="$(cut -f 4 -d ' ' "/proc/${pid}/stat")"
194 if [ -n "${ppid}" ]; then
195 # The below case accounts for the hidepid mount option for procfs, as well as setups with LSM
196 [ ! -r "/proc/${ppid}/comm" ] && return 1
197
198 [ "${ppid}" -eq "${pid}" ] && return 1
199
200 grep -q anacron "/proc/${ppid}/comm" && return 0
201
202 running_under_anacron "${ppid}" "$((iter + 1))"
203
204 return "$?"
205 fi
206 else
207 ppid="$(ps -o pid= -o ppid= 2>/dev/null | grep -e "^ *${pid}" | xargs | cut -f 2 -d ' ')"
208 if [ -n "${ppid}" ]; then
209 [ "${ppid}" -eq "${pid}" ] && return 1
210
211 ps -o pid= -o command= 2>/dev/null | grep -e "^ *${ppid}" | grep -q anacron && return 0
212
213 running_under_anacron "${ppid}" "$((iter + 1))"
214
215 return "$?"
216 fi
217 fi
218
219 return 1
220 }
221
222 _get_intervaldir() {
223 if [ -d /etc/cron.daily ]; then
224 echo /etc/cron.daily
225 elif [ -d /etc/periodic/daily ]; then
226 echo /etc/periodic/daily
227 else
228 return 1
229 fi
230
231 return 0
232 }
233
234 _get_scheduler_type() {
235 if _get_intervaldir > /dev/null ; then
236 echo 'interval'
237 elif issystemd ; then
238 echo 'systemd'
239 elif [ -d /etc/cron.d ] ; then
240 echo 'crontab'
241 else
242 echo 'none'
243 fi
244 }
245
246 confirm() {
247 prompt="${1} [y/n]"
248
249 while true; do
250 echo "${prompt}"
251 read -r yn
252
253 case "$yn" in
254 [Yy]*) return 0;;
255 [Nn]*) return 1;;
256 *) echo "Please answer yes or no.";;
257 esac
258 done
259 }
260
261 warn_major_update() {
262 nmv_suffix="New major versions generally involve breaking changes, and may not work in the same way as older versions."
263
264 if [ "${INTERACTIVE}" -eq 0 ]; then
265 warning "Would update to a new major version of Netdata. ${nmv_suffix}"
266 warning "To install the new major version anyway, either run the updater interactively, or include the new major version number in the NETDATA_ACCEPT_MAJOR_VERSIONS variable in ${UPDATER_CONFIG_PATH}."
267 fatal "Aborting update to new major version to avoid breaking things." U001B
268 else
269 warning "This update will install a new major version of Netdata. ${nmv_suffix}"
270 if confirm "Are you sure you want to update to a new major version of Netdata?"; then
271 notice "User accepted update to new major version of Netdata."
272 else
273 fatal "Aborting update to new major version at user request." U001C
274 fi
275 fi
276 }
277
278 install_build_dependencies() {
279 bash="$(command -v bash 2> /dev/null)"
280
281 if [ -z "${bash}" ] || [ ! -x "${bash}" ]; then
282 error "Unable to find a usable version of \`bash\` (required for local build)."
283 return 1
284 fi
285
286 info "Fetching dependency handling script..."
287 download "${PACKAGES_SCRIPT}" "./install-required-packages.sh" || true
288
289 if [ ! -s "./install-required-packages.sh" ]; then
290 error "Downloaded dependency installation script is empty."
291 else
292 info "Running dependency handling script..."
293
294 opts="--dont-wait --non-interactive"
295
296 # shellcheck disable=SC2086
297 if ! "${bash}" "./install-required-packages.sh" ${opts} netdata >&3 2>&3; then
298 error "Installing build dependencies failed. The update should still work, but you might be missing some features."
299 fi
300 fi
301 }
302
303 # Certain versions of this script had a bug that could cause /dev/null
304 # to be removed mistakenly under some circumstances.
305 #
306 # This function attempts to detect and fix the resulting situation.
307 #
308 # Fix limited to Linux for the moment because apparently trying to
309 # proactively fix systems that we aren’t certain have been affected is
310 # too invasive of a change for some people...
311 dev_null_fix() {
312 if [ -f /dev/null ] || [ ! -e /dev/null ]; then
313 case "$(uname -s)" in
314 Linux)
315 rm -f /dev/.null
316 mknod -m 666 /dev/.null c 1 3
317 # Some distros use ownership other than root:root for /dev/null,
318 # but it almost always matches the ownership of /dev/full,
319 # so if possible copy the onwership from there.
320 if [ -c /dev/full ]; then
321 chown --reference=/dev/full /dev/.null
322 fi
323 mv -f /dev/.null /dev/null
324 # If the system seems to be using SELinux, apply the correct
325 # security context to the new /dev/null.
326 #
327 # This check doesn’t use /dev/null as trying to access it
328 # without the right security context being set may fail.
329 dummy_null="$(mktemp)"
330 if command -v restorecon >"${dummy_null}" 2>&1; then
331 restorecon /dev/null
332 fi
333 rm -f "${dummy_null}" || true # Cleanup from the above check
334 ;;
335 *) ;;
336 esac
337 fi
338 }
339
340 enable_netdata_updater() {
341 updater_type="$(echo "${1}" | tr '[:upper:]' '[:lower:]')"
342 case "${updater_type}" in
343 systemd|interval|crontab)
344 updater_type="${1}"
345 ;;
346 "")
347 updater_type="$(_get_scheduler_type)"
348 ;;
349 *)
350 fatal "Unrecognized updater type ${updater_type} requested. Supported types are 'systemd', 'interval', and 'crontab'." U0001
351 ;;
352 esac
353
354 case "${updater_type}" in
355 "systemd")
356 if issystemd; then
357 if systemd_unit_exists netdata-updater.timer; then
358 systemctl enable netdata-updater.timer
359 systemctl start netdata-updater.timer
360
361 info "Auto-updating has been ENABLED using a systemd timer unit.\n"
362 info "If the update process fails, the failure will be logged to the systemd journal just like a regular service failure."
363 info "Successful updates should produce empty logs."
364 else
365 error "Systemd-based auto-update scheduling requested, but the required timer unit does not exist. Auto-updates have NOT been enabled."
366 return 1
367 fi
368 else
369 error "Systemd-based auto-update scheduling requested, but this does not appear to be a systemd system. Auto-updates have NOT been enabled."
370 return 1
371 fi
372 ;;
373 "interval")
374 if _get_intervaldir > /dev/null; then
375 ln -sf "${NETDATA_PREFIX}/usr/libexec/netdata/netdata-updater.sh" "$(_get_intervaldir)/netdata-updater"
376
377 info "Auto-updating has been ENABLED through cron, updater script linked to $(_get_intervaldir)/netdata-updater\n"
378 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."
379 info "Successful updates will not send an email."
380 else
381 error "Interval-based auto-update scheduling requested, but I could not find an interval scheduling directory. Auto-updates have NOT been enabled."
382 return 1
383 fi
384 ;;
385 "crontab")
386 if [ -d "/etc/cron.d" ]; then
387 [ -f "/etc/cron.d/netdata-updater" ] && rm -f "/etc/cron.d/netdata-updater"
388 install -p -m 0644 -o 0 -g 0 "${NETDATA_PREFIX}/usr/lib/netdata/system/cron/netdata-updater-daily" "/etc/cron.d/netdata-updater-daily"
389
390 info "Auto-updating has been ENABLED through cron, using a crontab at /etc/cron.d/netdata-updater\n"
391 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."
392 info "Successful updates will not send an email."
393 else
394 error "Crontab-based auto-update scheduling requested, but there is no '/etc/cron.d'. Auto-updates have NOT been enabled."
395 return 1
396 fi
397 ;;
398 *)
399 error "Unable to determine what type of auto-update scheduling to use. Auto-updates have NOT been enabled."
400 return 1
401 esac
402
403 return 0
404 }
405
406 disable_netdata_updater() {
407 if issystemd && systemd_unit_exists "netdata-updater.timer" ; then
408 systemctl disable netdata-updater.timer
409 systemctl stop netdata-updater.timer
410 fi
411
412 if [ -d /etc/cron.daily ]; then
413 rm -f /etc/cron.daily/netdata-updater.sh
414 rm -f /etc/cron.daily/netdata-updater
415 fi
416
417 if [ -d /etc/periodic/daily ]; then
418 rm -f /etc/periodic/daily/netdata-updater.sh
419 rm -f /etc/periodic/daily/netdata-updater
420 fi
421
422 if [ -d /etc/cron.d ]; then
423 rm -f /etc/cron.d/netdata-updater
424 rm -f /etc/cron.d/netdata-updater-daily
425 fi
426
427 info "Auto-updates have been DISABLED."
428
429 return 0
430 }
431
432 auto_update_status() {
433 case "$(_get_scheduler_type)" in
434 systemd) info "The default auto-update scheduling method for this system is: systemd timer units" ;;
435 crontab) info "The default auto-update scheduling method for this system is: drop-in crontab" ;;
436 interval) info "The default auto-update scheduling method for this system is: drop-in periodic script" ;;
437 *) info "No recognized auto-update scheduling method found" ; return ;;
438 esac
439
440 duplicate=""
441 enabled=""
442
443 if issystemd; then
444 if systemd_unit_exists "netdata-updater.timer"; then
445 if systemctl is-enabled netdata-updater.timer; then
446 info "Auto-updates using a systemd timer unit are ENABLED"
447 enabled="systemd"
448 else
449 info "Auto-updates using a systemd timer unit are DISABLED"
450 fi
451 else
452 info "Auto-updates using a systemd timer unit are NOT SUPPORTED due to: Required unit files not installed"
453 fi
454 else
455 info "Auto-updates using a systemd timer unit are NOT SUPPORTED due to: Systemd not present"
456 fi
457
458 interval_found=""
459
460 if [ -d /etc/cron.daily ]; then
461 interval_found="1"
462
463 if [ -x /etc/cron.daily/netdata-updater.sh ] || [ -x /etc/cron.daily/netdata-updater ]; then
464 info "Auto-updates using a drop-in periodic script in /etc/cron.daily are ENABLED"
465
466 if [ -n "${enabled}" ]; then
467 duplicate="1"
468 else
469 enabled="cron.daily"
470 fi
471 else
472 info "Auto-updates using a drop-in periodic script in /etc/cron.daily are DISABLED"
473 fi
474 else
475 info "Auto-updates using a drop-in periodic script in /etc/cron.daily are NOT SUPPORTED: due to: Directory does not exist"
476 fi
477
478 if [ -d /etc/periodic/daily ]; then
479 if [ -x /etc/periodic/daily/netdata-updater.sh ] || [ -x /etc/periodic/daily/netdata-updater ]; then
480 info "Auto-updates using a drop-in periodic script in /etc/periodic/daily are ENABLED"
481
482 if [ -n "${enabled}" ]; then
483 duplicate="1"
484 else
485 enabled="periodic/daily"
486 fi
487 else
488 if [ -z "${interval_found}" ]; then
489 info "Auto-updates using a drop-in periodic script in /etc/periodic/daily are DISABLED"
490 fi
491 fi
492 elif [ -z "${interval_found}" ]; then
493 info "Auto-updates using a drop-in periodic script in /etc/periodic/daily are NOT SUPPORTED due to: Directory does not exist"
494 fi
495
496 if [ -d /etc/cron.d ]; then
497 if [ -f /etc/cron.d/netdata-updater ] || [ -f /etc/cron.d/netdata-updater-daily ]; then
498 info "Auto-updates using a drop-in crontab are ENABLED"
499
500 if [ -n "${enabled}" ]; then
501 duplicate="1"
502 else
503 enabled="cron.d"
504 fi
505 else
506 info "Auto-updates using a drop-in crontab are DISABLED"
507 fi
508 else
509 info "Auto-updates using a drop-in crontab are NOT SUPPORTED due to: Directory does not exist"
510 fi
511
512 if [ -n "${duplicate}" ]; then
513 warning "More than one method of auto-updates is enabled! Please disable and re-enable auto-updates to correct this."
514 fi
515 }
516
517 str_in_list() {
518 printf "%s\n" "${2}" | tr ' ' "\n" | grep -qE "^${1}\$"
519 return $?
520 }
521
522 safe_sha256sum() {
523 # Within the context of the installer, we only use -c option that is common between the two commands
524 # We will have to reconsider if we start non-common options
525 if command -v shasum > /dev/null 2>&1; then
526 shasum -a 256 "$@"
527 elif command -v sha256sum > /dev/null 2>&1; then
528 sha256sum "$@"
529 else
530 fatal "I could not find a suitable checksum binary to use" U0002
531 fi
532 }
533
534 cleanup() {
535 if [ -n "${logfile}" ]; then
536 cat >&2 "${logfile}"
537 rm "${logfile}"
538 fi
539
540 if [ -n "$ndtmpdir" ] && [ -d "$ndtmpdir" ]; then
541 rm -rf "$ndtmpdir"
542 fi
543 }
544
545 _cannot_use_tmpdir() {
546 testfile="$(TMPDIR="${1}" mktemp -q -t netdata-test.XXXXXXXXXX)"
547 ret=0
548
549 if [ -z "${testfile}" ] ; then
550 return "${ret}"
551 fi
552
553 if printf '#!/bin/sh\necho SUCCESS\n' > "${testfile}" ; then
554 if chmod +x "${testfile}" ; then
555 if [ "$("${testfile}" 2>/dev/null)" = "SUCCESS" ] ; then
556 ret=1
557 fi
558 fi
559 fi
560
561 rm -f "${testfile}"
562 return "${ret}"
563 }
564
565 create_exec_tmp_directory() {
566 if [ -z "${ndtmpdir}" ]; then
567 if [ -n "${NETDATA_TMPDIR_PATH}" ]; then
568 ndtmpdir="${NETDATA_TMPDIR_PATH}"
569 else
570 root_dir=""
571
572 if [ -n "${NETDATA_TMPDIR}" ] && ! _cannot_use_tmpdir "${NETDATA_TMPDIR}"; then
573 root_dir="${NETDATA_TMPDIR}"
574 elif [ -n "${TMPDIR}" ] && ! _cannot_use_tmpdir "${TMPDIR}"; then
575 root_dir="${TMPDIR}"
576 elif ! _cannot_use_tmpdir /tmp; then
577 root_dir="/tmp"
578 elif ! _cannot_use_tmpdir "${PWD}"; then
579 root_dir="${PWD}"
580 else
581 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
582 fi
583
584 TMPDIR="${root_dir}"
585
586 ndtmpdir="$(mktemp -d -p "${root_dir}" -t netdata-updater-XXXXXXXXXX)"
587 fi
588 fi
589
590 info "Putting temporary files in ${ndtmpdir}"
591 }
592
593 check_for_curl() {
594 if [ -z "${curl}" ]; then
595 curl="$(PATH="${PATH}:/opt/netdata/bin" command -v curl 2>/dev/null || true)"
596 fi
597 }
598
599 check_for_wget() {
600 if [ -z "${wget}" ]; then
601 wget="$(command -v wget 2>/dev/null || true)"
602 fi
603
604 if [ -z "${wget}" ]; then
605 wget="$(command -v wget2 2>/dev/null || true)"
606 fi
607 }
608
609 _safe_download() {
610 url="${1}"
611 dest="${2}"
612
613 if echo "${url}" | grep -Eq "^file:///"; then
614 cp "${url#file://}" "${dest}" || return 1
615 return 0
616 fi
617
618 check_for_curl
619 check_for_wget
620 create_exec_tmp_directory
621 dl_log="${ndtmpdir}/download.log"
622 rm -f "${dl_log}"
623
624 if [ -n "${curl}" ]; then
625 set +e
626 "${curl}" --silent --fail --location --write-out "%{http_code}" --connect-timeout 10 --retry 3 "${url}" --output "${dest}" > "${dl_log}"
627 result="$?"
628 set -e
629
630 case "${result}" in
631 0) return 0 ;;
632 22|78)
633 [ "${dest}" != "/dev/null" ] && rm -f "${dest}"
634 case "$(tail -n 1 "${dl_log}")" in
635 404) return 1 ;;
636 4*) return 5 ;;
637 5*) return 6 ;;
638 *) return 4 ;;
639 esac
640 ;;
641 5|6|7)
642 [ "${dest}" != "/dev/null" ] && rm -f "${dest}"
643 return 2
644 ;;
645 35|60|83)
646 [ "${dest}" != "/dev/null" ] && rm -f "${dest}"
647 return 3
648 ;;
649 *)
650 [ "${dest}" != "/dev/null" ] && rm -f "${dest}"
651 return 4
652 ;;
653 esac
654 elif [ -n "${wget}" ]; then
655 set +e
656 "${wget}" -T 15 -S -o "${dl_log}" -O "${dest}" "${url}"
657 result="$?"
658 set -e
659
660 case "${result}" in
661 0) return 0 ;;
662 8)
663 [ "${dest}" != "/dev/null" ] && rm -f "${dest}"
664
665 case "$(grep "HTTP/" "${dl_log}" | tail -n 1 | awk '{ print $2 }')" in
666 404) return 1 ;;
667 4*) return 5 ;;
668 5*) return 6 ;;
669 *) return 4 ;;
670 esac
671 ;;
672 4)
673 [ "${dest}" != "/dev/null" ] && rm -f "${dest}"
674 return 2
675 ;;
676 5)
677 [ "${dest}" != "/dev/null" ] && rm -f "${dest}"
678 return 3
679 ;;
680 *)
681 [ "${dest}" != "/dev/null" ] && rm -f "${dest}"
682 return 4
683 ;;
684 esac
685 fi
686
687 return 255
688 }
689
690 download() {
691 url="${1}"
692 dest="${2}"
693
694 set +e
695 _safe_download "${url}" "${dest}"
696 ret=$?
697 set -e
698
699 case "${ret}" in
700 0) return 0 ;;
701 1) fatal "File ${url} not found on remote server" U0022 ;;
702 2) fatal "Unable to connect to remote host to download ${url}" U0023 ;;
703 3) fatal "TLS error connecting to remote host to download ${url}" U0024 ;;
704 5) fatal "Client error when trying to download ${url}" U0027 ;;
705 6) fatal "Internal server error when trying to download ${url}" U0028 ;;
706 255) fatal "I need curl or wget to proceed, but neither is available on this system." U0004 ;;
707 *) fatal "Cannot download ${url}" U0005 ;;
708 esac
709 }
710
711 get_netdata_latest_tag() {
712 url="${1}/latest"
713
714 check_for_curl
715 check_for_wget
716
717 if [ -z "${curl}" ] && [ -z "${wget}" ]; then
718 fatal "I need curl or wget to proceed, but neither of them are available on this system." U0006
719 fi
720
721 if [ -n "${curl}" ]; then
722 tag=$("${curl}" "${url}" -s -L -I -o /dev/null -w '%{url_effective}' || true)
723 fi
724
725 if [ -z "${tag}" ]; then
726 if [ -n "${wget}" ]; then
727 tag=$("${wget}" -S -O /dev/null "${url}" 2>&1 | grep Location || true)
728 fi
729 fi
730
731 if [ -z "${tag}" ]; then
732 tag='latest'
733 fi
734
735 tag="$(echo "${tag}" | grep -Eom 1 '[^/]*/?$')"
736
737 # Fallback case for simpler local testing.
738 if echo "${tag}" | grep -Eq 'latest/?$'; then
739 set +e
740 _safe_download "${url}/latest-version.txt" ./ndupdate-version.txt
741 result="$?"
742 set -e
743
744 case "${result}" in
745 0) tag="$(cat ./ndupdate-version.txt)" ;;
746 *) tag='latest' ;;
747 esac
748
749 rm -f ./ndupdate-version.txt
750 fi
751
752 echo "${tag}"
753 }
754
755 newer_commit_date() {
756 info "Checking if a newer version of the updater script is available."
757
758 create_exec_tmp_directory
759 commit_check_file="${ndtmpdir}/latest-commit.json"
760 commit_check_url="https://api.github.com/repos/netdata/netdata/commits?path=packaging%2Finstaller%2Fnetdata-updater.sh&page=1&per_page=1"
761 python_version_check="
762 from __future__ import print_function
763 import sys, json
764
765 try:
766 data = json.load(sys.stdin)
767 except:
768 print('')
769 else:
770 print(data[0]['commit']['committer']['date'] if isinstance(data, list) and data else '')
771 "
772
773 if ! _safe_download "${commit_check_url}" "${commit_check_file}"; then
774 warning "Failed to check for an updated updater script, skipping self-update check."
775 rm -f "${commit_check_file}" 2>/dev/null || true
776 return 1
777 fi
778
779 if command -v jq > /dev/null 2>&1; then
780 commit_date="$(jq '.[0].commit.committer.date' 2>/dev/null < "${commit_check_file}" | tr -d '"')"
781 elif command -v python > /dev/null 2>&1;then
782 commit_date="$(python -c "${python_version_check}" < "${commit_check_file}")"
783 elif command -v python3 > /dev/null 2>&1;then
784 commit_date="$(python3 -c "${python_version_check}" < "${commit_check_file}")"
785 fi
786
787 if [ -z "${NETDATA_TMPDIR_PATH}" ]; then
788 rm -f "${commit_check_file}" 2>/dev/null || true
789 fi
790
791 if [ -z "${commit_date}" ] ; then
792 return 0
793 elif [ "$(uname)" = "Linux" ]; then
794 commit_date="$(date -d "${commit_date}" +%s)"
795 else # assume BSD-style `date` if we are not on Linux
796 commit_date="$(/bin/date -j -f "%Y-%m-%dT%H:%M:%SZ" "${commit_date}" +%s 2>/dev/null)"
797
798 if [ -z "${commit_date}" ]; then
799 return 0
800 fi
801 fi
802
803 if [ -e "${script_source}" ]; then
804 script_date="$(date -r "${script_source}" +%s)"
805 else
806 script_date="$(date +%s)"
807 fi
808
809 [ "${commit_date}" -ge "${script_date}" ]
810 }
811
812 self_update() {
813 if [ -z "${NETDATA_NO_UPDATER_SELF_UPDATE}" ] && newer_commit_date; then
814 info "Downloading newest version of updater script."
815
816 create_exec_tmp_directory
817 cd "${ndtmpdir}" || exit 1
818
819 if _safe_download "https://raw.githubusercontent.com/netdata/netdata/master/packaging/installer/netdata-updater.sh" ./netdata-updater.sh; then
820 chmod +x ./netdata-updater.sh || exit 1
821 export ENVIRONMENT_FILE="${ENVIRONMENT_FILE}"
822
823 cmd="./netdata-updater.sh --not-running-from-cron --no-updater-self-update"
824 [ "$NETDATA_FORCE_UPDATE" = "1" ] && cmd="$cmd --force-update"
825 [ "$INTERACTIVE" = "0" ] && cmd="$cmd --non-interactive"
826 cmd="$cmd --tmpdir-path $(pwd)"
827
828 exec $cmd
829 else
830 error "Failed to download newest version of updater script, continuing with current version."
831 fi
832 fi
833 }
834
835 parse_version() {
836 r="${1}"
837 if [ "${r}" = "latest" ]; then
838 # If we get ‘latest’ as a version, return the largest possible
839 # version value.
840 printf "999999999999999"
841 return 0
842 elif echo "${r}" | grep -q '^v.*'; then
843 # shellcheck disable=SC2001
844 # XXX: Need a regex group substitution here.
845 r="$(echo "${r}" | sed -e 's/^v\(.*\)/\1/')"
846 fi
847
848 tmpfile="$(mktemp)"
849 echo "${r}" | tr '-' ' ' > "${tmpfile}"
850 read -r v b _ < "${tmpfile}"
851
852 if echo "${b}" | grep -vEq "^[0-9]+$"; then
853 b="0"
854 fi
855
856 echo "${v}" | tr '.' ' ' > "${tmpfile}"
857 read -r maj min patch _ < "${tmpfile}"
858
859 rm -f "${tmpfile}"
860
861 printf "%04d%03d%03d%05d" "${maj}" "${min}" "${patch}" "${b}"
862 }
863
864 get_latest_tag() {
865 if [ -z "${_latest_tag}" ]; then
866 if [ "${RELEASE_CHANNEL}" = "stable" ]; then
867 _latest_tag="$(get_netdata_latest_tag "${NETDATA_STABLE_BASE_URL}")"
868 else
869 _latest_tag="$(get_netdata_latest_tag "${NETDATA_NIGHTLY_BASE_URL}")"
870 fi
871 fi
872
873 echo "${_latest_tag}"
874 }
875
876 validate_environment_file() {
877 if [ -n "${NETDATA_PREFIX+SET_BUT_NULL}" ] && [ -n "${REINSTALL_OPTIONS+SET_BUT_NULL}" ]; then
878 return 0
879 else
880 fatal "Environment file located at ${ENVIRONMENT_FILE} is not valid, unable to update." U0007
881 fi
882 }
883
884 get_current_version() {
885 basepath="$(dirname "$(dirname "$(dirname "${NETDATA_LIB_DIR}")")")"
886 searchpath="${basepath}/bin:${basepath}/sbin:${basepath}/usr/bin:${basepath}/usr/sbin:${PATH}"
887 searchpath="${basepath}/netdata/bin:${basepath}/netdata/sbin:${basepath}/netdata/usr/bin:${basepath}/netdata/usr/sbin:${searchpath}"
888 ndbinary="$(PATH="${searchpath}" command -v netdata 2>/dev/null)"
889
890 if [ -z "${ndbinary}" ]; then
891 _current_version=0
892 else
893 _current_version="$(parse_version "$(${ndbinary} -V | cut -f 2 -d ' ')")"
894 fi
895
896 echo "${_current_version:-0}"
897 }
898
899 get_latest_version() {
900 parse_version "$(get_latest_tag)"
901 }
902
903 update_available() {
904 if [ "$NETDATA_FORCE_UPDATE" = "1" ]; then
905 info "Force update requested"
906 return 0
907 fi
908
909 current_version="$(get_current_version)"
910 latest_version="$(get_latest_version)"
911
912 info "Current Version: ${current_version}"
913 info "Latest Version: ${latest_version}"
914
915 if [ -z "${latest_version}" ] || [ -z "${current_version}" ] ; then
916 info "Unable to compare versions for update check, assuming an update is required."
917 return 0
918 elif [ "${latest_version}" -gt 0 ] && [ "${current_version}" -gt 0 ] && [ "${current_version}" -ge "${latest_version}" ]; then
919 info "Newest version (current=${current_version} >= latest=${latest_version}) is already installed"
920 return 1
921 else
922 info "Update available"
923
924 if [ "${current_version}" -ne 0 ] && [ "${latest_version}" -ne 0 ]; then
925 current_major="$(echo "${current_version}" | head -c 4)"
926 latest_major="$(echo "${latest_version}" | head -c 4)"
927
928 if [ "${current_major}" -ne "${latest_major}" ]; then
929 update_safe=0
930
931 for v in ${NETDATA_ACCEPT_MAJOR_VERSIONS}; do
932 if [ "${latest_major}" -eq "${v}" ]; then
933 update_safe=1
934 break
935 fi
936 done
937
938 if [ "${update_safe}" -eq 0 ]; then
939 warn_major_update
940 fi
941 fi
942 fi
943
944 return 0
945 fi
946 }
947
948 set_tarball_urls() {
949 filename="netdata-latest.tar.gz"
950
951 if [ "$2" = "yes" ]; then
952 if [ -e /opt/netdata/etc/netdata/.install-type ]; then
953 # shellcheck disable=SC1091
954 . /opt/netdata/etc/netdata/.install-type
955 [ -z "${PREBUILT_ARCH:-}" ] && PREBUILT_ARCH="$(uname -m)"
956 filename="netdata-${PREBUILT_ARCH}-latest.gz.run"
957 else
958 filename="netdata-x86_64-latest.gz.run"
959 fi
960 fi
961
962 if [ -n "${NETDATA_OFFLINE_INSTALL_SOURCE}" ]; then
963 path="$(cd "${NETDATA_OFFLINE_INSTALL_SOURCE}" || exit 1; pwd)"
964 export NETDATA_TARBALL_URL="file://${path}/${filename}"
965 export NETDATA_TARBALL_CHECKSUM_URL="file://${path}/sha256sums.txt"
966 elif [ "$1" = "stable" ]; then
967 latest="$(get_latest_tag)"
968 export NETDATA_TARBALL_URL="${NETDATA_STABLE_BASE_URL}/download/$latest/${filename}"
969 export NETDATA_TARBALL_CHECKSUM_URL="${NETDATA_STABLE_BASE_URL}/download/$latest/sha256sums.txt"
970 else
971 tag="$(get_latest_tag)"
972 export NETDATA_TARBALL_URL="${NETDATA_NIGHTLY_BASE_URL}/download/${tag}/${filename}"
973 export NETDATA_TARBALL_CHECKSUM_URL="${NETDATA_NIGHTLY_BASE_URL}/download/${tag}/sha256sums.txt"
974 fi
975 }
976
977 update_build() {
978 [ -z "${logfile}" ] && info "Running on a terminal - (this script also supports running headless from crontab)"
979
980 RUN_INSTALLER=0
981 create_exec_tmp_directory
982 cd "$ndtmpdir" || fatal "Failed to change current working directory to ${ndtmpdir}" U0016
983
984 install_build_dependencies
985
986 if update_available; then
987 download "${NETDATA_TARBALL_CHECKSUM_URL}" "${ndtmpdir}/sha256sum.txt" >&3 2>&3
988 download "${NETDATA_TARBALL_URL}" "${ndtmpdir}/netdata-latest.tar.gz"
989 if [ -n "${NETDATA_TARBALL_CHECKSUM}" ] &&
990 grep "${NETDATA_TARBALL_CHECKSUM}" sha256sum.txt >&3 2>&3 &&
991 [ "$NETDATA_FORCE_UPDATE" != "1" ]; then
992 info "Newest version is already installed"
993 else
994 if ! grep netdata-latest.tar.gz sha256sum.txt | safe_sha256sum -c - >&3 2>&3; then
995 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
996 fi
997 NEW_CHECKSUM="$(safe_sha256sum netdata-latest.tar.gz 2> /dev/null | cut -d' ' -f1)"
998 tar -xf netdata-latest.tar.gz >&3 2>&3
999 rm netdata-latest.tar.gz >&3 2>&3
1000 if [ -z "$path_version" ]; then
1001 latest_tag="$(get_latest_tag)"
1002 path_version="$(echo "${latest_tag}" | cut -f 1 -d "-")"
1003 fi
1004 cd "$(find . -maxdepth 1 -type d -name "netdata-${path_version}*" | head -n 1)" || fatal "Failed to switch to build directory" U0017
1005 RUN_INSTALLER=1
1006 fi
1007 fi
1008
1009 # We got the sources, run the update now
1010 if [ ${RUN_INSTALLER} -eq 1 ]; then
1011 # signal netdata to start saving its database
1012 # this is handy if your database is big
1013 possible_pids=$(pidof netdata)
1014 do_not_start=
1015 if [ -n "${possible_pids}" ]; then
1016 # shellcheck disable=SC2086
1017 kill -USR1 ${possible_pids}
1018 else
1019 # netdata is currently not running, so do not start it after updating
1020 do_not_start="--dont-start-it"
1021 fi
1022
1023 env="env TMPDIR=${TMPDIR}"
1024
1025 if [ -n "${NETDATA_SELECTED_DASHBOARD}" ]; then
1026 env="${env} NETDATA_SELECTED_DASHBOARD=${NETDATA_SELECTED_DASHBOARD}"
1027 fi
1028
1029 if [ ! -x ./netdata-installer.sh ]; then
1030 if [ "$(find . -mindepth 1 -maxdepth 1 -type d | wc -l)" -eq 1 ] && [ -x "$(find . -mindepth 1 -maxdepth 1 -type d)/netdata-installer.sh" ]; then
1031 cd "$(find . -mindepth 1 -maxdepth 1 -type d)" || fatal "Failed to switch to build directory" U0018
1032 fi
1033 fi
1034
1035 if [ -e "${NETDATA_PREFIX}/etc/netdata/.install-type" ] ; then
1036 install_type="$(cat "${NETDATA_PREFIX}"/etc/netdata/.install-type)"
1037 else
1038 install_type="INSTALL_TYPE='legacy-build'"
1039 fi
1040
1041 if [ "${INSTALL_TYPE}" = "custom" ] && [ -f "${NETDATA_PREFIX}" ]; then
1042 install_type="INSTALL_TYPE='legacy-build'"
1043 fi
1044
1045 info "Re-installing netdata..."
1046 export NETDATA_SAVE_WARNINGS=1
1047 export NETDATA_PROPAGATE_WARNINGS=1
1048 export NETDATA_WARNINGS="${NETDATA_WARNINGS}"
1049 export NETDATA_SCRIPT_STATUS_PATH="${NETDATA_SCRIPT_STATUS_PATH}"
1050 # shellcheck disable=SC2086
1051 if ! ${env} ./netdata-installer.sh ${REINSTALL_OPTIONS} --dont-wait ${do_not_start} >&3 2>&3; then
1052 if [ -r "${NETDATA_SCRIPT_STATUS_PATH}" ]; then
1053 # shellcheck disable=SC1090
1054 . "${NETDATA_SCRIPT_STATUS_PATH}"
1055 rm -f "${NETDATA_SCRIPT_STATUS_PATH}"
1056 fi
1057 if [ -n "${EXIT_REASON}" ]; then
1058 fatal "Failed to rebuild existing netdata install: ${EXIT_REASON}" "U${EXIT_CODE}"
1059 else
1060 fatal "Failed to rebuild existing netdata reinstall." UI0000
1061 fi
1062 fi
1063
1064 # We no longer store checksum info here. but leave this so that we clean up all environment files upon next update.
1065 sed -i '/NETDATA_TARBALL/d' "${ENVIRONMENT_FILE}"
1066
1067 info "Updating tarball checksum info"
1068 echo "${NEW_CHECKSUM}" > "${NETDATA_LIB_DIR}/netdata.tarball.checksum"
1069
1070 echo "${install_type}" > "${NETDATA_PREFIX}/etc/netdata/.install-type"
1071 fi
1072
1073 rm -rf "${ndtmpdir}" >&3 2>&3
1074 [ -n "${logfile}" ] && rm "${logfile}" && logfile=
1075
1076 return 0
1077 }
1078
1079 update_static() {
1080 create_exec_tmp_directory
1081 PREVDIR="$(pwd)"
1082
1083 info "Entering ${ndtmpdir}"
1084 cd "${ndtmpdir}" || fatal "Failed to change current working directory to ${ndtmpdir}" U0019
1085
1086 if update_available; then
1087 sysarch="${PREBUILT_ARCH}"
1088 [ -z "$sysarch" ] && sysarch="$(uname -m)"
1089 download "${NETDATA_TARBALL_CHECKSUM_URL}" "${ndtmpdir}/sha256sum.txt"
1090 download "${NETDATA_TARBALL_URL}" "${ndtmpdir}/netdata-${sysarch}-latest.gz.run"
1091 if ! grep "netdata-${sysarch}-latest.gz.run" "${ndtmpdir}/sha256sum.txt" | safe_sha256sum -c - > /dev/null 2>&1; then
1092 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
1093 fi
1094
1095 if [ -e /opt/netdata/etc/netdata/.install-type ] ; then
1096 install_type="$(cat /opt/netdata/etc/netdata/.install-type)"
1097 else
1098 install_type="INSTALL_TYPE='legacy-static'"
1099 fi
1100
1101 # Do not pass any options other than the accept, for now
1102 # shellcheck disable=SC2086
1103 if sh "${ndtmpdir}/netdata-${sysarch}-latest.gz.run" --accept -- ${REINSTALL_OPTIONS} >&3 2>&3; then
1104 rm -r "${ndtmpdir}"
1105 else
1106 info "NOTE: did not remove: ${ndtmpdir}"
1107 fi
1108
1109 echo "${install_type}" > /opt/netdata/etc/netdata/.install-type
1110 fi
1111
1112 if [ -e "${PREVDIR}" ]; then
1113 info "Switching back to ${PREVDIR}"
1114 cd "${PREVDIR}"
1115 fi
1116 [ -n "${logfile}" ] && rm "${logfile}" && logfile=
1117
1118 return 0
1119 }
1120
1121 get_new_binpkg_major() {
1122 case "${pm_cmd}" in
1123 apt-get) apt-get --just-print upgrade 2>&1 | grep Inst | grep ' netdata ' | cut -f 3 -d ' ' | tr -d '[]' | cut -f 1 -d '.' ;;
1124 yum) yum check-update netdata | grep -E '^netdata ' | awk '{print $2}' | cut -f 1 -d '.' ;;
1125 dnf) dnf check-update netdata | grep -E '^netdata ' | awk '{print $2}' | cut -f 1 -d '.' ;;
1126 zypper) zypper list-updates | grep '| netdata |' | cut -f 5 -d '|' | tr -d ' ' | cut -f 1 -d '.' ;;
1127 esac
1128 }
1129
1130 update_binpkg() {
1131 os_release_file=
1132 if [ -s "/etc/os-release" ] && [ -r "/etc/os-release" ]; then
1133 os_release_file="/etc/os-release"
1134 elif [ -s "/usr/lib/os-release" ] && [ -r "/usr/lib/os-release" ]; then
1135 os_release_file="/usr/lib/os-release"
1136 else
1137 fatal "Cannot find an os-release file ..." U000B
1138 fi
1139
1140 # shellcheck disable=SC1090
1141 . "${os_release_file}"
1142
1143 DISTRO="${ID}"
1144 SYSVERSION="${VERSION_ID}"
1145
1146 supported_compat_names="debian ubuntu centos centos-stream fedora opensuse ol amzn"
1147
1148 if str_in_list "${DISTRO}" "${supported_compat_names}"; then
1149 DISTRO_COMPAT_NAME="${DISTRO}"
1150 else
1151 case "${DISTRO}" in
1152 opensuse-leap|opensuse-tumbleweed)
1153 DISTRO_COMPAT_NAME="opensuse"
1154 ;;
1155 cloudlinux|almalinux|rocky|rhel)
1156 DISTRO_COMPAT_NAME="centos"
1157 ;;
1158 raspbian)
1159 SYSARCH="$(uname -m)"
1160 if [ "$SYSARCH" = "armv7l" ] || [ "$SYSARCH" = "aarch64" ]; then
1161 DISTRO_COMPAT_NAME="debian"
1162 fi
1163 ;;
1164 *)
1165 DISTRO_COMPAT_NAME="unknown"
1166 ;;
1167 esac
1168 fi
1169
1170 interactive_opts=""
1171 env=""
1172
1173 case "${DISTRO_COMPAT_NAME}" in
1174 debian|ubuntu)
1175 if [ "${INTERACTIVE}" = "0" ]; then
1176 upgrade_subcmd="-o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold --only-upgrade install"
1177 interactive_opts="-y"
1178 env="DEBIAN_FRONTEND=noninteractive"
1179 else
1180 upgrade_subcmd="--only-upgrade install"
1181 fi
1182 pm_cmd="apt-get"
1183 repo_subcmd="update"
1184 install_subcmd="install"
1185 mark_auto_cmd="apt-mark auto"
1186 pkg_install_opts="${interactive_opts}"
1187 repo_update_opts="${interactive_opts}"
1188 pkg_installed_check="dpkg-query -s"
1189 INSTALL_TYPE="binpkg-deb"
1190 if [ -n "${VERSION_CODENAME}" ]; then
1191 repo_path="${DISTRO_COMPAT_NAME}/${VERSION_CODENAME}"
1192 fi
1193 ;;
1194 centos|centos-stream|fedora|ol|amzn)
1195 if [ "${INTERACTIVE}" = "0" ]; then
1196 interactive_opts="-y"
1197 fi
1198 if command -v dnf > /dev/null; then
1199 pm_cmd="dnf"
1200 repo_subcmd="makecache"
1201 mark_auto_cmd="dnf mark remove"
1202 else
1203 pm_cmd="yum"
1204 mark_auto_cmd="yumdb set reason dep"
1205 fi
1206 upgrade_subcmd="upgrade"
1207 install_subcmd="install"
1208 pkg_install_opts="${interactive_opts}"
1209 repo_update_opts="${interactive_opts}"
1210 pkg_installed_check="rpm -q"
1211 INSTALL_TYPE="binpkg-rpm"
1212 case "${DISTRO_COMPAT_NAME}" in
1213 amzn) repo_path="amazonlinux/${SYSVERSION}/$(uname -m)" ;;
1214 centos-stream) repo_path="el/c${SYSVERSION}s/$(uname -m)" ;;
1215 fedora) repo_path="fedora/${SYSVERSION}/$(uname -m)" ;;
1216 ol) repo_path="ol/${SYSVERSION}/$(uname -m)" ;;
1217 *) repo_path="el/$(echo "${SYSVERSION}" | cut -f 1 -d '.')/$(uname -m)" ;;
1218 esac
1219 ;;
1220 opensuse)
1221 if [ "${INTERACTIVE}" = "0" ]; then
1222 upgrade_subcmd="--non-interactive update"
1223 else
1224 upgrade_subcmd="update"
1225 fi
1226 pm_cmd="zypper"
1227 repo_subcmd="--gpg-auto-import-keys refresh"
1228 install_subcmd="install"
1229 mark_auto_cmd=""
1230 pkg_install_opts=""
1231 repo_update_opts=""
1232 pkg_installed_check="rpm -q"
1233 INSTALL_TYPE="binpkg-rpm"
1234 repo_path="${DISTRO_COMPAT_NAME}/${SYSVERSION}/$(uname -m)"
1235 ;;
1236 *)
1237 warning "We do not provide native packages for ${DISTRO}."
1238 return 2
1239 ;;
1240 esac
1241
1242 initial_version="$(get_current_version)"
1243
1244 if [ -n "${repo_subcmd}" ]; then
1245 # shellcheck disable=SC2086
1246 env ${env} ${pm_cmd} ${repo_subcmd} ${repo_update_opts} >&3 2>&3 || fatal "Failed to update repository metadata." U000C
1247 fi
1248
1249 if ${pkg_installed_check} netdata-repo > /dev/null 2>&1; then
1250 RELEASE_CHANNEL="stable"
1251 repopkg="netdata-repo"
1252 elif ${pkg_installed_check} netdata-repo-edge > /dev/null 2>&1; then
1253 RELEASE_CHANNEL="nightly"
1254 repopkg="netdata-repo-edge"
1255 elif echo "${initial_version}" | grep -Eq -- '^[0-9]*[1-9][0-9]*0{5}$'; then # All five final digits are zero and at least one preceeding digit is non-zero.
1256 RELEASE_CHANNEL="stable"
1257 elif echo "${initial_version}" | grep -Eq -- '^[0-9]*[1-9][0-9]{0,4}$'; then # At least one of the final five digits is non-zero.
1258 RELEASE_CHANNEL="nightly"
1259 else
1260 RELEASE_CHANNEL="none"
1261 warning "Unable to determine which release channel is being used on this system, cannot check if packages are still being published."
1262 fi
1263
1264 if [ -n "${repo_path}" ]; then
1265 case "${RELEASE_CHANNEL}" in
1266 stable) check_url="${NETDATA_STABLE_REPO_URL}/${repo_path}/.currently.published" ;;
1267 nightly) check_url="${NETDATA_NIGHTLY_REPO_URL}/${repo_path}/.currently.published" ;;
1268 esac
1269 fi
1270
1271 if [ -n "${check_url}" ]; then
1272 info "Checking if native packages are still being published for this platform."
1273
1274 set +e
1275 _safe_download "${check_url}" /dev/null
1276 ret=$?
1277 set -e
1278
1279 case "${ret}" in
1280 0) info "Native packages are still being published for this platform." ;;
1281 1)
1282 error ""
1283 error "NETDATA CANNOT BE UPDATED ON THIS SYSTEM!"
1284 error ""
1285 error "Native packages are no longer being published for this platform."
1286 error ""
1287 error "To update to the latest version of Netdata, you will need to switch to a different install type."
1288 error "For details on how to do so, see https://learn.netdata.cloud/docs/netdata-agent/installation/linux/switch-install-types-and-release-channels"
1289 error ""
1290 fatal "Unable to update due to native packages no longer being published for this platform" U001E
1291 ;;
1292 2) fatal "Failed to connect to Netdata package repositories. This is most likely a result of networking problems with this system." U001F ;;
1293 3) fatal "TLS error when trying to connect to Netdata package repositories." U0020 ;;
1294 4) fatal "Unknown error when trying to connect to Netdata package repositories." U0021 ;;
1295 5) fatal "Client error when trying to connect to Netdata package repositories." U0025 ;;
1296 6) fatal "Internal server error when trying to connect to Netdata package repositories." U0026 ;;
1297 255) warning "Unable to check whether native packages are being published, wget or curl is required." ;;
1298 esac
1299 fi
1300
1301 if [ -n "${repopkg}" ]; then
1302 # shellcheck disable=SC2086
1303 env ${env} ${pm_cmd} ${upgrade_subcmd} ${pkg_install_opts} ${repopkg} >&3 2>&3 || fatal "Failed to update Netdata repository config." U000D
1304 # shellcheck disable=SC2086
1305 if [ -n "${repo_subcmd}" ]; then
1306 env ${env} ${pm_cmd} ${repo_subcmd} ${repo_update_opts} >&3 2>&3 || fatal "Failed to update repository metadata." U000E
1307 fi
1308 fi
1309
1310 current_major="$(get_current_version | head -c 4 | awk '{ print $1 + 0 }')"
1311 latest_major="$(get_new_binpkg_major)"
1312
1313 # current_major == 0 means we could not determine the installed version
1314 if [ -n "${latest_major}" ] && [ "${current_major}" -ne 0 ] && [ "${latest_major}" -ne "${current_major}" ]; then
1315 update_safe=0
1316
1317 for v in ${NETDATA_ACCEPT_MAJOR_VERSIONS}; do
1318 if [ "${latest_major}" -eq "${v}" ]; then
1319 update_safe=1
1320 break
1321 fi
1322 done
1323
1324 if [ "${update_safe}" -eq 0 ]; then
1325 warn_major_update
1326 fi
1327 fi
1328
1329 # shellcheck disable=SC2086
1330 env ${env} ${pm_cmd} ${upgrade_subcmd} ${pkg_install_opts} netdata >&3 2>&3 || fatal "Failed to update Netdata package." U000F
1331
1332 if ${pkg_installed_check} systemd > /dev/null 2>&1; then
1333 if [ "${NETDATA_NO_SYSTEMD_JOURNAL}" -eq 0 ]; then
1334 if ! ${pkg_installed_check} netdata-plugin-systemd-journal > /dev/null 2>&1; then
1335 env ${env} ${pm_cmd} ${install_subcmd} ${pkg_install_opts} netdata-plugin-systemd-journal >&3 2>&3
1336
1337 if [ -n "${mark_auto_cmd}" ]; then
1338 # shellcheck disable=SC2086
1339 env ${env} ${mark_auto_cmd} netdata-plugin-systemd-journal >&3 2>&3
1340 fi
1341 fi
1342 fi
1343 fi
1344
1345 current_version="$(get_current_version)"
1346 latest_version="$(get_latest_version)"
1347
1348 if [ "${RELEASE_CHANNEL}" != "none" ] && [ "${current_version}" -ne 0 ] && [ "${latest_version}" -ne 0 ]; then
1349 if [ "${current_version}" -lt "${latest_version}" ] && [ "${initial_version}" -eq "${current_version}" ]; then
1350 error ""
1351 error "NETDATA WAS NOT UPDATED!"
1352 error ""
1353 error "A newer version of Netdata is available, but the system package manager does not appear to have updated to that version."
1354 error ""
1355 error "Most likely, your system is not up to date, and you have it configured in a way that prevents updating one or more of Netdata's dependencies."
1356 error "Please try updating your system manually and then re-running the Netdata updater before reporting an issue with the update process."
1357 error ""
1358 fatal "Package manager did not fully update Netdata despite not reporting a failure." U001D
1359 fi
1360 fi
1361
1362 [ -n "${logfile}" ] && rm "${logfile}" && logfile=
1363 return 0
1364 }
1365
1366 # Simple function to encapsulate original updater behavior.
1367 update_legacy() {
1368 set_tarball_urls "${RELEASE_CHANNEL}" "${IS_NETDATA_STATIC_BINARY}"
1369 case "${IS_NETDATA_STATIC_BINARY}" in
1370 yes) update_static && exit 0 ;;
1371 *) update_build && exit 0 ;;
1372 esac
1373 }
1374
1375 logfile=
1376 ndtmpdir=
1377
1378 trap cleanup EXIT
1379
1380 if [ -t 2 ] || [ "${GITHUB_ACTIONS}" ]; then
1381 # we are running on a terminal or under CI
1382 # open fd 3 and send it to stderr
1383 exec 3>&2
1384 else
1385 # we are headless
1386 # create a temporary file for the log
1387 logfile="$(mktemp -t netdata-updater.log.XXXXXX)"
1388 # open fd 3 and send it to logfile
1389 exec 3> "${logfile}"
1390 fi
1391
1392 : "${ENVIRONMENT_FILE:=THIS_SHOULD_BE_REPLACED_BY_INSTALLER_SCRIPT}"
1393
1394 if [ "${ENVIRONMENT_FILE}" = "THIS_SHOULD_BE_REPLACED_BY_INSTALLER_SCRIPT" ]; then
1395 if [ -r "${script_dir}/../../../etc/netdata/.environment" ] || [ -r "${script_dir}/../../../etc/netdata/.install-type" ]; then
1396 ENVIRONMENT_FILE="${script_dir}/../../../etc/netdata/.environment"
1397 elif [ -r "/etc/netdata/.environment" ] || [ -r "/etc/netdata/.install-type" ]; then
1398 ENVIRONMENT_FILE="/etc/netdata/.environment"
1399 elif [ -r "/opt/netdata/etc/netdata/.environment" ] || [ -r "/opt/netdata/etc/netdata/.install-type" ]; then
1400 ENVIRONMENT_FILE="/opt/netdata/etc/netdata/.environment"
1401 else
1402 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)"
1403 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)"
1404 if [ -r "${envpath}" ]; then
1405 ENVIRONMENT_FILE="${envpath}"
1406 elif [ -r "${itpath}" ]; then
1407 ENVIRONMENT_FILE="$(dirname "${itpath}")/.environment"
1408 else
1409 fatal "Cannot find environment file or install type file, unable to update." U0010
1410 fi
1411 fi
1412 fi
1413
1414 if [ -r "${ENVIRONMENT_FILE}" ] ; then
1415 # shellcheck source=/dev/null
1416 . "${ENVIRONMENT_FILE}" || fatal "Failed to source ${ENVIRONMENT_FILE}" U0014
1417 fi
1418
1419 if [ -r "$(dirname "${ENVIRONMENT_FILE}")/.install-type" ]; then
1420 # shellcheck source=/dev/null
1421 . "$(dirname "${ENVIRONMENT_FILE}")/.install-type" || fatal "Failed to source $(dirname "${ENVIRONMENT_FILE}")/.install-type" U0015
1422 fi
1423
1424 UPDATER_CONFIG_PATH="$(dirname "${ENVIRONMENT_FILE}")/netdata-updater.conf"
1425 if [ -r "${UPDATER_CONFIG_PATH}" ]; then
1426 # shellcheck source=/dev/null
1427 . "${UPDATER_CONFIG_PATH}"
1428 fi
1429
1430 [ -z "${NETDATA_ACCEPT_MAJOR_VERSIONS}" ] && NETDATA_ACCEPT_MAJOR_VERSIONS="${NETDATA_DEFAULT_ACCEPT_MAJOR_VERSIONS}"
1431
1432 while [ -n "${1}" ]; do
1433 case "${1}" in
1434 --not-running-from-cron) NETDATA_NOT_RUNNING_FROM_CRON=1 ;;
1435 --no-updater-self-update) NETDATA_NO_UPDATER_SELF_UPDATE=1 ;;
1436 --force-update) NETDATA_FORCE_UPDATE=1 ;;
1437 --non-interactive) INTERACTIVE=0 ;;
1438 --interactive) INTERACTIVE=1 ;;
1439 --offline-install-source)
1440 NETDATA_OFFLINE_INSTALL_SOURCE="${2}"
1441 shift 1
1442 ;;
1443 --tmpdir-path)
1444 NETDATA_TMPDIR_PATH="${2}"
1445 shift 1
1446 ;;
1447 --enable-auto-updates)
1448 enable_netdata_updater "${2}"
1449 exit $?
1450 ;;
1451 --disable-auto-updates)
1452 disable_netdata_updater
1453 exit $?
1454 ;;
1455 --auto-update-status)
1456 auto_update_status
1457 exit 0
1458 ;;
1459 *) fatal "Unrecognized option ${1}" U001A ;;
1460 esac
1461
1462 shift 1
1463 done
1464
1465 if [ -n "${NETDATA_OFFLINE_INSTALL_SOURCE}" ]; then
1466 NETDATA_NO_UPDATER_SELF_UPDATE=1
1467 NETDATA_UPDATER_JITTER=0
1468 NETDATA_FORCE_UPDATE=1
1469 fi
1470
1471 # If we seem to be running under anacron, act as if we’re not running from cron.
1472 # This is mostly to disable jitter, which should not be needed when run from anacron.
1473 if running_under_anacron; then
1474 NETDATA_NOT_RUNNING_FROM_CRON="${NETDATA_NOT_RUNNING_FROM_CRON:-1}"
1475 fi
1476
1477 # Random sleep to alleviate stampede effect of Agents upgrading
1478 # and disconnecting/reconnecting at the same time (or near to).
1479 # But only we're not a controlling terminal (tty)
1480 # Randomly sleep between 1s and 60m
1481 if [ ! -t 1 ] && \
1482 [ -z "${GITHUB_ACTIONS}" ] && \
1483 [ -z "${NETDATA_NOT_RUNNING_FROM_CRON}" ] && \
1484 is_integer "${NETDATA_UPDATER_JITTER}" && \
1485 [ "${NETDATA_UPDATER_JITTER}" -gt 1 ]; then
1486 rnd="$(awk "
1487 BEGIN { srand()
1488 printf(\"%d\\n\", ${NETDATA_UPDATER_JITTER} * rand())
1489 }")"
1490 sleep $(((rnd % NETDATA_UPDATER_JITTER) + 1))
1491 fi
1492
1493 # We dont expect to find lib dir variable on older installations, so load this path if none found
1494 export NETDATA_LIB_DIR="${NETDATA_LIB_DIR:-${NETDATA_PREFIX}/var/lib/netdata}"
1495
1496 # Source the tarball checksum, if not already available from environment (for existing installations with the old logic)
1497 [ -z "${NETDATA_TARBALL_CHECKSUM}" ] && [ -f "${NETDATA_LIB_DIR}/netdata.tarball.checksum" ] && NETDATA_TARBALL_CHECKSUM="$(cat "${NETDATA_LIB_DIR}/netdata.tarball.checksum")"
1498
1499 if echo "$INSTALL_TYPE" | grep -qv ^binpkg && [ "${INSTALL_UID}" != "$(id -u)" ]; then
1500 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
1501 fi
1502
1503 self_update
1504
1505 dev_null_fix
1506
1507 # shellcheck disable=SC2153
1508 case "${INSTALL_TYPE}" in
1509 *-build)
1510 validate_environment_file
1511 set_tarball_urls "${RELEASE_CHANNEL}" "${IS_NETDATA_STATIC_BINARY}"
1512 update_build && exit 0
1513 ;;
1514 *-static*)
1515 validate_environment_file
1516 set_tarball_urls "${RELEASE_CHANNEL}" "${IS_NETDATA_STATIC_BINARY}"
1517 update_static && exit 0
1518 ;;
1519 *binpkg*) update_binpkg && exit 0 ;;
1520 "") # Fallback case for no `.install-type` file. This just works like the old install type detection.
1521 validate_environment_file
1522 update_legacy
1523 ;;
1524 custom)
1525 # At this point, we _should_ have a valid `.environment` file, but it's best to just check.
1526 # If we do, then behave like the legacy updater.
1527 if validate_environment_file && [ -n "${IS_NETDATA_STATIC_BINARY}" ]; then
1528 update_legacy
1529 else
1530 fatal "This script does not support updating custom installations without valid environment files." U0012
1531 fi
1532 ;;
1533 oci) fatal "This script does not support updating Netdata inside our official Docker containers, please instead update the container itself." U0013 ;;
1534 *) fatal "Unrecognized installation type (${INSTALL_TYPE}), unable to update." U0014 ;;
1535 esac