nc-backend.sh 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #!/usr/bin/env bash
  2. # SPDX-License-Identifier: GPL-3.0-or-later
  3. # This is a simple backend database proxy, written in BASH, using the nc command.
  4. # Run the script without any parameters for help.
  5. MODE="${1}"
  6. MY_PORT="${2}"
  7. BACKEND_HOST="${3}"
  8. BACKEND_PORT="${4}"
  9. FILE="${NETDATA_NC_BACKEND_DIR-/tmp}/netdata-nc-backend-${MY_PORT}"
  10. log() {
  11. logger --stderr --id=$$ --tag "netdata-nc-backend" "${*}"
  12. }
  13. mync() {
  14. local ret
  15. log "Running: nc ${*}"
  16. nc "${@}"
  17. ret=$?
  18. log "nc stopped with return code ${ret}."
  19. return ${ret}
  20. }
  21. listen_save_replay_forever() {
  22. local file="${1}" port="${2}" real_backend_host="${3}" real_backend_port="${4}" ret delay=1 started ended
  23. while true
  24. do
  25. log "Starting nc to listen on port ${port} and save metrics to ${file}"
  26. started=$(date +%s)
  27. mync -l -p "${port}" | tee -a -p --output-error=exit "${file}"
  28. ended=$(date +%s)
  29. if [ -s "${file}" ]
  30. then
  31. if [ ! -z "${real_backend_host}" ] && [ ! -z "${real_backend_port}" ]
  32. then
  33. log "Attempting to send the metrics to the real backend at ${real_backend_host}:${real_backend_port}"
  34. mync "${real_backend_host}" "${real_backend_port}" <"${file}"
  35. ret=$?
  36. if [ ${ret} -eq 0 ]
  37. then
  38. log "Successfully sent the metrics to ${real_backend_host}:${real_backend_port}"
  39. mv "${file}" "${file}.old"
  40. touch "${file}"
  41. else
  42. log "Failed to send the metrics to ${real_backend_host}:${real_backend_port} (nc returned ${ret}) - appending more data to ${file}"
  43. fi
  44. else
  45. log "No backend configured - appending more data to ${file}"
  46. fi
  47. fi
  48. # prevent a CPU hungry infinite loop
  49. # if nc cannot listen to port
  50. if [ $((ended - started)) -lt 5 ]
  51. then
  52. log "nc has been stopped too fast."
  53. delay=30
  54. else
  55. delay=1
  56. fi
  57. log "Waiting ${delay} seconds before listening again for data."
  58. sleep ${delay}
  59. done
  60. }
  61. if [ "${MODE}" = "start" ]
  62. then
  63. # start the listener, in exclusive mode
  64. # only one can use the same file/port at a time
  65. {
  66. flock -n 9
  67. # shellcheck disable=SC2181
  68. if [ $? -ne 0 ]
  69. then
  70. log "Cannot get exclusive lock on file ${FILE}.lock - Am I running multiple times?"
  71. exit 2
  72. fi
  73. # save our PID to the lock file
  74. echo "$$" >"${FILE}.lock"
  75. listen_save_replay_forever "${FILE}" "${MY_PORT}" "${BACKEND_HOST}" "${BACKEND_PORT}"
  76. ret=$?
  77. log "listener exited."
  78. exit ${ret}
  79. } 9>>"${FILE}.lock"
  80. # we can only get here if ${FILE}.lock cannot be created
  81. log "Cannot create file ${FILE}."
  82. exit 3
  83. elif [ "${MODE}" = "stop" ]
  84. then
  85. {
  86. flock -n 9
  87. # shellcheck disable=SC2181
  88. if [ $? -ne 0 ]
  89. then
  90. pid=$(<"${FILE}".lock)
  91. log "Killing process ${pid}..."
  92. kill -TERM "-${pid}"
  93. exit 0
  94. fi
  95. log "File ${FILE}.lock has been locked by me but it shouldn't. Is a collector running?"
  96. exit 4
  97. } 9<"${FILE}.lock"
  98. log "File ${FILE}.lock does not exist. Is a collector running?"
  99. exit 5
  100. else
  101. cat <<EOF
  102. Usage:
  103. "${0}" start|stop PORT [BACKEND_HOST BACKEND_PORT]
  104. PORT The port this script will listen
  105. (configure netdata to use this as a second backend)
  106. BACKEND_HOST The real backend host
  107. BACKEND_PORT The real backend port
  108. This script can act as fallback backend for netdata.
  109. It will receive metrics from netdata, save them to
  110. ${FILE}
  111. and once netdata reconnects to the real-backend, this script
  112. will push all metrics collected to the real-backend too and
  113. wait for a failure to happen again.
  114. Only one netdata can connect to this script at a time.
  115. If you need fallback for multiple netdata, run this script
  116. multiple times with different ports.
  117. You can run me in the background with this:
  118. screen -d -m "${0}" start PORT [BACKEND_HOST BACKEND_PORT]
  119. EOF
  120. exit 1
  121. fi