11 from Queue import Queue
14 __author__ = "Gary Wu"
15 __email__ = "gary.wu1@huawei.com"
18 GET_HEADERS = {"Accept": "application/json"}
20 INVENTORY_URL = "http://%s:%d/restconf/%s/opendaylight-inventory:nodes"
24 def __init__(self, verbose=False):
25 self.verbose = verbose
28 self.start = time.time()
31 def __exit__(self, *args):
32 self.end = time.time()
33 self.secs = self.end - self.start
34 self.msecs = self.secs * 1000 # millisecs
36 print("elapsed time: %f ms" % self.msecs)
39 def read(hosts, port, auth, datastore, print_lock, cycles, results_queue):
41 Make RESTconf request to read the flow configuration from the specified data store.
45 :param hosts: A comma-separated list of hosts to read from.
47 :param port: The port number to read from.
49 :param auth: The username and password pair to use for basic authentication, or None
50 if no authentication is required.
52 :param datastore: The datastore (operational/config) to read flows from.
54 :param print_lock: The thread lock to allow only one thread to output at a time.
56 :param cycles: The number of reads that this thread will perform.
58 :param results_queue: Used to store the HTTP status results of this method call.
60 s = requests.Session()
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
70 print(" %s results: %s" % (threading.current_thread().name, stats))
72 results_queue.put(stats)
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."
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.",
92 help="Port on which odl's RESTCONF is listening (default is 8181)",
96 choices=["operational", "config"],
97 default="operational",
98 help="Which data store to crawl; default operational",
104 help="Number of repeated reads; default 100. ",
110 help="Number of request worker threads to start in each cycle; default=1. "
111 "Each thread will add/delete <FLOWS> flows.",
118 help="Use the ODL default username/password 'admin'/'admin' to authenticate access to REST; "
119 "default: no authentication",
122 args = parser.parse_args()
124 hosts = args.host.split(",")
126 auth = ("admin", "admin") if args.auth else None
128 # Use a lock to ensure that output from multiple threads don't interrupt/overlap each other
129 print_lock = threading.Lock()
134 for i in range(args.threads):
135 thread = threading.Thread(
147 threads.append(thread)
150 # Wait for all threads to finish and measure the execution time
151 for thread in threads:
154 # Aggregate the results
155 stats = functools.reduce(operator.add, map(collections.Counter, results.queue))
157 print("\n*** Test summary:")
158 print(" Elapsed time: %.2fs" % t.secs)
159 print(" HTTP[OK] results: %d\n" % stats[200])