netdata-uninstaller.sh 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. #!/usr/bin/env bash
  2. #
  3. # This is the netdata uninstaller script
  4. #
  5. # Variables needed by script and taken from '.environment' file:
  6. # - NETDATA_PREFIX
  7. # - NETDATA_ADDED_TO_GROUPS
  8. #
  9. # Copyright: SPDX-License-Identifier: GPL-3.0-or-later
  10. #
  11. # Author: Paweł Krupa <paulfantom@gmail.com>
  12. # Author: Pavlos Emm. Katsoulakis <paul@netdata.cloud>
  13. usage="$(basename "$0") [-h] [-f ] -- program to calculate the answer to life, the universe and everything
  14. where:
  15. -e, --env path to environment file (defauls to '/etc/netdata/.environment'
  16. -f, --force force uninstallation and do not ask any questions
  17. -h show this help text
  18. -y, --yes flag needs to be set to proceed with uninstallation"
  19. FILE_REMOVAL_STATUS=0
  20. ENVIRONMENT_FILE="/etc/netdata/.environment"
  21. INTERACTIVITY="-i"
  22. YES=0
  23. while :; do
  24. case "$1" in
  25. -h | --help)
  26. echo "$usage" >&2
  27. exit 1
  28. ;;
  29. -f | --force)
  30. INTERACTIVITY="-f"
  31. shift
  32. ;;
  33. -y | --yes)
  34. YES=1
  35. shift
  36. ;;
  37. -e | --env)
  38. ENVIRONMENT_FILE="$2"
  39. shift 2
  40. ;;
  41. -*)
  42. echo "$usage" >&2
  43. exit 1
  44. ;;
  45. *) break ;;
  46. esac
  47. done
  48. if [ "$YES" != "1" ]; then
  49. echo >&2 "This script will REMOVE netdata from your system."
  50. echo >&2 "Run it again with --yes to do it."
  51. exit 1
  52. fi
  53. if [[ $EUID -ne 0 ]]; then
  54. echo >&2 "This script SHOULD be run as root or otherwise it won't delete all installed components."
  55. key="n"
  56. read -r -s -n 1 -p "Do you want to continue as non-root user [y/n] ? " key
  57. if [ "$key" != "y" ] && [ "$key" != "Y" ]; then
  58. exit 1
  59. fi
  60. fi
  61. # -----------------------------------------------------------------------------
  62. # portable service command
  63. service_cmd="$(command -v service 2> /dev/null)"
  64. rcservice_cmd="$(command -v rc-service 2> /dev/null)"
  65. systemctl_cmd="$(command -v systemctl 2> /dev/null)"
  66. service() {
  67. local cmd="${1}" action="${2}"
  68. if [ -n "${systemctl_cmd}" ]; then
  69. run "${systemctl_cmd}" "${action}" "${cmd}"
  70. return $?
  71. elif [ -n "${service_cmd}" ]; then
  72. run "${service_cmd}" "${cmd}" "${action}"
  73. return $?
  74. elif [ -n "${rcservice_cmd}" ]; then
  75. run "${rcservice_cmd}" "${cmd}" "${action}"
  76. return $?
  77. fi
  78. return 1
  79. }
  80. # -----------------------------------------------------------------------------
  81. setup_terminal() {
  82. TPUT_RESET=""
  83. TPUT_YELLOW=""
  84. TPUT_WHITE=""
  85. TPUT_BGRED=""
  86. TPUT_BGGREEN=""
  87. TPUT_BOLD=""
  88. TPUT_DIM=""
  89. # Is stderr on the terminal? If not, then fail
  90. test -t 2 || return 1
  91. if command -v tput 1> /dev/null 2>&1; then
  92. if [ $(($(tput colors 2> /dev/null))) -ge 8 ]; then
  93. # Enable colors
  94. TPUT_RESET="$(tput sgr 0)"
  95. TPUT_YELLOW="$(tput setaf 3)"
  96. TPUT_WHITE="$(tput setaf 7)"
  97. TPUT_BGRED="$(tput setab 1)"
  98. TPUT_BGGREEN="$(tput setab 2)"
  99. TPUT_BOLD="$(tput bold)"
  100. TPUT_DIM="$(tput dim)"
  101. fi
  102. fi
  103. return 0
  104. }
  105. setup_terminal || echo > /dev/null
  106. run_ok() {
  107. printf >&2 "%s OK %s\n\n" "${TPUT_BGGREEN}${TPUT_WHITE}${TPUT_BOLD}" "${TPUT_RESET}"
  108. }
  109. run_failed() {
  110. printf >&2 "%s FAILED %s\n\n" "${TPUT_BGRED}${TPUT_WHITE}${TPUT_BOLD}" "${TPUT_RESET}"
  111. }
  112. ESCAPED_PRINT_METHOD=
  113. if printf "%q " test > /dev/null 2>&1; then
  114. ESCAPED_PRINT_METHOD="printfq"
  115. fi
  116. escaped_print() {
  117. if [ "${ESCAPED_PRINT_METHOD}" = "printfq" ]; then
  118. printf "%q " "${@}"
  119. else
  120. printf "%s" "${*}"
  121. fi
  122. return 0
  123. }
  124. run_logfile="/dev/null"
  125. run() {
  126. local user="${USER--}" dir="${PWD}" info info_console
  127. if [ "${UID}" = "0" ]; then
  128. info="[root ${dir}]# "
  129. info_console="[${TPUT_DIM}${dir}${TPUT_RESET}]# "
  130. else
  131. info="[${user} ${dir}]$ "
  132. info_console="[${TPUT_DIM}${dir}${TPUT_RESET}]$ "
  133. fi
  134. {
  135. printf "%s" "${info}"
  136. escaped_print "${@}"
  137. printf "%s" " ... "
  138. } >> "${run_logfile}"
  139. printf "%s" "${info_console}${TPUT_BOLD}${TPUT_YELLOW}" >&2
  140. escaped_print >&2 "${@}"
  141. printf "%s\n" "${TPUT_RESET}" >&2
  142. "${@}"
  143. local ret=$?
  144. if [ ${ret} -ne 0 ]; then
  145. run_failed
  146. printf >> "${run_logfile}" "FAILED with exit code %s\n" "${ret}"
  147. else
  148. run_ok
  149. printf >> "${run_logfile}" "OK\n"
  150. fi
  151. return ${ret}
  152. }
  153. portable_del_group() {
  154. local groupname="${1}"
  155. # Check if group exist
  156. echo >&2 "Removing ${groupname} user group ..."
  157. # Linux
  158. if command -v groupdel 1> /dev/null 2>&1; then
  159. if grep -q "${groupname}" /etc/group; then
  160. run groupdel "${groupname}" && return 0
  161. else
  162. echo >&2 "Group ${groupname} already removed in a previous step."
  163. return 0
  164. fi
  165. fi
  166. # mac OS
  167. if command -v dseditgroup 1> /dev/null 2>&1; then
  168. if dseditgroup -o read netdata 1> /dev/null 2>&1; then
  169. run dseditgroup -o delete "${groupname}" && return 0
  170. else
  171. echo >&2 "Could not find group ${groupname}, nothing to do"
  172. return 0
  173. fi
  174. fi
  175. echo >&2 "Group ${groupname} was not automatically removed, you might have to remove it manually"
  176. return 1
  177. }
  178. issystemd() {
  179. local pids p myns ns systemctl
  180. # if the directory /lib/systemd/system OR /usr/lib/systemd/system (SLES 12.x) does not exit, it is not systemd
  181. if [ ! -d /lib/systemd/system ] && [ ! -d /usr/lib/systemd/system ]; then
  182. return 1
  183. fi
  184. # if there is no systemctl command, it is not systemd
  185. systemctl=$(command -v systemctl 2> /dev/null)
  186. if [ -z "${systemctl}" ] || [ ! -x "${systemctl}" ]; then
  187. return 1
  188. fi
  189. # if pid 1 is systemd, it is systemd
  190. [ "$(basename "$(readlink /proc/1/exe)" 2> /dev/null)" = "systemd" ] && return 0
  191. # if systemd is not running, it is not systemd
  192. pids=$(safe_pidof systemd 2> /dev/null)
  193. [ -z "${pids}" ] && return 1
  194. # check if the running systemd processes are not in our namespace
  195. myns="$(readlink /proc/self/ns/pid 2> /dev/null)"
  196. for p in ${pids}; do
  197. ns="$(readlink "/proc/${p}/ns/pid" 2> /dev/null)"
  198. # if pid of systemd is in our namespace, it is systemd
  199. [ -n "${myns}" ] && [ "${myns}" = "${ns}" ] && return 0
  200. done
  201. # else, it is not systemd
  202. return 1
  203. }
  204. portable_del_user() {
  205. local username="${1}"
  206. echo >&2 "Deleting ${username} user account ..."
  207. # Linux
  208. if command -v userdel 1> /dev/null 2>&1; then
  209. run userdel -f "${username}" && return 0
  210. fi
  211. # mac OS
  212. if command -v sysadminctl 1> /dev/null 2>&1; then
  213. run sysadminctl -deleteUser "${username}" && return 0
  214. fi
  215. echo >&2 "User ${username} could not be deleted from system, you might have to remove it manually"
  216. return 1
  217. }
  218. portable_del_user_from_group() {
  219. local groupname="${1}" username="${2}"
  220. # username is not in group
  221. echo >&2 "Deleting ${username} user from ${groupname} group ..."
  222. # Linux
  223. if command -v gpasswd 1> /dev/null 2>&1; then
  224. run gpasswd -d "netdata" "${group}" && return 0
  225. fi
  226. # FreeBSD
  227. if command -v pw 1> /dev/null 2>&1; then
  228. run pw groupmod "${groupname}" -d "${username}" && return 0
  229. fi
  230. # BusyBox
  231. if command -v delgroup 1> /dev/null 2>&1; then
  232. run delgroup "${username}" "${groupname}" && return 0
  233. fi
  234. # mac OS
  235. if command -v dseditgroup 1> /dev/null 2>&1; then
  236. run dseditgroup -o delete -u "${username}" "${groupname}" && return 0
  237. fi
  238. echo >&2 "Failed to delete user ${username} from group ${groupname} !"
  239. return 1
  240. }
  241. quit_msg() {
  242. echo
  243. if [ "$FILE_REMOVAL_STATUS" -eq 0 ]; then
  244. echo >&2 "Something went wrong :("
  245. else
  246. echo >&2 "Netdata files were successfully removed from your system"
  247. fi
  248. }
  249. user_input() {
  250. TEXT="$1"
  251. if [ "${INTERACTIVITY}" = "-i" ]; then
  252. read -r -p "$TEXT" >&2
  253. fi
  254. }
  255. rm_file() {
  256. FILE="$1"
  257. if [ -f "${FILE}" ]; then
  258. run rm -v ${INTERACTIVITY} "${FILE}"
  259. fi
  260. }
  261. rm_dir() {
  262. DIR="$1"
  263. if [ -n "$DIR" ] && [ -d "$DIR" ]; then
  264. user_input "Press ENTER to recursively delete directory '$DIR' > "
  265. run rm -v -f -R "${DIR}"
  266. fi
  267. }
  268. safe_pidof() {
  269. local pidof_cmd
  270. pidof_cmd="$(command -v pidof 2> /dev/null)"
  271. if [ -n "${pidof_cmd}" ]; then
  272. ${pidof_cmd} "${@}"
  273. return $?
  274. else
  275. ps -acxo pid,comm |
  276. sed "s/^ *//g" |
  277. grep netdata |
  278. cut -d ' ' -f 1
  279. return $?
  280. fi
  281. }
  282. pidisnetdata() {
  283. if [ -d /proc/self ]; then
  284. if [ -z "$1" ] || [ ! -f "/proc/$1/stat" ]; then
  285. return 1
  286. fi
  287. [ "$(cut -d '(' -f 2 "/proc/$1/stat" | cut -d ')' -f 1)" = "netdata" ] && return 0
  288. return 1
  289. fi
  290. return 0
  291. }
  292. stop_netdata_on_pid() {
  293. local pid="${1}" ret=0 count=0
  294. pidisnetdata "${pid}" || return 0
  295. printf >&2 "Stopping netdata on pid %s ..." "${pid}"
  296. while [ -n "$pid" ] && [ ${ret} -eq 0 ]; do
  297. if [ ${count} -gt 24 ]; then
  298. echo >&2 "Cannot stop the running netdata on pid ${pid}."
  299. return 1
  300. fi
  301. count=$((count + 1))
  302. pidisnetdata "${pid}" || ret=1
  303. if [ ${ret} -eq 1 ]; then
  304. break
  305. fi
  306. if [ ${count} -lt 12 ]; then
  307. run kill "${pid}" 2> /dev/null
  308. ret=$?
  309. else
  310. run kill -9 "${pid}" 2> /dev/null
  311. ret=$?
  312. fi
  313. test ${ret} -eq 0 && printf >&2 "." && sleep 5
  314. done
  315. echo >&2
  316. if [ ${ret} -eq 0 ]; then
  317. echo >&2 "SORRY! CANNOT STOP netdata ON PID ${pid} !"
  318. return 1
  319. fi
  320. echo >&2 "netdata on pid ${pid} stopped."
  321. return 0
  322. }
  323. netdata_pids() {
  324. local p myns ns
  325. myns="$(readlink /proc/self/ns/pid 2> /dev/null)"
  326. for p in \
  327. $(cat /var/run/netdata.pid 2> /dev/null) \
  328. $(cat /var/run/netdata/netdata.pid 2> /dev/null) \
  329. $(safe_pidof netdata 2> /dev/null); do
  330. ns="$(readlink "/proc/${p}/ns/pid" 2> /dev/null)"
  331. if [ -z "${myns}" ] || [ -z "${ns}" ] || [ "${myns}" = "${ns}" ]; then
  332. pidisnetdata "${p}" && echo "${p}"
  333. fi
  334. done
  335. }
  336. stop_all_netdata() {
  337. local p
  338. if [ "${UID}" -eq 0 ]; then
  339. uname="$(uname 2> /dev/null)"
  340. # Any of these may fail, but we need to not bail if they do.
  341. if issystemd; then
  342. if systemctl stop netdata; then
  343. sleep 5
  344. fi
  345. elif [ "${uname}" = "Darwin" ]; then
  346. if launchctl stop netdata; then
  347. sleep 5
  348. fi
  349. elif [ "${uname}" = "FreeBSD" ]; then
  350. if /etc/rc.d/netdata stop; then
  351. sleep 5
  352. fi
  353. else
  354. if service netdata stop; then
  355. sleep 5
  356. fi
  357. fi
  358. fi
  359. if [ -n "$(netdata_pids)" ] && [ -n "$(builtin type -P netdatacli)" ]; then
  360. netdatacli shutdown-agent
  361. sleep 20
  362. fi
  363. for p in $(netdata_pids); do
  364. # shellcheck disable=SC2086
  365. stop_netdata_on_pid ${p}
  366. done
  367. }
  368. trap quit_msg EXIT
  369. #shellcheck source=/dev/null
  370. source "${ENVIRONMENT_FILE}" || exit 1
  371. #### STOP NETDATA
  372. echo >&2 "Stopping a possibly running netdata..."
  373. stop_all_netdata
  374. #### REMOVE NETDATA FILES
  375. rm_file /etc/logrotate.d/netdata
  376. rm_file /etc/systemd/system/netdata.service
  377. rm_file /lib/systemd/system/netdata.service
  378. rm_file /usr/lib/systemd/system/netdata.service
  379. rm_file /etc/systemd/system/netdata-updater.service
  380. rm_file /lib/systemd/system/netdata-updater.service
  381. rm_file /usr/lib/systemd/system/netdata-updater.service
  382. rm_file /etc/systemd/system/netdata-updater.timer
  383. rm_file /lib/systemd/system/netdata-updater.timer
  384. rm_file /usr/lib/systemd/system/netdata-updater.timer
  385. rm_file /etc/init.d/netdata
  386. rm_file /etc/periodic/daily/netdata-updater
  387. rm_file /etc/cron.daily/netdata-updater
  388. rm_file /etc/cron.d/netdata-updater
  389. if [ -n "${NETDATA_PREFIX}" ] && [ -d "${NETDATA_PREFIX}" ]; then
  390. rm_dir "${NETDATA_PREFIX}"
  391. else
  392. rm_file "/usr/sbin/netdata"
  393. rm_file "/usr/sbin/netdatacli"
  394. rm_file "/tmp/netdata-ipc"
  395. rm_file "/usr/sbin/netdata-claim.sh"
  396. rm_dir "/usr/share/netdata"
  397. rm_dir "/usr/libexec/netdata"
  398. rm_dir "/var/lib/netdata"
  399. rm_dir "/var/cache/netdata"
  400. rm_dir "/var/log/netdata"
  401. rm_dir "/etc/netdata"
  402. fi
  403. FILE_REMOVAL_STATUS=1
  404. #### REMOVE NETDATA USER FROM ADDED GROUPS
  405. if [ -n "$NETDATA_ADDED_TO_GROUPS" ]; then
  406. user_input "Press ENTER to delete 'netdata' from following groups: '$NETDATA_ADDED_TO_GROUPS' > "
  407. for group in $NETDATA_ADDED_TO_GROUPS; do
  408. portable_del_user_from_group "${group}" "netdata"
  409. done
  410. fi
  411. #### REMOVE USER
  412. user_input "Press ENTER to delete 'netdata' system user > "
  413. portable_del_user "netdata" || :
  414. ### REMOVE GROUP
  415. user_input "Press ENTER to delete 'netdata' system group > "
  416. portable_del_group "netdata" || :