Auto-generated patch by python-black
[integration/test.git] / tools / odl-mdsal-clustering-tests / clustering-performance-test / inventory_read_blaster.py
1 #!/usr/bin/python
2
3 import requests
4 import argparse
5 import time
6 import threading
7 import functools
8 import operator
9 import collections
10
11 from Queue import Queue
12
13
14 __author__ = "Gary Wu"
15 __email__ = "gary.wu1@huawei.com"
16
17
18 GET_HEADERS = {"Accept": "application/json"}
19
20 INVENTORY_URL = "http://%s:%d/restconf/%s/opendaylight-inventory:nodes"
21
22
23 class Timer(object):
24     def __init__(self, verbose=False):
25         self.verbose = verbose
26
27     def __enter__(self):
28         self.start = time.time()
29         return self
30
31     def __exit__(self, *args):
32         self.end = time.time()
33         self.secs = self.end - self.start
34         self.msecs = self.secs * 1000  # millisecs
35         if self.verbose:
36             print("elapsed time: %f ms" % self.msecs)
37
38
39 def read(hosts, port, auth, datastore, print_lock, cycles, results_queue):
40     """
41     Make RESTconf request to read the flow configuration from the specified data store.
42
43     Args:
44
45         :param hosts: A comma-separated list of hosts to read from.
46
47         :param port: The port number to read from.
48
49         :param auth: The username and password pair to use for basic authentication, or None
50             if no authentication is required.
51
52         :param datastore: The datastore (operational/config) to read flows from.
53
54         :param print_lock: The thread lock to allow only one thread to output at a time.
55
56         :param cycles: The number of reads that this thread will perform.
57
58         :param results_queue: Used to store the HTTP status results of this method call.
59     """
60     s = requests.Session()
61     stats = {}
62     for i in range(cycles):
63         host = hosts[i % len(hosts)]
64         url = INVENTORY_URL % (host, port, datastore)
65         r = s.get(url, headers=GET_HEADERS, stream=False, auth=auth)
66         # If dict has no such entry, default to 0
67         stats[r.status_code] = stats.get(r.status_code, 0) + 1
68
69     with print_lock:
70         print("   %s results: %s" % (threading.current_thread().name, stats))
71
72     results_queue.put(stats)
73
74
75 if __name__ == "__main__":
76     parser = argparse.ArgumentParser(
77         description="Inventory read performance test: Repeatedly read openflow node data "
78         "from config datastore.  Note that the data needs to be created in the datastore "
79         "first using flow_config_blaster.py --no-delete."
80     )
81
82     parser.add_argument(
83         "--host",
84         default="127.0.0.1",
85         help="Host where odl controller is running (default is 127.0.0.1).  "
86         "Specify a comma-separated list of hosts to perform round-robin load-balancing.",
87     )
88     parser.add_argument(
89         "--port",
90         default="8181",
91         type=int,
92         help="Port on which odl's RESTCONF is listening (default is 8181)",
93     )
94     parser.add_argument(
95         "--datastore",
96         choices=["operational", "config"],
97         default="operational",
98         help="Which data store to crawl; default operational",
99     )
100     parser.add_argument(
101         "--cycles",
102         type=int,
103         default=100,
104         help="Number of repeated reads; default 100. ",
105     )
106     parser.add_argument(
107         "--threads",
108         type=int,
109         default=1,
110         help="Number of request worker threads to start in each cycle; default=1. "
111         "Each thread will add/delete <FLOWS> flows.",
112     )
113     parser.add_argument(
114         "--auth",
115         dest="auth",
116         action="store_true",
117         default=False,
118         help="Use the ODL default username/password 'admin'/'admin' to authenticate access to REST; "
119         "default: no authentication",
120     )
121
122     args = parser.parse_args()
123
124     hosts = args.host.split(",")
125     port = args.port
126     auth = ("admin", "admin") if args.auth else None
127
128     # Use a lock to ensure that output from multiple threads don't interrupt/overlap each other
129     print_lock = threading.Lock()
130     results = Queue()
131
132     with Timer() as t:
133         threads = []
134         for i in range(args.threads):
135             thread = threading.Thread(
136                 target=read,
137                 args=(
138                     hosts,
139                     port,
140                     auth,
141                     args.datastore,
142                     print_lock,
143                     args.cycles,
144                     results,
145                 ),
146             )
147             threads.append(thread)
148             thread.start()
149
150         # Wait for all threads to finish and measure the execution time
151         for thread in threads:
152             thread.join()
153
154     # Aggregate the results
155     stats = functools.reduce(operator.add, map(collections.Counter, results.queue))
156
157     print("\n*** Test summary:")
158     print("    Elapsed time:    %.2fs" % t.secs)
159     print("    HTTP[OK] results:  %d\n" % stats[200])