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"
17 def __init__(self, verbose=False):
18 self.verbose = verbose
21 self.start = time.time()
24 def __exit__(self, *args):
25 self.end = time.time()
26 self.secs = self.end - self.start
27 self.msecs = self.secs * 1000 # millisecs
29 print("elapsed time: %f ms" % self.msecs)
32 def wait_for_stats(crawler, exp_found, timeout, delay):
34 Waits for the ODL stats manager to catch up. Polls ODL inventory every
35 <delay> seconds and compares the retrieved stats to the expected values. If
36 stats collection has not finished within <timeout> seconds, the test is
38 :param crawler: Inventory crawler object
39 :param exp_found: Expected value for flows found in the network
40 :param timeout: Max number of seconds to wait for stats collector to
42 :param delay: poll interval for inventory
46 print("Waiting for stats to catch up:")
50 crawler.crawl_inventory()
51 print(" %d, %d" % (crawler.reported_flows, crawler.found_flows))
52 if crawler.found_flows == exp_found or total_delay > timeout:
57 if total_delay < timeout:
58 print("Stats collected in %d seconds." % t.secs)
61 "Stats collection did not finish in %d seconds. Aborting..." % total_delay
65 if __name__ == "__main__":
66 ############################################################################
67 # This program executes an ODL performance test. The test is executed in
70 # 1. The specified number of flows is added in the 'add cycle' (uses
71 # flow_config_blaster to blast flows)
72 # 2. The network is polled for flow statistics from the network (using the
73 # inventory_crawler.py script) to make sure that all flows have been
74 # properly programmed into the network and the ODL statistics collector
75 # can properly read them
76 # 3. The flows are deleted in the flow cycle. Deletion happens either in
77 # 'bulk' (using the config_cleanup) script or one by one (using the
78 # flow_config_blaster 'delete' method)
79 ############################################################################
81 parser = argparse.ArgumentParser(
82 description="Flow programming performance test: First adds and then deletes flows "
83 "into the config tree, as specified by optional parameters."
89 help="Host where odl controller is running (default is 127.0.0.1)",
94 help="Port on which odl's RESTCONF is listening (default is 8181)",
100 help="Number of flow add/delete cycles; default 1. Both Flow Adds and Flow Deletes are "
101 "performed in cycles. <THREADS> worker threads are started in each cycle and the cycle "
102 "ends when all threads finish. Another cycle is started when the previous cycle finished.",
108 help="Number of request worker threads to start in each cycle; default=1. "
109 "Each thread will add/delete <FLOWS> flows.",
115 help="Number of flows that will be added/deleted by each worker thread in each cycle; "
122 help="Flows-per-Request - number of flows (batch size) sent in each HTTP request; "
129 help="Time (seconds) to between inventory polls when waiting for stats to catch up; default=1",
135 help="The maximum time (seconds) to wait between the add and delete cycles; default=100",
142 help="Delete all added flows one by one, benchmark delete " "performance.",
149 help="Delete all flows in bulk; default=False",
155 help="Use authenticated access to REST (username: 'admin', password: 'admin'); default=False",
158 "--startflow", type=int, default=0, help="The starting Flow ID; default=0"
163 help="File from which to read the JSON flow template; default: no file, use a built in "
167 in_args = parser.parse_args()
170 if in_args.file != "":
171 flow_template = get_json_from_file(in_args.file)
175 ic = InventoryCrawler(
176 in_args.host, in_args.port, 0, "operational", in_args.auth, False
179 fct = FlowConfigBlaster(
190 # Get the baseline stats. Required in Step 3 to validate if the delete
191 # function gets the controller back to the baseline
193 reported = ic.reported_flows
194 found = ic.found_flows
197 print(" Reported flows: %d" % reported)
198 print(" Found flows: %d" % found)
200 # Run through <CYCLES> add cycles, where <THREADS> threads are started in
201 # each cycle and <FLOWS> flows are added from each thread
204 print("\n*** Total flows added: %d" % fct.get_ok_flows())
205 print(" HTTP[OK] results: %d\n" % fct.get_ok_rqsts())
207 # Wait for stats to catch up
208 wait_for_stats(ic, found + fct.get_ok_flows(), in_args.timeout, in_args.delay)
210 # Run through <CYCLES> delete cycles, where <THREADS> threads are started
211 # in each cycle and <FLOWS> flows previously added in an add cycle are
212 # deleted in each thread
213 if in_args.bulk_delete:
214 print("\nDeleting all flows in bulk:")
215 sts = cleanup_config_odl(in_args.host, in_args.port, in_args.auth)
217 print(" Failed to delete flows, code %d" % sts)
219 print(" All flows deleted.")
221 print("\nDeleting flows one by one\n ")
223 print("\n*** Total flows deleted: %d" % fct.get_ok_flows())
224 print(" HTTP[OK] results: %d\n" % fct.get_ok_rqsts())
226 # Wait for stats to catch up back to baseline
227 wait_for_stats(ic, found, in_args.timeout, in_args.delay)