]> git.proxmox.com Git - ovs.git/blob - tests/test-ovsdb.py
python: Fix exception handler compatibility.
[ovs.git] / tests / test-ovsdb.py
1 # Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
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
15 import getopt
16 import re
17 import os
18 import signal
19 import sys
20 import uuid
21
22 from ovs.db import error
23 import ovs.db.idl
24 import ovs.db.schema
25 from ovs.db import data
26 import ovs.db.types
27 import ovs.ovsuuid
28 import ovs.poller
29 import ovs.util
30
31
32 def unbox_json(json):
33 if type(json) == list and len(json) == 1:
34 return json[0]
35 else:
36 return json
37
38
39 def do_default_atoms():
40 for type_ in ovs.db.types.ATOMIC_TYPES:
41 if type_ == ovs.db.types.VoidType:
42 continue
43
44 sys.stdout.write("%s: " % type_.to_string())
45
46 atom = data.Atom.default(type_)
47 if atom != data.Atom.default(type_):
48 sys.stdout.write("wrong\n")
49 sys.exit(1)
50
51 sys.stdout.write("OK\n")
52
53
54 def do_default_data():
55 any_errors = False
56 for n_min in 0, 1:
57 for key in ovs.db.types.ATOMIC_TYPES:
58 if key == ovs.db.types.VoidType:
59 continue
60 for value in ovs.db.types.ATOMIC_TYPES:
61 if value == ovs.db.types.VoidType:
62 valueBase = None
63 else:
64 valueBase = ovs.db.types.BaseType(value)
65 type_ = ovs.db.types.Type(ovs.db.types.BaseType(key),
66 valueBase, n_min, 1)
67 assert type_.is_valid()
68
69 sys.stdout.write("key %s, value %s, n_min %d: "
70 % (key.to_string(), value.to_string(), n_min))
71
72 datum = data.Datum.default(type_)
73 if datum != data.Datum.default(type_):
74 sys.stdout.write("wrong\n")
75 any_errors = True
76 else:
77 sys.stdout.write("OK\n")
78 if any_errors:
79 sys.exit(1)
80
81
82 def do_parse_atomic_type(type_string):
83 type_json = unbox_json(ovs.json.from_string(type_string))
84 atomic_type = ovs.db.types.AtomicType.from_json(type_json)
85 print ovs.json.to_string(atomic_type.to_json(), sort_keys=True)
86
87
88 def do_parse_base_type(type_string):
89 type_json = unbox_json(ovs.json.from_string(type_string))
90 base_type = ovs.db.types.BaseType.from_json(type_json)
91 print ovs.json.to_string(base_type.to_json(), sort_keys=True)
92
93
94 def do_parse_type(type_string):
95 type_json = unbox_json(ovs.json.from_string(type_string))
96 type_ = ovs.db.types.Type.from_json(type_json)
97 print ovs.json.to_string(type_.to_json(), sort_keys=True)
98
99
100 def do_parse_atoms(type_string, *atom_strings):
101 type_json = unbox_json(ovs.json.from_string(type_string))
102 base = ovs.db.types.BaseType.from_json(type_json)
103 for atom_string in atom_strings:
104 atom_json = unbox_json(ovs.json.from_string(atom_string))
105 try:
106 atom = data.Atom.from_json(base, atom_json)
107 print ovs.json.to_string(atom.to_json())
108 except error.Error as e:
109 print e.args[0].encode("utf8")
110
111
112 def do_parse_data(type_string, *data_strings):
113 type_json = unbox_json(ovs.json.from_string(type_string))
114 type_ = ovs.db.types.Type.from_json(type_json)
115 for datum_string in data_strings:
116 datum_json = unbox_json(ovs.json.from_string(datum_string))
117 datum = data.Datum.from_json(type_, datum_json)
118 print ovs.json.to_string(datum.to_json())
119
120
121 def do_sort_atoms(type_string, atom_strings):
122 type_json = unbox_json(ovs.json.from_string(type_string))
123 base = ovs.db.types.BaseType.from_json(type_json)
124 atoms = [data.Atom.from_json(base, atom_json)
125 for atom_json in unbox_json(ovs.json.from_string(atom_strings))]
126 print ovs.json.to_string([data.Atom.to_json(atom)
127 for atom in sorted(atoms)])
128
129
130 def do_parse_column(name, column_string):
131 column_json = unbox_json(ovs.json.from_string(column_string))
132 column = ovs.db.schema.ColumnSchema.from_json(column_json, name)
133 print ovs.json.to_string(column.to_json(), sort_keys=True)
134
135
136 def do_parse_table(name, table_string, default_is_root_string='false'):
137 default_is_root = default_is_root_string == 'true'
138 table_json = unbox_json(ovs.json.from_string(table_string))
139 table = ovs.db.schema.TableSchema.from_json(table_json, name)
140 print ovs.json.to_string(table.to_json(default_is_root), sort_keys=True)
141
142
143 def do_parse_schema(schema_string):
144 schema_json = unbox_json(ovs.json.from_string(schema_string))
145 schema = ovs.db.schema.DbSchema.from_json(schema_json)
146 print ovs.json.to_string(schema.to_json(), sort_keys=True)
147
148
149 def print_idl(idl, step):
150 n = 0
151 if "simple" in idl.tables:
152 simple_columns = ["i", "r", "b", "s", "u", "ia",
153 "ra", "ba", "sa", "ua", "uuid"]
154 simple = idl.tables["simple"].rows
155 for row in simple.itervalues():
156 s = "%03d:" % step
157 for column in simple_columns:
158 if hasattr(row, column) and not (type(getattr(row, column))
159 is ovs.db.data.Atom):
160 s += " %s=%s" % (column, getattr(row, column))
161 s = re.sub('""|,|u?\'', "", s)
162 s = re.sub('UUID\(([^)]+)\)', r'\1', s)
163 s = re.sub('False', 'false', s)
164 s = re.sub('True', 'true', s)
165 s = re.sub(r'(ba)=([^[][^ ]*) ', r'\1=[\2] ', s)
166 print(s)
167 n += 1
168
169 if "link1" in idl.tables:
170 l1 = idl.tables["link1"].rows
171 for row in l1.itervalues():
172 s = ["%03d: i=%s k=" % (step, row.i)]
173 if hasattr(row, "k") and row.k:
174 s.append(str(row.k.i))
175 if hasattr(row, "ka"):
176 s.append(" ka=[")
177 s.append(' '.join(sorted(str(ka.i) for ka in row.ka)))
178 s.append("] l2=")
179 if hasattr(row, "l2") and row.l2:
180 s.append(str(row.l2[0].i))
181 if hasattr(row, "uuid"):
182 s.append(" uuid=%s" % row.uuid)
183 print(''.join(s))
184 n += 1
185
186 if "link2" in idl.tables:
187 l2 = idl.tables["link2"].rows
188 for row in l2.itervalues():
189 s = ["%03d:" % step]
190 s.append(" i=%s l1=" % row.i)
191 if hasattr(row, "l1") and row.l1:
192 s.append(str(row.l1[0].i))
193 if hasattr(row, "uuid"):
194 s.append(" uuid=%s" % row.uuid)
195 print(''.join(s))
196 n += 1
197
198 if not n:
199 print("%03d: empty" % step)
200 sys.stdout.flush()
201
202
203 def substitute_uuids(json, symtab):
204 if type(json) in [str, unicode]:
205 symbol = symtab.get(json)
206 if symbol:
207 return str(symbol)
208 elif type(json) == list:
209 return [substitute_uuids(element, symtab) for element in json]
210 elif type(json) == dict:
211 d = {}
212 for key, value in json.iteritems():
213 d[key] = substitute_uuids(value, symtab)
214 return d
215 return json
216
217
218 def parse_uuids(json, symtab):
219 if type(json) in [str, unicode] and ovs.ovsuuid.is_valid_string(json):
220 name = "#%d#" % len(symtab)
221 sys.stderr.write("%s = %s\n" % (name, json))
222 symtab[name] = json
223 elif type(json) == list:
224 for element in json:
225 parse_uuids(element, symtab)
226 elif type(json) == dict:
227 for value in json.itervalues():
228 parse_uuids(value, symtab)
229
230
231 def idltest_find_simple(idl, i):
232 for row in idl.tables["simple"].rows.itervalues():
233 if row.i == i:
234 return row
235 return None
236
237
238 def idl_set(idl, commands, step):
239 txn = ovs.db.idl.Transaction(idl)
240 increment = False
241 fetch_cmds = []
242 events = []
243 for command in commands.split(','):
244 words = command.split()
245 name = words[0]
246 args = words[1:]
247
248 if name == "notifytest":
249 name = args[0]
250 args = args[1:]
251 old_notify = idl.notify
252
253 def notify(event, row, updates=None):
254 if updates:
255 upcol = updates._data.keys()[0]
256 else:
257 upcol = None
258 events.append("%s|%s|%s" % (event, row.i, upcol))
259 idl.notify = old_notify
260
261 idl.notify = notify
262
263 if name == "set":
264 if len(args) != 3:
265 sys.stderr.write('"set" command requires 3 arguments\n')
266 sys.exit(1)
267
268 s = idltest_find_simple(idl, int(args[0]))
269 if not s:
270 sys.stderr.write('"set" command asks for nonexistent i=%d\n'
271 % int(args[0]))
272 sys.exit(1)
273
274 if args[1] == "b":
275 s.b = args[2] == "1"
276 elif args[1] == "s":
277 s.s = args[2]
278 elif args[1] == "u":
279 s.u = uuid.UUID(args[2])
280 elif args[1] == "r":
281 s.r = float(args[2])
282 else:
283 sys.stderr.write('"set" comamnd asks for unknown column %s\n'
284 % args[2])
285 sys.stderr.exit(1)
286 elif name == "insert":
287 if len(args) != 1:
288 sys.stderr.write('"set" command requires 1 argument\n')
289 sys.exit(1)
290
291 s = txn.insert(idl.tables["simple"])
292 s.i = int(args[0])
293 elif name == "delete":
294 if len(args) != 1:
295 sys.stderr.write('"delete" command requires 1 argument\n')
296 sys.exit(1)
297
298 s = idltest_find_simple(idl, int(args[0]))
299 if not s:
300 sys.stderr.write('"delete" command asks for nonexistent i=%d\n'
301 % int(args[0]))
302 sys.exit(1)
303 s.delete()
304 elif name == "verify":
305 if len(args) != 2:
306 sys.stderr.write('"verify" command requires 2 arguments\n')
307 sys.exit(1)
308
309 s = idltest_find_simple(idl, int(args[0]))
310 if not s:
311 sys.stderr.write('"verify" command asks for nonexistent i=%d\n'
312 % int(args[0]))
313 sys.exit(1)
314
315 if args[1] in ("i", "b", "s", "u", "r"):
316 s.verify(args[1])
317 else:
318 sys.stderr.write('"verify" command asks for unknown column '
319 '"%s"\n' % args[1])
320 sys.exit(1)
321 elif name == "fetch":
322 if len(args) != 2:
323 sys.stderr.write('"fetch" command requires 2 argument\n')
324 sys.exit(1)
325
326 row = idltest_find_simple(idl, int(args[0]))
327 if not row:
328 sys.stderr.write('"fetch" command asks for nonexistent i=%d\n'
329 % int(args[0]))
330 sys.exit(1)
331
332 column = args[1]
333 row.fetch(column)
334 fetch_cmds.append([row, column])
335 elif name == "increment":
336 if len(args) != 1:
337 sys.stderr.write('"increment" command requires 1 argument\n')
338 sys.exit(1)
339
340 s = idltest_find_simple(idl, int(args[0]))
341 if not s:
342 sys.stderr.write('"set" command asks for nonexistent i=%d\n'
343 % int(args[0]))
344 sys.exit(1)
345
346 s.increment("i")
347 increment = True
348 elif name == "abort":
349 txn.abort()
350 break
351 elif name == "destroy":
352 print "%03d: destroy" % step
353 sys.stdout.flush()
354 txn.abort()
355 return
356 elif name == "linktest":
357 l1_0 = txn.insert(idl.tables["link1"])
358 l1_0.i = 1
359 l1_0.k = [l1_0]
360 l1_0.ka = [l1_0]
361 l1_1 = txn.insert(idl.tables["link1"])
362 l1_1.i = 2
363 l1_1.k = [l1_0]
364 l1_1.ka = [l1_0, l1_1]
365 elif name == 'getattrtest':
366 l1 = txn.insert(idl.tables["link1"])
367 i = getattr(l1, 'i', 1)
368 assert i == 1
369 l1.i = 2
370 i = getattr(l1, 'i', 1)
371 assert i == 2
372 l1.k = [l1]
373 else:
374 sys.stderr.write("unknown command %s\n" % name)
375 sys.exit(1)
376
377 status = txn.commit_block()
378 sys.stdout.write("%03d: commit, status=%s"
379 % (step, ovs.db.idl.Transaction.status_to_string(status)))
380 if increment and status == ovs.db.idl.Transaction.SUCCESS:
381 sys.stdout.write(", increment=%d" % txn.get_increment_new_value())
382 if events:
383 # Event notifications from operations in a single transaction are
384 # not in a gauranteed order due to update messages being dicts
385 sys.stdout.write(", events=" + ", ".join(sorted(events)))
386 sys.stdout.write("\n")
387 sys.stdout.flush()
388
389
390 def do_idl(schema_file, remote, *commands):
391 schema_helper = ovs.db.idl.SchemaHelper(schema_file)
392 if commands and commands[0].startswith("?"):
393 readonly = {}
394 for x in commands[0][1:].split("?"):
395 readonly = []
396 table, columns = x.split(":")
397 columns = columns.split(",")
398 for index, column in enumerate(columns):
399 if column[-1] == '!':
400 columns[index] = columns[index][:-1]
401 readonly.append(columns[index])
402 schema_helper.register_columns(table, columns, readonly)
403 commands = commands[1:]
404 else:
405 schema_helper.register_all()
406 idl = ovs.db.idl.Idl(remote, schema_helper)
407
408 if commands:
409 error, stream = ovs.stream.Stream.open_block(
410 ovs.stream.Stream.open(remote))
411 if error:
412 sys.stderr.write("failed to connect to \"%s\"" % remote)
413 sys.exit(1)
414 rpc = ovs.jsonrpc.Connection(stream)
415 else:
416 rpc = None
417
418 symtab = {}
419 seqno = 0
420 step = 0
421 for command in commands:
422 if command.startswith("+"):
423 # The previous transaction didn't change anything.
424 command = command[1:]
425 else:
426 # Wait for update.
427 while idl.change_seqno == seqno and not idl.run():
428 rpc.run()
429
430 poller = ovs.poller.Poller()
431 idl.wait(poller)
432 rpc.wait(poller)
433 poller.block()
434
435 print_idl(idl, step)
436 step += 1
437
438 seqno = idl.change_seqno
439
440 if command == "reconnect":
441 print("%03d: reconnect" % step)
442 sys.stdout.flush()
443 step += 1
444 idl.force_reconnect()
445 elif not command.startswith("["):
446 idl_set(idl, command, step)
447 step += 1
448 else:
449 json = ovs.json.from_string(command)
450 if type(json) in [str, unicode]:
451 sys.stderr.write("\"%s\": %s\n" % (command, json))
452 sys.exit(1)
453 json = substitute_uuids(json, symtab)
454 request = ovs.jsonrpc.Message.create_request("transact", json)
455 error, reply = rpc.transact_block(request)
456 if error:
457 sys.stderr.write("jsonrpc transaction failed: %s"
458 % os.strerror(error))
459 sys.exit(1)
460 elif reply.error is not None:
461 sys.stderr.write("jsonrpc transaction failed: %s"
462 % reply.error)
463 sys.exit(1)
464
465 sys.stdout.write("%03d: " % step)
466 sys.stdout.flush()
467 step += 1
468 if reply.result is not None:
469 parse_uuids(reply.result, symtab)
470 reply.id = None
471 sys.stdout.write("%s\n" % ovs.json.to_string(reply.to_json()))
472 sys.stdout.flush()
473
474 if rpc:
475 rpc.close()
476 while idl.change_seqno == seqno and not idl.run():
477 poller = ovs.poller.Poller()
478 idl.wait(poller)
479 poller.block()
480 print_idl(idl, step)
481 step += 1
482 idl.close()
483 print("%03d: done" % step)
484
485
486 def usage():
487 print """\
488 %(program_name)s: test utility for Open vSwitch database Python bindings
489 usage: %(program_name)s [OPTIONS] COMMAND ARG...
490
491 The following commands are supported:
492 default-atoms
493 test ovsdb_atom_default()
494 default-data
495 test ovsdb_datum_default()
496 parse-atomic-type TYPE
497 parse TYPE as OVSDB atomic type, and re-serialize
498 parse-base-type TYPE
499 parse TYPE as OVSDB base type, and re-serialize
500 parse-type JSON
501 parse JSON as OVSDB type, and re-serialize
502 parse-atoms TYPE ATOM...
503 parse JSON ATOMs as atoms of TYPE, and re-serialize
504 parse-atom-strings TYPE ATOM...
505 parse string ATOMs as atoms of given TYPE, and re-serialize
506 sort-atoms TYPE ATOM...
507 print JSON ATOMs in sorted order
508 parse-data TYPE DATUM...
509 parse JSON DATUMs as data of given TYPE, and re-serialize
510 parse-column NAME OBJECT
511 parse column NAME with info OBJECT, and re-serialize
512 parse-table NAME OBJECT [DEFAULT-IS-ROOT]
513 parse table NAME with info OBJECT
514 parse-schema JSON
515 parse JSON as an OVSDB schema, and re-serialize
516 idl SCHEMA SERVER [?T1:C1,C2...[?T2:C1,C2,...]...] [TRANSACTION...]
517 connect to SERVER (which has the specified SCHEMA) and dump the
518 contents of the database as seen initially by the IDL implementation
519 and after executing each TRANSACTION. (Each TRANSACTION must modify
520 the database or this command will hang.)
521 By default, all columns of all tables are monitored. The "?" option
522 can be used to monitor specific Table:Column(s). The table and their
523 columns are listed as a string of the form starting with "?":
524 ?<table-name>:<column-name>,<column-name>,...
525 e.g.:
526 ?simple:b - Monitor column "b" in table "simple"
527 Entries for multiple tables are seperated by "?":
528 ?<table-name>:<column-name>,...?<table-name>:<column-name>,...
529 e.g.:
530 ?simple:b?link1:i,k - Monitor column "b" in table "simple",
531 and column "i", "k" in table "link1"
532 Readonly columns: Suffixing a "!" after a column indicates that the
533 column is to be registered "readonly".
534 e.g.:
535 ?simple:i,b! - Register interest in column "i" (monitoring) and
536 column "b" (readonly).
537
538
539 The following options are also available:
540 -t, --timeout=SECS give up after SECS seconds
541 -h, --help display this help message\
542 """ % {'program_name': ovs.util.PROGRAM_NAME}
543 sys.exit(0)
544
545
546 def main(argv):
547 try:
548 options, args = getopt.gnu_getopt(argv[1:], 't:h',
549 ['timeout',
550 'help'])
551 except getopt.GetoptError as geo:
552 sys.stderr.write("%s: %s\n" % (ovs.util.PROGRAM_NAME, geo.msg))
553 sys.exit(1)
554
555 for key, value in options:
556 if key in ['-h', '--help']:
557 usage()
558 elif key in ['-t', '--timeout']:
559 try:
560 timeout = int(value)
561 if timeout < 1:
562 raise TypeError
563 except TypeError:
564 raise error.Error("value %s on -t or --timeout is not at "
565 "least 1" % value)
566 signal.alarm(timeout)
567 else:
568 sys.exit(0)
569
570 if not args:
571 sys.stderr.write("%s: missing command argument "
572 "(use --help for help)\n" % ovs.util.PROGRAM_NAME)
573 sys.exit(1)
574
575 commands = {"default-atoms": (do_default_atoms, 0),
576 "default-data": (do_default_data, 0),
577 "parse-atomic-type": (do_parse_atomic_type, 1),
578 "parse-base-type": (do_parse_base_type, 1),
579 "parse-type": (do_parse_type, 1),
580 "parse-atoms": (do_parse_atoms, (2,)),
581 "parse-data": (do_parse_data, (2,)),
582 "sort-atoms": (do_sort_atoms, 2),
583 "parse-column": (do_parse_column, 2),
584 "parse-table": (do_parse_table, (2, 3)),
585 "parse-schema": (do_parse_schema, 1),
586 "idl": (do_idl, (2,))}
587
588 command_name = args[0]
589 args = args[1:]
590 if command_name not in commands:
591 sys.stderr.write("%s: unknown command \"%s\" "
592 "(use --help for help)\n" % (ovs.util.PROGRAM_NAME,
593 command_name))
594 sys.exit(1)
595
596 func, n_args = commands[command_name]
597 if type(n_args) == tuple:
598 if len(args) < n_args[0]:
599 sys.stderr.write("%s: \"%s\" requires at least %d arguments but "
600 "only %d provided\n"
601 % (ovs.util.PROGRAM_NAME, command_name,
602 n_args, len(args)))
603 sys.exit(1)
604 elif type(n_args) == int:
605 if len(args) != n_args:
606 sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
607 "provided\n"
608 % (ovs.util.PROGRAM_NAME, command_name,
609 n_args, len(args)))
610 sys.exit(1)
611 else:
612 assert False
613
614 func(*args)
615
616
617 if __name__ == '__main__':
618 try:
619 main(sys.argv)
620 except error.Error as e:
621 sys.stderr.write("%s\n" % e)
622 sys.exit(1)