2 __author__ = "Jan Medved"
3 __copyright__ = "Copyright(c) 2014, Cisco Systems, Inc."
4 __license__ = "New-style BSD"
5 __email__ = "jmedved@cisco.com"
13 class InventoryCrawler(object):
18 INVENTORY_URL = 'restconf/%s/opendaylight-inventory:nodes'
19 hdr = {'Accept': 'application/json'}
21 table_stats_unavailable = 0
22 table_stats_fails = []
24 def __init__(self, host, port, plevel, datastore, auth, debug):
25 self.url = 'http://' + host + ":" + port + '/' + self.INVENTORY_URL % datastore
31 def crawl_flows(self, flows):
33 Collects and prints summary information for all flows in a table
35 self.found_flows += len(flows)
37 print ' Flows found: %d\n' % len(flows)
40 s = json.dumps(f, sort_keys=True, indent=4, separators=(',', ': '))
41 # s = s.replace('{\n', '')
42 # s = s.replace('}', '')
46 s = s.replace('\n', '\n ')
48 print " Flow %s:" % f['id']
52 def crawl_table(self, table):
54 Collects and prints summary statistics information about a single table. Depending on the print level
55 (plevel), it also invokes the crawl_flows
58 stats = table['opendaylight-flow-table-statistics:flow-table-statistics']
59 active_flows = int(stats['active-flows'])
62 self.reported_flows += active_flows
64 print ' Table %s:' % table['id']
65 s = json.dumps(stats, sort_keys=True, indent=12, separators=(',', ': '))
66 s = s.replace('{\n', '')
67 s = s.replace('}', '')
71 print " Stats for Table '%s' not available." % table['id']
72 self.table_stats_unavailable += 1
76 flows_in_table = table['flow']
77 self.crawl_flows(flows_in_table)
82 def crawl_node(self, node):
84 Collects and prints summary information about a single node
86 self.table_stats_unavailable = 0
90 print "\nNode '%s':" % (node['id'])
92 print "%s" % (node['id'])
95 tables = node['flow-node-inventory:table']
97 print ' Tables: %d' % len(tables)
102 if self.table_stats_unavailable > 0:
103 self.table_stats_fails.append(node['id'])
107 print ' Data for tables not available.'
110 def crawl_inventory(self):
112 Collects and prints summary information about all openflow nodes in a data store (either operational or config)
115 self.reported_flows = 0
116 self.table_stats_unavailable = 0
117 self.table_stats_fails = []
119 s = requests.Session()
121 r = s.get(self.url, headers=self.hdr, stream=False)
123 r = s.get(self.url, headers=self.hdr, stream=False, auth=('admin', 'admin'))
125 if r.status_code == 200:
127 inv = json.loads(r.content)['nodes']['node']
129 for n in range(len(inv)):
130 if re.search('openflow', inv[n]['id']) is not None:
133 sinv = sorted(sinv, key=lambda k: int(re.findall('\d+', k['id'])[0]))
135 for n in range(len(sinv)):
137 self.crawl_node(sinv[n])
139 print 'Can not crawl %s' % sinv[n]['id']
142 print 'Could not retrieve inventory, response not in JSON format'
144 print 'Could not retrieve inventory, HTTP error %d' % r.status_code
149 def set_plevel(self, plevel):
155 if __name__ == "__main__":
156 parser = argparse.ArgumentParser(description='Restconf test program')
157 parser.add_argument('--host', default='127.0.0.1', help='host where '
158 'the controller is running; default 127.0.0.1')
159 parser.add_argument('--port', default='8181', help='port on '
160 'which odl\'s RESTCONF is listening; default 8181')
161 parser.add_argument('--plevel', type=int, default=0,
162 help='Print Level: 0 - Summary (stats only); 1 - Node names; 2 - Node details;'
164 parser.add_argument('--datastore', choices=['operational', 'config'],
165 default='operational', help='Which data store to crawl; default operational')
166 parser.add_argument('--no-auth', dest='auth', action='store_false', default=False,
167 help="Do not use authenticated access to REST (default)")
168 parser.add_argument('--auth', dest='auth', action='store_true',
169 help="Use authenticated access to REST (username: 'admin', password: 'admin').")
170 parser.add_argument('--debug', dest='debug', action='store_true', default=False,
171 help="List nodes that have not provided proper statistics data")
173 in_args = parser.parse_args()
175 ic = InventoryCrawler(in_args.host, in_args.port, in_args.plevel, in_args.datastore, in_args.auth,
178 print "Crawling '%s'" % ic.url
182 print ' Nodes: %d' % ic.nodes
183 print ' Reported flows: %d' % ic.reported_flows
184 print ' Found flows: %d' % ic.found_flows
187 n_missing = len(ic.table_stats_fails)
189 print '\nMissing table stats (%d nodes):' % n_missing
190 print "%s\n" % ", ".join([x for x in ic.table_stats_fails])