Auto-generated patch by python-black
[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(
61             "Stats collection did not finish in %d seconds. Aborting..." % total_delay
62         )
63
64
65 if __name__ == "__main__":
66     ############################################################################
67     # This program executes an ODL performance test. The test is executed in
68     # three steps:
69     #
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     ############################################################################
80
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."
84     )
85
86     parser.add_argument(
87         "--host",
88         default="127.0.0.1",
89         help="Host where odl controller is running (default is 127.0.0.1)",
90     )
91     parser.add_argument(
92         "--port",
93         default="8181",
94         help="Port on which odl's RESTCONF is listening (default is 8181)",
95     )
96     parser.add_argument(
97         "--cycles",
98         type=int,
99         default=1,
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.",
103     )
104     parser.add_argument(
105         "--threads",
106         type=int,
107         default=1,
108         help="Number of request worker threads to start in each cycle; default=1. "
109         "Each thread will add/delete <FLOWS> flows.",
110     )
111     parser.add_argument(
112         "--flows",
113         type=int,
114         default=10,
115         help="Number of flows that will be added/deleted by each worker thread in each cycle; "
116         "default 10",
117     )
118     parser.add_argument(
119         "--fpr",
120         type=int,
121         default=1,
122         help="Flows-per-Request - number of flows (batch size) sent in each HTTP request; "
123         "default 1",
124     )
125     parser.add_argument(
126         "--delay",
127         type=int,
128         default=2,
129         help="Time (seconds) to between inventory polls when waiting for stats to catch up; default=1",
130     )
131     parser.add_argument(
132         "--timeout",
133         type=int,
134         default=100,
135         help="The maximum time (seconds) to wait between the add and delete cycles; default=100",
136     )
137     parser.add_argument(
138         "--delete",
139         dest="delete",
140         action="store_true",
141         default=True,
142         help="Delete all added flows one by one, benchmark delete " "performance.",
143     )
144     parser.add_argument(
145         "--bulk-delete",
146         dest="bulk_delete",
147         action="store_true",
148         default=False,
149         help="Delete all flows in bulk; default=False",
150     )
151     parser.add_argument(
152         "--auth",
153         dest="auth",
154         action="store_true",
155         help="Use authenticated access to REST (username: 'admin', password: 'admin'); default=False",
156     )
157     parser.add_argument(
158         "--startflow", type=int, default=0, help="The starting Flow ID; default=0"
159     )
160     parser.add_argument(
161         "--file",
162         default="",
163         help="File from which to read the JSON flow template; default: no file, use a built in "
164         "template.",
165     )
166
167     in_args = parser.parse_args()
168
169     # Initialize
170     if in_args.file != "":
171         flow_template = get_json_from_file(in_args.file)
172     else:
173         flow_template = None
174
175     ic = InventoryCrawler(
176         in_args.host, in_args.port, 0, "operational", in_args.auth, False
177     )
178
179     fct = FlowConfigBlaster(
180         in_args.host,
181         in_args.port,
182         in_args.cycles,
183         in_args.threads,
184         in_args.fpr,
185         16,
186         in_args.flows,
187         in_args.startflow,
188         in_args.auth,
189     )
190     # Get the baseline stats. Required in Step 3 to validate if the delete
191     # function gets the controller back to the baseline
192     ic.crawl_inventory()
193     reported = ic.reported_flows
194     found = ic.found_flows
195
196     print("Baseline:")
197     print("   Reported flows: %d" % reported)
198     print("   Found flows:    %d" % found)
199
200     # Run through <CYCLES> add cycles, where <THREADS> threads are started in
201     # each cycle and <FLOWS> flows are added from each thread
202     fct.add_blaster()
203
204     print("\n*** Total flows added: %d" % fct.get_ok_flows())
205     print("    HTTP[OK] results:  %d\n" % fct.get_ok_rqsts())
206
207     # Wait for stats to catch up
208     wait_for_stats(ic, found + fct.get_ok_flows(), in_args.timeout, in_args.delay)
209
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)
216         if sts != 200:
217             print("   Failed to delete flows, code %d" % sts)
218         else:
219             print("   All flows deleted.")
220     else:
221         print("\nDeleting flows one by one\n   ")
222         fct.delete_blaster()
223         print("\n*** Total flows deleted: %d" % fct.get_ok_flows())
224         print("    HTTP[OK] results:    %d\n" % fct.get_ok_rqsts())
225
226     # Wait for stats to catch up back to baseline
227     wait_for_stats(ic, found, in_args.timeout, in_args.delay)