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