Fixed flow_config_blaster Floodlight edition
[integration/test.git] / tools / odl-mdsal-clustering-tests / clustering-performance-test / flow_add_delete_test.py
1 #!/usr/bin/python
2
3 import argparse
4 import time
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
8
9
10 __author__ = "Jan Medved"
11 __copyright__ = "Copyright(c) 2014, Cisco Systems, Inc."
12 __license__ = "New-style BSD"
13 __email__ = "jmedved@cisco.com"
14
15
16 class Timer(object):
17     def __init__(self, verbose=False):
18         self.verbose = verbose
19
20     def __enter__(self):
21         self.start = time.time()
22         return self
23
24     def __exit__(self, *args):
25         self.end = time.time()
26         self.secs = self.end - self.start
27         self.msecs = self.secs * 1000  # millisecs
28         if self.verbose:
29             print ("elapsed time: %f ms" % self.msecs)
30
31
32 def wait_for_stats(crawler, exp_found, timeout, delay):
33     """
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
37     aborted.
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
41                     collect all stats
42     :param delay: poll interval for inventory
43     :return: None
44     """
45     total_delay = 0
46     print 'Waiting for stats to catch up:'
47
48     with Timer() as t:
49         while True:
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:
53                 break
54             total_delay += delay
55             time.sleep(delay)
56
57     if total_delay < timeout:
58         print 'Stats collected in %d seconds.' % t.secs
59     else:
60         print 'Stats collection did not finish in %d seconds. Aborting...' % total_delay
61
62
63 if __name__ == "__main__":
64     ############################################################################
65     # This program executes an ODL performance test. The test is executed in
66     # three steps:
67     #
68     # 1. The specified number of flows is added in the 'add cycle' (uses
69     #    flow_config_blaster to blast flows)
70     # 2. The network is polled for flow statistics from the network (using the
71     #    inventory_crawler.py script) to make sure that all flows have been
72     #    properly programmed into the network and the ODL statistics collector
73     #    can properly read them
74     # 3. The flows are deleted in the flow cycle. Deletion happens either in
75     #    'bulk' (using the config_cleanup) script or one by one (using the
76     #     flow_config_blaster 'delete' method)
77     ############################################################################
78
79     parser = argparse.ArgumentParser(description='Flow programming performance test: First adds and then deletes flows '
80                                                  'into the config tree, as specified by optional parameters.')
81
82     parser.add_argument('--host', default='127.0.0.1',
83                         help='Host where odl controller is running (default is 127.0.0.1)')
84     parser.add_argument('--port', default='8181',
85                         help='Port on which odl\'s RESTCONF is listening (default is 8181)')
86     parser.add_argument('--cycles', type=int, default=1,
87                         help='Number of flow add/delete cycles; default 1. Both Flow Adds and Flow Deletes are '
88                              'performed in cycles. <THREADS> worker threads are started in each cycle and the cycle '
89                              'ends when all threads finish. Another cycle is started when the previous cycle finished.')
90     parser.add_argument('--threads', type=int, default=1,
91                         help='Number of request worker threads to start in each cycle; default=1. '
92                              'Each thread will add/delete <FLOWS> flows.')
93     parser.add_argument('--flows', type=int, default=10,
94                         help='Number of flows that will be added/deleted by each worker thread in each cycle; '
95                              'default 10')
96     parser.add_argument('--fpr', type=int, default=1,
97                         help='Flows-per-Request - number of flows (batch size) sent in each HTTP request; '
98                              'default 1')
99     parser.add_argument('--delay', type=int, default=2,
100                         help='Time (seconds) to between inventory polls when waiting for stats to catch up; default=1')
101     parser.add_argument('--timeout', type=int, default=100,
102                         help='The maximum time (seconds) to wait between the add and delete cycles; default=100')
103     parser.add_argument('--delete', dest='delete', action='store_true', default=True,
104                         help='Delete all added flows one by one, benchmark delete '
105                              'performance.')
106     parser.add_argument('--bulk-delete', dest='bulk_delete', action='store_true', default=False,
107                         help='Delete all flows in bulk; default=False')
108     parser.add_argument('--auth', dest='auth', action='store_true',
109                         help="Use authenticated access to REST (username: 'admin', password: 'admin'); default=False")
110     parser.add_argument('--startflow', type=int, default=0,
111                         help='The starting Flow ID; default=0')
112     parser.add_argument('--file', default='',
113                         help='File from which to read the JSON flow template; default: no file, use a built in '
114                              'template.')
115
116     in_args = parser.parse_args()
117
118     # Initialize
119     if in_args.file != '':
120         flow_template = get_json_from_file(in_args.file)
121     else:
122         flow_template = None
123
124     ic = InventoryCrawler(in_args.host, in_args.port, 0, 'operational', in_args.auth, False)
125
126     fct = FlowConfigBlaster(in_args.host, in_args.port, in_args.cycles, in_args.threads, in_args.fpr,
127                             16, in_args.flows, in_args.startflow, in_args.auth)
128     # Get the baseline stats. Required in Step 3 to validate if the delete
129     # function gets the controller back to the baseline
130     ic.crawl_inventory()
131     reported = ic.reported_flows
132     found = ic.found_flows
133
134     print 'Baseline:'
135     print '   Reported flows: %d' % reported
136     print '   Found flows:    %d' % found
137
138     # Run through <CYCLES> add cycles, where <THREADS> threads are started in
139     # each cycle and <FLOWS> flows are added from each thread
140     fct.add_blaster()
141
142     print '\n*** Total flows added: %d' % fct.get_ok_flows()
143     print '    HTTP[OK] results:  %d\n' % fct.get_ok_rqsts()
144
145     # Wait for stats to catch up
146     wait_for_stats(ic, found + fct.get_ok_flows(), in_args.timeout, in_args.delay)
147
148     # Run through <CYCLES> delete cycles, where <THREADS> threads  are started
149     # in each cycle and <FLOWS> flows previously added in an add cycle are
150     # deleted in each thread
151     if in_args.bulk_delete:
152         print '\nDeleting all flows in bulk:'
153         sts = cleanup_config_odl(in_args.host, in_args.port, in_args.auth)
154         if sts != 200:
155             print '   Failed to delete flows, code %d' % sts
156         else:
157             print '   All flows deleted.'
158     else:
159         print '\nDeleting flows one by one\n   ',
160         fct.delete_blaster()
161         print '\n*** Total flows deleted: %d' % fct.get_ok_flows()
162         print '    HTTP[OK] results:    %d\n' % fct.get_ok_rqsts()
163
164     # Wait for stats to catch up back to baseline
165     wait_for_stats(ic, found, in_args.timeout, in_args.delay)