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