Make pep8 more picky
[integration/test.git] / tools / odl-ovsdb-performance-tests / ovsdbconfigblaster.py
1 """
2 Script to add bridges/ports/termination points to ovsdb config
3 """
4 import argparse
5 import logging
6 import requests
7
8
9 __author__ = 'Marcus Williams'
10 __copyright__ = "Copyright (c) 2015, Intel Corp Inc., Cisco Systems Inc. and others"
11 __credits__ = ["Jan Medved, Lori Jakab"]
12 __license__ = "New-style BSD"
13 __email__ = "marcus.williams@intel.com"
14 __version__ = "0.0.1"
15
16
17 class OvsdbConfigBlaster (object):
18     PUT_HEADERS = {'Content-Type': 'application/json',
19                    'Authorization': 'Basic YWRtaW46YWRtaW4=',
20                    'Accept': 'application/json'}
21     GET_HEADERS = {'Accept': 'application/json',
22                    'Authorization': 'Basic YWRtaW46YWRtaW4='}
23     DELETE_HEADERS = {'Accept': 'application/json',
24                       'Authorization': 'Basic YWRtaW46YWRtaW4='}
25     TIMEOUT = 10
26
27     def __init__(self,
28                  controller_ip,
29                  controller_port,
30                  vswitch_ip,
31                  vswitch_ovsdb_port,
32                  vswitch_remote_ip,
33                  vswitch_remote_ovsdb_port,
34                  vswitch_port_type,
35                  vswitch_lst_del_br,
36                  num_instances):
37         """
38         Args:
39             :param controller_ip: The ODL host ip used to send RPCs
40             :param controller_port: The RESTCONF port on the ODL host
41             :param vswitch_ip: The ip of OpenvSwitch to use
42             :param vswitch_ovsdb_port: The ovsdb port of OpenvSwitch to use
43             :param vswitch_remote_ip: The ip of remote OpenvSwitch to use
44             :param vswitch_remote_ovsdb_port: The ovsdb port of remote OpenvSwitch to use
45             :param vswitch_port_type: Port type to create
46             :param vswitch_lst_del_br: string containing a list of ovs switches on which BR'S should be deleted.
47             :param num_instances: The number of instances (bridges, ports etc)to be added
48         """
49         logging.basicConfig(level=logging.DEBUG)
50         self.session = requests.Session()
51         self.controller_ip = controller_ip
52         self.controller_port = controller_port
53         self.vswitch_dict = dict()
54         self.add_vswitch_to_dict(
55             vswitch_ip,
56             vswitch_remote_ip,
57             vswitch_ovsdb_port, 'ovs-1')
58         if vswitch_remote_ip:
59             self.add_vswitch_to_dict(
60                 vswitch_remote_ip,
61                 vswitch_ip,
62                 vswitch_remote_ovsdb_port, 'ovs-2')
63         self.vswitch_port_type = vswitch_port_type
64         self.vswitch_lst_del_br = vswitch_lst_del_br
65         self.num_instances = num_instances
66         self.connect_vswitch(self.vswitch_dict['ovs-1'])
67         if self.vswitch_dict.get('ovs-2'):
68             self.connect_vswitch(self.vswitch_dict['ovs-2'])
69
70     @staticmethod
71     def return_ovsdb_url(vswitch_ip, vswitch_ovsdb_port, url_type="config"):
72         """ Return an ovsdb restconf url
73         Args:
74             :param vswitch_ip: The ip of Open vSwitch to use
75             :param vswitch_ovsdb_port: The ovsdb port of Open vSwitch to use
76             :param url_tyep: The type of url 'config' | 'oper'
77         """
78         url_prefix = None
79         if url_type == "config":
80             url_prefix = 'restconf/config/'
81         elif url_type == "oper":
82             url_prefix = 'restconf/operational/'
83         ovsdb_url = url_prefix \
84             + 'network-topology:' \
85             'network-topology/topology/' \
86             'ovsdb:1/node/ovsdb:%2F%2F' \
87             + vswitch_ip\
88             + ':' \
89             + vswitch_ovsdb_port
90         return ovsdb_url
91
92     def add_vswitch_to_dict(self, vswitch_ip, vswitch_remote_ip, vswitch_ovsdb_port, vswitch_name):
93
94         """ Add details of an Open vSwitch instance to self.vswitch_dict
95         Args:
96             :param vswitch_ip: The ip of Open vSwitch to use
97             :param vswitch_remote_ip: The ip of remote Open vSwitch to use
98             :param vswitch_ovsdb_port: The ovsdb port of Open vSwitch to use
99             :param vswitch_name: The name to label the added Open vSwitch instance
100         """
101         urlprefix = 'http://' \
102                     + self.controller_ip + \
103                     ':' \
104                     + self.controller_port + \
105                     '/'
106         self.vswitch_dict.update({
107             vswitch_name: {
108                 'name': vswitch_name,
109                 'ip': vswitch_ip,
110                 'remote-ip': vswitch_remote_ip,
111                 'ovsdb-port': vswitch_ovsdb_port,
112                 'node-id': 'ovsdb://%s:%s'
113                            % (vswitch_ip,
114                               vswitch_ovsdb_port),
115                 'post-url': urlprefix +
116                 OvsdbConfigBlaster.return_ovsdb_url(
117                     vswitch_ip,
118                     vswitch_ovsdb_port),
119                 'get-config-url': urlprefix +
120                 OvsdbConfigBlaster.return_ovsdb_url(
121                     vswitch_ip,
122                     vswitch_ovsdb_port),
123                 'get-oper-url': urlprefix +
124                 OvsdbConfigBlaster.return_ovsdb_url(
125                     vswitch_ip,
126                     vswitch_ovsdb_port)}})
127
128     def connect_vswitch(self, vswitch_dict):
129         """ Connect ODL to an Open vSwitch instance using restconf
130         Args:
131             :param vswitch_dict: A dictionary detailing
132                                  an instance of Open vSwitch
133         """
134         connect_ovs_body = {
135             u'network-topology:node': [
136                 {
137                     u'node-id': unicode(vswitch_dict['node-id']),
138                     u'connection-info': {
139                         u'ovsdb:remote-port': unicode(vswitch_dict['ovsdb-port']),
140                         u'ovsdb:remote-ip': unicode(vswitch_dict['ip'])
141                     }
142                 }
143             ]
144         }
145         self.send_rest(self.session,
146                        vswitch_dict['post-url'],
147                        connect_ovs_body)
148
149     def add_bridge(self, num_instances, vswitch_name='ovs-1'):
150         """Add num_instances of bridge to ODL config
151         Args:
152             :param num_instances: Number of bridges to create
153             :param vswitch_name: A name describing
154                                  an instance of Open vSwitch
155         """
156
157         for i in range(num_instances):
158             bridge_name = unicode('br-' + str(i) + '-test')
159             add_bridge_body = {
160                 u"network-topology:node": [
161                     {
162                         u"node-id": u"%s/bridge/%s"
163                                     % (unicode(self.vswitch_dict[vswitch_name]
164                                                .get('node-id')),
165                                        unicode(bridge_name)),
166                         u"ovsdb:bridge-name": unicode(bridge_name),
167                         u"ovsdb:datapath-id": u"00:00:b2:bf:48:25:f2:4b",
168                         u"ovsdb:protocol-entry": [
169                             {
170                                 u"protocol":
171                                     u"ovsdb:ovsdb-bridge-protocol-openflow-13"
172                             }],
173                         u"ovsdb:controller-entry": [
174                             {
175                                 u"target": u"tcp:%s:%s" % (self.controller_ip, self.controller_port)
176                             }],
177                         u"ovsdb:managed-by": u"/network-topology:network-topology/"
178                                              u"network-topology:topology"
179                                              u"[network-topology:topology-id"
180                                              u"='ovsdb:1']/network-topology:node"
181                                              u"[network-topology:node-id="
182                                              u"'%s']"
183                                              % unicode(self.vswitch_dict[vswitch_name]
184                                                            .get('node-id'))
185                     }
186                 ]
187             }
188             self.send_rest(self.session,
189                            self.vswitch_dict[vswitch_name]
190                            .get('post-url') +
191                            '%2Fbridge%2F' +
192                            bridge_name,
193                            add_bridge_body)
194         self.session.close()
195
196     def add_port(self, port_type="ovsdb:interface-type-vxlan"):
197         """Add self.num_instances of port to ODL config
198         Args:
199             :param port_type: The type of port to create
200                                 default: 'ovsdb:interface-type-vxlan'
201         """
202         bridge_name = 'br-0-test'
203         self.add_bridge(1, 'ovs-1')
204 #        self.add_bridge(1, 'ovs-2')
205
206         for instance in range(self.num_instances):
207             for vswitch in self.vswitch_dict.itervalues():
208                 if port_type == "ovsdb:interface-type-vxlan":
209                     port_prefix = "tp-"
210                     ovsdb_rest_url = vswitch.get('post-url') \
211                         + '%2Fbridge%2F'\
212                         + bridge_name\
213                         + '/termination-point/'
214                     body_name = 'tp-body'
215                 else:
216                     port_prefix = "port-"
217                     ovsdb_rest_url = vswitch.get('post-url') \
218                         + '%2Fbridge%2F' \
219                         + bridge_name\
220                         + '/port/'
221                     body_name = 'port-body'
222                 port_name = port_prefix + str(instance) + '-test-' + vswitch.get('ip')
223                 body = {'tp-body': {
224                     u"network-topology:termination-point": [
225                         {
226                             u"ovsdb:options": [
227                                 {
228                                     u"ovsdb:option": u"remote_ip",
229                                     u"ovsdb:value": unicode(vswitch.get('remote-ip'))
230                                 }
231                             ],
232                             u"ovsdb:name": unicode(port_name),
233                             u"ovsdb:interface-type": unicode(port_type),
234                             u"tp-id": unicode(port_name),
235                             u"vlan-tag": unicode(instance + 1),
236                             u"trunks": [
237                                 {
238                                     u"trunk": u"5"
239                                 }
240                             ],
241                             u"vlan-mode": u"access"
242                         }
243                     ]
244                 },
245                     # TODO add port-body
246                     'port-body': {}}
247                 self.send_rest(self.session,
248                                ovsdb_rest_url + port_name,
249                                body.get(body_name))
250
251         self.session.close()
252
253     def delete_bridge(self, vswitch_lst_del_br, num_bridges):
254         """Delete num_instances of bridge in ODL config
255         Args:
256             :param num_bridges: Number of bridges to delete
257             :param vswitch_lst_del_br: A list containing instances of Open vSwitch on which bridges should be deleted.
258         """
259         for vswitch_names in vswitch_lst_del_br:
260             for br_num in range(num_bridges):
261                 bridge_name = unicode('br-' + str(br_num) + '-test')
262                 self.send_rest_del(self.session,
263                                    self.vswitch_dict[vswitch_names]
264                                    .get('post-url') +
265                                    '%2Fbridge%2F' +
266                                    bridge_name)
267             self.session.close()
268
269     def send_rest_del(self, session, rest_url):
270         """Send an HTTP DELETE to the Rest URL and return the status code
271         Args:
272             :param session: The HTTP session handle
273             :return int: status_code - HTTP status code
274         """
275         ret = session.delete(rest_url,
276                              headers=self.DELETE_HEADERS,
277                              stream=False,
278                              timeout=self.TIMEOUT)
279
280         if ret.status_code is not 200:
281             raise ValueError(ret.text,
282                              ret.status_code,
283                              rest_url)
284         return ret.status_code
285
286     def send_rest(self, session, rest_url, json_body):
287         """Send an HTTP PUT to the Rest URL and return the status code
288         Args:
289             :param session: The HTTP session handle
290             :param json_body: the JSON body to be sent
291         Returns:
292             :return int: status_code - HTTP status code
293         """
294         ret = session.put(rest_url,
295                           json=json_body,
296                           headers=self.PUT_HEADERS,
297                           stream=False,
298                           timeout=self.TIMEOUT)
299
300         if ret.status_code is not 200:
301             raise ValueError(ret.text,
302                              ret.status_code,
303                              rest_url,
304                              json_body)
305         return ret.status_code
306
307 if __name__ == "__main__":
308     parser = argparse.ArgumentParser(description='Add:delete bridge/port/term-points to OpenDaylight')
309
310     parser.add_argument('--mode', default='None',
311                         help='Operating mode, can be "bridge", "port" or "term" \
312                             (default is "bridge")')
313     parser.add_argument('--controller', default='127.0.0.1',
314                         help='IP of running ODL controller \
315                              (default is 127.0.0.1)')
316     parser.add_argument('--controllerport', default='8181',
317                         help='Port of ODL RESTCONF \
318                             (default is 8181)')
319     parser.add_argument('--vswitch', default='127.0.0.1',
320                         help='IP of Open vSwitch \
321                             (default is 127.0.0.1)')
322     parser.add_argument('--vswitchport', default='6640',
323                         help='Port of Open vSwitch OVSDB server \
324                             (default is 6640)')
325     parser.add_argument('--vswitchremote', default=None,
326                         help='IP of remote Open vSwitch \
327                             (default is none)')
328     parser.add_argument('--vswitchremoteport', default=None,
329                         help='Port of remote Open vSwitch OVSDB server \
330                             (default is none)')
331     parser.add_argument('--vswitchporttype', default=None,
332                         help='Port of remote Open vSwitch OVSDB server \
333                             (default is none)')
334     parser.add_argument('--deletebridges', nargs='*', type=str, default=None,
335                         help='A list of switches on which to delete bridges, '
336                              'uses instances for number of bridges. \
337                               Example: "ovs-1 ovs2" \
338                             (default is none)')
339     parser.add_argument('--instances', type=int, default=1,
340                         help='Number of instances to add/get (default 1)')
341
342     args = parser.parse_args()
343
344     ovsdb_config_blaster = OvsdbConfigBlaster(args.controller,
345                                               args.controllerport,
346                                               args.vswitch,
347                                               args.vswitchport,
348                                               args.vswitchremote,
349                                               args.vswitchremoteport,
350                                               args.vswitchporttype,
351                                               args.deletebridges,
352                                               args.instances)
353
354     if args.mode == "bridge":
355         if args.deletebridges is not None:
356             ovsdb_config_blaster.delete_bridge(ovsdb_config_blaster.
357                                                vswitch_lst_del_br,
358                                                ovsdb_config_blaster.
359                                                num_instances)
360         else:
361             ovsdb_config_blaster.add_bridge(ovsdb_config_blaster.num_instances)
362     elif args.mode == "term":
363         ovsdb_config_blaster.add_port()
364     elif args.mode == "port" and args.vswitchporttype is not None:
365         ovsdb_config_blaster.add_port(args.vswitchporttype)
366     else:
367         print "please use: python ovsdbconfigblaster.py --help " \
368               "\nUnsupported mode: ", args.mode