Refactoring: Changed all check parameters starting with an 'o' to the new rulespec...
[check_mk.git] / checks / azure.include
blob2f5bccf5a0c6463ee0222376906a4ce1c683a77f
1 #!/usr/bin/python
2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
9 # | |
10 # | Copyright Mathias Kettner 2018 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
26 import json
28 _AZURE_METRIC_FMT = {
29 "count": lambda n: "%d" % n,
30 "percent": get_percent_human_readable,
31 "bytes": get_bytes_human_readable,
32 "bytes_per_second": lambda b: "%s/s" % get_bytes_human_readable(b),
33 "seconds": lambda s: "%.2f s" % s,
34 "milli_seconds": lambda ms: "%d ms" % (ms * 1000),
38 def azure_iter_informative_attrs(resource, include_keys=('location',)):
39 def cap(string): # not quite what str.title() does
40 return string[0].upper() + string[1:]
42 for key in include_keys:
43 if key in resource:
44 yield cap(key), resource[key]
46 for key, value in sorted(resource.get('tags', {}).iteritems()):
47 if not key.startswith("hidden-"):
48 yield cap(key), value
51 def check_azure_metric(
52 resource, # pylint: disable=too-many-locals
53 metric_key,
54 cmk_key,
55 display_name,
56 levels=None,
57 levels_lower=None,
58 minv=None,
59 maxv=None,
60 use_rate=False):
61 metric = resource.get('metrics', {}).get(metric_key)
62 if metric is None:
63 return None
65 if use_rate:
66 countername = "%s.%s" % (resource['id'], metric_key)
67 value = get_rate(countername, time.time(), metric.value)
68 unit = "%s_rate" % metric.unit
69 else:
70 value = metric.value
71 unit = metric.unit
73 if value is None:
74 return 3, "Metric %s is 'None'" % display_name, []
76 # convert to SI-unit
77 if unit == "milli_seconds":
78 value /= 1000.
79 elif unit == "seconds_rate":
80 # we got seconds, but we computed the rate -> seconds per second:
81 # how long happend something / time period = percent of the time
82 # e.g. CPU time: how much percent of of the time was the CPU busy.
83 value *= 100.
84 unit = "percent"
86 formatter = _AZURE_METRIC_FMT.get(unit, str)
87 text = "%s: %s" % (display_name, formatter(value))
89 l_state, u_state = 0, 0
90 warn_lower, crit_lower = levels_lower or (None, None)
91 if crit_lower is not None and value <= crit_lower:
92 l_state = 2
93 elif warn_lower is not None and value <= warn_lower:
94 l_state = 1
95 if l_state != 0:
96 text += " (warn/crit below %s/%s)" % (formatter(warn_lower), formatter(crit_lower))
98 warn, crit = levels or (None, None)
99 if crit is not None and value >= crit:
100 u_state = 2
101 elif warn is not None and value >= warn:
102 u_state = 1
103 if u_state != 0:
104 text += " (warn/crit at %s/%s)" % (formatter(warn), formatter(crit))
106 return max(l_state, u_state), text, [(cmk_key, value, warn, crit, minv, maxv)]
109 # .--Parse---------------------------------------------------------------.
110 # | ____ |
111 # | | _ \ __ _ _ __ ___ ___ |
112 # | | |_) / _` | '__/ __|/ _ \ |
113 # | | __/ (_| | | \__ \ __/ |
114 # | |_| \__,_|_| |___/\___| |
115 # | |
116 # '----------------------------------------------------------------------'
118 _AZURE_AGENT_SEPARATOR = '|'
120 Metric = collections.namedtuple(
121 "Metric", ["name", "aggregation", "value", "unit", "timestamp", "timegrain", "filters"])
124 def _read(row, types, defaults=None):
125 if defaults is None:
126 defaults = [None for __ in types]
127 if len(defaults) != len(types):
128 raise ValueError("expected %d default values" % len(types))
130 for i, (tfunc, default) in enumerate(zip(types, defaults)):
131 try:
132 raw = row[i]
133 yield tfunc(raw)
134 except (IndexError, ValueError):
135 yield default
138 def _parse_resource(info):
139 '''read resource json and parse metric lines
141 Metrics are stored in a dict. Key is name, prefixed by their aggregation,
142 spaces become underspcores:
143 Disk Read Bytes|average|0.0|...
144 is stored at
145 resource["metrics"]["average_Disk_Read_Bytes"]
147 try:
148 resource = json.loads(_AZURE_AGENT_SEPARATOR.join(info[0]))
149 except (ValueError, IndexError):
150 return None
152 if len(info) < 4:
153 return resource
155 key, count = _read(info[1], (str, int), ("", 0))
156 if key != "metrics following":
157 return resource
159 # header = info[2]
160 for mline in info[3:3 + count]:
161 name, aggregation, value, unit, timestamp, timegrain, filters = _read(
162 mline, (str, str, float, str, str, str, str))
163 if unit in ('count', 'bytes') and value is not None:
164 # even integer values are formated '42.0', so we needed float(.)
165 value = int(value)
167 key = "%s_%s" % (aggregation, name.replace(" ", "_"))
168 metr = Metric(name, aggregation, value, unit, timestamp, timegrain, filters)
169 resource.setdefault('metrics', {})[key] = metr
171 return resource
174 def parse_azure(info):
175 raw_resources = []
177 # create list of lines per resource
178 for row in info:
179 if row == ["Resource"]:
180 raw_resources.append([])
181 continue
182 if raw_resources:
183 raw_resources[-1].append(row)
185 parsed_resources = (_parse_resource(r) for r in raw_resources)
187 return {r['name']: r for r in parsed_resources if r}
192 # .--Discovery-----------------------------------------------------------.
193 # | ____ _ |
194 # | | _ \(_)___ ___ _____ _____ _ __ _ _ |
195 # | | | | | / __|/ __/ _ \ \ / / _ \ '__| | | | |
196 # | | |_| | \__ \ (_| (_) \ V / __/ | | |_| | |
197 # | |____/|_|___/\___\___/ \_/ \___|_| \__, | |
198 # | |___/ |
199 # +----------------------------------------------------------------------+
202 def discover_azure_by_metrics(*desired_metrics):
203 """Return a discovery function, that will discover if any of the metrics are found"""
205 def discovery_function(parsed):
206 for name, resource in parsed.iteritems():
207 metr = resource.get('metrics', {})
208 if set(desired_metrics) & set(metr.keys()):
209 yield name, {}
211 return discovery_function