Step 2: Move test folder to root
[integration/test.git] / tools / odl-mdsal-clustering-tests / clustering-performance-test / inventory_crawler.py
1 #!/usr/bin/python
2 __author__ = "Jan Medved"
3 __copyright__ = "Copyright(c) 2014, Cisco Systems, Inc."
4 __license__ = "New-style BSD"
5 __email__ = "jmedved@cisco.com"
6
7 import argparse
8 import requests
9 import re
10 import json
11
12
13 class InventoryCrawler(object):
14     reported_flows = 0
15     found_flows = 0
16     nodes = 0
17
18     INVENTORY_URL = 'restconf/%s/opendaylight-inventory:nodes'
19     hdr = {'Accept': 'application/json'}
20     OK, ERROR = range(2)
21     table_stats_unavailable = 0
22     table_stats_fails = []
23
24     def __init__(self, host, port, plevel, datastore, auth, debug):
25         self.url = 'http://' + host + ":" + port + '/' + self.INVENTORY_URL % datastore
26         self.plevel = plevel
27         self.auth = auth
28         self.debug = debug
29
30     def crawl_flows(self, flows):
31         """
32         Collects and prints summary information for all flows in a table
33         """
34         self.found_flows += len(flows)
35         if self.plevel > 1:
36             print '             Flows found: %d\n' % len(flows)
37             if self.plevel > 2:
38                 for f in flows:
39                     s = json.dumps(f, sort_keys=True, indent=4, separators=(',', ': '))
40                     # s = s.replace('{\n', '')
41                     # s = s.replace('}', '')
42                     s = s.strip()
43                     s = s.lstrip('{')
44                     s = s.rstrip('}')
45                     s = s.replace('\n', '\n            ')
46                     s = s.lstrip('\n')
47                     print "             Flow %s:" % f['id']
48                     print s
49
50     def crawl_table(self, table):
51         """
52         Collects and prints summary statistics information about a single table. Depending on the print level
53         (plevel), it also invokes the crawl_flows
54         """
55         try:
56             stats = table['opendaylight-flow-table-statistics:flow-table-statistics']
57             active_flows = int(stats['active-flows'])
58
59             if active_flows > 0:
60                 self.reported_flows += active_flows
61                 if self.plevel > 1:
62                     print '        Table %s:' % table['id']
63                     s = json.dumps(stats, sort_keys=True, indent=12, separators=(',', ': '))
64                     s = s.replace('{\n', '')
65                     s = s.replace('}', '')
66                     print s
67         except KeyError:
68             if self.plevel > 1:
69                 print "        Stats for Table '%s' not available." % table['id']
70             self.table_stats_unavailable += 1
71             pass
72
73         try:
74             flows_in_table = table['flow']
75             self.crawl_flows(flows_in_table)
76         except KeyError:
77             pass
78
79     def crawl_node(self, node):
80         """
81         Collects and prints summary information about a single node
82         """
83         self.table_stats_unavailable = 0
84         self.nodes += 1
85
86         if self.plevel > 1:
87             print "\nNode '%s':" % (node['id'])
88         elif self.plevel > 0:
89             print "%s" % (node['id'])
90
91         try:
92             tables = node['flow-node-inventory:table']
93             if self.plevel > 1:
94                 print '    Tables: %d' % len(tables)
95
96             for t in tables:
97                 self.crawl_table(t)
98
99             if self.table_stats_unavailable > 0:
100                 self.table_stats_fails.append(node['id'])
101
102         except KeyError:
103             if self.plevel > 1:
104                 print '    Data for tables not available.'
105
106     def crawl_inventory(self):
107         """
108         Collects and prints summary information about all openflow nodes in a data store (either operational or config)
109         """
110         self.nodes = 0
111         self.found_flows = 0
112         self.reported_flows = 0
113         self.table_stats_unavailable = 0
114         self.table_stats_fails = []
115
116         s = requests.Session()
117         if not self.auth:
118             r = s.get(self.url, headers=self.hdr, stream=False)
119         else:
120             r = s.get(self.url, headers=self.hdr, stream=False, auth=('admin', 'admin'))
121
122         if r.status_code == 200:
123             try:
124                 inv = json.loads(r.content)['nodes']['node']
125                 sinv = []
126                 for n in range(len(inv)):
127                     if re.search('openflow', inv[n]['id']) is not None:
128                         sinv.append(inv[n])
129
130                 sinv = sorted(sinv, key=lambda k: int(re.findall('\d+', k['id'])[0]))
131
132                 for n in range(len(sinv)):
133                     try:
134                         self.crawl_node(sinv[n])
135                     except:
136                         print 'Can not crawl %s' % sinv[n]['id']
137
138             except KeyError:
139                 print 'Could not retrieve inventory, response not in JSON format'
140         else:
141             print 'Could not retrieve inventory, HTTP error %d' % r.status_code
142
143         s.close()
144
145     def set_plevel(self, plevel):
146         self.plevel = plevel
147
148
149 if __name__ == "__main__":
150     parser = argparse.ArgumentParser(description='Restconf test program')
151     parser.add_argument('--host', default='127.0.0.1', help='host where '
152                         'the controller is running; default 127.0.0.1')
153     parser.add_argument('--port', default='8181', help='port on '
154                         'which odl\'s RESTCONF is listening; default 8181')
155     parser.add_argument('--plevel', type=int, default=0,
156                         help='Print Level: 0 - Summary (stats only); 1 - Node names; 2 - Node details;'
157                              '3 - Flow details')
158     parser.add_argument('--datastore', choices=['operational', 'config'],
159                         default='operational', help='Which data store to crawl; default operational')
160     parser.add_argument('--no-auth', dest='auth', action='store_false', default=False,
161                         help="Do not use authenticated access to REST (default)")
162     parser.add_argument('--auth', dest='auth', action='store_true',
163                         help="Use authenticated access to REST (username: 'admin', password: 'admin').")
164     parser.add_argument('--debug', dest='debug', action='store_true', default=False,
165                         help="List nodes that have not provided proper statistics data")
166
167     in_args = parser.parse_args()
168
169     ic = InventoryCrawler(in_args.host, in_args.port, in_args.plevel, in_args.datastore, in_args.auth,
170                           in_args.debug)
171
172     print "Crawling '%s'" % ic.url
173     ic.crawl_inventory()
174
175     print '\nTotals:'
176     print '    Nodes:          %d' % ic.nodes
177     print '    Reported flows: %d' % ic.reported_flows
178     print '    Found flows:    %d' % ic.found_flows
179
180     if in_args.debug:
181         n_missing = len(ic.table_stats_fails)
182         if n_missing > 0:
183             print '\nMissing table stats (%d nodes):' % n_missing
184             print "%s\n" % ", ".join([x for x in ic.table_stats_fails])