2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
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.
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
:
44 yield cap(key
), resource
[key
]
46 for key
, value
in sorted(resource
.get('tags', {}).iteritems()):
47 if not key
.startswith("hidden-"):
51 def check_azure_metric(
52 resource
, # pylint: disable=too-many-locals
61 metric
= resource
.get('metrics', {}).get(metric_key
)
66 countername
= "%s.%s" % (resource
['id'], metric_key
)
67 value
= get_rate(countername
, time
.time(), metric
.value
)
68 unit
= "%s_rate" % metric
.unit
74 return 3, "Metric %s is 'None'" % display_name
, []
77 if unit
== "milli_seconds":
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.
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
:
93 elif warn_lower
is not None and value
<= warn_lower
:
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
:
101 elif warn
is not None and value
>= warn
:
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---------------------------------------------------------------.
111 # | | _ \ __ _ _ __ ___ ___ |
112 # | | |_) / _` | '__/ __|/ _ \ |
113 # | | __/ (_| | | \__ \ __/ |
114 # | |_| \__,_|_| |___/\___| |
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):
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
)):
134 except (IndexError, ValueError):
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|...
145 resource["metrics"]["average_Disk_Read_Bytes"]
148 resource
= json
.loads(_AZURE_AGENT_SEPARATOR
.join(info
[0]))
149 except (ValueError, IndexError):
155 key
, count
= _read(info
[1], (str, int), ("", 0))
156 if key
!= "metrics following":
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(.)
167 key
= "%s_%s" % (aggregation
, name
.replace(" ", "_"))
168 metr
= Metric(name
, aggregation
, value
, unit
, timestamp
, timegrain
, filters
)
169 resource
.setdefault('metrics', {})[key
] = metr
174 def parse_azure(info
):
177 # create list of lines per resource
179 if row
== ["Resource"]:
180 raw_resources
.append([])
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-----------------------------------------------------------.
194 # | | _ \(_)___ ___ _____ _____ _ __ _ _ |
195 # | | | | | / __|/ __/ _ \ \ / / _ \ '__| | | | |
196 # | | |_| | \__ \ (_| (_) \ V / __/ | | |_| | |
197 # | |____/|_|___/\___\___/ \_/ \___|_| \__, | |
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()):
211 return discovery_function