Migrate Get Requests invocations(libraries)
[integration/test.git] / tools / odl-mdsal-clustering-tests / clustering-performance-test / flow_config_blaster_fle.py
1 #!/usr/bin/python
2 from flow_config_blaster import FlowConfigBlaster
3 import argparse
4 import time
5 import json
6 import copy
7 import requests
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 FlowConfigBlasterFLE(FlowConfigBlaster):
17     """
18     FlowConfigBlaster, Floodlight Edition; Uses the Floodlight Static Flow Entry Pusher REST API to inject flows.
19     """
20
21     flow = {
22         "switch": "00:00:00:00:00:00:00:01",
23         "name": "flow-mod",
24         "cookie": "0",
25         "priority": "32768",
26         "eth_type": "2048",
27         "ipv4_dst": "10.0.0.1/32",
28         "active": "true",
29         "actions": "output=flood",
30     }
31
32     def __init__(self, host, port, ncycles, nthreads, nnodes, nflows, startflow):
33         FlowConfigBlaster.__init__(
34             self, host, port, ncycles, nthreads, 1, nnodes, nflows, startflow, False
35         )
36
37     def create_floodlight_url(self, host):
38         return "http://" + host + ":" + self.port + "/wm/staticflowpusher/json"
39
40     def get_num_nodes(self, session):
41         """
42         Determines the number of nodes in the network. Overrides the get_num_nodes method in FlowConfigBlaster.
43         :param session:
44         :return:
45         """
46         url = (
47             "http://"
48             + self.host
49             + ":"
50             + self.port
51             + "/wm/core/controller/switches/json"
52         )
53         nodes = self.nnodes
54
55         r = session.get(url, headers=self.getheaders, stream=False)
56
57         if r.status_code == 200:
58             try:
59                 nodes = len(json.loads(r.content))
60             except KeyError:
61                 pass
62
63         return nodes
64
65     def post_flows(self, session, node, flow_list, flow_count):
66         """
67         Performs a RESTCONF post of flows passed in the 'flow_list' parameters
68         :param session: 'requests' session on which to perform the POST
69         :param node: The ID of the openflow node to which to post the flows
70         :param flow_list: List of flows (in dictionary form) to POST
71         :param flow_count: Number of flows in flow_list (must be 1)
72         :return: status code from the POST operation
73         """
74         flow = copy.deepcopy(self.flow)
75         flow["switch"] = "00:00:00:00:00:00:00:%s" % "{0:02x}".format(node)
76         flow["name"] = flow_list[0]["flow-name"]
77         flow["table"] = flow_list[0]["table_id"]
78         flow["cookie"] = flow_list[0]["cookie"]
79         # flow['cookie_mask'] = flow_list[0]['cookie_mask']
80         flow["idle_timeout"] = flow_list[0]["idle-timeout"]
81         flow["hard_timeout"] = flow_list[0]["hard-timeout"]
82         flow["ipv4_dst"] = flow_list[0]["match"]["ipv4-destination"]
83
84         flow_data = json.dumps(flow)
85
86         hosts = self.host.split(",")
87         host = hosts[flow_count % len(hosts)]
88         flow_url = self.create_floodlight_url(host)
89
90         r = session.post(
91             flow_url, data=flow_data, headers=self.putheaders, stream=False
92         )
93         return r.status_code
94
95     def delete_flow(self, session, node, flow_id, flow_count):
96         """
97         Deletes a single flow from the ODL config data store using RESTCONF
98         :param session: 'requests' session on which to perform the POST
99         :param node: Id of the openflow node from which to delete the flow
100         :param flow_id: ID of the to-be-deleted flow
101         :param flow_count: Flow counter for round-robin of delete operations
102         :return: status code from the DELETE operation
103         """
104
105         hosts = self.host.split(",")
106         host = hosts[flow_count % len(hosts)]
107         flow_url = self.create_floodlight_url(host)
108         flow_data = json.dumps({"name": self.create_flow_name(flow_id)})
109
110         r = session.delete(flow_url, data=flow_data, headers=self.getheaders)
111         return r.status_code
112
113     def clear_all_flows(self):
114         clear_url = (
115             "http://"
116             + self.host
117             + ":"
118             + self.port
119             + "/wm/staticflowpusher/clear/all/json"
120         )
121         r = requests.get(clear_url)
122         if r.status_code == 200:
123             print("All flows cleared before the test")
124         else:
125             print("Failed to clear flows from the controller, your results may vary")
126
127
128 if __name__ == "__main__":
129
130     parser = argparse.ArgumentParser(
131         description="Flow programming performance test for Floodlight: First adds and "
132         "then deletes flows using the Static Flow Entry Pusher REST API."
133     )
134
135     parser.add_argument(
136         "--host",
137         default="127.0.0.1",
138         help="Host where the controller is running (default is 127.0.0.1)",
139     )
140     parser.add_argument(
141         "--port",
142         default="8080",
143         help="Port on which the controller's RESTCONF is listening (default is 8080)",
144     )
145     parser.add_argument(
146         "--cycles",
147         type=int,
148         default=1,
149         help="Number of flow add/delete cycles; default 1. Both Flow Adds and Flow Deletes are "
150         "performed in cycles. <THREADS> worker threads are started in each cycle and the cycle "
151         "ends when all threads finish. Another cycle is started when the previous cycle finished.",
152     )
153     parser.add_argument(
154         "--threads",
155         type=int,
156         default=1,
157         help="Number of request worker threads to start in each cycle; default=1. "
158         "Each thread will add/delete <FLOWS> flows.",
159     )
160     parser.add_argument(
161         "--flows",
162         type=int,
163         default=10,
164         help="Number of flows that will be added/deleted by each worker thread in each cycle; "
165         "default 10",
166     )
167     parser.add_argument(
168         "--nodes",
169         type=int,
170         default=16,
171         help="Number of nodes if mininet is not connected; default=16. If mininet is connected, "
172         "flows will be evenly distributed (programmed) into connected nodes.",
173     )
174     parser.add_argument(
175         "--delay",
176         type=int,
177         default=0,
178         help="Time (in seconds) to wait between the add and delete cycles; default=0",
179     )
180     parser.add_argument(
181         "--no-delete",
182         dest="delete",
183         action="store_false",
184         help="Do not perform the delete cycle.",
185     )
186     parser.add_argument(
187         "--startflow", type=int, default=0, help="The starting Flow ID; default=0"
188     )
189
190     in_args = parser.parse_args()
191
192     fct = FlowConfigBlasterFLE(
193         in_args.host,
194         in_args.port,
195         in_args.cycles,
196         in_args.threads,
197         in_args.nodes,
198         in_args.flows,
199         in_args.startflow,
200     )
201
202     fct.clear_all_flows()
203
204     # Run through <cycles>, where <threads> are started in each cycle and <flows> are added from each thread
205     fct.add_blaster()
206
207     print("\n*** Total flows added: %s" % fct.get_ok_flows())
208     print("    HTTP[OK] results:  %d\n" % fct.get_ok_rqsts())
209
210     if in_args.delay > 0:
211         print(
212             "*** Waiting for %d seconds before the delete cycle ***\n" % in_args.delay
213         )
214         time.sleep(in_args.delay)
215
216     # Run through <cycles>, where <threads> are started in each cycle and <flows> previously added in an add cycle are
217     # deleted in each thread
218     if in_args.delete:
219         fct.delete_blaster()
220         print("\n*** Total flows deleted: %s" % fct.get_ok_flows())
221         print("    HTTP[OK] results:    %d\n" % fct.get_ok_rqsts())