alarm-notify.sh.in 135 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630
  1. #!/usr/bin/env bash
  2. #shellcheck source=/dev/null disable=SC2086,SC2154
  3. # netdata
  4. # real-time performance and health monitoring, done right!
  5. # (C) 2023 Netdata Inc.
  6. # SPDX-License-Identifier: GPL-3.0-or-later
  7. #
  8. # Script to send alarm notifications for netdata
  9. #
  10. # Features:
  11. # - multiple notification methods
  12. # - multiple roles per alarm
  13. # - multiple recipients per role
  14. # - severity filtering per recipient
  15. #
  16. # Supported notification methods:
  17. # - emails by @ktsaou
  18. # - slack.com notifications by @ktsaou
  19. # - alerta.io notifications by @kattunga
  20. # - discord.com notifications by @lowfive
  21. # - pushover.net notifications by @ktsaou
  22. # - pushbullet.com push notifications by Tiago Peralta @tperalta82 #1070
  23. # - telegram.org notifications by @hashworks #1002
  24. # - twilio.com notifications by Levi Blaney @shadycuz #1211
  25. # - kafka notifications by @ktsaou #1342
  26. # - pagerduty.com notifications by Jim Cooley @jimcooley #1373
  27. # - messagebird.com notifications by @tech_no_logical #1453
  28. # - hipchat notifications by @ktsaou #1561
  29. # - fleep notifications by @Ferroin
  30. # - prowlapp.com notifications by @Ferroin
  31. # - irc notifications by @manosf
  32. # - custom notifications by @ktsaou
  33. # - syslog messages by @Ferroin
  34. # - Microsoft Team notification by @tioumen
  35. # - RocketChat notifications by @Hermsi1337 #3777
  36. # - Dynatrace Event by @illumine
  37. # - Opsgenie by @thiaoftsm #9858
  38. # - Gotify by @coffeegrind123
  39. # - ntfy.sh by @Dim-P
  40. # -----------------------------------------------------------------------------
  41. # testing notifications
  42. cmd_line="'${0}' $(printf "'%s' " "${@}")"
  43. if { [ "${1}" = "test" ] || [ "${2}" = "test" ]; } && [ "${#}" -le 2 ]; then
  44. if [ "${2}" = "test" ]; then
  45. recipient="${1}"
  46. else
  47. recipient="${2}"
  48. fi
  49. [ -z "${recipient}" ] && recipient="sysadmin"
  50. id=1
  51. last="CLEAR"
  52. test_res=0
  53. for x in "WARNING" "CRITICAL" "CLEAR"; do
  54. echo >&2
  55. echo >&2 "# SENDING TEST ${x} ALARM TO ROLE: ${recipient}"
  56. "${0}" "${recipient}" "$(hostname)" 1 1 "${id}" "$(date +%s)" "test_alarm" "test.chart" "${x}" "${last}" 100 90 "${0}" 1 $((0 + id)) "units" "this is a test alarm to verify notifications work" "new value" "old value" "evaluated expression" "expression variable values" 0 0 "" "" "Test" "command to edit the alarm=0=$(hostname)" "" "" "a test alarm"
  57. #shellcheck disable=SC2181
  58. if [ $? -ne 0 ]; then
  59. echo >&2 "# FAILED"
  60. test_res=1
  61. else
  62. echo >&2 "# OK"
  63. fi
  64. last="${x}"
  65. id=$((id + 1))
  66. done
  67. exit $test_res
  68. fi
  69. export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/sbin:@sbindir_POST@"
  70. export LC_ALL=C
  71. # -----------------------------------------------------------------------------
  72. # logging
  73. PROGRAM_NAME="$(basename "${0}")"
  74. # these should be the same with syslog() priorities
  75. NDLP_EMERG=0 # system is unusable
  76. NDLP_ALERT=1 # action must be taken immediately
  77. NDLP_CRIT=2 # critical conditions
  78. NDLP_ERR=3 # error conditions
  79. NDLP_WARN=4 # warning conditions
  80. NDLP_NOTICE=5 # normal but significant condition
  81. NDLP_INFO=6 # informational
  82. NDLP_DEBUG=7 # debug-level messages
  83. # the max (numerically) log level we will log
  84. LOG_LEVEL=$NDLP_INFO
  85. set_log_min_priority() {
  86. case "${NETDATA_LOG_LEVEL,,}" in
  87. "emerg" | "emergency")
  88. LOG_LEVEL=$NDLP_EMERG
  89. ;;
  90. "alert")
  91. LOG_LEVEL=$NDLP_ALERT
  92. ;;
  93. "crit" | "critical")
  94. LOG_LEVEL=$NDLP_CRIT
  95. ;;
  96. "err" | "error")
  97. LOG_LEVEL=$NDLP_ERR
  98. ;;
  99. "warn" | "warning")
  100. LOG_LEVEL=$NDLP_WARN
  101. ;;
  102. "notice")
  103. LOG_LEVEL=$NDLP_NOTICE
  104. ;;
  105. "info")
  106. LOG_LEVEL=$NDLP_INFO
  107. ;;
  108. "debug")
  109. LOG_LEVEL=$NDLP_DEBUG
  110. ;;
  111. esac
  112. }
  113. set_log_min_priority
  114. log() {
  115. local level="${1}"
  116. shift 1
  117. [[ -n "$level" && -n "$LOG_LEVEL" && "$level" -gt "$LOG_LEVEL" ]] && return
  118. systemd-cat-native --log-as-netdata --newline="--NEWLINE--" <<EOFLOG
  119. INVOCATION_ID=${NETDATA_INVOCATION_ID}
  120. SYSLOG_IDENTIFIER=${PROGRAM_NAME}
  121. PRIORITY=${level}
  122. THREAD_TAG=alarm-notify
  123. ND_LOG_SOURCE=health
  124. ND_NIDL_NODE=${host}
  125. ND_NIDL_INSTANCE=${chart}
  126. ND_NIDL_CONTEXT=${context}
  127. ND_ALERT_NAME=${name}
  128. ND_ALERT_ID=${alarm_id}
  129. ND_ALERT_UNIQUE_ID=${unique_id}
  130. ND_ALERT_EVENT_ID=${alarm_event_id}
  131. ND_ALERT_TRANSITION_ID=${transition_id//-/}
  132. ND_ALERT_CLASS=${classification}
  133. ND_ALERT_COMPONENT=${component}
  134. ND_ALERT_TYPE=${type}
  135. ND_ALERT_RECIPIENT=${roles}
  136. ND_ALERT_VALUE=${value}
  137. ND_ALERT_VALUE_OLD=${old_value}
  138. ND_ALERT_STATUS=${status}
  139. ND_ALERT_STATUS_OLD=${old_status}
  140. ND_ALERT_UNITS=${units}
  141. ND_ALERT_SUMMARY=${summary}
  142. ND_ALERT_INFO=${info}
  143. ND_ALERT_DURATION=${duration}
  144. ND_REQUEST=${cmd_line}
  145. MESSAGE_ID=6db0018e83e34320ae2a659d78019fb7
  146. MESSAGE=[ALERT NOTIFICATION]: ${*//\\n/--NEWLINE--}
  147. EOFLOG
  148. # AN EMPTY LINE IS NEEDED ABOVE
  149. }
  150. info() {
  151. log "$NDLP_INFO" "${@}"
  152. }
  153. warning() {
  154. log "$NDLP_WARN" "${@}"
  155. }
  156. error() {
  157. log "$NDLP_ERR" "${@}"
  158. }
  159. fatal() {
  160. log "$NDLP_ALERT" "${@}"
  161. exit 1
  162. }
  163. debug() {
  164. log "$NDLP_DEBUG" "${@}"
  165. }
  166. debug=0
  167. if [ "${NETDATA_ALARM_NOTIFY_DEBUG-0}" = "1" ]; then
  168. debug=1
  169. LOG_LEVEL=$NDLP_DEBUG
  170. fi
  171. # -----------------------------------------------------------------------------
  172. # check for BASH v4+ (required for associative arrays)
  173. if [ ${BASH_VERSINFO[0]} -lt 4 ]; then
  174. echo >&2 "BASH version 4 or later is required (this is ${BASH_VERSION})."
  175. exit 1
  176. fi
  177. # -----------------------------------------------------------------------------
  178. docurl() {
  179. if [ -z "${curl}" ]; then
  180. error "${curl} is unset."
  181. return 1
  182. fi
  183. if [ "${debug}" = "1" ]; then
  184. echo >&2 "--- BEGIN curl command ---"
  185. printf >&2 "%q " ${curl} "${@}"
  186. echo >&2
  187. echo >&2 "--- END curl command ---"
  188. local out code ret
  189. out=$(mktemp /tmp/netdata-health-alarm-notify-XXXXXXXX)
  190. code=$(${curl} ${curl_options} --write-out "%{http_code}" --output "${out}" --silent --show-error "${@}")
  191. ret=$?
  192. echo >&2 "--- BEGIN received response ---"
  193. cat >&2 "${out}"
  194. echo >&2
  195. echo >&2 "--- END received response ---"
  196. echo >&2 "RECEIVED HTTP RESPONSE CODE: ${code}"
  197. rm "${out}"
  198. echo "${code}"
  199. return ${ret}
  200. fi
  201. ${curl} ${curl_options} --write-out "%{http_code}" --output /dev/null --silent --show-error "${@}"
  202. return $?
  203. }
  204. # -----------------------------------------------------------------------------
  205. # List of all the notification mechanisms we support.
  206. # Used in a couple of places to write more compact code.
  207. method_names="
  208. email
  209. pushover
  210. pushbullet
  211. telegram
  212. slack
  213. alerta
  214. flock
  215. discord
  216. hipchat
  217. twilio
  218. messagebird
  219. pd
  220. fleep
  221. syslog
  222. custom
  223. msteams
  224. kavenegar
  225. prowl
  226. irc
  227. awssns
  228. rocketchat
  229. sms
  230. dynatrace
  231. matrix
  232. ntfy
  233. "
  234. # -----------------------------------------------------------------------------
  235. # this is to be overwritten by the config file
  236. custom_sender() {
  237. info "custom notification mechanism is not configured; not sending ${notification_description}"
  238. }
  239. # -----------------------------------------------------------------------------
  240. # defaults to allow running this script by hand
  241. [ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="@configdir_POST@"
  242. [ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="@libconfigdir_POST@"
  243. [ -z "${NETDATA_CACHE_DIR}" ] && NETDATA_CACHE_DIR="@cachedir_POST@"
  244. [ -z "${NETDATA_REGISTRY_URL}" ] && NETDATA_REGISTRY_URL="https://registry.my-netdata.io"
  245. [ -z "${NETDATA_REGISTRY_CLOUD_BASE_URL}" ] && NETDATA_REGISTRY_CLOUD_BASE_URL="https://app.netdata.cloud"
  246. # -----------------------------------------------------------------------------
  247. # parse command line parameters
  248. if [[ ${1} = "unittest" ]]; then
  249. unittest=1 # enable unit testing mode
  250. roles="${2}" # the role that should be used for unit testing
  251. cfgfile="${3}" # the location of the config file to use for unit testing
  252. status="${4}" # the current status : REMOVED, UNINITIALIZED, UNDEFINED, CLEAR, WARNING, CRITICAL
  253. old_status="${5}" # the previous status: REMOVED, UNINITIALIZED, UNDEFINED, CLEAR, WARNING, CRITICAL
  254. elif [[ ${1} = "dump_methods" ]]; then
  255. dump_methods=1
  256. status="WARNING"
  257. else
  258. roles="${1}" # the roles that should be notified for this event
  259. args_host="${2}" # the host generated this event
  260. unique_id="${3}" # the unique id of this event
  261. alarm_id="${4}" # the unique id of the alarm that generated this event
  262. event_id="${5}" # the incremental id of the event, for this alarm id
  263. when="${6}" # the timestamp this event occurred
  264. name="${7}" # the name of the alarm, as given in netdata health.d entries
  265. chart="${8}" # the name of the chart (type.id)
  266. status="${9}" # the current status : REMOVED, UNINITIALIZED, UNDEFINED, CLEAR, WARNING, CRITICAL
  267. old_status="${10}" # the previous status: REMOVED, UNINITIALIZED, UNDEFINED, CLEAR, WARNING, CRITICAL
  268. value="${11}" # the current value of the alarm
  269. old_value="${12}" # the previous value of the alarm
  270. src="${13}" # the line number and file the alarm has been configured
  271. duration="${14}" # the duration in seconds of the previous alarm state
  272. non_clear_duration="${15}" # the total duration in seconds this is/was non-clear
  273. units="${16}" # the units of the value
  274. info="${17}" # a short description of the alarm
  275. value_string="${18}" # friendly value (with units)
  276. # shellcheck disable=SC2034
  277. # variable is unused, but https://github.com/netdata/netdata/pull/5164#discussion_r255572947
  278. old_value_string="${19}" # friendly old value (with units), previously named "old_value_string"
  279. calc_expression="${20}" # contains the expression that was evaluated to trigger the alarm
  280. calc_param_values="${21}" # the values of the parameters in the expression, at the time of the evaluation
  281. total_warnings="${22}" # Total number of alarms in WARNING state
  282. total_critical="${23}" # Total number of alarms in CRITICAL state
  283. total_warn_alarms="${24}" # List of alarms in warning state
  284. total_crit_alarms="${25}" # List of alarms in critical state
  285. classification="${26}" # The class field from .conf files
  286. edit_command_line="${27}" # The command to edit the alarm, with the line number
  287. child_machine_guid="${28}" # the machine_guid of the child
  288. transition_id="${29}" # the transition_id of the alert
  289. summary="${30}" # the summary text field of the alert
  290. context="${31}" # the context of the chart
  291. component="${32}"
  292. type="${33}"
  293. fi
  294. # -----------------------------------------------------------------------------
  295. # find a suitable hostname to use, if netdata did not supply a hostname
  296. if [ -z "${args_host}" ]; then
  297. this_host=$(hostname -s 2>/dev/null)
  298. host="${this_host}"
  299. args_host="${this_host}"
  300. else
  301. host="${args_host}"
  302. fi
  303. notification_description="notification to '${roles}' for transition from ${old_status} to ${status}, of alert '${name}' = '${value_string}', of instance '${chart}', context '${context}' on host '${host}'"
  304. # -----------------------------------------------------------------------------
  305. # screen statuses we don't need to send a notification
  306. # don't do anything if this is not WARNING, CRITICAL or CLEAR
  307. if [ "${status}" != "WARNING" ] && [ "${status}" != "CRITICAL" ] && [ "${status}" != "CLEAR" ]; then
  308. debug "not sending ${notification_description}"
  309. exit 1
  310. fi
  311. # don't do anything if this is CLEAR, but it was not WARNING or CRITICAL
  312. if [ "${clear_alarm_always}" != "YES" ] && [ "${old_status}" != "WARNING" ] && [ "${old_status}" != "CRITICAL" ] && [ "${status}" = "CLEAR" ]; then
  313. debug "not sending ${notification_description}"
  314. exit 1
  315. fi
  316. # -----------------------------------------------------------------------------
  317. # load configuration
  318. # By default fetch images from the global public registry.
  319. # This is required by default, since all notification methods need to download
  320. # images via the Internet, and private registries might not be reachable.
  321. # This can be overwritten at the configuration file.
  322. images_base_url="https://registry.my-netdata.io"
  323. # curl options to use
  324. curl_options=""
  325. # hostname handling
  326. use_fqdn="NO"
  327. # needed commands
  328. # if empty they will be searched in the system path
  329. curl=
  330. sendmail=
  331. # enable / disable features
  332. for method_name in ${method_names^^}; do
  333. declare SEND_${method_name}="YES"
  334. declare DEFAULT_RECIPIENT_${method_name}
  335. done
  336. for method_name in ${method_names}; do
  337. declare -A role_recipients_${method_name}
  338. done
  339. # slack configs
  340. SLACK_WEBHOOK_URL=
  341. # Microsoft Teams configs
  342. MSTEAMS_WEBHOOK_URL=
  343. # Legacy Microsoft Teams configs for backwards compatibility:
  344. declare -A role_recipients_msteam
  345. # rocketchat configs
  346. ROCKETCHAT_WEBHOOK_URL=
  347. # alerta configs
  348. ALERTA_WEBHOOK_URL=
  349. ALERTA_API_KEY=
  350. # flock configs
  351. FLOCK_WEBHOOK_URL=
  352. # discord configs
  353. DISCORD_WEBHOOK_URL=
  354. # pushover configs
  355. PUSHOVER_APP_TOKEN=
  356. # pushbullet configs
  357. PUSHBULLET_ACCESS_TOKEN=
  358. PUSHBULLET_SOURCE_DEVICE=
  359. # twilio configs
  360. TWILIO_ACCOUNT_SID=
  361. TWILIO_ACCOUNT_TOKEN=
  362. TWILIO_NUMBER=
  363. # hipchat configs
  364. HIPCHAT_SERVER=
  365. HIPCHAT_AUTH_TOKEN=
  366. # messagebird configs
  367. MESSAGEBIRD_ACCESS_KEY=
  368. MESSAGEBIRD_NUMBER=
  369. # kavenegar configs
  370. KAVENEGAR_API_KEY=
  371. KAVENEGAR_SENDER=
  372. # telegram configs
  373. TELEGRAM_BOT_TOKEN=
  374. # kafka configs
  375. SEND_KAFKA="YES"
  376. KAFKA_URL=
  377. KAFKA_SENDER_IP=
  378. # pagerduty.com configs
  379. PD_SERVICE_KEY=
  380. USE_PD_VERSION=
  381. # fleep.io configs
  382. FLEEP_SENDER="${host}"
  383. # Amazon SNS configs
  384. AWSSNS_MESSAGE_FORMAT=
  385. # Matrix configs
  386. MATRIX_HOMESERVER=
  387. MATRIX_ACCESSTOKEN=
  388. # syslog configs
  389. SYSLOG_FACILITY=
  390. # email configs
  391. EMAIL_SENDER=
  392. EMAIL_CHARSET=$(locale charmap 2>/dev/null)
  393. EMAIL_THREADING=
  394. EMAIL_PLAINTEXT_ONLY=
  395. # irc configs
  396. IRC_NICKNAME=
  397. IRC_REALNAME=
  398. IRC_NETWORK=
  399. IRC_PORT=6667
  400. # dynatrace configs
  401. DYNATRACE_SPACE=
  402. DYNATRACE_SERVER=
  403. DYNATRACE_TOKEN=
  404. DYNATRACE_TAG_VALUE=
  405. DYNATRACE_ANNOTATION_TYPE=
  406. DYNATRACE_EVENT=
  407. SEND_DYNATRACE=
  408. # gotify configs
  409. GOTIFY_APP_URL=
  410. GOTIFY_APP_TOKEN=
  411. # opsgenie configs
  412. OPSGENIE_API_KEY=
  413. # load the stock and user configuration files
  414. # these will overwrite the variables above
  415. if [ ${unittest} ]; then
  416. if source "${cfgfile}"; then
  417. error "Failed to load requested config file."
  418. exit 1
  419. fi
  420. else
  421. for CONFIG in "${NETDATA_STOCK_CONFIG_DIR}/health_alarm_notify.conf" "${NETDATA_USER_CONFIG_DIR}/health_alarm_notify.conf"; do
  422. if [ -f "${CONFIG}" ]; then
  423. debug "Loading config file '${CONFIG}'..."
  424. source "${CONFIG}" || error "Failed to load config file '${CONFIG}'."
  425. else
  426. debug "Cannot find file '${CONFIG}'."
  427. fi
  428. done
  429. fi
  430. if [[ ! $curl_options =~ .*\--connect-timeout ]]; then
  431. curl_options+=" --connect-timeout 5"
  432. fi
  433. OPSGENIE_API_URL=${OPSGENIE_API_URL:-"https://api.opsgenie.com"}
  434. # If we didn't autodetect the character set for e-mail and it wasn't
  435. # set by the user, we need to set it to a reasonable default. UTF-8
  436. # should be correct for almost all modern UNIX systems.
  437. if [ -z ${EMAIL_CHARSET} ]; then
  438. EMAIL_CHARSET="UTF-8"
  439. fi
  440. # If we've been asked to use FQDN's for the URL's in the alarm, do so,
  441. # unless we're sending an alarm for a child system which we can't get the
  442. # FQDN of easily.
  443. if [ "${use_fqdn}" = "YES" ] && [ "${host}" = "$(hostname -s 2>/dev/null)" ]; then
  444. host="$(hostname -f 2>/dev/null)"
  445. fi
  446. # -----------------------------------------------------------------------------
  447. # migrate old Microsoft Teams configuration keys after loading configuration
  448. msteams_migration() {
  449. SEND_MSTEAMS=${SEND_MSTEAM:-$SEND_MSTEAMS}
  450. unset -v SEND_MSTEAM
  451. DEFAULT_RECIPIENT_MSTEAMS=${DEFAULT_RECIPIENT_MSTEAM:-$DEFAULT_RECIPIENT_MSTEAMS}
  452. MSTEAMS_WEBHOOK_URL=${MSTEAM_WEBHOOK_URL:-$MSTEAMS_WEBHOOK_URL}
  453. MSTEAMS_ICON_DEFAULT=${MSTEAM_ICON_DEFAULT:-$MSTEAMS_ICON_DEFAULT}
  454. MSTEAMS_ICON_CLEAR=${MSTEAM_ICON_CLEAR:-$MSTEAMS_ICON_CLEAR}
  455. MSTEAMS_ICON_WARNING=${MSTEAM_ICON_WARNING:-$MSTEAMS_ICON_WARNING}
  456. MSTEAMS_ICON_CRITICAL=${MSTEAM_ICON_CRITICAL:-$MSTEAMS_ICON_CRITICAL}
  457. MSTEAMS_COLOR_DEFAULT=${MSTEAM_COLOR_DEFAULT:-$MSTEAMS_COLOR_DEFAULT}
  458. MSTEAMS_COLOR_CLEAR=${MSTEAM_COLOR_CLEAR:-$MSTEAMS_COLOR_CLEAR}
  459. MSTEAMS_COLOR_WARNING=${MSTEAM_COLOR_WARNING:-$MSTEAMS_COLOR_WARNING}
  460. MSTEAMS_COLOR_CRITICAL=${MSTEAM_COLOR_CRITICAL:-$MSTEAMS_COLOR_CRITICAL}
  461. # migrate role specific recipients:
  462. for key in "${!role_recipients_msteam[@]}"; do
  463. # Disable check, if role_recipients_msteams is ever used:
  464. # The role_recipients_$method are created and used programmatically
  465. # by iterating over $methods. shellcheck therefore doesn't realize
  466. # that role_recipients_msteams is actually used in the block
  467. # "find the recipients' addresses per method".
  468. # shellcheck disable=SC2034
  469. role_recipients_msteams["$key"]="${role_recipients_msteam["$key"]}"
  470. done
  471. }
  472. msteams_migration
  473. # -----------------------------------------------------------------------------
  474. # filter a recipient based on alarm event severity
  475. filter_recipient_by_criticality() {
  476. local method="${1}" recipient_arg="${2}"
  477. local tracking_dir tracking_file modifier modifiers recipient="${recipient_arg/|*/}"
  478. local mod_critical=0 mod_noclear=0 mod_nowarn=0
  479. # no severity filtering for this person
  480. [ "${recipient}" = "${recipient_arg}" ] && return 0
  481. # find out which modifiers are set
  482. modifiers="${recipient_arg#*|}"
  483. modifiers="${modifiers//|/ }" # replace pipes with spaces
  484. modifiers="${modifiers,,}" # lowercase
  485. for modifier in ${modifiers}; do
  486. case "${modifier}" in
  487. critical) mod_critical=1 ;;
  488. noclear) mod_noclear=1 ;;
  489. nowarn) mod_nowarn=1 ;;
  490. *)
  491. error "SEVERITY FILTERING for ${recipient_arg} VIA ${method}: invalid modifier '${modifier}'."
  492. # invalid modifier, always send notification
  493. return 0
  494. ;;
  495. esac
  496. done
  497. # set status tracking directory/file var
  498. tracking_dir="${NETDATA_CACHE_DIR}/alarm-notify/${method}/${recipient}"
  499. tracking_file="${tracking_dir}/${alarm_id}"
  500. # create the status tracking directory for this user if "critical" modifier is set
  501. [ "${mod_critical}" == "1" ] && [ ! -d "${tracking_dir}" ] && mkdir -p "${tracking_dir}"
  502. case "${status}" in
  503. CRITICAL)
  504. # "critical" modifier set, create tracking file for future status changes
  505. if [ "${mod_critical}" == "1" ]; then
  506. touch "${tracking_file}"
  507. debug "SEVERITY FILTERING for ${recipient_arg} VIA ${method}: ALLOW: the alarm is CRITICAL (will now receive next status change)"
  508. return 0
  509. fi
  510. # always send CRITICAL notification
  511. debug "SEVERITY FILTERING for ${recipient_arg} VIA ${method}: ALLOW: the alarm is CRITICAL"
  512. return 0
  513. ;;
  514. WARNING)
  515. # "nowarn" modifier set, block notification
  516. if [ "${mod_nowarn}" == "1" ]; then
  517. debug "SEVERITY FILTERING for ${recipient_arg} VIA ${method}: BLOCK: recipient should not receive this notification (nowarn modifier set)"
  518. return 1
  519. fi
  520. # "critical" modifier not set, send notification
  521. if [ "${mod_critical}" == "0" ]; then
  522. debug "SEVERITY FILTERING for ${recipient_arg} VIA ${method}: ALLOW: the alarm is WARNING"
  523. return 0
  524. fi
  525. # "critical" modifier set, send notification if tracking file exists
  526. if [ "${mod_critical}" == "1" ] && [ -f "${tracking_file}" ]; then
  527. debug "SEVERITY FILTERING for ${recipient_arg} VIA ${method}: ALLOW: recipient has been notified for this alarm in the past (will still receive next status change)"
  528. return 0
  529. fi
  530. ;;
  531. CLEAR)
  532. # remove tracking file
  533. [ -f "${tracking_file}" ] && rm "${tracking_file}"
  534. # "noclear" modifier set, block notification
  535. if [ "${mod_noclear}" == "1" ]; then
  536. debug "SEVERITY FILTERING for ${recipient_arg} VIA ${method}: BLOCK: recipient should not receive this notification (noclear modifier set)"
  537. return 1
  538. fi
  539. # "critical" modifier not set, send notification
  540. if [ "${mod_critical}" == "0" ]; then
  541. debug "SEVERITY FILTERING for ${recipient_arg} VIA ${method}: ALLOW: the alarm is CLEAR"
  542. return 0
  543. fi
  544. # "critical" modifier set, send notification if tracking file exists
  545. if [ "${mod_critical}" == "1" ] && [ -f "${tracking_file}" ]; then
  546. debug "SEVERITY FILTERING for ${recipient_arg} VIA ${method}: ALLOW: recipient has been notified for this alarm in the past (no status change will be sent from now)"
  547. return 0
  548. fi
  549. ;;
  550. *)
  551. # "critical" modifier set, send notification if tracking file exists
  552. if [ "${mod_critical}" == "1" ] && [ -f "${tracking_file}" ]; then
  553. debug "SEVERITY FILTERING for ${recipient_arg} VIA ${method}: ALLOW: recipient has been notified for this alarm in the past (will still receive next status change)"
  554. return 0
  555. fi
  556. ;;
  557. esac
  558. debug "SEVERITY FILTERING for ${recipient_arg} VIA ${method}: BLOCK: recipient should not receive this notification"
  559. return 1
  560. }
  561. # -----------------------------------------------------------------------------
  562. # check the configured targets
  563. # check email
  564. if [ "${SEND_EMAIL}" = "AUTO" ]; then
  565. if command -v curl >/dev/null 2>&1; then
  566. SEND_EMAIL="YES"
  567. else
  568. SEND_EMAIL="NO"
  569. fi
  570. fi
  571. # check slack
  572. [ -z "${SLACK_WEBHOOK_URL}" ] && SEND_SLACK="NO"
  573. # check rocketchat
  574. [ -z "${ROCKETCHAT_WEBHOOK_URL}" ] && SEND_ROCKETCHAT="NO"
  575. # check alerta
  576. [ -z "${ALERTA_WEBHOOK_URL}" ] && SEND_ALERTA="NO"
  577. # check flock
  578. [ -z "${FLOCK_WEBHOOK_URL}" ] && SEND_FLOCK="NO"
  579. # check discord
  580. [ -z "${DISCORD_WEBHOOK_URL}" ] && SEND_DISCORD="NO"
  581. # check pushover
  582. [ -z "${PUSHOVER_APP_TOKEN}" ] && SEND_PUSHOVER="NO"
  583. # check pushbullet
  584. [ -z "${PUSHBULLET_ACCESS_TOKEN}" ] && SEND_PUSHBULLET="NO"
  585. # check twilio
  586. { [ -z "${TWILIO_ACCOUNT_TOKEN}" ] || [ -z "${TWILIO_ACCOUNT_SID}" ] || [ -z "${TWILIO_NUMBER}" ]; } && SEND_TWILIO="NO"
  587. # check hipchat
  588. [ -z "${HIPCHAT_AUTH_TOKEN}" ] && SEND_HIPCHAT="NO"
  589. # check messagebird
  590. { [ -z "${MESSAGEBIRD_ACCESS_KEY}" ] || [ -z "${MESSAGEBIRD_NUMBER}" ]; } && SEND_MESSAGEBIRD="NO"
  591. # check kavenegar
  592. { [ -z "${KAVENEGAR_API_KEY}" ] || [ -z "${KAVENEGAR_SENDER}" ]; } && SEND_KAVENEGAR="NO"
  593. # check telegram
  594. [ -z "${TELEGRAM_BOT_TOKEN}" ] && SEND_TELEGRAM="NO"
  595. # check kafka
  596. { [ -z "${KAFKA_URL}" ] || [ -z "${KAFKA_SENDER_IP}" ]; } && SEND_KAFKA="NO"
  597. # check irc
  598. [ -z "${IRC_NETWORK}" ] && SEND_IRC="NO"
  599. # check fleep
  600. #shellcheck disable=SC2153
  601. { [ -z "${FLEEP_SERVER}" ] || [ -z "${FLEEP_SENDER}" ]; } && SEND_FLEEP="NO"
  602. # check dynatrace
  603. { [ -z "${DYNATRACE_SPACE}" ] ||
  604. [ -z "${DYNATRACE_SERVER}" ] ||
  605. [ -z "${DYNATRACE_TOKEN}" ] ||
  606. [ -z "${DYNATRACE_TAG_VALUE}" ] ||
  607. [ -z "${DYNATRACE_EVENT}" ]; } && SEND_DYNATRACE="NO"
  608. # check opsgenie
  609. [ -z "${OPSGENIE_API_KEY}" ] && SEND_OPSGENIE="NO"
  610. # check matrix
  611. { [ -z "${MATRIX_HOMESERVER}" ] || [ -z "${MATRIX_ACCESSTOKEN}" ]; } && SEND_MATRIX="NO"
  612. # check gotify
  613. { [ -z "${GOTIFY_APP_TOKEN}" ] || [ -z "${GOTIFY_APP_URL}" ]; } && SEND_GOTIFY="NO"
  614. # check ntfy
  615. [ -z "${DEFAULT_RECIPIENT_NTFY}" ] && SEND_NTFY="NO"
  616. # check msteams
  617. [ -z "${MSTEAMS_WEBHOOK_URL}" ] && SEND_MSTEAMS="NO"
  618. # check pd
  619. [ -z "${DEFAULT_RECIPIENT_PD}" ] && SEND_PD="NO"
  620. # check prowl
  621. [ -z "${DEFAULT_RECIPIENT_PROWL}" ] && SEND_PROWL="NO"
  622. # check custom
  623. [ -z "${DEFAULT_RECIPIENT_CUSTOM}" ] && SEND_CUSTOM="NO"
  624. # -----------------------------------------------------------------------------
  625. # check the availability of targets
  626. check_supported_targets() {
  627. local log=${1}
  628. shift
  629. if [ "${SEND_PUSHOVER}" = "YES" ] ||
  630. [ "${SEND_SLACK}" = "YES" ] ||
  631. [ "${SEND_ROCKETCHAT}" = "YES" ] ||
  632. [ "${SEND_ALERTA}" = "YES" ] ||
  633. [ "${SEND_PD}" = "YES" ] ||
  634. [ "${SEND_FLOCK}" = "YES" ] ||
  635. [ "${SEND_DISCORD}" = "YES" ] ||
  636. [ "${SEND_HIPCHAT}" = "YES" ] ||
  637. [ "${SEND_TWILIO}" = "YES" ] ||
  638. [ "${SEND_MESSAGEBIRD}" = "YES" ] ||
  639. [ "${SEND_KAVENEGAR}" = "YES" ] ||
  640. [ "${SEND_TELEGRAM}" = "YES" ] ||
  641. [ "${SEND_PUSHBULLET}" = "YES" ] ||
  642. [ "${SEND_KAFKA}" = "YES" ] ||
  643. [ "${SEND_FLEEP}" = "YES" ] ||
  644. [ "${SEND_PROWL}" = "YES" ] ||
  645. [ "${SEND_MATRIX}" = "YES" ] ||
  646. [ "${SEND_CUSTOM}" = "YES" ] ||
  647. [ "${SEND_MSTEAMS}" = "YES" ] ||
  648. [ "${SEND_DYNATRACE}" = "YES" ] ||
  649. [ "${SEND_OPSGENIE}" = "YES" ] ||
  650. [ "${SEND_GOTIFY}" = "YES" ] ||
  651. [ "${SEND_NTFY}" = "YES" ]; then
  652. # if we need curl, check for the curl command
  653. if [ -z "${curl}" ]; then
  654. curl="$(command -v curl 2>/dev/null)"
  655. fi
  656. if [ -z "${curl}" ]; then
  657. $log "Cannot find curl command in the system path. Disabling all curl based notifications."
  658. SEND_PUSHOVER="NO"
  659. SEND_PUSHBULLET="NO"
  660. SEND_TELEGRAM="NO"
  661. SEND_SLACK="NO"
  662. SEND_MSTEAMS="NO"
  663. SEND_ROCKETCHAT="NO"
  664. SEND_ALERTA="NO"
  665. SEND_PD="NO"
  666. SEND_FLOCK="NO"
  667. SEND_DISCORD="NO"
  668. SEND_TWILIO="NO"
  669. SEND_HIPCHAT="NO"
  670. SEND_MESSAGEBIRD="NO"
  671. SEND_KAVENEGAR="NO"
  672. SEND_KAFKA="NO"
  673. SEND_FLEEP="NO"
  674. SEND_PROWL="NO"
  675. SEND_MATRIX="NO"
  676. SEND_CUSTOM="NO"
  677. SEND_DYNATRACE="NO"
  678. SEND_OPSGENIE="NO"
  679. SEND_GOTIFY="NO"
  680. SEND_NTFY="NO"
  681. fi
  682. fi
  683. if [ "${SEND_SMS}" = "YES" ]; then
  684. if [ -z "${sendsms}" ]; then
  685. sendsms="$(command -v sendsms 2>/dev/null)"
  686. fi
  687. if [ -z "${sendsms}" ]; then
  688. SEND_SMS="NO"
  689. fi
  690. fi
  691. # if we need sendmail, check for the sendmail command
  692. if [ "${SEND_EMAIL}" = "YES" ] && [ -z "${sendmail}" ]; then
  693. sendmail="$(command -v sendmail 2>/dev/null)"
  694. if [ -z "${sendmail}" ]; then
  695. $log "Cannot find sendmail command in the system path. Disabling email notifications."
  696. SEND_EMAIL="NO"
  697. fi
  698. fi
  699. # if we need logger, check for the logger command
  700. if [ "${SEND_SYSLOG}" = "YES" ] && [ -z "${logger}" ]; then
  701. logger="$(command -v logger 2>/dev/null)"
  702. if [ -z "${logger}" ]; then
  703. $log "Cannot find logger command in the system path. Disabling syslog notifications."
  704. SEND_SYSLOG="NO"
  705. fi
  706. fi
  707. # if we need aws, check for the aws command
  708. if [ "${SEND_AWSSNS}" = "YES" ] && [ -z "${aws}" ]; then
  709. aws="$(command -v aws 2>/dev/null)"
  710. if [ -z "${aws}" ]; then
  711. $log "Cannot find aws command in the system path. Disabling Amazon SNS notifications."
  712. SEND_AWSSNS="NO"
  713. fi
  714. fi
  715. # if we need nc, check for the nc command
  716. if [ "${SEND_IRC}" = "YES" ] && [ -z "${nc}" ]; then
  717. nc="$(command -v nc 2>/dev/null)"
  718. if [ -z "${nc}" ]; then
  719. $log "Cannot find nc command in the system path. Disabling IRC notifications."
  720. SEND_IRC="NO"
  721. fi
  722. fi
  723. }
  724. if [ ${dump_methods} ]; then
  725. check_supported_targets debug
  726. for name in "${!SEND_@}"; do
  727. if [ "${!name}" = "YES" ]; then
  728. echo "$name"
  729. fi
  730. done
  731. exit 0
  732. fi
  733. # -----------------------------------------------------------------------------
  734. # find the recipients' addresses per method
  735. # netdata may call us with multiple roles, and roles may have multiple but
  736. # overlapping recipients - so, here we find the unique recipients.
  737. have_to_send_something="NO"
  738. for method_name in ${method_names}; do
  739. send_var="SEND_${method_name^^}"
  740. if [ "${!send_var}" = "NO" ]; then
  741. continue
  742. fi
  743. declare -A arr_var=()
  744. for x in ${roles//,/ }; do
  745. # the roles 'silent' and 'disabled' mean:
  746. # don't send a notification for this role
  747. if [ "${x}" = "silent" ] || [ "${x}" = "disabled" ]; then
  748. continue
  749. fi
  750. role_recipients="role_recipients_${method_name}[$x]"
  751. default_recipient_var="DEFAULT_RECIPIENT_${method_name^^}"
  752. a="${!role_recipients}"
  753. [ -z "${a}" ] && a="${!default_recipient_var}"
  754. for r in ${a//,/ }; do
  755. [ "${r}" != "disabled" ] && filter_recipient_by_criticality ${method_name} "${r}" && arr_var[${r/|*/}]="1"
  756. done
  757. done
  758. # build the list of recipients
  759. to_var="to_${method_name}"
  760. declare to_${method_name}="${!arr_var[*]}"
  761. if [ -z "${!to_var}" ]; then
  762. declare ${send_var}="NO"
  763. else
  764. have_to_send_something="YES"
  765. fi
  766. done
  767. # -----------------------------------------------------------------------------
  768. # handle fixup of the email recipient list.
  769. fix_to_email() {
  770. to_email=
  771. while [ -n "${1}" ]; do
  772. [ -n "${to_email}" ] && to_email="${to_email}, "
  773. to_email="${to_email}${1}"
  774. shift 1
  775. done
  776. }
  777. # ${to_email} without quotes here
  778. fix_to_email ${to_email}
  779. # -----------------------------------------------------------------------------
  780. # handle output if we're running in unit test mode
  781. if [ ${unittest} ]; then
  782. for method_name in ${method_names}; do
  783. to_var="to_${method_name}"
  784. echo "results: ${method_name}: ${!to_var}"
  785. done
  786. exit 0
  787. fi
  788. # -----------------------------------------------------------------------------
  789. # check that we have at least a method enabled
  790. proceed=0
  791. for method in "${SEND_EMAIL}" \
  792. "${SEND_PUSHOVER}" \
  793. "${SEND_TELEGRAM}" \
  794. "${SEND_SLACK}" \
  795. "${SEND_ROCKETCHAT}" \
  796. "${SEND_ALERTA}" \
  797. "${SEND_FLOCK}" \
  798. "${SEND_DISCORD}" \
  799. "${SEND_TWILIO}" \
  800. "${SEND_HIPCHAT}" \
  801. "${SEND_MESSAGEBIRD}" \
  802. "${SEND_KAVENEGAR}" \
  803. "${SEND_PUSHBULLET}" \
  804. "${SEND_KAFKA}" \
  805. "${SEND_PD}" \
  806. "${SEND_FLEEP}" \
  807. "${SEND_PROWL}" \
  808. "${SEND_MATRIX}" \
  809. "${SEND_CUSTOM}" \
  810. "${SEND_IRC}" \
  811. "${SEND_AWSSNS}" \
  812. "${SEND_SYSLOG}" \
  813. "${SEND_SMS}" \
  814. "${SEND_MSTEAMS}" \
  815. "${SEND_DYNATRACE}" \
  816. "${SEND_OPSGENIE}" \
  817. "${SEND_GOTIFY}" \
  818. "${SEND_NTFY}" ; do
  819. if [ "${method}" == "YES" ]; then
  820. proceed=1
  821. break
  822. fi
  823. done
  824. if [ "$proceed" -eq 0 ]; then
  825. if [ "${have_to_send_something}" = "NO" ]; then
  826. debug "All notification methods are disabled; not sending ${notification_description}."
  827. exit 0
  828. else
  829. fatal "All notification methods are disabled; not sending ${notification_description}."
  830. fi
  831. fi
  832. check_supported_targets error
  833. # -----------------------------------------------------------------------------
  834. # get the date the alarm happened
  835. date=$(date --date=@${when} "${date_format}" 2>/dev/null)
  836. [ -z "${date}" ] && date=$(date "${date_format}" 2>/dev/null)
  837. [ -z "${date}" ] && date=$(date --date=@${when} 2>/dev/null)
  838. [ -z "${date}" ] && date=$(date 2>/dev/null)
  839. # -----------------------------------------------------------------------------
  840. # get the date in utc the alarm happened
  841. date_utc=$(date --date=@${when} "${date_format}" -u 2>/dev/null)
  842. [ -z "${date_utc}" ] && date_utc=$(date -u "${date_format}" 2>/dev/null)
  843. [ -z "${date_utc}" ] && date_utc=$(date -u --date=@${when} 2>/dev/null)
  844. [ -z "${date_utc}" ] && date_utc=$(date -u 2>/dev/null)
  845. # ----------------------------------------------------------------------------
  846. # prepare some extra headers if we've been asked to thread e-mails
  847. if [ "${SEND_EMAIL}" == "YES" ] && [ "${EMAIL_THREADING}" != "NO" ]; then
  848. email_thread_headers="In-Reply-To: <${chart}-${name}@${host}>\\r\\nReferences: <${chart}-${name}@${host}>"
  849. else
  850. email_thread_headers=
  851. fi
  852. # -----------------------------------------------------------------------------
  853. # function to URL encode a string
  854. urlencode() {
  855. local string="${1}" strlen encoded pos c o
  856. strlen=${#string}
  857. for ((pos = 0; pos < strlen; pos++)); do
  858. c=${string:pos:1}
  859. case "${c}" in
  860. [-_.~a-zA-Z0-9])
  861. o="${c}"
  862. ;;
  863. *)
  864. printf -v o '%%%02x' "'${c}"
  865. ;;
  866. esac
  867. encoded+="${o}"
  868. done
  869. REPLY="${encoded}"
  870. echo "${REPLY}"
  871. }
  872. # -----------------------------------------------------------------------------
  873. # function to convert a duration in seconds, to a human readable duration
  874. # using DAYS, MINUTES, SECONDS
  875. duration4human() {
  876. local s="${1}" d=0 h=0 m=0 ds="day" hs="hour" ms="minute" ss="second" ret
  877. d=$((s / 86400))
  878. s=$((s - (d * 86400)))
  879. h=$((s / 3600))
  880. s=$((s - (h * 3600)))
  881. m=$((s / 60))
  882. s=$((s - (m * 60)))
  883. if [ ${d} -gt 0 ]; then
  884. [ ${m} -ge 30 ] && h=$((h + 1))
  885. [ ${d} -gt 1 ] && ds="days"
  886. [ ${h} -gt 1 ] && hs="hours"
  887. if [ ${h} -gt 0 ]; then
  888. ret="${d} ${ds} and ${h} ${hs}"
  889. else
  890. ret="${d} ${ds}"
  891. fi
  892. elif [ ${h} -gt 0 ]; then
  893. [ ${s} -ge 30 ] && m=$((m + 1))
  894. [ ${h} -gt 1 ] && hs="hours"
  895. [ ${m} -gt 1 ] && ms="minutes"
  896. if [ ${m} -gt 0 ]; then
  897. ret="${h} ${hs} and ${m} ${ms}"
  898. else
  899. ret="${h} ${hs}"
  900. fi
  901. elif [ ${m} -gt 0 ]; then
  902. [ ${m} -gt 1 ] && ms="minutes"
  903. [ ${s} -gt 1 ] && ss="seconds"
  904. if [ ${s} -gt 0 ]; then
  905. ret="${m} ${ms} and ${s} ${ss}"
  906. else
  907. ret="${m} ${ms}"
  908. fi
  909. else
  910. [ ${s} -gt 1 ] && ss="seconds"
  911. ret="${s} ${ss}"
  912. fi
  913. REPLY="${ret}"
  914. echo "${REPLY}"
  915. }
  916. # -----------------------------------------------------------------------------
  917. # email sender
  918. send_email() {
  919. local ret opts=() sender_email="${EMAIL_SENDER}" sender_name=
  920. if [ "${SEND_EMAIL}" = "YES" ]; then
  921. if [ -n "${EMAIL_SENDER}" ]; then
  922. if [[ ${EMAIL_SENDER} =~ ^\".*\"\ \<.*\>$ ]]; then
  923. # the name includes double quotes
  924. sender_email="$(echo "${EMAIL_SENDER}" | cut -d '<' -f 2 | cut -d '>' -f 1)"
  925. sender_name="$(echo "${EMAIL_SENDER}" | cut -d '"' -f 2)"
  926. elif [[ ${EMAIL_SENDER} =~ ^\'.*\'\ \<.*\>$ ]]; then
  927. # the name includes single quotes
  928. sender_email="$(echo "${EMAIL_SENDER}" | cut -d '<' -f 2 | cut -d '>' -f 1)"
  929. sender_name="$(echo "${EMAIL_SENDER}" | cut -d "'" -f 2)"
  930. elif [[ ${EMAIL_SENDER} =~ ^.*\ \<.*\>$ ]]; then
  931. # the name does not have any quotes
  932. sender_email="$(echo "${EMAIL_SENDER}" | cut -d '<' -f 2 | cut -d '>' -f 1)"
  933. sender_name="$(echo "${EMAIL_SENDER}" | cut -d '<' -f 1)"
  934. fi
  935. fi
  936. [ -n "${sender_email}" ] && opts+=(-f "${sender_email}")
  937. [ -n "${sender_name}" ] && ${sendmail} -F 2>&1 | head -1 | grep -qv "sendmail: unrecognized option: F" && opts+=(-F "${sender_name}")
  938. if [ "${debug}" = "1" ]; then
  939. echo >&2 "--- BEGIN sendmail command ---"
  940. printf >&2 "%q " "${sendmail}" -t "${opts[@]}"
  941. echo >&2
  942. echo >&2 "--- END sendmail command ---"
  943. fi
  944. local cmd_output
  945. cmd_output=$("${sendmail}" -t "${opts[@]}" 2>&1)
  946. ret=$?
  947. if [ ${ret} -eq 0 ]; then
  948. info "sent email to '${to_email}' for ${notification_description}"
  949. return 0
  950. else
  951. error "failed to send email to '${to_email}' for ${notification_description}, with error code ${ret} (${cmd_output})."
  952. return 1
  953. fi
  954. fi
  955. return 1
  956. }
  957. # -----------------------------------------------------------------------------
  958. # pushover sender
  959. send_pushover() {
  960. local apptoken="${1}" usertokens="${2}" when="${3}" url="${4}" status="${5}" title="${6}" message="${7}" httpcode sent=0 user priority
  961. if [ "${SEND_PUSHOVER}" = "YES" ] && [ -n "${apptoken}" ] && [ -n "${usertokens}" ] && [ -n "${title}" ] && [ -n "${message}" ]; then
  962. # https://pushover.net/api
  963. priority=-2
  964. case "${status}" in
  965. CLEAR) priority=-1 ;; # low priority: no sound or vibration
  966. WARNING) priority=0 ;; # normal priority: respect quiet hours
  967. CRITICAL) priority=1 ;; # high priority: bypass quiet hours
  968. *) priority=-2 ;; # lowest priority: no notification at all
  969. esac
  970. for user in ${usertokens}; do
  971. httpcode=$(docurl \
  972. --form-string "token=${apptoken}" \
  973. --form-string "user=${user}" \
  974. --form-string "html=1" \
  975. --form-string "title=${title}" \
  976. --form-string "message=${message}" \
  977. --form-string "timestamp=${when}" \
  978. --form-string "url=${url}" \
  979. --form-string "url_title=Open netdata dashboard to view the alarm" \
  980. --form-string "priority=${priority}" \
  981. https://api.pushover.net/1/messages.json)
  982. if [ "${httpcode}" = "200" ]; then
  983. info "sent pushover notification to '${user}' for ${notification_description}"
  984. sent=$((sent + 1))
  985. else
  986. error "failed to send pushover notification to '${user}' for ${notification_description}, with HTTP response status code ${httpcode}."
  987. fi
  988. done
  989. [ ${sent} -gt 0 ] && return 0
  990. fi
  991. return 1
  992. }
  993. # -----------------------------------------------------------------------------
  994. # pushbullet sender
  995. send_pushbullet() {
  996. local userapikey="${1}" source_device="${2}" recipients="${3}" url="${4}" title="${5}" message="${6}" httpcode sent=0 userOrChannelTag
  997. if [ "${SEND_PUSHBULLET}" = "YES" ] && [ -n "${userapikey}" ] && [ -n "${recipients}" ] && [ -n "${message}" ] && [ -n "${title}" ]; then
  998. # https://docs.pushbullet.com/#create-push
  999. # Accept specification of user(s) (PushBullet account email address) and/or channel tag(s), separated by spaces.
  1000. # If recipient begins with a "#" then send to channel tag, otherwise send to email recipient.
  1001. for userOrChannelTag in ${recipients}; do
  1002. if [ "${userOrChannelTag::1}" = "#" ]; then
  1003. userOrChannelTag_type="channel_tag"
  1004. userOrChannelTag="${userOrChannelTag:1}" # Remove hash from start of channel tag (required by pushbullet API)
  1005. else
  1006. userOrChannelTag_type="email"
  1007. fi
  1008. httpcode=$(docurl \
  1009. --header 'Access-Token: '${userapikey}'' \
  1010. --header 'Content-Type: application/json' \
  1011. --data-binary @<(
  1012. cat <<EOF
  1013. {"title": "${title}",
  1014. "type": "link",
  1015. "${userOrChannelTag_type}": "${userOrChannelTag}",
  1016. "body": "$(echo -n ${message})",
  1017. "url": "${url}",
  1018. "source_device_iden": "${source_device}"}
  1019. EOF
  1020. ) "https://api.pushbullet.com/v2/pushes" -X POST)
  1021. if [ "${httpcode}" = "200" ]; then
  1022. info "sent pushbullet notification to '${userOrChannelTag}' for ${notification_description}"
  1023. sent=$((sent + 1))
  1024. else
  1025. error "failed to send pushbullet notification to '${userOrChannelTag}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1026. fi
  1027. done
  1028. [ ${sent} -gt 0 ] && return 0
  1029. fi
  1030. return 1
  1031. }
  1032. # -----------------------------------------------------------------------------
  1033. # kafka sender
  1034. send_kafka() {
  1035. local httpcode sent=0
  1036. if [ "${SEND_KAFKA}" = "YES" ]; then
  1037. httpcode=$(docurl -X POST \
  1038. --data "{host_ip:\"${KAFKA_SENDER_IP}\",when:${when},name:\"${name}\",chart:\"${chart}\",status:\"${status}\",old_status:\"${old_status}\",value:${value},old_value:${old_value},duration:${duration},non_clear_duration:${non_clear_duration},units:\"${units}\",info:\"${info}\"}" \
  1039. "${KAFKA_URL}")
  1040. if [ "${httpcode}" = "204" ]; then
  1041. info "sent kafka data to '${KAFKA_SENDER_IP}' for ${notification_description}"
  1042. sent=$((sent + 1))
  1043. else
  1044. error "failed to send kafka data to '${KAFKA_SENDER_IP}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1045. fi
  1046. [ ${sent} -gt 0 ] && return 0
  1047. fi
  1048. return 1
  1049. }
  1050. # -----------------------------------------------------------------------------
  1051. # pagerduty.com sender
  1052. send_pd() {
  1053. local recipients="${1}" sent=0 severity current_time payload url response_code
  1054. unset t
  1055. case ${status} in
  1056. CLEAR) t='resolve' ; severity='info' ;;
  1057. WARNING) t='trigger' ; severity='warning' ;;
  1058. CRITICAL) t='trigger' ; severity='critical' ;;
  1059. esac
  1060. if [ ${SEND_PD} = "YES" ] && [ -n "${t}" ]; then
  1061. if [ "$(uname)" == "Linux" ]; then
  1062. current_time=$(date -d @${when} +'%Y-%m-%dT%H:%M:%S.000')
  1063. else
  1064. current_time=$(date -r ${when} +'%Y-%m-%dT%H:%M:%S.000')
  1065. fi
  1066. for PD_SERVICE_KEY in ${recipients}; do
  1067. d="${status} ${name} = ${value_string} - ${host}"
  1068. if [ ${USE_PD_VERSION} = "2" ]; then
  1069. payload="$(
  1070. cat <<EOF
  1071. {
  1072. "payload" : {
  1073. "summary": "${info:0:1024}",
  1074. "source" : "${args_host}",
  1075. "severity" : "${severity}",
  1076. "timestamp" : "${current_time}",
  1077. "class" : "${chart}",
  1078. "custom_details": {
  1079. "value_w_units": "${value_string}",
  1080. "when": "${when}",
  1081. "duration" : "${duration}",
  1082. "roles": "${roles}",
  1083. "alarm_id" : "${alarm_id}",
  1084. "name" : "${name}",
  1085. "chart" : "${chart}",
  1086. "status" : "${status}",
  1087. "old_status" : "${old_status}",
  1088. "value" : "${value}",
  1089. "old_value" : "${old_value}",
  1090. "src" : "${src}",
  1091. "non_clear_duration" : "${non_clear_duration}",
  1092. "units" : "${units}",
  1093. "info" : "${info}"
  1094. }
  1095. },
  1096. "routing_key": "${PD_SERVICE_KEY}",
  1097. "event_action": "${t}",
  1098. "dedup_key": "${unique_id}"
  1099. }
  1100. EOF
  1101. )"
  1102. url="https://events.pagerduty.com/v2/enqueue"
  1103. response_code="202"
  1104. else
  1105. payload="$(
  1106. cat <<EOF
  1107. {
  1108. "service_key": "${PD_SERVICE_KEY}",
  1109. "event_type": "${t}",
  1110. "incident_key" : "${alarm_id}",
  1111. "description": "${d}",
  1112. "details": {
  1113. "value_w_units": "${value_string}",
  1114. "when": "${when}",
  1115. "duration" : "${duration}",
  1116. "roles": "${roles}",
  1117. "alarm_id" : "${alarm_id}",
  1118. "name" : "${name}",
  1119. "chart" : "${chart}",
  1120. "status" : "${status}",
  1121. "old_status" : "${old_status}",
  1122. "value" : "${value}",
  1123. "old_value" : "${old_value}",
  1124. "src" : "${src}",
  1125. "non_clear_duration" : "${non_clear_duration}",
  1126. "units" : "${units}",
  1127. "info" : "${info}"
  1128. }
  1129. }
  1130. EOF
  1131. )"
  1132. url="https://events.pagerduty.com/generic/2010-04-15/create_event.json"
  1133. response_code="200"
  1134. fi
  1135. httpcode=$(docurl -X POST --data "${payload}" ${url})
  1136. if [ "${httpcode}" = "${response_code}" ]; then
  1137. info "sent pagerduty event for ${notification_description}"
  1138. sent=$((sent + 1))
  1139. else
  1140. error "failed to send pagerduty event for ${notification_description}, with HTTP response status code ${httpcode}."
  1141. fi
  1142. done
  1143. [ ${sent} -gt 0 ] && return 0
  1144. fi
  1145. return 1
  1146. }
  1147. # -----------------------------------------------------------------------------
  1148. # twilio sender
  1149. send_twilio() {
  1150. local accountsid="${1}" accounttoken="${2}" twilionumber="${3}" recipients="${4}" title="${5}" message="${6}" httpcode sent=0 user
  1151. if [ "${SEND_TWILIO}" = "YES" ] && [ -n "${accountsid}" ] && [ -n "${accounttoken}" ] && [ -n "${twilionumber}" ] && [ -n "${recipients}" ] && [ -n "${message}" ] && [ -n "${title}" ]; then
  1152. #https://www.twilio.com/packages/labs/code/bash/twilio-sms
  1153. for user in ${recipients}; do
  1154. httpcode=$(docurl -X POST \
  1155. --data-urlencode "From=${twilionumber}" \
  1156. --data-urlencode "To=${user}" \
  1157. --data-urlencode "Body=${title} ${message}" \
  1158. -u "${accountsid}:${accounttoken}" \
  1159. "https://api.twilio.com/2010-04-01/Accounts/${accountsid}/Messages.json")
  1160. if [ "${httpcode}" = "201" ]; then
  1161. info "sent Twilio SMS to '${user}' for ${notification_description}"
  1162. sent=$((sent + 1))
  1163. else
  1164. error "failed to send Twilio SMS to '${user}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1165. fi
  1166. done
  1167. [ ${sent} -gt 0 ] && return 0
  1168. fi
  1169. return 1
  1170. }
  1171. # -----------------------------------------------------------------------------
  1172. # hipchat sender
  1173. send_hipchat() {
  1174. local authtoken="${1}" recipients="${2}" message="${3}" httpcode sent=0 room color msg_format notify
  1175. # remove <small></small> from the message
  1176. message="${message//<small>/}"
  1177. message="${message//<\/small>/}"
  1178. if [ "${SEND_HIPCHAT}" = "YES" ] && [ -n "${HIPCHAT_SERVER}" ] && [ -n "${authtoken}" ] && [ -n "${recipients}" ] && [ -n "${message}" ]; then
  1179. # Valid values: html, text.
  1180. # Defaults to 'html'.
  1181. msg_format="html"
  1182. # Background color for message. Valid values: yellow, green, red, purple, gray, random. Defaults to 'yellow'.
  1183. case "${status}" in
  1184. WARNING) color="yellow" ;;
  1185. CRITICAL) color="red" ;;
  1186. CLEAR) color="green" ;;
  1187. *) color="gray" ;;
  1188. esac
  1189. # Whether this message should trigger a user notification (change the tab color, play a sound, notify mobile phones, etc).
  1190. # Each recipient's notification preferences are taken into account.
  1191. # Defaults to false.
  1192. notify="true"
  1193. for room in ${recipients}; do
  1194. httpcode=$(docurl -X POST \
  1195. -H "Content-type: application/json" \
  1196. -H "Authorization: Bearer ${authtoken}" \
  1197. -d "{\"color\": \"${color}\", \"from\": \"${host}\", \"message_format\": \"${msg_format}\", \"message\": \"${message}\", \"notify\": \"${notify}\"}" \
  1198. "https://${HIPCHAT_SERVER}/v2/room/${room}/notification")
  1199. if [ "${httpcode}" = "204" ]; then
  1200. info "sent HipChat notification to '${room}' for ${notification_description}"
  1201. sent=$((sent + 1))
  1202. else
  1203. error "failed to send HipChat notification to '${room}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1204. fi
  1205. done
  1206. [ ${sent} -gt 0 ] && return 0
  1207. fi
  1208. return 1
  1209. }
  1210. # -----------------------------------------------------------------------------
  1211. # messagebird sender
  1212. send_messagebird() {
  1213. local accesskey="${1}" messagebirdnumber="${2}" recipients="${3}" title="${4}" message="${5}" httpcode sent=0 user
  1214. if [ "${SEND_MESSAGEBIRD}" = "YES" ] && [ -n "${accesskey}" ] && [ -n "${messagebirdnumber}" ] && [ -n "${recipients}" ] && [ -n "${message}" ] && [ -n "${title}" ]; then
  1215. #https://developers.messagebird.com/docs/messaging
  1216. for user in ${recipients}; do
  1217. httpcode=$(docurl -X POST \
  1218. --data-urlencode "originator=${messagebirdnumber}" \
  1219. --data-urlencode "recipients=${user}" \
  1220. --data-urlencode "body=${title} ${message}" \
  1221. --data-urlencode "datacoding=auto" \
  1222. -H "Authorization: AccessKey ${accesskey}" \
  1223. "https://rest.messagebird.com/messages")
  1224. if [ "${httpcode}" = "201" ]; then
  1225. info "sent Messagebird SMS to '${user}' for ${notification_description}"
  1226. sent=$((sent + 1))
  1227. else
  1228. error "failed to send Messagebird SMS to '${user}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1229. fi
  1230. done
  1231. [ ${sent} -gt 0 ] && return 0
  1232. fi
  1233. return 1
  1234. }
  1235. # -----------------------------------------------------------------------------
  1236. # kavenegar sender
  1237. send_kavenegar() {
  1238. local API_KEY="${1}" kavenegarsender="${2}" recipients="${3}" title="${4}" message="${5}" httpcode sent=0 user
  1239. if [ "${SEND_KAVENEGAR}" = "YES" ] && [ -n "${API_KEY}" ] && [ -n "${kavenegarsender}" ] && [ -n "${recipients}" ] && [ -n "${message}" ] && [ -n "${title}" ]; then
  1240. # http://api.kavenegar.com/v1/{API-KEY}/sms/send.json
  1241. for user in ${recipients}; do
  1242. httpcode=$(docurl -X POST http://api.kavenegar.com/v1/${API_KEY}/sms/send.json \
  1243. --data-urlencode "sender=${kavenegarsender}" \
  1244. --data-urlencode "receptor=${user}" \
  1245. --data-urlencode "message=${title} ${message}")
  1246. if [ "${httpcode}" = "200" ]; then
  1247. info "sent Kavenegar SMS to '${user}' for ${notification_description}"
  1248. sent=$((sent + 1))
  1249. else
  1250. error "failed to send Kavenegar SMS to '${user}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1251. fi
  1252. done
  1253. [ ${sent} -gt 0 ] && return 0
  1254. fi
  1255. return 1
  1256. }
  1257. # -----------------------------------------------------------------------------
  1258. # telegram sender
  1259. send_telegram() {
  1260. local bottoken="${1}" chatids="${2}" message="${3}" httpcode sent=0 chatid emoji disableNotification=""
  1261. if [ "${status}" = "CLEAR" ]; then disableNotification="--data-urlencode disable_notification=true"; fi
  1262. case "${status}" in
  1263. WARNING) emoji="⚠️" ;;
  1264. CRITICAL) emoji="🔴" ;;
  1265. CLEAR) emoji="✅" ;;
  1266. *) emoji="⚪️" ;;
  1267. esac
  1268. if [ "${SEND_TELEGRAM}" = "YES" ] && [ -n "${bottoken}" ] && [ -n "${chatids}" ] && [ -n "${message}" ]; then
  1269. for chatid in ${chatids}; do
  1270. notify_telegram=1
  1271. notify_retries=${TELEGRAM_RETRIES_ON_LIMIT:-0}
  1272. while [ ${notify_telegram} -eq 1 ]; do
  1273. # https://core.telegram.org/bots/api#sendmessage
  1274. httpcode=$(docurl ${disableNotification} \
  1275. --data-urlencode "parse_mode=HTML" \
  1276. --data-urlencode "disable_web_page_preview=true" \
  1277. --data-urlencode "text=${emoji} ${message}" \
  1278. "https://api.telegram.org/bot${bottoken}/sendMessage?chat_id=${chatid}")
  1279. notify_telegram=0
  1280. if [ "${httpcode}" = "200" ]; then
  1281. info "sent telegram notification to '${chatid}' for ${notification_description}"
  1282. sent=$((sent + 1))
  1283. elif [ "${httpcode}" = "401" ]; then
  1284. error "failed to send telegram notification to '${chatid}' for ${notification_description}, wrong bot token."
  1285. elif [ "${httpcode}" = "429" ]; then
  1286. if [ "$notify_retries" -gt 0 ]; then
  1287. error "failed to send telegram notification to '${chatid}' for ${notification_description}, rate limit exceeded, retrying after 1s."
  1288. notify_retries=$((notify_retries - 1))
  1289. notify_telegram=1
  1290. sleep 1
  1291. else
  1292. error "failed to send telegram notification to '${chatid}' for ${notification_description}, rate limit exceeded."
  1293. fi
  1294. else
  1295. error "failed to send telegram notification to '${chatid}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1296. fi
  1297. done
  1298. done
  1299. [ ${sent} -gt 0 ] && return 0
  1300. fi
  1301. return 1
  1302. }
  1303. # -----------------------------------------------------------------------------
  1304. # Microsoft Team sender
  1305. send_msteams() {
  1306. local webhook="${1}" channels="${2}" httpcode sent=0 channel color payload
  1307. [ "${SEND_MSTEAMS}" != "YES" ] && return 1
  1308. case "${status}" in
  1309. WARNING) icon="${MSTEAMS_ICON_WARNING}" && color="${MSTEAMS_COLOR_WARNING}" ;;
  1310. CRITICAL) icon="${MSTEAMS_ICON_CRITICAL}" && color="${MSTEAMS_COLOR_CRITICAL}" ;;
  1311. CLEAR) icon="${MSTEAMS_ICON_CLEAR}" && color="${MSTEAMS_COLOR_CLEAR}" ;;
  1312. *) icon="${MSTEAMS_ICON_DEFAULT}" && color="${MSTEAMS_COLOR_DEFAULT}" ;;
  1313. esac
  1314. for channel in ${channels}; do
  1315. ## More details are available here regarding the payload syntax options : https://docs.microsoft.com/en-us/outlook/actionable-messages/message-card-reference
  1316. ## Online designer : https://adaptivecards.io/designer/
  1317. payload="$(
  1318. cat <<EOF
  1319. {
  1320. "@context": "http://schema.org/extensions",
  1321. "@type": "MessageCard",
  1322. "themeColor": "${color}",
  1323. "title": "$icon Alert ${status} from netdata for ${host}",
  1324. "text": "${host} ${status_message}, ${chart}, *${alarm}*",
  1325. "potentialAction": [
  1326. {
  1327. "@type": "OpenUri",
  1328. "name": "Netdata",
  1329. "targets": [
  1330. { "os": "default", "uri": "${goto_url}" }
  1331. ]
  1332. }
  1333. ]
  1334. }
  1335. EOF
  1336. )"
  1337. # Replacing in the webhook CHANNEL string by the MS Teams channel name from conf file.
  1338. cur_webhook="${webhook//CHANNEL/${channel}}"
  1339. httpcode=$(docurl -H "Content-Type: application/json" -d "${payload}" "${cur_webhook}")
  1340. if [ "${httpcode}" = "200" ]; then
  1341. info "sent Microsoft team notification to '${cur_webhook}' for ${notification_description}"
  1342. sent=$((sent + 1))
  1343. else
  1344. error "failed to send Microsoft team to '${cur_webhook}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1345. fi
  1346. done
  1347. [ ${sent} -gt 0 ] && return 0
  1348. return 1
  1349. }
  1350. # slack sender
  1351. send_slack() {
  1352. local webhook="${1}" channels="${2}" httpcode sent=0 channel color payload
  1353. [ "${SEND_SLACK}" != "YES" ] && return 1
  1354. case "${status}" in
  1355. WARNING) color="warning" ;;
  1356. CRITICAL) color="danger" ;;
  1357. CLEAR) color="good" ;;
  1358. *) color="#777777" ;;
  1359. esac
  1360. for channel in ${channels}; do
  1361. # Default entry in the recipient is without a hash in front (backwards-compatible). Accept specification of channel or user.
  1362. if [ "${channel::1}" != "#" ] && [ "${channel::1}" != "@" ]; then channel="#$channel"; fi
  1363. # If channel is equal to "#" then do not send the channel attribute at all. Slack also defines channels and users in webhooks.
  1364. if [ "${channel}" = "#" ]; then
  1365. ch=""
  1366. chstr="without specifying a channel"
  1367. else
  1368. ch="\"channel\": \"${channel}\","
  1369. chstr="to '${channel}'"
  1370. fi
  1371. payload="$(
  1372. cat <<EOF
  1373. {
  1374. $ch
  1375. "username": "netdata on ${host}",
  1376. "icon_url": "${images_base_url}/images/banner-icon-144x144.png",
  1377. "text": "${host} ${status_message}, \`${chart}\`, *${alarm}*",
  1378. "attachments": [
  1379. {
  1380. "fallback": "${alarm} - ${chart} - ${info}",
  1381. "color": "${color}",
  1382. "title": "${alarm}",
  1383. "title_link": "${goto_url}",
  1384. "text": "${info}",
  1385. "fields": [
  1386. {
  1387. "title": "${chart}",
  1388. "value": "chart",
  1389. "short": true
  1390. }
  1391. ],
  1392. "thumb_url": "${image}",
  1393. "footer": "by ${host}",
  1394. "ts": ${when}
  1395. }
  1396. ]
  1397. }
  1398. EOF
  1399. )"
  1400. httpcode=$(docurl -X POST --data-urlencode "payload=${payload}" "${webhook}")
  1401. if [ "${httpcode}" = "200" ]; then
  1402. info "sent slack notification ${chstr} for ${notification_description}"
  1403. sent=$((sent + 1))
  1404. else
  1405. error "failed to send slack notification ${chstr} for ${notification_description}, with HTTP response status code ${httpcode}."
  1406. fi
  1407. done
  1408. [ ${sent} -gt 0 ] && return 0
  1409. return 1
  1410. }
  1411. # -----------------------------------------------------------------------------
  1412. # rocketchat sender
  1413. send_rocketchat() {
  1414. local webhook="${1}" channels="${2}" httpcode sent=0 channel color payload
  1415. [ "${SEND_ROCKETCHAT}" != "YES" ] && return 1
  1416. case "${status}" in
  1417. WARNING) color="warning" ;;
  1418. CRITICAL) color="danger" ;;
  1419. CLEAR) color="good" ;;
  1420. *) color="#777777" ;;
  1421. esac
  1422. for channel in ${channels}; do
  1423. payload="$(
  1424. cat <<EOF
  1425. {
  1426. "channel": "#${channel}",
  1427. "alias": "netdata on ${host}",
  1428. "avatar": "${images_base_url}/images/banner-icon-144x144.png",
  1429. "text": "${host} ${status_message}, \`${chart}\`, *${alarm}*",
  1430. "attachments": [
  1431. {
  1432. "color": "${color}",
  1433. "title": "${alarm}",
  1434. "title_link": "${goto_url}",
  1435. "text": "${info}",
  1436. "fields": [
  1437. {
  1438. "title": "${chart}",
  1439. "short": true,
  1440. "value": "chart"
  1441. }
  1442. ],
  1443. "thumb_url": "${image}",
  1444. "ts": "${when}"
  1445. }
  1446. ]
  1447. }
  1448. EOF
  1449. )"
  1450. httpcode=$(docurl -X POST --data-urlencode "payload=${payload}" "${webhook}")
  1451. if [ "${httpcode}" = "200" ]; then
  1452. info "sent rocketchat notification to '${channel}' for ${notification_description}"
  1453. sent=$((sent + 1))
  1454. else
  1455. error "failed to send rocketchat notification to '${channel}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1456. fi
  1457. done
  1458. [ ${sent} -gt 0 ] && return 0
  1459. return 1
  1460. }
  1461. # -----------------------------------------------------------------------------
  1462. # alerta sender
  1463. send_alerta() {
  1464. local webhook="${1}" channels="${2}" httpcode sent=0 channel severity resource event payload auth
  1465. [ "${SEND_ALERTA}" != "YES" ] && return 1
  1466. case "${status}" in
  1467. CRITICAL) severity="critical" ;;
  1468. WARNING) severity="warning" ;;
  1469. CLEAR) severity="cleared" ;;
  1470. *) severity="indeterminate" ;;
  1471. esac
  1472. if [[ ${chart} == httpcheck* ]]; then
  1473. resource=$chart
  1474. event=$name
  1475. else
  1476. resource="${host}"
  1477. event="${chart}.${name}"
  1478. fi
  1479. for channel in ${channels}; do
  1480. payload="$(
  1481. cat <<EOF
  1482. {
  1483. "resource": "${resource}",
  1484. "event": "${event}",
  1485. "environment": "${channel}",
  1486. "severity": "${severity}",
  1487. "service": ["Netdata"],
  1488. "group": "Performance",
  1489. "value": "${value_string}",
  1490. "text": "${info}",
  1491. "tags": ["alarm_id:${alarm_id}"],
  1492. "attributes": {
  1493. "roles": "${roles}",
  1494. "name": "${name}",
  1495. "chart": "${chart}",
  1496. "source": "${src}",
  1497. "moreInfo": "<a href=\"${goto_url}\">View Netdata</a>"
  1498. },
  1499. "origin": "netdata/${host}",
  1500. "type": "netdataAlarm",
  1501. "rawData": "${BASH_ARGV[@]}"
  1502. }
  1503. EOF
  1504. )"
  1505. if [ -n "${ALERTA_API_KEY}" ]; then
  1506. auth="Key ${ALERTA_API_KEY}"
  1507. fi
  1508. httpcode=$(docurl -X POST "${webhook}/alert" -H "Content-Type: application/json" -H "Authorization: $auth" --data "${payload}")
  1509. if [ "${httpcode}" = "200" ] || [ "${httpcode}" = "201" ]; then
  1510. info "sent alerta notification to '${channel}' for ${notification_description}"
  1511. sent=$((sent + 1))
  1512. elif [ "${httpcode}" = "202" ]; then
  1513. info "suppressed alerta notification to '${channel}' for ${notification_description}"
  1514. else
  1515. error "failed to send alerta notification to '${channel}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1516. fi
  1517. done
  1518. [ ${sent} -gt 0 ] && return 0
  1519. return 1
  1520. }
  1521. # -----------------------------------------------------------------------------
  1522. # flock sender
  1523. send_flock() {
  1524. local webhook="${1}" channels="${2}" httpcode sent=0 channel color payload
  1525. [ "${SEND_FLOCK}" != "YES" ] && return 1
  1526. case "${status}" in
  1527. WARNING) color="warning" ;;
  1528. CRITICAL) color="danger" ;;
  1529. CLEAR) color="good" ;;
  1530. *) color="#777777" ;;
  1531. esac
  1532. for channel in ${channels}; do
  1533. httpcode=$(docurl -X POST "${webhook}" -H "Content-Type: application/json" -d "{
  1534. \"sendAs\": {
  1535. \"name\" : \"netdata on ${host}\",
  1536. \"profileImage\" : \"${images_base_url}/images/banner-icon-144x144.png\"
  1537. },
  1538. \"text\": \"${host} *${status_message}*\",
  1539. \"timestamp\": \"${when}\",
  1540. \"attachments\": [
  1541. {
  1542. \"description\": \"${chart} - ${info}\",
  1543. \"color\": \"${color}\",
  1544. \"title\": \"${alarm}\",
  1545. \"url\": \"${goto_url}\",
  1546. \"text\": \"${info}\",
  1547. \"views\": {
  1548. \"image\": {
  1549. \"original\": { \"src\": \"${image}\", \"width\": 400, \"height\": 400 },
  1550. \"thumbnail\": { \"src\": \"${image}\", \"width\": 50, \"height\": 50 },
  1551. \"filename\": \"${image}\"
  1552. }
  1553. }
  1554. }
  1555. ]
  1556. }")
  1557. if [ "${httpcode}" = "200" ]; then
  1558. info "sent flock notification to '${channel}' for ${notification_description}"
  1559. sent=$((sent + 1))
  1560. else
  1561. error "failed to send flock notification to '${channel}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1562. fi
  1563. done
  1564. [ ${sent} -gt 0 ] && return 0
  1565. return 1
  1566. }
  1567. # -----------------------------------------------------------------------------
  1568. # discord sender
  1569. send_discord() {
  1570. local webhook="${1}/slack" channels="${2}" httpcode sent=0 channel color payload username
  1571. [ "${SEND_DISCORD}" != "YES" ] && return 1
  1572. case "${status}" in
  1573. WARNING) color="warning" ;;
  1574. CRITICAL) color="danger" ;;
  1575. CLEAR) color="good" ;;
  1576. *) color="#777777" ;;
  1577. esac
  1578. for channel in ${channels}; do
  1579. username="netdata on ${host}"
  1580. [ ${#username} -gt 32 ] && username="${username:0:29}..."
  1581. payload="$(
  1582. cat <<EOF
  1583. {
  1584. "channel": "#${channel}",
  1585. "username": "${username}",
  1586. "text": "${host} ${status_message}, \`${chart}\`, *${alarm}*",
  1587. "icon_url": "${images_base_url}/images/banner-icon-144x144.png",
  1588. "attachments": [
  1589. {
  1590. "color": "${color}",
  1591. "title": "${alarm}",
  1592. "title_link": "${goto_url}",
  1593. "text": "${info}",
  1594. "fields": [
  1595. {
  1596. "title": "${chart}"
  1597. }
  1598. ],
  1599. "thumb_url": "${image}",
  1600. "footer_icon": "${images_base_url}/images/banner-icon-144x144.png",
  1601. "footer": "${host}",
  1602. "ts": ${when}
  1603. }
  1604. ]
  1605. }
  1606. EOF
  1607. )"
  1608. httpcode=$(docurl -X POST --data-urlencode "payload=${payload}" "${webhook}")
  1609. if [ "${httpcode}" = "200" ]; then
  1610. info "sent discord notification to '${channel}' for ${notification_description}"
  1611. sent=$((sent + 1))
  1612. else
  1613. error "failed to send discord notification to '${channel}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1614. fi
  1615. done
  1616. [ ${sent} -gt 0 ] && return 0
  1617. return 1
  1618. }
  1619. # -----------------------------------------------------------------------------
  1620. # fleep sender
  1621. send_fleep() {
  1622. local httpcode sent=0 webhooks="${1}" data message
  1623. if [ "${SEND_FLEEP}" = "YES" ]; then
  1624. message="${host} ${status_message}, \`${chart}\`, *${alarm}*\\n${info}"
  1625. for hook in ${webhooks}; do
  1626. data="{ "
  1627. data="${data} 'message': '${message}', "
  1628. data="${data} 'user': '${FLEEP_SENDER}' "
  1629. data="${data} }"
  1630. httpcode=$(docurl -X POST --data "${data}" "https://fleep.io/hook/${hook}")
  1631. if [ "${httpcode}" = "200" ]; then
  1632. info "sent fleep data to user '${FLEEP_SENDER}' for ${notification_description}"
  1633. sent=$((sent + 1))
  1634. else
  1635. error "failed to send fleep data to user '${FLEEP_SENDER}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1636. fi
  1637. done
  1638. [ ${sent} -gt 0 ] && return 0
  1639. fi
  1640. return 1
  1641. }
  1642. # -----------------------------------------------------------------------------
  1643. # Prowl sender
  1644. send_prowl() {
  1645. local httpcode sent=0 data message keys prio=0 alarm_url event
  1646. if [ "${SEND_PROWL}" = "YES" ]; then
  1647. message="$(urlencode "${host} ${status_message}, \`${chart}\`, *${alarm}*\\n${info}")"
  1648. message="description=${message}"
  1649. keys="$(urlencode "$(echo "${1}" | tr ' ' ,)")"
  1650. keys="apikey=${keys}"
  1651. app="application=Netdata"
  1652. case "${status}" in
  1653. CRITICAL)
  1654. prio=2
  1655. ;;
  1656. WARNING)
  1657. prio=1
  1658. ;;
  1659. esac
  1660. prio="priority=${prio}"
  1661. alarm_url="$(urlencode ${goto_url})"
  1662. alarm_url="url=${alarm_url}"
  1663. event="$(urlencode "${host} ${status_message}")"
  1664. event="event=${event}"
  1665. data="${keys}&${prio}&${alarm_url}&${app}&${event}&${message}"
  1666. httpcode=$(docurl -X POST --data "${data}" "https://api.prowlapp.com/publicapi/add")
  1667. if [ "${httpcode}" = "200" ]; then
  1668. info "sent prowl event for ${notification_description}"
  1669. sent=1
  1670. else
  1671. error "failed to send prowl event for ${notification_description}, with HTTP response status code ${httpcode}."
  1672. fi
  1673. [ ${sent} -gt 0 ] && return 0
  1674. fi
  1675. return 1
  1676. }
  1677. # -----------------------------------------------------------------------------
  1678. # irc sender
  1679. send_irc() {
  1680. local NICKNAME="${1}" REALNAME="${2}" CHANNELS="${3}" NETWORK="${4}" PORT="${5}" SERVERNAME="${6}" MESSAGE="${7}" sent=0 channel color send_alarm reply_codes error
  1681. if [ "${SEND_IRC}" = "YES" ] && [ -n "${NICKNAME}" ] && [ -n "${REALNAME}" ] && [ -n "${CHANNELS}" ] && [ -n "${NETWORK}" ] && [ -n "${SERVERNAME}" ] && [ -n "${PORT}" ]; then
  1682. case "${status}" in
  1683. WARNING) color="warning" ;;
  1684. CRITICAL) color="danger" ;;
  1685. CLEAR) color="good" ;;
  1686. *) color="#777777" ;;
  1687. esac
  1688. SNDMESSAGE="${MESSAGE//$'\n'/", "}"
  1689. for CHANNEL in ${CHANNELS}; do
  1690. error=0
  1691. send_alarm=$(echo -e "USER ${NICKNAME} guest ${REALNAME} ${SERVERNAME}\\nNICK ${NICKNAME}\\nJOIN ${CHANNEL}\\nPRIVMSG ${CHANNEL} :${SNDMESSAGE}\\nQUIT\\n" \ | ${nc} "${NETWORK}" "${PORT}")
  1692. reply_codes=$(echo "${send_alarm}" | cut -d ' ' -f 2 | grep -o '[0-9]*')
  1693. for code in ${reply_codes}; do
  1694. if [ "${code}" -ge 400 ] && [ "${code}" -le 599 ]; then
  1695. error=1
  1696. break
  1697. fi
  1698. done
  1699. if [ "${error}" -eq 0 ]; then
  1700. info "sent irc notification to '${CHANNEL}' for ${notification_description}"
  1701. sent=$((sent + 1))
  1702. else
  1703. error "failed to send irc notification to '${CHANNEL}' for ${notification_description}, with error code ${code}."
  1704. fi
  1705. done
  1706. fi
  1707. [ ${sent} -gt 0 ] && return 0
  1708. return 1
  1709. }
  1710. # -----------------------------------------------------------------------------
  1711. # Amazon SNS sender
  1712. send_awssns() {
  1713. local targets="${1}" message='' sent=0 region=''
  1714. local default_format="${status} on ${host} at ${date}: ${chart} ${value_string}"
  1715. [ "${SEND_AWSSNS}" = "YES" ] || return 1
  1716. message=${AWSSNS_MESSAGE_FORMAT:-${default_format}}
  1717. for target in ${targets}; do
  1718. # Extract the region from the target ARN. We need to explicitly specify the region so that it matches up correctly.
  1719. region="$(echo ${target} | cut -f 4 -d ':')"
  1720. if ${aws} sns publish --region "${region}" --subject "${host} ${status_message} - ${name//_/ } - ${chart}" --message "${message}" --target-arn ${target} &>/dev/null; then
  1721. info "sent Amazon SNS notification to '${target}' for ${notification_description}"
  1722. sent=$((sent + 1))
  1723. else
  1724. error "failed to send Amazon SNS notification to '${target}' for ${notification_description}"
  1725. fi
  1726. done
  1727. [ ${sent} -gt 0 ] && return 0
  1728. return 1
  1729. }
  1730. # -----------------------------------------------------------------------------
  1731. # Matrix sender
  1732. send_matrix() {
  1733. local homeserver="${1}" webhook accesstoken rooms="${2}" httpcode sent=0 payload
  1734. [ "${SEND_MATRIX}" != "YES" ] && return 1
  1735. [ -z "${MATRIX_ACCESSTOKEN}" ] && return 1
  1736. accesstoken="${MATRIX_ACCESSTOKEN}"
  1737. case "${status}" in
  1738. WARNING) emoji="⚠️" ;;
  1739. CRITICAL) emoji="🔴" ;;
  1740. CLEAR) emoji="✅" ;;
  1741. *) emoji="⚪️" ;;
  1742. esac
  1743. for room in ${rooms}; do
  1744. webhook="$homeserver/_matrix/client/r0/rooms/$(urlencode $room)/send/m.room.message?access_token=$accesstoken"
  1745. payload="$(
  1746. cat <<EOF
  1747. {
  1748. "msgtype": "m.notice",
  1749. "format": "org.matrix.custom.html",
  1750. "formatted_body": "${emoji} ${host} ${status_message} - <b>${name//_/ }</b><br>${chart}<br><a href=\"${goto_url}\">${alarm}</a><br><i>${info}</i>",
  1751. "body": "${emoji} ${host} ${status_message} - ${name//_/ } ${chart} ${goto_url} ${alarm} ${info}"
  1752. }
  1753. EOF
  1754. )"
  1755. httpcode=$(docurl -X POST --data "${payload}" "${webhook}")
  1756. if [ "${httpcode}" == "200" ]; then
  1757. info "sent Matrix notification to '${room}' for ${notification_description}"
  1758. sent=$((sent + 1))
  1759. else
  1760. error "failed to send Matrix notification to '${room}' for ${notification_description}, with HTTP response status code ${httpcode}."
  1761. fi
  1762. done
  1763. [ ${sent} -gt 0 ] && return 0
  1764. return 1
  1765. }
  1766. # -----------------------------------------------------------------------------
  1767. # syslog sender
  1768. send_syslog() {
  1769. local facility=${SYSLOG_FACILITY:-"local6"} level='info' targets="${1}"
  1770. local priority='' message='' server='' port='' prefix=''
  1771. local temp1='' temp2=''
  1772. [ "${SEND_SYSLOG}" = "YES" ] || return 1
  1773. if [ "${status}" = "CRITICAL" ]; then
  1774. level='crit'
  1775. elif [ "${status}" = "WARNING" ]; then
  1776. level='warning'
  1777. fi
  1778. for target in ${targets}; do
  1779. priority="${facility}.${level}"
  1780. message=''
  1781. server=''
  1782. port=''
  1783. prefix=''
  1784. temp1=''
  1785. temp2=''
  1786. prefix=$(echo ${target} | cut -d '/' -f 2)
  1787. temp1=$(echo ${target} | cut -d '/' -f 1)
  1788. if [ ${prefix} != ${temp1} ]; then
  1789. if (echo ${temp1} | grep -q '@'); then
  1790. temp2=$(echo ${temp1} | cut -d '@' -f 1)
  1791. server=$(echo ${temp1} | cut -d '@' -f 2)
  1792. if [ ${temp2} != ${server} ]; then
  1793. priority=${temp2}
  1794. fi
  1795. port=$(echo ${server} | rev | cut -d ':' -f 1 | rev)
  1796. if (echo ${server} | grep -E -q '\[.*\]'); then
  1797. if (echo ${port} | grep -q ']'); then
  1798. port=''
  1799. else
  1800. server=$(echo ${server} | rev | cut -d ':' -f 2- | rev)
  1801. fi
  1802. else
  1803. if [ ${port} = ${server} ]; then
  1804. port=''
  1805. else
  1806. server=$(echo ${server} | cut -d ':' -f 1)
  1807. fi
  1808. fi
  1809. else
  1810. priority=${temp1}
  1811. fi
  1812. fi
  1813. message="${prefix} ${status} on ${host} at ${date}: ${chart} ${value_string}"
  1814. if [ ${server} ]; then
  1815. logger_options="${logger_options} -n ${server}"
  1816. if [ ${port} ]; then
  1817. logger_options="${logger_options} -P ${port}"
  1818. fi
  1819. fi
  1820. ${logger} -p ${priority} ${logger_options} "${message}"
  1821. done
  1822. return $?
  1823. }
  1824. # -----------------------------------------------------------------------------
  1825. # SMS sender
  1826. send_sms() {
  1827. local recipients="${1}" errcode errmessage sent=0
  1828. # Human readable SMS
  1829. local msg="${host} ${status_message}: ${chart}, ${alarm}"
  1830. # limit it to 160 characters
  1831. msg="${msg:0:160}"
  1832. if [ "${SEND_SMS}" = "YES" ] && [ -n "${sendsms}" ] && [ -n "${recipients}" ] && [ -n "${msg}" ]; then
  1833. # http://api.kavenegar.com/v1/{API-KEY}/sms/send.json
  1834. for phone in ${recipients}; do
  1835. errmessage=$($sendsms $phone "$msg" 2>&1)
  1836. errcode=$?
  1837. if [ ${errcode} -eq 0 ]; then
  1838. info "sent smstools3 SMS to '${user}' for ${notification_description}"
  1839. sent=$((sent + 1))
  1840. else
  1841. error "failed to send smstools3 SMS to '${user}' for ${notification_description}, with error code ${errcode}: ${errmessage}."
  1842. fi
  1843. done
  1844. [ ${sent} -gt 0 ] && return 0
  1845. fi
  1846. return 1
  1847. }
  1848. # -----------------------------------------------------------------------------
  1849. # Dynatrace sender
  1850. send_dynatrace() {
  1851. [ "${SEND_DYNATRACE}" != "YES" ] && return 1
  1852. local dynatrace_url="${DYNATRACE_SERVER}/e/${DYNATRACE_SPACE}/api/v1/events"
  1853. local description="Netdata Notification for: ${host} ${chart}.${name} is ${status}"
  1854. local payload=""
  1855. payload=$(cat <<EOF
  1856. {
  1857. "title": "Netdata Alarm from ${host}",
  1858. "source" : "${DYNATRACE_ANNOTATION_TYPE}",
  1859. "description" : "${description}",
  1860. "eventType": "${DYNATRACE_EVENT}",
  1861. "attachRules":{
  1862. "tagRule":[{
  1863. "meTypes":["HOST"],
  1864. "tags":["${DYNATRACE_TAG_VALUE}"]
  1865. }]
  1866. },
  1867. "customProperties":{
  1868. "description": "${description}"
  1869. }
  1870. }
  1871. EOF
  1872. )
  1873. # echo ${payload}
  1874. httpcode=$(docurl -X POST -H "Authorization: Api-token ${DYNATRACE_TOKEN}" -H "Content-Type: application/json" -d "${payload}" ${dynatrace_url})
  1875. ret=$?
  1876. if [ ${ret} -eq 0 ]; then
  1877. if [ "${httpcode}" = "200" ]; then
  1878. info "sent Dynatrace event '${DYNATRACE_EVENT}' to '${DYNATRACE_SERVER}' for ${notification_description}"
  1879. return 0
  1880. else
  1881. warning "failed to send Dynatrace event to '${DYNATRACE_SERVER}' for ${notification_description}, with HTTP response status code ${httpcode}"
  1882. return 1
  1883. fi
  1884. else
  1885. error "failed to sent Dynatrace '${DYNATRACE_EVENT}' to '${DYNATRACE_SERVER}' for ${notification_description}, with code ${ret}."
  1886. return 1
  1887. fi
  1888. }
  1889. # -----------------------------------------------------------------------------
  1890. # Opsgenie sender
  1891. send_opsgenie() {
  1892. local payload httpcode oldv currv priority
  1893. [ "${SEND_OPSGENIE}" != "YES" ] && return 1
  1894. if [ -z "${OPSGENIE_API_KEY}" ] ; then
  1895. info "Can't send Opsgenie notification, because OPSGENIE_API_KEY is not defined"
  1896. return 1
  1897. fi
  1898. # Priority for OpsGenie alert (https://support.atlassian.com/opsgenie/docs/update-alert-priority-level/)
  1899. case "${status}" in
  1900. CRITICAL) priority="P1" ;; # Critical is P1
  1901. WARNING) priority="P3" ;; # Warning is P3
  1902. CLEAR) priority="P5" ;; # Clear is P5
  1903. *) priority="P3" ;; # OpsGenie's default alert level is P3
  1904. esac
  1905. # We are sending null when values are nan to avoid errors while JSON message is parsed
  1906. [ "${old_value}" != "nan" ] && oldv="${old_value}" || oldv="null"
  1907. [ "${value}" != "nan" ] && currv="${value}" || currv="null"
  1908. payload=$(cat <<EOF
  1909. {
  1910. "host" : "${host}",
  1911. "unique_id" : "${unique_id}",
  1912. "alarmId" : ${alarm_id},
  1913. "eventId" : ${event_id},
  1914. "chart" : "${chart}",
  1915. "when": ${when},
  1916. "name" : "${name}",
  1917. "priority" : "${priority}",
  1918. "status" : "${status}",
  1919. "old_status" : "${old_status}",
  1920. "value" : ${currv},
  1921. "old_value" : ${oldv},
  1922. "duration": ${duration},
  1923. "non_clear_duration": ${non_clear_duration},
  1924. "units" : "${units}",
  1925. "info" : "${status_message}, ${info}",
  1926. "calc_expression" : "${calc_expression}",
  1927. "total_warnings" : "${total_warnings}",
  1928. "total_critical" : "${total_critical}",
  1929. "src" : "${src}"
  1930. }
  1931. EOF
  1932. )
  1933. httpcode=$(docurl -X POST -H "Content-Type: application/json" -d "${payload}" "${OPSGENIE_API_URL}/v1/json/integrations/webhooks/netdata?apiKey=${OPSGENIE_API_KEY}")
  1934. # https://docs.opsgenie.com/docs/alert-api#create-alert
  1935. if [ "${httpcode}" = "200" ]; then
  1936. info "sent opsgenie event for ${notification_description}"
  1937. else
  1938. error "failed to send opsgenie event for ${notification_description}, with HTTP response status code ${httpcode}."
  1939. return 1
  1940. fi
  1941. return 0
  1942. }
  1943. # -----------------------------------------------------------------------------
  1944. # Gotify sender
  1945. send_gotify() {
  1946. local payload httpcode priority
  1947. [ "${SEND_GOTIFY}" != "YES" ] && return 1
  1948. if [ -z "${GOTIFY_APP_TOKEN}" ] ; then
  1949. info "Can't send Gotify notification, because GOTIFY_APP_TOKEN is not defined"
  1950. return 1
  1951. fi
  1952. # priority for Gotify Android app
  1953. case "${status}" in
  1954. CRITICAL) priority=10 ;; # sound + vibration
  1955. WARNING) priority=4 ;; # sound
  1956. *) priority=1 ;; # notification only
  1957. esac
  1958. payload=$(cat <<EOF
  1959. {
  1960. "title" : "${status}, ${name} = ${value_string}, on ${host}",
  1961. "message" : "${date}: ${chart} ${value_string}",
  1962. "priority" : ${priority}
  1963. }
  1964. EOF
  1965. )
  1966. httpcode=$(docurl -X POST -H "Content-Type: application/json" -d "${payload}" "${GOTIFY_APP_URL}/message?token=${GOTIFY_APP_TOKEN}")
  1967. if [ "${httpcode}" = "200" ]; then
  1968. info "sent gotify event for ${notification_description}"
  1969. else
  1970. error "failed to send gotify event for ${notification_description}, with HTTP response status code ${httpcode}."
  1971. return 1
  1972. fi
  1973. return 0
  1974. }
  1975. # -----------------------------------------------------------------------------
  1976. # ntfy sender
  1977. send_ntfy() {
  1978. local httpcode priority recipients=${1} sent=0 msg
  1979. [ "${SEND_NTFY}" != "YES" ] && return 1
  1980. case "${status}" in
  1981. WARNING) emoji="warning" ;;
  1982. CRITICAL) emoji="red_circle" ;;
  1983. CLEAR) emoji="white_check_mark" ;;
  1984. *) emoji="white_circle" ;;
  1985. esac
  1986. case ${status} in
  1987. WARNING) priority="high";;
  1988. CRITICAL) priority="urgent";;
  1989. *) priority="default" ;;
  1990. esac
  1991. # Adding ntfy header generation logic
  1992. # Heavily inspired by https://github.com/nickexyz/ntfy-shellscripts/blob/main/sabnzbd.sh
  1993. tmp_header=""
  1994. if [[ -n "${NTFY_USERNAME}" ]] && [[ -n "${NTFY_PASSWORD}" ]]; then
  1995. ntfy_base64=$( echo -n "$NTFY_USERNAME:$NTFY_PASSWORD" | base64 )
  1996. tmp_header="Authorization: Basic ${ntfy_base64}"
  1997. elif [ -n "${NTFY_ACCESS_TOKEN}" ]; then
  1998. tmp_header="Authorization: Bearer ${NTFY_ACCESS_TOKEN}"
  1999. fi
  2000. ntfy_auth_header=()
  2001. if [ -n "${tmp_header}" ]; then
  2002. ntfy_auth_header=("-H" "${tmp_header}")
  2003. fi
  2004. for recipient in ${recipients}; do
  2005. msg="${host} ${status_message}: ${alarm} - ${info}"
  2006. httpcode=$(docurl -X POST \
  2007. "${ntfy_auth_header[@]}" \
  2008. -H "Icon: https://raw.githubusercontent.com/netdata/netdata/master/web/gui/dashboard/images/favicon-196x196.png" \
  2009. -H "Title: ${host}: ${name//_/ }" \
  2010. -H "Tags: ${emoji}" \
  2011. -H "Priority: ${priority}" \
  2012. -H "Actions: view, View node, ${goto_url}, clear=true;" \
  2013. -d "${msg}" \
  2014. ${recipient})
  2015. if [ "${httpcode}" == "200" ]; then
  2016. info "sent ntfy notification to '${recipient}' for ${notification_description}"
  2017. sent=$((sent + 1))
  2018. else
  2019. error "failed to send ntfy notification to '${recipient}' for ${notification_description}, with HTTP response status code ${httpcode}."
  2020. fi
  2021. done
  2022. [ ${sent} -gt 0 ] && return 0
  2023. return 1
  2024. }
  2025. # -----------------------------------------------------------------------------
  2026. # prepare the content of the notification
  2027. # the url to send the user on click
  2028. urlencode "${args_host}" >/dev/null
  2029. url_host="${REPLY}"
  2030. urlencode "${chart}" >/dev/null
  2031. url_chart="${REPLY}"
  2032. urlencode "${name}" >/dev/null
  2033. url_name="${REPLY}"
  2034. urlencode "${value_string}" >/dev/null
  2035. url_value_string="${REPLY}"
  2036. redirect_params="host=${url_host}&chart=${url_chart}&alarm=${url_name}&alarm_unique_id=${unique_id}&alarm_id=${alarm_id}&alarm_event_id=${event_id}&alarm_when=${when}&alarm_status=${status}&alarm_chart=${chart}&alarm_value=${url_value_string}"
  2037. if [ -z "${NETDATA_REGISTRY_UNIQUE_ID}" ]; then
  2038. if [ -f "@registrydir_POST@/netdata.public.unique.id" ]; then
  2039. NETDATA_REGISTRY_UNIQUE_ID="$(cat "@registrydir_POST@/netdata.public.unique.id")"
  2040. else
  2041. error "failed to identify this agent via its NETDATA_REGISTRY_UNIQUE_ID."
  2042. fi
  2043. fi
  2044. goto_url="${NETDATA_REGISTRY_URL}/registry-alert-redirect.html?agent_machine_guid=${NETDATA_REGISTRY_UNIQUE_ID}&host_machine_guid=${child_machine_guid}&transition_id=${transition_id}&${redirect_params}"
  2045. # the severity of the alarm
  2046. severity="${status}"
  2047. # the time the alarm was raised
  2048. duration4human ${duration} >/dev/null
  2049. duration_txt="${REPLY}"
  2050. duration4human ${non_clear_duration} >/dev/null
  2051. non_clear_duration_txt="${REPLY}"
  2052. raised_for="(was ${old_status,,} for ${duration_txt})"
  2053. # the key status message
  2054. status_message="status unknown"
  2055. # the color of the alarm
  2056. color="grey"
  2057. # the alarm value
  2058. alarm="${summary//_/ } = ${value_string}"
  2059. # the image of the alarm
  2060. image="${images_base_url}/images/banner-icon-144x144.png"
  2061. # have a default email status, in case the following case does not catch it
  2062. status_email_subject="${status}"
  2063. # prepare the title based on status
  2064. case "${status}" in
  2065. CRITICAL)
  2066. image="${images_base_url}/images/alert-128-red.png"
  2067. alarm_badge="https://app.netdata.cloud/static/email/img/label_critical.png"
  2068. status_message="is critical"
  2069. status_email_subject="Critical"
  2070. color="#ca414b"
  2071. rich_status_raised_for="Raised to critical, for ${non_clear_duration_txt}"
  2072. background_color="#FFEBEF"
  2073. border_color="#FF4136"
  2074. text_color="#FF4136"
  2075. action_text_color="#FFFFFF"
  2076. ;;
  2077. WARNING)
  2078. image="${images_base_url}/images/alert-128-orange.png"
  2079. alarm_badge="https://app.netdata.cloud/static/email/img/label_warning.png"
  2080. status_message="needs attention"
  2081. status_email_subject="Warning"
  2082. color="#ffc107"
  2083. rich_status_raised_for="Raised to warning, for ${non_clear_duration_txt}"
  2084. background_color="#FFF8E1"
  2085. border_color="#FFC300"
  2086. text_color="#536775"
  2087. action_text_color="#35414A"
  2088. ;;
  2089. CLEAR)
  2090. image="${images_base_url}/images/check-mark-2-128-green.png"
  2091. alarm_badge="https://app.netdata.cloud/static/email/img/label_recovered.png"
  2092. status_message="recovered"
  2093. status_email_subject="Clear"
  2094. color="#77ca6d"
  2095. rich_status_raised_for=
  2096. background_color="#E5F5E8"
  2097. border_color="#68C47D"
  2098. text_color="#00AB44"
  2099. action_text_color="#FFFFFF"
  2100. ;;
  2101. esac
  2102. # the html email subject
  2103. html_email_subject="${status_email_subject}, ${summary} = ${value_string}, on ${host}"
  2104. if [ "${status}" = "CLEAR" ]; then
  2105. severity="Recovered from ${old_status}"
  2106. if [ ${non_clear_duration} -gt ${duration} ]; then
  2107. raised_for="(alarm was raised for ${non_clear_duration_txt})"
  2108. fi
  2109. rich_status_raised_for="Recovered from ${old_status,,}, ${raised_for}"
  2110. # don't show the value when the status is CLEAR
  2111. # for certain alarms, this value might not have any meaning
  2112. alarm="${summary//_/ } ${raised_for}"
  2113. html_email_subject="${status_email_subject}, ${summary} ${raised_for}, on ${host}"
  2114. elif { [ "${old_status}" = "WARNING" ] && [ "${status}" = "CRITICAL" ]; }; then
  2115. severity="Escalated to ${status}"
  2116. if [ ${non_clear_duration} -gt ${duration} ]; then
  2117. raised_for="(alarm is raised for ${non_clear_duration_txt})"
  2118. fi
  2119. rich_status_raised_for="Escalated to critical, ${raised_for}"
  2120. elif { [ "${old_status}" = "CRITICAL" ] && [ "${status}" = "WARNING" ]; }; then
  2121. severity="Demoted to ${status}"
  2122. if [ ${non_clear_duration} -gt ${duration} ]; then
  2123. raised_for="(alarm is raised for ${non_clear_duration_txt})"
  2124. fi
  2125. rich_status_raised_for="Demoted to warning, ${raised_for}"
  2126. else
  2127. raised_for=
  2128. fi
  2129. # prepare HTML versions of elements
  2130. info_html=
  2131. [ -n "${info}" ] && info_html=" <small><br/>${info}</small>"
  2132. raised_for_html=
  2133. [ -n "${raised_for}" ] && raised_for_html="<br/><small>${raised_for}</small>"
  2134. # -----------------------------------------------------------------------------
  2135. # send the slack notification
  2136. # slack aggregates posts from the same username
  2137. # so we use "${host} ${status}" as the bot username, to make them diff
  2138. send_slack "${SLACK_WEBHOOK_URL}" "${to_slack}"
  2139. SENT_SLACK=$?
  2140. # -----------------------------------------------------------------------------
  2141. # send the Microsoft Teams notification
  2142. # Microsoft teams aggregates posts from the same username
  2143. # so we use "${host} ${status}" as the bot username, to make them diff
  2144. send_msteams "${MSTEAMS_WEBHOOK_URL}" "${to_msteams}"
  2145. SENT_MSTEAMS=$?
  2146. # -----------------------------------------------------------------------------
  2147. # send the rocketchat notification
  2148. # rocketchat aggregates posts from the same username
  2149. # so we use "${host} ${status}" as the bot username, to make them diff
  2150. send_rocketchat "${ROCKETCHAT_WEBHOOK_URL}" "${to_rocketchat}"
  2151. SENT_ROCKETCHAT=$?
  2152. # -----------------------------------------------------------------------------
  2153. # send the alerta notification
  2154. # alerta aggregates posts from the same username
  2155. # so we use "${host} ${status}" as the bot username, to make them diff
  2156. send_alerta "${ALERTA_WEBHOOK_URL}" "${to_alerta}"
  2157. SENT_ALERTA=$?
  2158. # -----------------------------------------------------------------------------
  2159. # send the flock notification
  2160. # flock aggregates posts from the same username
  2161. # so we use "${host} ${status}" as the bot username, to make them diff
  2162. send_flock "${FLOCK_WEBHOOK_URL}" "${to_flock}"
  2163. SENT_FLOCK=$?
  2164. # -----------------------------------------------------------------------------
  2165. # send the discord notification
  2166. # discord aggregates posts from the same username
  2167. # so we use "${host} ${status}" as the bot username, to make them diff
  2168. send_discord "${DISCORD_WEBHOOK_URL}" "${to_discord}"
  2169. SENT_DISCORD=$?
  2170. # -----------------------------------------------------------------------------
  2171. # send the pushover notification
  2172. send_pushover "${PUSHOVER_APP_TOKEN}" "${to_pushover}" "${when}" "${goto_url}" "${status}" "${host} ${status_message} - ${name//_/ } - ${chart}" "
  2173. <font color=\"${color}\"><b>${alarm}</b></font>${info_html}<br/>&nbsp;
  2174. <small><b>${chart}</b><br/>Chart<br/>&nbsp;</small>
  2175. <small><b>${severity}</b><br/>Severity<br/>&nbsp;</small>
  2176. <small><b>${date}${raised_for_html}</b><br/>Time<br/>&nbsp;</small>
  2177. <a href=\"${goto_url}\">View Netdata</a><br/>&nbsp;
  2178. <small><small>The source of this alarm is line ${src}</small></small>
  2179. "
  2180. SENT_PUSHOVER=$?
  2181. # -----------------------------------------------------------------------------
  2182. # send the pushbullet notification
  2183. send_pushbullet "${PUSHBULLET_ACCESS_TOKEN}" "${PUSHBULLET_SOURCE_DEVICE}" "${to_pushbullet}" "${goto_url}" "${host} ${status_message} - ${name//_/ } - ${chart}" "${alarm}\\n
  2184. Severity: ${severity}\\n
  2185. Chart: ${chart}\\n
  2186. ${date}\\n
  2187. The source of this alarm is line ${src}"
  2188. SENT_PUSHBULLET=$?
  2189. # -----------------------------------------------------------------------------
  2190. # send the twilio SMS
  2191. send_twilio "${TWILIO_ACCOUNT_SID}" "${TWILIO_ACCOUNT_TOKEN}" "${TWILIO_NUMBER}" "${to_twilio}" "${host} ${status_message} - ${name//_/ } - ${chart}" "${alarm}
  2192. Severity: ${severity}
  2193. Chart: ${chart}
  2194. ${info}"
  2195. SENT_TWILIO=$?
  2196. # -----------------------------------------------------------------------------
  2197. # send the messagebird SMS
  2198. send_messagebird "${MESSAGEBIRD_ACCESS_KEY}" "${MESSAGEBIRD_NUMBER}" "${to_messagebird}" "${host} ${status_message} - ${name//_/ } - ${chart}" "${alarm}
  2199. Severity: ${severity}
  2200. Chart: ${chart}
  2201. ${info}"
  2202. SENT_MESSAGEBIRD=$?
  2203. # -----------------------------------------------------------------------------
  2204. # send the kavenegar SMS
  2205. send_kavenegar "${KAVENEGAR_API_KEY}" "${KAVENEGAR_SENDER}" "${to_kavenegar}" "${host} ${status_message} - ${name//_/ } - ${chart}" "${alarm}
  2206. Severity: ${severity}
  2207. Chart: ${chart}
  2208. ${info}"
  2209. SENT_KAVENEGAR=$?
  2210. # -----------------------------------------------------------------------------
  2211. # send the telegram.org message
  2212. # https://core.telegram.org/bots/api#formatting-options
  2213. send_telegram "${TELEGRAM_BOT_TOKEN}" "${to_telegram}" "${host} ${status_message} - <b>${name//_/ }</b>
  2214. ${chart}
  2215. <a href=\"${goto_url}\">${alarm}</a>
  2216. <i>${info}</i>"
  2217. SENT_TELEGRAM=$?
  2218. # -----------------------------------------------------------------------------
  2219. # send the kafka message
  2220. send_kafka
  2221. SENT_KAFKA=$?
  2222. # -----------------------------------------------------------------------------
  2223. # send the pagerduty.com message
  2224. send_pd "${to_pd}"
  2225. SENT_PD=$?
  2226. # -----------------------------------------------------------------------------
  2227. # send the fleep message
  2228. send_fleep "${to_fleep}"
  2229. SENT_FLEEP=$?
  2230. # -----------------------------------------------------------------------------
  2231. # send the Prowl message
  2232. send_prowl "${to_prowl}"
  2233. SENT_PROWL=$?
  2234. # -----------------------------------------------------------------------------
  2235. # send the irc message
  2236. send_irc "${IRC_NICKNAME}" "${IRC_REALNAME}" "${to_irc}" "${IRC_NETWORK}" "${IRC_PORT}" "${host}" "${host} ${status_message} - ${name//_/ } - ${chart} ----- ${alarm}
  2237. Severity: ${severity}
  2238. Chart: ${chart}
  2239. ${info}"
  2240. SENT_IRC=$?
  2241. # -----------------------------------------------------------------------------
  2242. # send the SMS message with smstools3
  2243. send_sms "${to_sms}"
  2244. SENT_SMS=$?
  2245. # -----------------------------------------------------------------------------
  2246. # send the custom message
  2247. send_custom() {
  2248. # is it enabled?
  2249. [ "${SEND_CUSTOM}" != "YES" ] && return 1
  2250. # do we have any sender?
  2251. [ -z "${1}" ] && return 1
  2252. # call the custom_sender function
  2253. custom_sender "${@}"
  2254. }
  2255. send_custom "${to_custom}"
  2256. SENT_CUSTOM=$?
  2257. # -----------------------------------------------------------------------------
  2258. # send hipchat message
  2259. send_hipchat "${HIPCHAT_AUTH_TOKEN}" "${to_hipchat}" " \
  2260. ${host} ${status_message}<br/> \
  2261. <b>${alarm}</b> ${info_html}<br/> \
  2262. <b>${chart}</b><br/> \
  2263. <b>${date}${raised_for_html}</b><br/> \
  2264. <a href=\\\"${goto_url}\\\">View netdata dashboard</a> \
  2265. (source of alarm ${src}) \
  2266. "
  2267. SENT_HIPCHAT=$?
  2268. # -----------------------------------------------------------------------------
  2269. # send the Amazon SNS message
  2270. send_awssns "${to_awssns}"
  2271. SENT_AWSSNS=$?
  2272. # -----------------------------------------------------------------------------
  2273. # send the Matrix message
  2274. send_matrix "${MATRIX_HOMESERVER}" "${to_matrix}"
  2275. SENT_MATRIX=$?
  2276. # -----------------------------------------------------------------------------
  2277. # send the syslog message
  2278. send_syslog "${to_syslog}"
  2279. SENT_SYSLOG=$?
  2280. # -----------------------------------------------------------------------------
  2281. # send the email
  2282. IFS='' read -r -d '' email_plaintext_part <<EOF
  2283. Content-Type: text/plain; encoding=${EMAIL_CHARSET}
  2284. Content-Disposition: inline
  2285. Content-Transfer-Encoding: 8bit
  2286. ${host} ${status_message}
  2287. ${alarm} ${info}
  2288. ${raised_for}
  2289. Chart : ${chart}
  2290. Severity: ${severity}
  2291. URL : ${goto_url}
  2292. Source : ${src}
  2293. Date : ${date}
  2294. Notification generated on ${host}
  2295. Evaluated Expression : ${calc_expression}
  2296. Expression Variables : ${calc_param_values}
  2297. The host has ${total_warnings} WARNING and ${total_critical} CRITICAL alarm(s) raised.
  2298. EOF
  2299. if [[ "${EMAIL_PLAINTEXT_ONLY}" == "YES" ]]; then
  2300. send_email <<EOF
  2301. To: ${to_email}
  2302. Subject: ${host} ${status_message} - ${name//_/ } - ${chart}
  2303. MIME-Version: 1.0
  2304. Content-Type: multipart/alternative; boundary="multipart-boundary"
  2305. ${email_thread_headers}
  2306. X-Netdata-Severity: ${status,,}
  2307. X-Netdata-Alert-Name: $name
  2308. X-Netdata-Chart: $chart
  2309. X-Netdata-Classification: $classification
  2310. X-Netdata-Host: $host
  2311. X-Netdata-Role: $roles
  2312. This is a MIME-encoded multipart message
  2313. --multipart-boundary
  2314. ${email_plaintext_part}
  2315. --multipart-boundary--
  2316. EOF
  2317. else
  2318. now=$(date "+%s")
  2319. if [ -n "$total_warn_alarms" ]; then
  2320. while read -d, -r pair; do
  2321. IFS='=' read -r key val <<<"$pair"
  2322. date_w=$(date --date=@${val} "${date_format}" 2>/dev/null)
  2323. [ -z "${date_w}" ] && date_w=$(date "${date_format}" 2>/dev/null)
  2324. [ -z "${date_w}" ] && date_w=$(date --date=@${val} 2>/dev/null)
  2325. [ -z "${date_w}" ] && date_w=$(date 2>/dev/null)
  2326. elapsed=$((now - val))
  2327. duration4human ${elapsed} >/dev/null
  2328. elapsed_txt="${REPLY}"
  2329. WARN_ALARMS+="
  2330. <div class=\"set-font\" style=\"font-family: 'IBM Plex Sans', sans-serif; background: #FFFFFF; background-color: #FFFFFF; margin: 0px auto; max-width: 600px;\">
  2331. <table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"background:#FFFFFF;background-color:#FFFFFF;width:100%;\">
  2332. <tbody>
  2333. <tr>
  2334. <td style=\"border-top:8px solid #F7F8F8;direction:ltr;font-size:0px;padding:20px 0;text-align:center;\">
  2335. <!--[if mso | IE]><table role=\"presentation\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr><td class=\"\" style=\"vertical-align:top;width:300px;\" ><![endif]-->
  2336. <div class=\"mj-column-per-50 mj-outlook-group-fix\" style=\"font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:50%;\">
  2337. <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"vertical-align:top;\" width=\"100%\">
  2338. <tbody>
  2339. <tr>
  2340. <td align=\"left\" style=\"font-size:0px;padding:10px 25px;word-break:break-word;\">
  2341. <div style=\"font-family:Open Sans, sans-serif;font-size:14px;font-weight:600;line-height:1;text-align:left;color:#35414A;\">${key}</div>
  2342. </td>
  2343. </tr>
  2344. <tr>
  2345. <td align=\"left\" style=\"font-size:0px;padding:10px 25px;padding-top:2px;word-break:break-word;\">
  2346. <div style=\"font-family:Open Sans, sans-serif;font-size:12px;line-height:1;text-align:left;color:#35414A;\">${date_w}</div>
  2347. </td>
  2348. </tr>
  2349. </tbody>
  2350. </table>
  2351. </div>
  2352. <!--[if mso | IE]></td><td class=\"\" style=\"vertical-align:top;width:300px;\" ><![endif]-->
  2353. <div class=\"mj-column-per-50 mj-outlook-group-fix\" style=\"font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:50%;\">
  2354. <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">
  2355. <tbody>
  2356. <tr>
  2357. <td style=\"vertical-align:top;padding-top:13px;\">
  2358. <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style width=\"100%\">
  2359. <tbody>
  2360. <tr>
  2361. <td align=\"right\" style=\"font-size:0px;padding:10px 25px;word-break:break-word;\">
  2362. <div style=\"font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:right;color:#555555;\"><span style=\"background-color:#FFF8E1; border: 1px solid #FFC300; border-radius:36px; padding: 2px 12px; margin-top: 20px; white-space: nowrap\">
  2363. Warning for ${elapsed_txt}
  2364. </span></div>
  2365. </td>
  2366. </tr>
  2367. </tbody>
  2368. </table>
  2369. </td>
  2370. </tr>
  2371. </tbody>
  2372. </table>
  2373. </div>
  2374. <!--[if mso | IE]></td></tr></table><![endif]-->
  2375. </td>
  2376. </tr>
  2377. </tbody>
  2378. </table>
  2379. </div>
  2380. "
  2381. done <<<"$total_warn_alarms,"
  2382. fi
  2383. if [ -n "$total_crit_alarms" ]; then
  2384. while read -d, -r pair; do
  2385. IFS='=' read -r key val <<<"$pair"
  2386. date_c=$(date --date=@${val} "${date_format}" 2>/dev/null)
  2387. [ -z "${date_c}" ] && date_c=$(date "${date_format}" 2>/dev/null)
  2388. [ -z "${date_c}" ] && date_c=$(date --date=@${val} 2>/dev/null)
  2389. [ -z "${date_c}" ] && date_c=$(date 2>/dev/null)
  2390. elapsed=$((now - val))
  2391. duration4human ${elapsed} >/dev/null
  2392. elapsed_txt="${REPLY}"
  2393. CRIT_ALARMS+="
  2394. <div class=\"set-font\" style=\"font-family: 'IBM Plex Sans', sans-serif; background: #FFFFFF; background-color: #FFFFFF; margin: 0px auto; max-width: 600px;\">
  2395. <table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"background:#FFFFFF;background-color:#FFFFFF;width:100%;\">
  2396. <tbody>
  2397. <tr>
  2398. <td style=\"border-top:8px solid #F7F8F8;direction:ltr;font-size:0px;padding:20px 0;text-align:center;\">
  2399. <!--[if mso | IE]><table role=\"presentation\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr><td class=\"\" style=\"vertical-align:top;width:300px;\" ><![endif]-->
  2400. <div class=\"mj-column-per-50 mj-outlook-group-fix\" style=\"font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:50%;\">
  2401. <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"vertical-align:top;\" width=\"100%\">
  2402. <tbody>
  2403. <tr>
  2404. <td align=\"left\" style=\"font-size:0px;padding:10px 25px;word-break:break-word;\">
  2405. <div style=\"font-family:Open Sans, sans-serif;font-size:14px;font-weight:600;line-height:1;text-align:left;color:#35414A;\">${key}</div>
  2406. </td>
  2407. </tr>
  2408. <tr>
  2409. <td align=\"left\" style=\"font-size:0px;padding:10px 25px;padding-top:2px;word-break:break-word;\">
  2410. <div style=\"font-family:Open Sans, sans-serif;font-size:12px;line-height:1;text-align:left;color:#35414A;\">${date_c}</div>
  2411. </td>
  2412. </tr>
  2413. </tbody>
  2414. </table>
  2415. </div>
  2416. <!--[if mso | IE]></td><td class=\"\" style=\"vertical-align:top;width:300px;\" ><![endif]-->
  2417. <div class=\"mj-column-per-50 mj-outlook-group-fix\" style=\"font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:50%;\">
  2418. <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">
  2419. <tbody>
  2420. <tr>
  2421. <td style=\"vertical-align:top;padding-top:13px;\">
  2422. <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style width=\"100%\">
  2423. <tbody>
  2424. <tr>
  2425. <td align=\"right\" style=\"font-size:0px;padding:10px 25px;word-break:break-word;\">
  2426. <div style=\"font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:right;color:#35414A;\"><span style=\"background-color:#FFEBEF; border: 1px solid #FF4136; border-radius:36px; padding: 2px 12px; margin-top: 20px; white-space: nowrap\">
  2427. Critical for ${elapsed_txt}
  2428. </span></div>
  2429. </td>
  2430. </tr>
  2431. </tbody>
  2432. </table>
  2433. </td>
  2434. </tr>
  2435. </tbody>
  2436. </table>
  2437. </div>
  2438. <!--[if mso | IE]></td></tr></table><![endif]-->
  2439. </td>
  2440. </tr>
  2441. </tbody>
  2442. </table>
  2443. </div>
  2444. "
  2445. done <<<"$total_crit_alarms,"
  2446. fi
  2447. if (( total_warnings + total_critical > 15 )); then
  2448. EXTRA_ALARMS_LIST_TEXT="(Showing latest 15 alerts)"
  2449. fi
  2450. if [ -n "$edit_command_line" ]; then
  2451. IFS='=' read -r edit_command line s_host <<<"$edit_command_line"
  2452. fi
  2453. IFS='' read -r -d '' email_html_part <<EOF
  2454. Content-Type: text/html; encoding=${EMAIL_CHARSET}
  2455. Content-Disposition: inline
  2456. Content-Transfer-Encoding: 8bit
  2457. <!doctype html>
  2458. <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
  2459. <head>
  2460. <title>
  2461. </title>
  2462. <!--[if !mso]><!-->
  2463. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  2464. <!--<![endif]-->
  2465. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  2466. <meta name="viewport" content="width=device-width, initial-scale=1">
  2467. <style type="text/css">
  2468. #outlook a { padding:0; }
  2469. body { margin:0;padding:0;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%; }
  2470. table, td { border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt; }
  2471. img { border:0;height:auto;line-height:100%; outline:none;text-decoration:none;-ms-interpolation-mode:bicubic; }
  2472. p { display:block;margin:13px 0; }
  2473. </style>
  2474. <!--[if mso]>
  2475. <xml>
  2476. <o:OfficeDocumentSettings>
  2477. <o:AllowPNG/>
  2478. <o:PixelsPerInch>96</o:PixelsPerInch>
  2479. </o:OfficeDocumentSettings>
  2480. </xml>
  2481. <![endif]-->
  2482. <!--[if lte mso 11]>
  2483. <style type="text/css">
  2484. .mj-outlook-group-fix { width:100% !important; }
  2485. </style>
  2486. <![endif]-->
  2487. <!--[if !mso]><!-->
  2488. <link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;600;700&display=swap" rel="stylesheet" type="text/css">
  2489. <link href="https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700" rel="stylesheet" type="text/css">
  2490. <style type="text/css">
  2491. @import url(https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;600;700&display=swap);
  2492. @import url(https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700);
  2493. </style>
  2494. <!--<![endif]-->
  2495. <style type="text/css">
  2496. @media only screen and (min-width:100px) {
  2497. .mj-column-px-130 { width:130px !important; max-width: 130px; }
  2498. .mj-column-per-50 { width:50% !important; max-width: 50%; }
  2499. .mj-column-per-70 { width:70% !important; max-width: 70%; }
  2500. .mj-column-per-30 { width:30% !important; max-width: 30%; }
  2501. .mj-column-per-100 { width:100% !important; max-width: 100%; }
  2502. .mj-column-px-66 { width:66px !important; max-width: 66px; }
  2503. .mj-column-px-400 { width:400px !important; max-width: 400px; }
  2504. }
  2505. </style>
  2506. <style type="text/css">
  2507. @media only screen and (max-width:100px) {
  2508. table.mj-full-width-mobile { width: 100% !important; }
  2509. td.mj-full-width-mobile { width: auto !important; }
  2510. }
  2511. </style>
  2512. </head>
  2513. <body style="word-spacing:normal;">
  2514. <div class="svgbg" style="background-image: url('https://staging.netdata.cloud/static/email/img/isotype_600.png'); background-repeat: no-repeat; background-position: top center; background-size: 600px 192px;">
  2515. <!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2516. <div style="margin:0px auto;max-width:600px;">
  2517. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
  2518. <tbody>
  2519. <tr>
  2520. <td style="direction:ltr;font-size:0px;padding:20px 0;padding-bottom:50px;padding-left:0;text-align:left;">
  2521. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:130px;" ><![endif]-->
  2522. <div class="mj-column-px-130 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:130px;">
  2523. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
  2524. <tbody>
  2525. <tr>
  2526. <td align="center" style="font-size:0px;padding:10px 25px;padding-right:0;padding-left:0;word-break:break-word;">
  2527. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
  2528. <tbody>
  2529. <tr>
  2530. <td style="width:130px;">
  2531. <img alt="Netdata Logo" height="auto" src="https://app.netdata.cloud/static/email/img/full_logo.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="130">
  2532. </td>
  2533. </tr>
  2534. </tbody>
  2535. </table>
  2536. </td>
  2537. </tr>
  2538. </tbody>
  2539. </table>
  2540. </div>
  2541. <!--[if mso | IE]></td><td class="" style="vertical-align:top;width:300px;" ><![endif]-->
  2542. <div class="mj-column-per-50 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:50%;">
  2543. <table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
  2544. <tbody>
  2545. <tr>
  2546. <td style="vertical-align:top;padding-top:4px;">
  2547. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style width="100%">
  2548. <tbody>
  2549. <tr>
  2550. <td align="left" style="font-size:0px;padding:10px 25px;padding-left:10px;word-break:break-word;">
  2551. <div style="font-family:Open Sans, sans-serif;font-size:16px;line-height:1;text-align:left;color:#35414A;">Notification</div>
  2552. </td>
  2553. </tr>
  2554. </tbody>
  2555. </table>
  2556. </td>
  2557. </tr>
  2558. </tbody>
  2559. </table>
  2560. </div>
  2561. <!--[if mso | IE]></td></tr></table><![endif]-->
  2562. </td>
  2563. </tr>
  2564. </tbody>
  2565. </table>
  2566. </div>
  2567. <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="no-collapse-outlook" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2568. <div class="no-collapse" style="border-collapse: initial; margin: 0px auto; border-radius: 4px; max-width: 600px;">
  2569. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;border-radius:4px;">
  2570. <tbody>
  2571. <tr>
  2572. <td style="border:1px solid ${border_color};direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
  2573. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="set-font-outlook" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="set-font-outlook" style="width:598px;" width="598" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2574. <div class="set-font" style="font-family: 'IBM Plex Sans', sans-serif; margin: 0px auto; max-width: 598px;">
  2575. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
  2576. <tbody>
  2577. <tr>
  2578. <td style="direction:ltr;font-size:0px;padding:20px 0;padding-bottom:0;padding-top:0;text-align:center;">
  2579. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:418.6px;" ><![endif]-->
  2580. <div class="mj-column-per-70 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:70%;">
  2581. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
  2582. <tbody>
  2583. <tr>
  2584. <td align="left" style="font-size:0px;padding:10px 25px;padding-top:15px;word-break:break-word;">
  2585. <div style="font-family:Open Sans, sans-serif;font-size:20px;font-weight:700;line-height:1;text-align:left;color:#35414A;">${summary}</div>
  2586. </td>
  2587. </tr>
  2588. </tbody>
  2589. </table>
  2590. </div>
  2591. <!--[if mso | IE]></td><td class="" style="vertical-align:top;width:179.4px;" ><![endif]-->
  2592. <div class="mj-column-per-30 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:30%;">
  2593. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
  2594. <tbody>
  2595. <tr>
  2596. <td align="right" style="font-size:0px;padding:10px 25px;padding-right:25px;word-break:break-word;">
  2597. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
  2598. <tbody>
  2599. <tr>
  2600. <td style="width:100px;">
  2601. <img height="auto" src="${alarm_badge}" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="100"/>
  2602. </td>
  2603. </tr>
  2604. </tbody>
  2605. </table>
  2606. </td>
  2607. </tr>
  2608. </tbody>
  2609. </table>
  2610. </div>
  2611. <!--[if mso | IE]></td></tr></table><![endif]-->
  2612. </td>
  2613. </tr>
  2614. </tbody>
  2615. </table>
  2616. </div>
  2617. <!--[if mso | IE]></td></tr></table></td></tr><tr><td class="set-font-outlook" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="set-font-outlook" style="width:598px;" width="598" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2618. <div class="set-font" style="font-family: 'IBM Plex Sans', sans-serif; margin: 0px auto; max-width: 598px;">
  2619. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
  2620. <tbody>
  2621. <tr>
  2622. <td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
  2623. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:598px;" ><![endif]-->
  2624. <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
  2625. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
  2626. <tbody>
  2627. <tr>
  2628. <td align="left" style="font-size:0px;padding:10px 25px;padding-top:0;word-break:break-word;">
  2629. <div style="font-family:IBM Plex Sans, sans-serif;font-size:16px;line-height:1;text-align:left;color:#35414A;">on ${host}</div>
  2630. </td>
  2631. </tr>
  2632. </tbody>
  2633. </table>
  2634. </div>
  2635. <!--[if mso | IE]></td></tr></table><![endif]-->
  2636. </td>
  2637. </tr>
  2638. </tbody>
  2639. </table>
  2640. </div>
  2641. <!--[if mso | IE]></td></tr></table></td></tr><tr><td class="set-font-outlook" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="set-font-outlook" style="width:598px;" width="598" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2642. <div class="set-font" style="font-family: 'IBM Plex Sans', sans-serif; margin: 0px auto; max-width: 598px;">
  2643. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
  2644. <tbody>
  2645. <tr>
  2646. <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
  2647. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:598px;" ><![endif]-->
  2648. <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
  2649. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
  2650. <tbody>
  2651. <tr>
  2652. <td align="left" style="font-size:0px;padding:10px 25px;padding-top:0;word-break:break-word;">
  2653. <div style="font-family:Open Sans, sans-serif;font-size:26px;font-weight:700;line-height:1;text-align:left;color:#35414A;"><span style="color: ${text_color}; font-size:26px; background: ${background_color}; padding:4px 24px; border-radius: 36px">${value_string}
  2654. </span></div>
  2655. </td>
  2656. </tr>
  2657. </tbody>
  2658. </table>
  2659. </div>
  2660. <!--[if mso | IE]></td></tr></table><![endif]-->
  2661. </td>
  2662. </tr>
  2663. </tbody>
  2664. </table>
  2665. </div>
  2666. <!--[if mso | IE]></td></tr></table></td></tr><tr><td class="set-font-outlook" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="set-font-outlook" style="width:598px;" width="598" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2667. <div class="set-font" style="font-family: 'IBM Plex Sans', sans-serif; margin: 0px auto; max-width: 598px;">
  2668. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
  2669. <tbody>
  2670. <tr>
  2671. <td style="direction:ltr;font-size:0px;padding:20px 0;padding-bottom:0;padding-top:0;text-align:center;">
  2672. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:598px;" ><![endif]-->
  2673. <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
  2674. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
  2675. <tbody>
  2676. <tr>
  2677. <td align="left" style="font-size:0px;padding:10px 25px;padding-top:0;word-break:break-word;">
  2678. <div style="font-family:Open Sans, sans-serif;font-size:16px;line-height:21px;text-align:left;color:#35414A;">Details: ${info}</div>
  2679. </td>
  2680. </tr>
  2681. </tbody>
  2682. </table>
  2683. </div>
  2684. <!--[if mso | IE]></td></tr></table><![endif]-->
  2685. </td>
  2686. </tr>
  2687. </tbody>
  2688. </table>
  2689. </div>
  2690. <!--[if mso | IE]></td></tr></table></td></tr><tr><td class="set-font-outlook" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="set-font-outlook" style="width:598px;" width="598" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2691. <div class="set-font" style="font-family: 'IBM Plex Sans', sans-serif; margin: 0px auto; max-width: 598px;">
  2692. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
  2693. <tbody>
  2694. <tr>
  2695. <td style="direction:ltr;font-size:0px;padding:20px 0;padding-bottom:0;padding-top:0;text-align:center;">
  2696. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:598px;" ><![endif]-->
  2697. <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
  2698. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
  2699. <tbody>
  2700. <tr>
  2701. <td align="center" vertical-align="middle" style="font-size:0px;padding:10px 25px;word-break:break-word;">
  2702. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;width:100%;line-height:100%;">
  2703. <tr>
  2704. <td
  2705. align="center" bgcolor="${border_color}" role="presentation" style="border:none;border-radius:3px;cursor:auto;height:44px;background:${border_color};" valign="middle">
  2706. <p style="display:block;background:${border_color};color:#ffffff;font-size:13px;font-weight:600;line-height:44px;margin:0;text-decoration:none;text-transform:none;mso-padding-alt:0px;border-radius:3px;">
  2707. <a href="${goto_url}" style="color: ${action_text_color}; text-decoration: none; width: 100%; display: inline-block">GO TO CHART</a>
  2708. </p>
  2709. </td>
  2710. </tr>
  2711. </table>
  2712. </td>
  2713. </tr>
  2714. </tbody>
  2715. </table>
  2716. </div>
  2717. <!--[if mso | IE]></td></tr></table><![endif]-->
  2718. </td>
  2719. </tr>
  2720. </tbody>
  2721. </table>
  2722. </div>
  2723. <!--[if mso | IE]></td></tr></table></td></tr></table><![endif]-->
  2724. </td>
  2725. </tr>
  2726. </tbody>
  2727. </table>
  2728. </div>
  2729. <!--[if mso | IE]></td></tr></table><![endif]-->
  2730. <div style="height:32px;line-height:32px;">&#8202;</div>
  2731. <!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="set-font-outlook" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2732. <div class="set-font" style="font-family: 'IBM Plex Sans', sans-serif; background: ${background_color}; background-color: ${background_color}; margin: 0px auto; border-radius: 4px; max-width: 600px;">
  2733. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:${background_color};background-color:${background_color};width:100%;border-radius:4px;">
  2734. <tbody>
  2735. <tr>
  2736. <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
  2737. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->
  2738. <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
  2739. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
  2740. <tbody>
  2741. <tr>
  2742. <td align="left" style="font-size:0px;padding:10px 25px;padding-bottom:6px;word-break:break-word;">
  2743. <div style="font-family:Open Sans, sans-serif;font-size:18px;line-height:1;text-align:left;color:#35414A;">Alert:
  2744. <span style="font-weight:700; font-size:20px">${name}</span></div>
  2745. </td>
  2746. </tr>
  2747. <tr>
  2748. <td align="left" style="font-size:0px;padding:10px 25px;padding-top:0;word-break:break-word;">
  2749. <div style="font-family:Open Sans, sans-serif;font-size:18px;line-height:1;text-align:left;color:#35414A;">Chart:
  2750. <span style="font-weight:700; font-size:20px">${chart}</span></div>
  2751. </td>
  2752. </tr>
  2753. <tr>
  2754. <td align="left" style="font-size:0px;padding:10px 25px;padding-top:4px;word-break:break-word;">
  2755. <div style="font-family:Open Sans, sans-serif;font-size:14px;line-height:1;text-align:left;color:#35414A;">${rich_status_raised_for}</div>
  2756. </td>
  2757. </tr>
  2758. <tr>
  2759. <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
  2760. <p style="border-top:solid 1px lightgrey;font-size:1px;margin:0px auto;width:100%;">
  2761. </p>
  2762. <!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" style="border-top:solid 1px lightgrey;font-size:1px;margin:0px auto;width:550px;" role="presentation" width="550px" ><tr><td style="height:0;line-height:0;"> &nbsp;
  2763. </td></tr></table><![endif]-->
  2764. </td>
  2765. </tr>
  2766. <tr>
  2767. <td align="left" style="font-size:0px;padding:10px 25px;padding-bottom:6px;word-break:break-word;">
  2768. <div style="font-family:Open Sans, sans-serif;font-size:16px;line-height:1;text-align:left;color:#35414A;">On
  2769. <span style="font-weight:600">${date}</span></div>
  2770. </td>
  2771. </tr>
  2772. <tr>
  2773. <td align="left" style="font-size:0px;padding:10px 25px;padding-top:0;word-break:break-word;">
  2774. <div style="font-family:Open Sans, sans-serif;font-size:16px;line-height:1;text-align:left;color:#35414A;">By:
  2775. <span style="font-weight:600">${host}</span></div>
  2776. </td>
  2777. </tr>
  2778. <tr>
  2779. <td align="left" style="font-size:0px;padding:10px 25px;padding-top:4px;word-break:break-word;">
  2780. <div style="font-family:Open Sans, sans-serif;font-size:14px;line-height:1;text-align:left;color:#35414A;">Global time:
  2781. <span style="font-weight:600">${date_utc}</span></div>
  2782. </td>
  2783. </tr>
  2784. <tr>
  2785. <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
  2786. <p style="border-top:solid 1px lightgrey;font-size:1px;margin:0px auto;width:100%;">
  2787. </p>
  2788. <!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" style="border-top:solid 1px lightgrey;font-size:1px;margin:0px auto;width:550px;" role="presentation" width="550px" ><tr><td style="height:0;line-height:0;"> &nbsp;
  2789. </td></tr></table><![endif]-->
  2790. </td>
  2791. </tr>
  2792. <tr>
  2793. <td align="left" style="font-size:0px;padding:10px 25px;padding-bottom:6px;word-break:break-word;">
  2794. <div style="font-family:Open Sans, sans-serif;font-size:16px;line-height:1;text-align:left;color:#35414A;">Classification:
  2795. <span style="font-weight:600">${classification}</span></div>
  2796. </td>
  2797. </tr>
  2798. <tr>
  2799. <td align="left" style="font-size:0px;padding:10px 25px;padding-top:0;word-break:break-word;">
  2800. <div style="font-family:Open Sans, sans-serif;font-size:16px;line-height:1;text-align:left;color:#35414A;">Role:
  2801. <span style="font-weight:600">${roles}</span></div>
  2802. </td>
  2803. </tr>
  2804. </tbody>
  2805. </table>
  2806. </div>
  2807. <!--[if mso | IE]></td></tr></table><![endif]-->
  2808. </td>
  2809. </tr>
  2810. </tbody>
  2811. </table>
  2812. </div>
  2813. <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="set-font-outlook" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2814. <div class="set-font" style="font-family: 'IBM Plex Sans', sans-serif; margin: 0px auto; max-width: 600px;">
  2815. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
  2816. <tbody>
  2817. <tr>
  2818. <td style="direction:ltr;font-size:0px;padding:20px 0;padding-left:25px;text-align:left;">
  2819. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:66px;" ><![endif]-->
  2820. <div class="mj-column-px-66 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:66px;">
  2821. <table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
  2822. <tbody>
  2823. <tr>
  2824. <td style="vertical-align:top;padding:0;">
  2825. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style width="100%">
  2826. <tbody>
  2827. <tr>
  2828. <td align="left" style="font-size:0px;padding:10px 25px;padding-right:0;padding-left:0;word-break:break-word;">
  2829. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
  2830. <tbody>
  2831. <tr>
  2832. <td style="width:48px;">
  2833. <img height="auto" src="https://app.netdata.cloud/static/email/img/community_icon.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="48">
  2834. </td>
  2835. </tr>
  2836. </tbody>
  2837. </table>
  2838. </td>
  2839. </tr>
  2840. </tbody>
  2841. </table>
  2842. </td>
  2843. </tr>
  2844. </tbody>
  2845. </table>
  2846. </div>
  2847. <!--[if mso | IE]></td><td align="left" class="" style="vertical-align:top;width:400px;" ><![endif]-->
  2848. <div class="mj-column-px-400 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:400px;">
  2849. <table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
  2850. <tbody>
  2851. <tr>
  2852. <td style="vertical-align:top;padding-left:0;">
  2853. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style width="100%">
  2854. <tbody>
  2855. <tr>
  2856. <td align="left" style="font-size:0px;padding:10px 25px;padding-left:0;word-break:break-word;">
  2857. <div style="font-family:Open Sans, sans-serif;font-size:16px;font-weight:700;line-height:1;text-align:left;color:#35414A;">Want to know more about this alert?</div>
  2858. </td>
  2859. </tr>
  2860. <tr>
  2861. <td align="left" style="font-size:0px;padding:10px 25px;padding-left:0;word-break:break-word;">
  2862. <div style="font-family:Open Sans, sans-serif;font-size:14px;line-height:1.3;text-align:left;color:#35414A;">Join the troubleshooting discussion for this alert on our <a href="https://community.netdata.cloud/t/${name//[._]/-}" class="link" style="color: #00AB44; text-decoration: none;">community forums</a>.</div>
  2863. </td>
  2864. </tr>
  2865. </tbody>
  2866. </table>
  2867. </td>
  2868. </tr>
  2869. </tbody>
  2870. </table>
  2871. </div>
  2872. <!--[if mso | IE]></td></tr></table><![endif]-->
  2873. </td>
  2874. </tr>
  2875. </tbody>
  2876. </table>
  2877. </div>
  2878. <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="set-font-outlook" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2879. <div class="set-font" style="font-family: 'IBM Plex Sans', sans-serif; margin: 0px auto; max-width: 600px;">
  2880. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
  2881. <tbody>
  2882. <tr>
  2883. <td style="direction:ltr;font-size:0px;padding:20px 0;padding-left:25px;text-align:left;">
  2884. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:66px;" ><![endif]-->
  2885. <div class="mj-column-px-66 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:66px;">
  2886. <table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
  2887. <tbody>
  2888. <tr>
  2889. <td style="vertical-align:top;padding:0;">
  2890. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style width="100%">
  2891. <tbody>
  2892. <tr>
  2893. <td align="left" style="font-size:0px;padding:10px 25px;padding-right:0;padding-left:0;word-break:break-word;">
  2894. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
  2895. <tbody>
  2896. <tr>
  2897. <td style="width:48px;">
  2898. <img height="auto" src="https://app.netdata.cloud/static/email/img/configure_icon.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="48">
  2899. </td>
  2900. </tr>
  2901. </tbody>
  2902. </table>
  2903. </td>
  2904. </tr>
  2905. </tbody>
  2906. </table>
  2907. </td>
  2908. </tr>
  2909. </tbody>
  2910. </table>
  2911. </div>
  2912. <!--[if mso | IE]></td><td align="left" class="" style="vertical-align:top;width:400px;" ><![endif]-->
  2913. <div class="mj-column-px-400 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:400px;">
  2914. <table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
  2915. <tbody>
  2916. <tr>
  2917. <td style="vertical-align:top;padding-left:0;">
  2918. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style width="100%">
  2919. <tbody>
  2920. <tr>
  2921. <td align="left" style="font-size:0px;padding:10px 25px;padding-left:0;word-break:break-word;">
  2922. <div style="font-family:Open Sans, sans-serif;font-size:16px;font-weight:700;line-height:1;text-align:left;color:#35414A;">Need to configure this alert?</div>
  2923. </td>
  2924. </tr>
  2925. <tr>
  2926. <td align="left" style="font-size:0px;padding:10px 25px;padding-left:0;word-break:break-word;">
  2927. <div style="font-family:Open Sans, sans-serif;font-size:14px;line-height:1.3;text-align:left;color:#35414A;"><span style="color: #00AB44"><a href="https://learn.netdata.cloud/docs/agent/health/notifications#:~:text=To%20edit%20it%20on%20your,have%20one%20or%20more%20destinations" class="link" style="color: #00AB44; text-decoration: none;">Edit</a></span> this alert's configuration file by logging into $s_host and running the following command:</div>
  2928. </td>
  2929. </tr>
  2930. <tr>
  2931. <td align="left" style="font-size:0px;padding:10px 25px;padding-top:8px;padding-left:0;word-break:break-word;">
  2932. <div style="font-family:Open Sans, sans-serif;font-size:12px;line-height:1.3;text-align:left;color:#35414A;">${edit_command} <br>
  2933. <br>The alarm to edit is at line ${line}</div>
  2934. </td>
  2935. </tr>
  2936. </tbody>
  2937. </table>
  2938. </td>
  2939. </tr>
  2940. </tbody>
  2941. </table>
  2942. </div>
  2943. <!--[if mso | IE]></td></tr></table><![endif]-->
  2944. </td>
  2945. </tr>
  2946. </tbody>
  2947. </table>
  2948. </div>
  2949. <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="history-wrapper-outlook" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2950. <div class="history-wrapper" style="background: #F7F8F8; background-color: #F7F8F8; margin: 0px auto; max-width: 100%;">
  2951. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#F7F8F8;background-color:#F7F8F8;width:100%;">
  2952. <tbody>
  2953. <tr>
  2954. <td style="direction:ltr;font-size:0px;padding:0;padding-bottom:24px;text-align:center;">
  2955. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="set-font-outlook" width="600px" ><table align="center" border="0" cellpadding="0" cellspacing="0" class="set-font-outlook" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2956. <div class="set-font" style="font-family: 'IBM Plex Sans', sans-serif; margin: 0px auto; max-width: 600px;">
  2957. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
  2958. <tbody>
  2959. <tr>
  2960. <td style="direction:ltr;font-size:0px;padding:20px 0;padding-bottom:12px;text-align:center;">
  2961. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->
  2962. <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
  2963. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
  2964. <tbody>
  2965. <tr>
  2966. <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
  2967. <div style="font-family:Open Sans, sans-serif;font-size:16px;line-height:1;text-align:center;color:#35414A;">The node has
  2968. <span style="font-weight:600">${total_warnings} warning</span>
  2969. and
  2970. <span style="font-weight:600">${total_critical} critical</span>
  2971. additional active alert(s)</div>
  2972. </td>
  2973. </tr>
  2974. <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
  2975. <div style="font-family:Open Sans, sans-serif;font-size:12px;line-height:1;text-align:center;color:#35414A;">${EXTRA_ALARMS_LIST_TEXT}</div>
  2976. </td>
  2977. </tr>
  2978. </tbody>
  2979. </table>
  2980. </div>
  2981. <!--[if mso | IE]></td></tr></table><![endif]-->
  2982. </td>
  2983. </tr>
  2984. </tbody>
  2985. </table>
  2986. </div>
  2987. ${CRIT_ALARMS}
  2988. ${WARN_ALARMS}
  2989. <!--[if mso | IE]></td></tr></table></td></tr></table><![endif]-->
  2990. </td>
  2991. </tr>
  2992. </tbody>
  2993. </table>
  2994. </div>
  2995. <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="set-font-outlook" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
  2996. <div class="set-font" style="font-family: 'IBM Plex Sans', sans-serif; margin: 0px auto; max-width: 600px;">
  2997. <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
  2998. <tbody>
  2999. <tr>
  3000. <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
  3001. <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->
  3002. <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
  3003. <table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
  3004. <tbody>
  3005. <tr>
  3006. <td style="vertical-align:top;padding-top:44px;padding-bottom:12px;">
  3007. <table border="0" cellpadding="0" cellspacing="0" role="presentation" style width="100%">
  3008. <tbody>
  3009. <tr>
  3010. <td align="left" style="font-size:0px;padding:10px 25px;padding-top:0;padding-bottom:0;word-break:break-word;">
  3011. <div style="font-family:Open Sans, sans-serif;font-size:13px;line-height:1;text-align:center;color:#35414A;">© Netdata $(date +'%Y') - The real-time performance and health monitoring</div>
  3012. </td>
  3013. </tr>
  3014. </tbody>
  3015. </table>
  3016. </td>
  3017. </tr>
  3018. </tbody>
  3019. </table>
  3020. </div>
  3021. <!--[if mso | IE]></td></tr></table><![endif]-->
  3022. </td>
  3023. </tr>
  3024. </tbody>
  3025. </table>
  3026. </div>
  3027. <!--[if mso | IE]></td></tr></table><![endif]-->
  3028. </div>
  3029. </body>
  3030. </html>
  3031. EOF
  3032. send_email <<EOF
  3033. To: ${to_email}
  3034. Subject: ${html_email_subject}
  3035. MIME-Version: 1.0
  3036. Content-Type: multipart/alternative; boundary="multipart-boundary"
  3037. ${email_thread_headers}
  3038. X-Netdata-Severity: ${status,,}
  3039. X-Netdata-Alert-Name: $name
  3040. X-Netdata-Chart: $chart
  3041. X-Netdata-Classification: $classification
  3042. X-Netdata-Host: $host
  3043. X-Netdata-Role: $roles
  3044. This is a MIME-encoded multipart message
  3045. --multipart-boundary
  3046. ${email_plaintext_part}
  3047. --multipart-boundary
  3048. ${email_html_part}
  3049. --multipart-boundary--
  3050. EOF
  3051. fi
  3052. SENT_EMAIL=$?
  3053. # -----------------------------------------------------------------------------
  3054. # send the EVENT to Dynatrace
  3055. send_dynatrace "${host}" "${chart}" "${name}" "${status}"
  3056. SENT_DYNATRACE=$?
  3057. # -----------------------------------------------------------------------------
  3058. # send messages to Opsgenie
  3059. send_opsgenie
  3060. SENT_OPSGENIE=$?
  3061. # -----------------------------------------------------------------------------
  3062. # send messages to Gotify
  3063. send_gotify
  3064. SENT_GOTIFY=$?
  3065. # -----------------------------------------------------------------------------
  3066. # send messages to ntfy
  3067. send_ntfy "${DEFAULT_RECIPIENT_NTFY}"
  3068. SENT_NTFY=$?
  3069. # -----------------------------------------------------------------------------
  3070. # let netdata know
  3071. for state in "${SENT_EMAIL}" \
  3072. "${SENT_PUSHOVER}" \
  3073. "${SENT_TELEGRAM}" \
  3074. "${SENT_SLACK}" \
  3075. "${SENT_ROCKETCHAT}" \
  3076. "${SENT_ALERTA}" \
  3077. "${SENT_FLOCK}" \
  3078. "${SENT_DISCORD}" \
  3079. "${SENT_TWILIO}" \
  3080. "${SENT_HIPCHAT}" \
  3081. "${SENT_MESSAGEBIRD}" \
  3082. "${SENT_KAVENEGAR}" \
  3083. "${SENT_PUSHBULLET}" \
  3084. "${SENT_KAFKA}" \
  3085. "${SENT_PD}" \
  3086. "${SENT_FLEEP}" \
  3087. "${SENT_PROWL}" \
  3088. "${SENT_CUSTOM}" \
  3089. "${SENT_IRC}" \
  3090. "${SENT_AWSSNS}" \
  3091. "${SENT_MATRIX}" \
  3092. "${SENT_SYSLOG}" \
  3093. "${SENT_SMS}" \
  3094. "${SENT_MSTEAMS}" \
  3095. "${SENT_DYNATRACE}" \
  3096. "${SENT_OPSGENIE}" \
  3097. "${SENT_GOTIFY}" \
  3098. "${SENT_NTFY}"; do
  3099. if [ "${state}" -eq 0 ]; then
  3100. # we sent something
  3101. exit 0
  3102. fi
  3103. done
  3104. # we did not send anything
  3105. exit 1