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