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