]> git.sven.stormbind.net Git - sven/scripts.git/blob - weblogpro/pvmon2opsgenie.sh
Make use of alert priorities
[sven/scripts.git] / weblogpro / pvmon2opsgenie.sh
1 #!/bin/sh
2 # Checks inverter state as repoted by a meteocontrol weblog
3 # device HTML interface, reports issues via Atlassian
4 # Opsgenie. Written with the intention to run via cron on
5 # a LTE Router with either OpenWRT or Teltonika RutOS.
6 # Requires curl other stock sh/cut/cat/test are enough.
7
8 ### path to the suntime / check for daylight script
9 checkdaylight="./suntime.lua"
10
11 ### opsgenie configuration
12 API_HOST="api.eu.opsgenie.com"
13 API_KEY=""
14
15 # adjust meteocontrol default password and IPs
16 # meteocontrol devices must be added to the main loop as well
17 mc1="http://admin:ist02@192.168.1.2/html/de/onlineOverWr.html"
18 mc2="http://admin:ist02@192.168.1.3/html/de/onlineOverWr.html"
19
20
21 ### check for daylight, otherwise exit early
22 ${checkdaylight} || exit 3
23
24
25 # createAlert <alias> <message> <priority> <description>
26 createAlert() {
27     local alias="${1}"
28     local message="${2}"
29     local priority="${3}"
30     local description="${4}"
31     local date="$(date)"
32
33     if [ -z "${alias}" ]; then
34         echo "ERROR: Empty alert alias"
35         return
36     fi
37
38     if [ -z "${message}" ]; then
39         echo "ERROR: Empty alert message"
40         return
41     fi
42
43     if [ -z "${priority}" ]; then
44         priority="P3"
45     fi
46
47     curl -o /dev/null -s \
48         -X POST https://${API_HOST}/v2/alerts \
49         -H "Content-Type: application/json" \
50         -H "Authorization: GenieKey ${API_KEY}" \
51         -d \
52         "{
53             \"message\":\"${message}\",
54             \"alias\":\"${alias}\",
55             \"priority\":\"${priority}\",
56             \"description\":\"${description}\",
57             \"note\":\"Localtime ${date}\"
58         }"
59 }
60
61 # closeAlert <alias>
62 closeAlert() {
63     local alias=${1}
64
65     if [ -z "${alias}" ]; then
66         echo "ERROR: Empty alert alias"
67         return
68     fi
69
70     curl -o /dev/null -s \
71         -X POST https://${API_HOST}/v2/alerts/${alias}/close?identifierType=alias \
72         -H "Authorization: GenieKey ${API_KEY}" \
73         -H "Content-Type: application/json" \
74         -d '{}'
75
76 }
77
78 # parseMcLine <meteocontrol html page output line>
79 parseMcLine() {
80     local input="${@}"
81
82     local wrleistung="$(echo ${input} | cut -d'>' -f 13 | cut -d'<' -f 1)"
83     local wradresse="$(echo ${input} | cut -d'>' -f 4 | cut -d'<' -f 1)"
84     local wrserial="$(echo ${input} | cut -d'>' -f 7 | cut -d'<' -f 1)"
85
86     # known bad case e.g. during the night
87     if [ "${wrleistung}" = "---" ]; then
88         echo "No Power Value at WR${wradresse} Serial:${wrserial}"
89         return 3
90     fi
91
92     # known good case
93     if [ "${wrleistung}" -gt 0 ]; then
94         echo "OK"
95         return
96     fi
97
98     echo "ERROR: WR${wradresse} ${wrleistung}W Serial:${wrserial}"
99     return 1
100 }
101
102 # parseMcOutput <meteocontrol status html output page>
103 parseMcOutput() {
104     local file="${1}"
105     local result=""
106     if ! [ -f "${file}" ]; then
107         echo "ERROR: Supplied input ${file} is not a regular file"
108         return
109     fi
110
111     grep "cLink" "${file}" | while read line; do
112         result="$(parseMcLine \"${line}\")"
113         # good case
114         if [ "${result}" = "OK" ]; then
115             continue
116         fi
117         # return failure data
118         echo -n "${result} -- "
119     done
120 }
121
122 # getMCstates <outfile> <status-url>
123 getMCstates() {
124     local outfile="${1}"
125     local url="${2}"
126
127     if [ -z "${outfile}" ]; then
128         echo "ERROR: no meteocontrol tmp file provided"
129         exit 1
130     fi
131
132     if [ -z "${url}" ]; then
133         echo "ERROR: no meteocontrol URL provided"
134         exit 1
135     fi
136
137     # remove eventual remains of prior runs
138     rm -f "${outfile}"
139
140     # ready to try to download the data from meteocontrol
141     if ! curl -s -o "${outfile}" "${url}"; then
142         echo "ERROR: could not download ${url} into ${outfile}"
143         exit 1
144     fi
145
146     # verify we have content to parse in our downloaded file
147     if ! grep -c -q cLink "${outfile}"; then
148         echo "ERROR: no matching cLink lines found in output file ${outfile}"
149         exit 1
150     fi
151 }
152
153 # checkAlertState <statefile> <new-status>
154 # return 0 on alert state change
155 # return 1 if nothing changed
156 checkAlertState() {
157     local statefile="${1}"
158     local newstatus="${2}"
159     local oldstatus="null"
160
161     test -f "${statefile}" && oldstatus="$(cat ${statefile})"
162     if [ "${oldstatus}" = "${newstatus}" ]; then
163         return 1
164     fi
165
166     # update state file on state change
167     echo "${newstatus}" > "${statefile}"
168     return 0
169 }
170
171 # calcPriority <outfile> <failures>
172 # returns an Opsgenie priority string
173 # If all devies fail return P1, otherwise stick with P3.
174 calcPriority() {
175     local outfile="${1}"
176     local failures="${2}"
177     local priority="P3"
178     local numWR="$(grep -c cLink ${outfile})"
179     # to be able to count with grep, we've to have our pattern ones per line
180     local numFailed=$(echo "${failures}"| tr ' ' '\n' | grep -c 'WR')
181
182     if [ "${numWR}" -eq "${numFailed}" ]; then
183         priority="P1"
184     fi
185
186     echo "${priority}"
187 }
188
189 ### main loop
190 for dev in mc1 mc2; do
191     outfile="/tmp/${dev}.html"
192     statefile="/tmp/pvstate-${dev}"
193     url=$(eval echo \${$dev})
194
195     # download the html overview page from meteocontrol device
196     getMCstates "${outfile}" "${url}"
197
198     # parse the overview page and collect failures
199     failures=$(parseMcOutput "${outfile}")
200
201     # handle failures and alerting
202     if ! [ -z "${failures}" ]; then
203         priority=$(calcPriority "${outfile}" "${failures}")
204         checkAlertState "${statefile}" "FAILED" && \
205         createAlert "${dev}" "PV Ossendorf ${dev}" "${priority}" "${failures}"
206         continue
207     fi
208
209     # update alert state close alert on state change
210     checkAlertState "${statefile}" "OK" && \
211     closeAlert "${dev}"
212 done