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