]> git.proxmox.com Git - ovs.git/blame - tests/test-ovsdb.py
Implement initial Python bindings for Open vSwitch database.
[ovs.git] / tests / test-ovsdb.py
CommitLineData
99155935
BP
1# Copyright (c) 2009, 2010 Nicira Networks
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at:
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import codecs
16import getopt
17import re
18import os
19import signal
20import sys
21
22from ovs.db import error
23import ovs.db.idl
24import ovs.db.schema
25from ovs.db import data
26from ovs.db import types
27import ovs.ovsuuid
28import ovs.poller
29import ovs.util
30
31def unbox_json(json):
32 if type(json) == list and len(json) == 1:
33 return json[0]
34 else:
35 return json
36
37def do_default_atoms():
38 for type in types.ATOMIC_TYPES:
39 if type == types.VoidType:
40 continue
41
42 sys.stdout.write("%s: " % type.to_string())
43
44 atom = data.Atom.default(type)
45 if atom != data.Atom.default(type):
46 sys.stdout.write("wrong\n")
47 sys.exit(1)
48
49 sys.stdout.write("OK\n")
50
51def do_default_data():
52 any_errors = False
53 for n_min in 0, 1:
54 for key in types.ATOMIC_TYPES:
55 if key == types.VoidType:
56 continue
57 for value in types.ATOMIC_TYPES:
58 if value == types.VoidType:
59 valueBase = None
60 else:
61 valueBase = types.BaseType(value)
62 type = types.Type(types.BaseType(key), valueBase, n_min, 1)
63 assert type.is_valid()
64
65 sys.stdout.write("key %s, value %s, n_min %d: "
66 % (key.to_string(), value.to_string(), n_min))
67
68 datum = data.Datum.default(type)
69 if datum != data.Datum.default(type):
70 sys.stdout.write("wrong\n")
71 any_errors = True
72 else:
73 sys.stdout.write("OK\n")
74 if any_errors:
75 sys.exit(1)
76
77def do_parse_atomic_type(type_string):
78 type_json = unbox_json(ovs.json.from_string(type_string))
79 atomic_type = types.AtomicType.from_json(type_json)
80 print ovs.json.to_string(atomic_type.to_json(), sort_keys=True)
81
82def do_parse_base_type(type_string):
83 type_json = unbox_json(ovs.json.from_string(type_string))
84 base_type = types.BaseType.from_json(type_json)
85 print ovs.json.to_string(base_type.to_json(), sort_keys=True)
86
87def do_parse_type(type_string):
88 type_json = unbox_json(ovs.json.from_string(type_string))
89 type = types.Type.from_json(type_json)
90 print ovs.json.to_string(type.to_json(), sort_keys=True)
91
92def do_parse_atoms(type_string, *atom_strings):
93 type_json = unbox_json(ovs.json.from_string(type_string))
94 base = types.BaseType.from_json(type_json)
95 for atom_string in atom_strings:
96 atom_json = unbox_json(ovs.json.from_string(atom_string))
97 try:
98 atom = data.Atom.from_json(base, atom_json)
99 print ovs.json.to_string(atom.to_json())
100 except error.Error, e:
101 print e
102
103def do_parse_data(type_string, *data_strings):
104 type_json = unbox_json(ovs.json.from_string(type_string))
105 type = types.Type.from_json(type_json)
106 for datum_string in data_strings:
107 datum_json = unbox_json(ovs.json.from_string(datum_string))
108 datum = data.Datum.from_json(type, datum_json)
109 print ovs.json.to_string(datum.to_json())
110
111def do_sort_atoms(type_string, atom_strings):
112 type_json = unbox_json(ovs.json.from_string(type_string))
113 base = types.BaseType.from_json(type_json)
114 atoms = [data.Atom.from_json(base, atom_json)
115 for atom_json in unbox_json(ovs.json.from_string(atom_strings))]
116 print ovs.json.to_string([data.Atom.to_json(atom)
117 for atom in sorted(atoms)])
118
119def do_parse_column(name, column_string):
120 column_json = unbox_json(ovs.json.from_string(column_string))
121 column = ovs.db.schema.ColumnSchema.from_json(column_json, name)
122 print ovs.json.to_string(column.to_json(), sort_keys=True)
123
124def do_parse_table(name, table_string):
125 table_json = unbox_json(ovs.json.from_string(table_string))
126 table = ovs.db.schema.TableSchema.from_json(table_json, name)
127 print ovs.json.to_string(table.to_json(), sort_keys=True)
128
129def do_parse_rows(table_string, *rows):
130 table_json = unbox_json(ovs.json.from_string(table_string))
131 table = ovs.db.schema.TableSchema.from_json(table_json, name)
132
133def do_parse_schema(schema_string):
134 schema_json = unbox_json(ovs.json.from_string(schema_string))
135 schema = ovs.db.schema.DbSchema.from_json(schema_json)
136 print ovs.json.to_string(schema.to_json(), sort_keys=True)
137
138def print_idl(idl, step):
139 n = 0
140 for uuid, row in idl.data["simple"].iteritems():
141 s = ("%03d: i=%s r=%s b=%s s=%s u=%s "
142 "ia=%s ra=%s ba=%s sa=%s ua=%s uuid=%s"
143 % (step, row.i, row.r, row.b, row.s, row.u,
144 row.ia, row.ra, row.ba, row.sa, row.ua, uuid))
145 print(re.sub('""|,', "", s))
146 n += 1
147 if not n:
148 print("%03d: empty" % step)
149
150def substitute_uuids(json, symtab):
151 if type(json) in [str, unicode]:
152 symbol = symtab.get(json)
153 if symbol:
154 return str(symbol)
155 elif type(json) == list:
156 return [substitute_uuids(element, symtab) for element in json]
157 elif type(json) == dict:
158 d = {}
159 for key, value in json.iteritems():
160 d[key] = substitute_uuids(value, symtab)
161 return d
162 return json
163
164def parse_uuids(json, symtab):
165 if type(json) in [str, unicode] and ovs.ovsuuid.UUID.is_valid_string(json):
166 name = "#%d#" % len(symtab)
167 sys.stderr.write("%s = %s\n" % (name, json))
168 symtab[name] = json
169 elif type(json) == list:
170 for element in json:
171 parse_uuids(element, symtab)
172 elif type(json) == dict:
173 for value in json.itervalues():
174 parse_uuids(value, symtab)
175
176def do_idl(remote, *commands):
177 idl = ovs.db.idl.Idl(remote, "idltest")
178
179 if commands:
180 error, stream = ovs.stream.Stream.open_block(
181 ovs.stream.Stream.open(remote))
182 if error:
183 sys.stderr.write("failed to connect to \"%s\"" % remote)
184 sys.exit(1)
185 rpc = ovs.jsonrpc.Connection(stream)
186 else:
187 rpc = None
188
189 symtab = {}
190 seqno = 0
191 step = 0
192 for command in commands:
193 if command.startswith("+"):
194 # The previous transaction didn't change anything.
195 command = command[1:]
196 else:
197 # Wait for update.
198 while idl.get_seqno() == seqno and not idl.run():
199 rpc.run()
200
201 poller = ovs.poller.Poller()
202 idl.wait(poller)
203 rpc.wait(poller)
204 poller.block()
205
206 print_idl(idl, step)
207 step += 1
208
209 seqno = idl.get_seqno()
210
211 if command == "reconnect":
212 print("%03d: reconnect" % step)
213 step += 1
214 idl.force_reconnect()
215 elif not command.startswith("["):
216 idl_set(idl, command, step)
217 step += 1
218 else:
219 json = ovs.json.from_string(command)
220 if type(json) in [str, unicode]:
221 sys.stderr.write("\"%s\": %s\n" % (command, json))
222 sys.exit(1)
223 json = substitute_uuids(json, symtab)
224 request = ovs.jsonrpc.Message.create_request("transact", json)
225 error, reply = rpc.transact_block(request)
226 if error:
227 sys.stderr.write("jsonrpc transaction failed: %s"
228 % os.strerror(error))
229 sys.exit(1)
230 sys.stdout.write("%03d: " % step)
231 sys.stdout.flush()
232 step += 1
233 if reply.result is not None:
234 parse_uuids(reply.result, symtab)
235 reply.id = None
236 sys.stdout.write("%s\n" % ovs.json.to_string(reply.to_json()))
237
238 if rpc:
239 rpc.close()
240 while idl.get_seqno() == seqno and not idl.run():
241 poller = ovs.poller.Poller()
242 idl.wait(poller)
243 poller.block()
244 print_idl(idl, step)
245 step += 1
246 idl.close()
247 print("%03d: done" % step)
248
249def usage():
250 print """\
251%(program_name)s: test utility for Open vSwitch database Python bindings
252usage: %(program_name)s [OPTIONS] COMMAND ARG...
253
254The following commands are supported:
255default-atoms
256 test ovsdb_atom_default()
257default-data
258 test ovsdb_datum_default()
259parse-atomic-type TYPE
260 parse TYPE as OVSDB atomic type, and re-serialize
261parse-base-type TYPE
262 parse TYPE as OVSDB base type, and re-serialize
263parse-type JSON
264 parse JSON as OVSDB type, and re-serialize
265parse-atoms TYPE ATOM...
266 parse JSON ATOMs as atoms of TYPE, and re-serialize
267parse-atom-strings TYPE ATOM...
268 parse string ATOMs as atoms of given TYPE, and re-serialize
269sort-atoms TYPE ATOM...
270 print JSON ATOMs in sorted order
271parse-data TYPE DATUM...
272 parse JSON DATUMs as data of given TYPE, and re-serialize
273parse-column NAME OBJECT
274 parse column NAME with info OBJECT, and re-serialize
275parse-table NAME OBJECT
276 parse table NAME with info OBJECT
277parse-schema JSON
278 parse JSON as an OVSDB schema, and re-serialize
279idl SERVER [TRANSACTION...]
280 connect to SERVER and dump the contents of the database
281 as seen initially by the IDL implementation and after
282 executing each TRANSACTION. (Each TRANSACTION must modify
283 the database or this command will hang.)
284
285The following options are also available:
286 -t, --timeout=SECS give up after SECS seconds
287 -h, --help display this help message\
288""" % {'program_name': ovs.util.PROGRAM_NAME}
289 sys.exit(0)
290
291def main(argv):
292 # Make stdout and stderr UTF-8, even if they are redirected to a file.
293 sys.stdout = codecs.getwriter("utf-8")(sys.stdout)
294 sys.stderr = codecs.getwriter("utf-8")(sys.stderr)
295
296 try:
297 options, args = getopt.gnu_getopt(argv[1:], 't:h',
298 ['timeout',
299 'help'])
300 except getopt.GetoptError, geo:
301 sys.stderr.write("%s: %s\n" % (ovs.util.PROGRAM_NAME, geo.msg))
302 sys.exit(1)
303
304 for key, value in options:
305 if key in ['-h', '--help']:
306 usage()
307 elif key in ['-t', '--timeout']:
308 try:
309 timeout = int(value)
310 if timeout < 1:
311 raise TypeError
312 except TypeError:
313 raise error.Error("value %s on -t or --timeout is not at "
314 "least 1" % value)
315 signal.alarm(timeout)
316 else:
317 sys.exit(0)
318
319 optKeys = [key for key, value in options]
320
321 if not args:
322 sys.stderr.write("%s: missing command argument "
323 "(use --help for help)\n" % ovs.util.PROGRAM_NAME)
324 sys.exit(1)
325
326 commands = {"default-atoms": (do_default_atoms, 0),
327 "default-data": (do_default_data, 0),
328 "parse-atomic-type": (do_parse_atomic_type, 1),
329 "parse-base-type": (do_parse_base_type, 1),
330 "parse-type": (do_parse_type, 1),
331 "parse-atoms": (do_parse_atoms, (2,)),
332 "parse-data": (do_parse_data, (2,)),
333 "sort-atoms": (do_sort_atoms, 2),
334 "parse-column": (do_parse_column, 2),
335 "parse-table": (do_parse_table, 2),
336 "parse-schema": (do_parse_schema, 1),
337 "idl": (do_idl, (1,))}
338
339 command_name = args[0]
340 args = args[1:]
341 if not command_name in commands:
342 sys.stderr.write("%s: unknown command \"%s\" "
343 "(use --help for help)\n" % (ovs.util.PROGRAM_NAME,
344 command_name))
345 sys.exit(1)
346
347 func, n_args = commands[command_name]
348 if type(n_args) == tuple:
349 if len(args) < n_args[0]:
350 sys.stderr.write("%s: \"%s\" requires at least %d arguments but "
351 "only %d provided\n"
352 % (ovs.util.PROGRAM_NAME, command_name,
353 n_args, len(args)))
354 sys.exit(1)
355 elif type(n_args) == int:
356 if len(args) != n_args:
357 sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
358 "provided\n"
359 % (ovs.util.PROGRAM_NAME, command_name,
360 n_args, len(args)))
361 sys.exit(1)
362 else:
363 assert False
364
365 func(*args)
366
367if __name__ == '__main__':
368 try:
369 main(sys.argv)
370 except error.Error, e:
371 sys.stderr.write("%s\n" % e)
372 sys.exit(1)