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