forked from vimeo/graph-explorer
/
backend.py
120 lines (101 loc) · 4.29 KB
/
backend.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env python2
import json
import os
import logging
from urlparse import urljoin
class MetricsError(Exception):
def __init__(self, msg, underlying_error):
Exception.__init__(self, msg, underlying_error)
self.msg = str(msg)
self.underlying_error = str(underlying_error)
def __str__(self):
return "%s (%s)" % (self.msg, self.underlying_error)
class Backend(object):
def __init__(self, config, logger=logging):
self.config = config
self.logger = logger
def download_metrics_json(self):
import urllib2
url = urljoin(self.config.graphite_url_server, "metrics/index.json")
if (self.config.graphite_username is not None and self.config.graphite_password is not None):
#user/pass from the config file
username = self.config.graphite_username
password = self.config.graphite_password
# create the password manager
passmanager = urllib2.HTTPPasswordMgrWithDefaultRealm()
# add the credentials to the password manager
passmanager.add_password(None, url, username, password)
# add the authentication handler
authhandler = urllib2.HTTPBasicAuthHandler(passmanager)
opener = urllib2.build_opener(authhandler)
# install the authentication handler, all url_open commands will now use it
urllib2.install_opener(opener)
response = urllib2.urlopen(url)
m = open('%s.tmp' % self.config.filename_metrics, 'w')
m.write(response.read())
m.close()
os.rename('%s.tmp' % self.config.filename_metrics, self.config.filename_metrics)
def load_metrics(self):
try:
f = open(self.config.filename_metrics, 'r')
metrics = json.load(f)
# workaround for graphite bug where metrics can have leading dots
# has been fixed (https://github.com/graphite-project/graphite-web/pull/293)
# but older graphite versions still do it
if len(metrics) and metrics[0][0] == '.':
metrics = [m.lstrip('.') for m in metrics]
return metrics
except IOError, e:
raise MetricsError("Can't load metrics file", e)
except ValueError, e:
raise MetricsError("Can't parse metrics file", e)
def stat_metrics(self):
try:
return os.stat(self.config.filename_metrics)
except OSError, e:
raise MetricsError("Can't load metrics file", e)
def update_data(self, s_metrics):
self.logger.debug("loading metrics")
metrics = self.load_metrics()
self.logger.debug("removing outdated targets")
s_metrics.remove_metrics_not_in(metrics)
self.logger.debug("updating targets")
s_metrics.update_targets(metrics)
def make_config(config):
# backwards compat.
if hasattr(config, 'graphite_url'):
if not hasattr(config, 'graphite_url_server'):
config.graphite_url_server = config.graphite_url
if not hasattr(config, 'graphite_url_client'):
config.graphite_url_client = config.graphite_url
return config
def get_action_on_rules_match(rules, subject):
'''
rules being a a list of tuples, and each tuple having 2 elements, like:
{'plugin': ['diskspace', 'memory'], 'unit': 'B'},
action
the dict is a list of conditions that must match (and). if the value is an iterable, those count as OR
action can be whatever you want. the actions for all matching rules are yielded.
'''
for (match_rules, action) in rules:
rule_match = True
for (tag_k, tag_v) in match_rules.items():
if tag_k not in subject:
rule_match = False
break
if isinstance(tag_v, basestring):
if subject[tag_k] != tag_v:
rule_match = False
break
else:
# tag_v is a list -> OR of multiple allowed options
tag_match = False
for option in tag_v:
if subject[tag_k] == option:
tag_match = True
if not tag_match:
rule_match = False
break
if rule_match:
yield action
# vim: ts=4 et sw=4: