Demo script enables waypoint now. Fixed original analytics script so that it can...
[affinity.git] / scripts / stats.py
1 #!/usr/bin/python
2
3 import httplib2
4 import json
5
6 '''
7 Class for keeping track of host statistics
8 '''
9 class Stats:
10
11     TYPE_HOST = 0
12     TYPE_AL = 1 # AffinityLink
13     TYPE_PREFIX = 2
14
15     def __init__(self, stat_type, **kwargs):
16         self.stat_type = stat_type
17         if stat_type == Stats.TYPE_HOST:
18             self.src = kwargs['src']
19             self.dst = kwargs['dst']
20             self.url_prefix = "http://localhost:8080/affinity/nb/v2/analytics/default/hoststats/" 
21         elif stat_type == Stats.TYPE_AL:
22             self.al = kwargs['al']
23             self.url_prefix = "http://localhost:8080/affinity/nb/v2/analytics/default/affinitylinkstats/"
24         elif stat_type == Stats.TYPE_PREFIX:
25             self.subnet = kwargs['subnet']
26             self.url_prefix = "http://localhost:8080/affinity/nb/v2/analytics/default/prefixstats/"
27         else:
28             print "incorrect stat type", stat_type
29
30         self.stats = {}
31         self.rate_ewma = None
32         self.http = httplib2.Http(".cache")
33         self.http.add_credentials('admin', 'admin')
34
35     def __str__(self):
36         if (self.stat_type == Stats.TYPE_HOST):
37             return "host pair %s -> %s" % (self.src, self.dst)
38         elif (self.stat_type == Stats.TYPE_AL):
39             return "affinity link %s" % self.al
40         elif (self.stat_type == Stats.TYPE_PREFIX):
41             return "prefix %s" % self.subnet
42         else:
43             return "unknown Stats type"
44
45     # Refresh statistics
46     def refresh(self):
47         if (self.stat_type == Stats.TYPE_HOST):
48             resp, content = self.http.request(self.url_prefix + self.src + "/" + self.dst, "GET")
49         elif (self.stat_type == Stats.TYPE_AL):
50             resp, content = self.http.request(self.url_prefix + self.al, "GET")
51         elif (self.stat_type == Stats.TYPE_PREFIX):
52             resp, content = self.http.request(self.url_prefix + self.subnet, "GET")
53         try:
54             self.stats = json.loads(content)
55             is_fast = self.handle_rate_ewma()
56             is_big = self.check_large_flow()
57             return [is_fast, is_big]
58         except Exception as e:
59             print "error: ", e
60             return [False, False]
61
62     # Return hosts that transferred data into this entity.  Right now only supports prefixes.
63     def get_incoming_hosts(self):
64         if (self.stat_type == Stats.TYPE_PREFIX):
65             resp, content = self.http.request(self.url_prefix + "incoming/" + self.subnet, "GET")
66             data = json.loads(content)
67             if (data != {}):
68                 # IPs sometimes (always?) get returned as strings like /1.2.3.4; strip off the leading /
69                 ips = [h.replace("/", "") for h in data['hosts']]
70                 return ips
71         else:
72             print "Stat type not supported for incoming hosts"
73         return []
74
75     # EWMA calculation for bit rate.  Returns true if there is an anomaly.
76     def handle_rate_ewma(self):
77         alpha = .25
78         anomaly_threshold = 2.0
79         new_bitrate = self.get_bit_rate()
80
81         return_val = False
82
83         if self.rate_ewma == None:
84             self.rate_ewma = new_bitrate
85         else:
86             new_rate_ewma = alpha * new_bitrate + (1 - alpha) * self.rate_ewma
87             if (self.rate_ewma > 0 and new_rate_ewma > anomaly_threshold * self.rate_ewma):
88                 return_val = True
89             self.rate_ewma = new_rate_ewma
90         return return_val
91
92     # Returns true if this is a large flow
93     def check_large_flow(self):
94         if (self.get_bytes() > 5 * (10**6)):
95             return True
96         return False
97
98     # Bytes
99     def get_bytes(self):
100         try:
101             bytes = long(self.stats["byteCount"])
102         except Exception as e:
103             bytes = 0
104         return bytes
105
106     # Bit Rate
107     def get_bit_rate(self):
108         try:
109             bitrate = float(self.stats["bitRate"])
110         except Exception as e:
111             bitrate = 0.0
112         return bitrate