5 from flow_config_blaster import FlowConfigBlaster, get_json_from_file
6 from inventory_crawler import InventoryCrawler
7 from config_cleanup import cleanup_config_odl
10 __author__ = "Jan Medved"
11 __copyright__ = "Copyright(c) 2014, Cisco Systems, Inc."
12 __license__ = "New-style BSD"
13 __email__ = "jmedved@cisco.com"
16 def wait_for_stats(crawler, exp_found, timeout, delay):
18 Waits for the ODL stats manager to catch up. Polls ODL inventory every
19 <delay> seconds and compares the retrieved stats to the expected values. If
20 stats collection has not finished within <timeout> seconds, the test is
22 :param crawler: Inventory crawler object
23 :param exp_found: Expected value for flows found in the network
24 :param timeout: Max number of seconds to wait for stats collector to
26 :param delay: poll interval for inventory
30 print 'Waiting for stats to catch up:'
32 crawler.crawl_inventory()
33 print ' %d, %d' % (crawler.reported_flows, crawler.found_flows)
34 if crawler.found_flows == exp_found or total_delay > timeout:
39 if total_delay < timeout:
40 print 'Stats collected in %d seconds.' % total_delay
42 print 'Stats collection did not finish in %d seconds. Aborting...' % total_delay
45 if __name__ == "__main__":
46 ############################################################################
47 # This program executes an ODL performance test. The test is executed in
50 # 1. The specified number of flows is added in the 'add cycle' (uses
51 # flow_config_blaster to blast flows)
52 # 2. The network is polled for flow statistics from the network (using the
53 # inventory_crawler.py script) to make sure that all flows have been
54 # properly programmed into the network and the ODL statistics collector
55 # can properly read them
56 # 3. The flows are deleted in the flow cycle. Deletion happens either in
57 # 'bulk' (using the config_cleanup) script or one by one (using the
58 # flow_config_blaster 'delete' method)
59 ############################################################################
61 parser = argparse.ArgumentParser(description='Flow programming performance test: First adds and then deletes flows '
62 'into the config tree, as specified by optional parameters.')
64 parser.add_argument('--host', default='127.0.0.1',
65 help='Host where odl controller is running (default is 127.0.0.1)')
66 parser.add_argument('--port', default='8181',
67 help='Port on which odl\'s RESTCONF is listening (default is 8181)')
68 parser.add_argument('--cycles', type=int, default=1,
69 help='Number of flow add/delete cycles; default 1. Both Flow Adds and Flow Deletes are '
70 'performed in cycles. <THREADS> worker threads are started in each cycle and the cycle '
71 'ends when all threads finish. Another cycle is started when the previous cycle finished.')
72 parser.add_argument('--threads', type=int, default=1,
73 help='Number of request worker threads to start in each cycle; default=1. '
74 'Each thread will add/delete <FLOWS> flows.')
75 parser.add_argument('--flows', type=int, default=10,
76 help='Number of flows that will be added/deleted by each worker thread in each cycle; '
78 parser.add_argument('--fpr', type=int, default=1,
79 help='Flows-per-Request - number of flows (batch size) sent in each HTTP request; '
81 parser.add_argument('--delay', type=int, default=2,
82 help='Time (seconds) to between inventory polls when waiting for stats to catch up; default=1')
83 parser.add_argument('--timeout', type=int, default=100,
84 help='The maximum time (seconds) to wait between the add and delete cycles; default=100')
85 parser.add_argument('--delete', dest='delete', action='store_true', default=True,
86 help='Delete all added flows one by one, benchmark delete '
88 parser.add_argument('--bulk-delete', dest='bulk_delete', action='store_true', default=False,
89 help='Delete all flows in bulk; default=False')
90 parser.add_argument('--auth', dest='auth', action='store_true',
91 help="Use authenticated access to REST (username: 'admin', password: 'admin'); default=False")
92 parser.add_argument('--startflow', type=int, default=0,
93 help='The starting Flow ID; default=0')
94 parser.add_argument('--file', default='',
95 help='File from which to read the JSON flow template; default: no file, use a built in '
98 in_args = parser.parse_args()
101 if in_args.file != '':
102 flow_template = get_json_from_file(in_args.file)
106 ic = InventoryCrawler(in_args.host, in_args.port, 0, 'operational', in_args.auth, False)
108 fct = FlowConfigBlaster(in_args.host, in_args.port, in_args.cycles, in_args.threads, in_args.fpr,
109 16, in_args.flows, in_args.startflow, in_args.auth)
110 # Get the baseline stats. Required in Step 3 to validate if the delete
111 # function gets the controller back to the baseline
113 reported = ic.reported_flows
114 found = ic.found_flows
117 print ' Reported flows: %d' % reported
118 print ' Found flows: %d' % found
120 # Run through <CYCLES> add cycles, where <THREADS> threads are started in
121 # each cycle and <FLOWS> flows are added from each thread
124 print '\n*** Total flows added: %d' % fct.get_ok_flows()
125 print ' HTTP[OK] results: %d\n' % fct.get_ok_rqsts()
127 # Wait for stats to catch up
128 wait_for_stats(ic, found + fct.get_ok_flows(), in_args.timeout, in_args.delay)
130 # Run through <CYCLES> delete cycles, where <THREADS> threads are started
131 # in each cycle and <FLOWS> flows previously added in an add cycle are
132 # deleted in each thread
133 if in_args.bulk_delete:
134 print '\nDeleting all flows in bulk:'
135 sts = cleanup_config_odl(in_args.host, in_args.port, in_args.auth)
137 print ' Failed to delete flows, code %d' % sts
139 print ' All flows deleted.'
141 print '\nDeleting flows one by one\n ',
143 print '\n*** Total flows deleted: %d' % fct.get_ok_flows()
144 print ' HTTP[OK] results: %d\n' % fct.get_ok_rqsts()
146 # Wait for stats to catch up back to baseline
147 wait_for_stats(ic, found, in_args.timeout, in_args.delay)