]> git.proxmox.com Git - mirror_ovs.git/blob - tests/test-ovsdb.py
ofp-actions: Only set defined bits when encoding "load" actions.
[mirror_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 from ovs.db import 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 types.ATOMIC_TYPES:
41 if type_ == 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 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)
65 type_ = types.Type(types.BaseType(key), valueBase, n_min, 1)
66 assert type_.is_valid()
67
68 sys.stdout.write("key %s, value %s, n_min %d: "
69 % (key.to_string(), value.to_string(), n_min))
70
71 datum = data.Datum.default(type_)
72 if datum != data.Datum.default(type_):
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
80
81 def 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
86
87 def 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
92
93 def do_parse_type(type_string):
94 type_json = unbox_json(ovs.json.from_string(type_string))
95 type_ = types.Type.from_json(type_json)
96 print ovs.json.to_string(type_.to_json(), sort_keys=True)
97
98
99 def 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:
108 print e.args[0].encode("utf8")
109
110
111 def do_parse_data(type_string, *data_strings):
112 type_json = unbox_json(ovs.json.from_string(type_string))
113 type_ = types.Type.from_json(type_json)
114 for datum_string in data_strings:
115 datum_json = unbox_json(ovs.json.from_string(datum_string))
116 datum = data.Datum.from_json(type_, datum_json)
117 print ovs.json.to_string(datum.to_json())
118
119
120 def 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
128
129 def 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
134
135 def do_parse_table(name, table_string, default_is_root_string='false'):
136 default_is_root = default_is_root_string == 'true'
137 table_json = unbox_json(ovs.json.from_string(table_string))
138 table = ovs.db.schema.TableSchema.from_json(table_json, name)
139 print ovs.json.to_string(table.to_json(default_is_root), sort_keys=True)
140
141
142 def 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
147
148 def print_idl(idl, step):
149 simple = idl.tables["simple"].rows
150 l1 = idl.tables["link1"].rows
151 l2 = idl.tables["link2"].rows
152
153 n = 0
154 for row in simple.itervalues():
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,
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)
165 n += 1
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:
183 s.append(str(row.l1[0].i))
184 s.append(" uuid=%s" % row.uuid)
185 print(''.join(s))
186 n += 1
187
188 if not n:
189 print("%03d: empty" % step)
190 sys.stdout.flush()
191
192
193 def 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
207
208 def parse_uuids(json, symtab):
209 if type(json) in [str, unicode] and ovs.ovsuuid.is_valid_string(json):
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
220
221 def 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
227
228 def idl_set(idl, commands, step):
229 txn = ovs.db.idl.Transaction(idl)
230 increment = False
231 for command in commands.split(','):
232 words = command.split()
233 name = words[0]
234 args = words[1:]
235
236 if name == "set":
237 if len(args) != 3:
238 sys.stderr.write('"set" command requires 3 arguments\n')
239 sys.exit(1)
240
241 s = idltest_find_simple(idl, int(args[0]))
242 if not s:
243 sys.stderr.write('"set" command asks for nonexistent i=%d\n'
244 % int(args[0]))
245 sys.exit(1)
246
247 if args[1] == "b":
248 s.b = args[2] == "1"
249 elif args[1] == "s":
250 s.s = args[2]
251 elif args[1] == "u":
252 s.u = uuid.UUID(args[2])
253 elif args[1] == "r":
254 s.r = float(args[2])
255 else:
256 sys.stderr.write('"set" comamnd asks for unknown column %s\n'
257 % args[2])
258 sys.stderr.exit(1)
259 elif name == "insert":
260 if len(args) != 1:
261 sys.stderr.write('"set" command requires 1 argument\n')
262 sys.exit(1)
263
264 s = txn.insert(idl.tables["simple"])
265 s.i = int(args[0])
266 elif name == "delete":
267 if len(args) != 1:
268 sys.stderr.write('"delete" command requires 1 argument\n')
269 sys.exit(1)
270
271 s = idltest_find_simple(idl, int(args[0]))
272 if not s:
273 sys.stderr.write('"delete" command asks for nonexistent i=%d\n'
274 % int(args[0]))
275 sys.exit(1)
276 s.delete()
277 elif name == "verify":
278 if len(args) != 2:
279 sys.stderr.write('"verify" command requires 2 arguments\n')
280 sys.exit(1)
281
282 s = idltest_find_simple(idl, int(args[0]))
283 if not s:
284 sys.stderr.write('"verify" command asks for nonexistent i=%d\n'
285 % int(args[0]))
286 sys.exit(1)
287
288 if args[1] in ("i", "b", "s", "u", "r"):
289 s.verify(args[1])
290 else:
291 sys.stderr.write('"verify" command asks for unknown column '
292 '"%s"\n' % args[1])
293 sys.exit(1)
294 elif name == "increment":
295 if len(args) != 1:
296 sys.stderr.write('"increment" command requires 1 argument\n')
297 sys.exit(1)
298
299 s = idltest_find_simple(idl, int(args[0]))
300 if not s:
301 sys.stderr.write('"set" command asks for nonexistent i=%d\n'
302 % int(args[0]))
303 sys.exit(1)
304
305 s.increment("i")
306 increment = True
307 elif name == "abort":
308 txn.abort()
309 break
310 elif name == "destroy":
311 print "%03d: destroy" % step
312 sys.stdout.flush()
313 txn.abort()
314 return
315 elif name == "linktest":
316 l1_0 = txn.insert(idl.tables["link1"])
317 l1_0.i = 1
318 l1_0.k = [l1_0]
319 l1_0.ka = [l1_0]
320 l1_1 = txn.insert(idl.tables["link1"])
321 l1_1.i = 2
322 l1_1.k = [l1_0]
323 l1_1.ka = [l1_0, l1_1]
324 elif name == 'getattrtest':
325 l1 = txn.insert(idl.tables["link1"])
326 i = getattr(l1, 'i', 1)
327 assert i == 1
328 l1.i = 2
329 i = getattr(l1, 'i', 1)
330 assert i == 2
331 l1.k = [l1]
332 else:
333 sys.stderr.write("unknown command %s\n" % name)
334 sys.exit(1)
335
336 status = txn.commit_block()
337 sys.stdout.write("%03d: commit, status=%s"
338 % (step, ovs.db.idl.Transaction.status_to_string(status)))
339 if increment and status == ovs.db.idl.Transaction.SUCCESS:
340 sys.stdout.write(", increment=%d" % txn.get_increment_new_value())
341 sys.stdout.write("\n")
342 sys.stdout.flush()
343
344
345 def do_idl(schema_file, remote, *commands):
346 schema_helper = ovs.db.idl.SchemaHelper(schema_file)
347 schema_helper.register_all()
348 idl = ovs.db.idl.Idl(remote, schema_helper)
349
350 if commands:
351 error, stream = ovs.stream.Stream.open_block(
352 ovs.stream.Stream.open(remote))
353 if error:
354 sys.stderr.write("failed to connect to \"%s\"" % remote)
355 sys.exit(1)
356 rpc = ovs.jsonrpc.Connection(stream)
357 else:
358 rpc = None
359
360 symtab = {}
361 seqno = 0
362 step = 0
363 for command in commands:
364 if command.startswith("+"):
365 # The previous transaction didn't change anything.
366 command = command[1:]
367 else:
368 # Wait for update.
369 while idl.change_seqno == seqno and not idl.run():
370 rpc.run()
371
372 poller = ovs.poller.Poller()
373 idl.wait(poller)
374 rpc.wait(poller)
375 poller.block()
376
377 print_idl(idl, step)
378 step += 1
379
380 seqno = idl.change_seqno
381
382 if command == "reconnect":
383 print("%03d: reconnect" % step)
384 sys.stdout.flush()
385 step += 1
386 idl.force_reconnect()
387 elif not command.startswith("["):
388 idl_set(idl, command, step)
389 step += 1
390 else:
391 json = ovs.json.from_string(command)
392 if type(json) in [str, unicode]:
393 sys.stderr.write("\"%s\": %s\n" % (command, json))
394 sys.exit(1)
395 json = substitute_uuids(json, symtab)
396 request = ovs.jsonrpc.Message.create_request("transact", json)
397 error, reply = rpc.transact_block(request)
398 if error:
399 sys.stderr.write("jsonrpc transaction failed: %s"
400 % os.strerror(error))
401 sys.exit(1)
402 elif reply.error is not None:
403 sys.stderr.write("jsonrpc transaction failed: %s"
404 % reply.error)
405 sys.exit(1)
406
407 sys.stdout.write("%03d: " % step)
408 sys.stdout.flush()
409 step += 1
410 if reply.result is not None:
411 parse_uuids(reply.result, symtab)
412 reply.id = None
413 sys.stdout.write("%s\n" % ovs.json.to_string(reply.to_json()))
414 sys.stdout.flush()
415
416 if rpc:
417 rpc.close()
418 while idl.change_seqno == seqno and not idl.run():
419 poller = ovs.poller.Poller()
420 idl.wait(poller)
421 poller.block()
422 print_idl(idl, step)
423 step += 1
424 idl.close()
425 print("%03d: done" % step)
426
427
428 def usage():
429 print """\
430 %(program_name)s: test utility for Open vSwitch database Python bindings
431 usage: %(program_name)s [OPTIONS] COMMAND ARG...
432
433 The following commands are supported:
434 default-atoms
435 test ovsdb_atom_default()
436 default-data
437 test ovsdb_datum_default()
438 parse-atomic-type TYPE
439 parse TYPE as OVSDB atomic type, and re-serialize
440 parse-base-type TYPE
441 parse TYPE as OVSDB base type, and re-serialize
442 parse-type JSON
443 parse JSON as OVSDB type, and re-serialize
444 parse-atoms TYPE ATOM...
445 parse JSON ATOMs as atoms of TYPE, and re-serialize
446 parse-atom-strings TYPE ATOM...
447 parse string ATOMs as atoms of given TYPE, and re-serialize
448 sort-atoms TYPE ATOM...
449 print JSON ATOMs in sorted order
450 parse-data TYPE DATUM...
451 parse JSON DATUMs as data of given TYPE, and re-serialize
452 parse-column NAME OBJECT
453 parse column NAME with info OBJECT, and re-serialize
454 parse-table NAME OBJECT [DEFAULT-IS-ROOT]
455 parse table NAME with info OBJECT
456 parse-schema JSON
457 parse JSON as an OVSDB schema, and re-serialize
458 idl SCHEMA SERVER [TRANSACTION...]
459 connect to SERVER (which has the specified SCHEMA) and dump the
460 contents of the database as seen initially by the IDL implementation
461 and after executing each TRANSACTION. (Each TRANSACTION must modify
462 the database or this command will hang.)
463
464 The following options are also available:
465 -t, --timeout=SECS give up after SECS seconds
466 -h, --help display this help message\
467 """ % {'program_name': ovs.util.PROGRAM_NAME}
468 sys.exit(0)
469
470
471 def main(argv):
472 try:
473 options, args = getopt.gnu_getopt(argv[1:], 't:h',
474 ['timeout',
475 'help'])
476 except getopt.GetoptError, geo:
477 sys.stderr.write("%s: %s\n" % (ovs.util.PROGRAM_NAME, geo.msg))
478 sys.exit(1)
479
480 for key, value in options:
481 if key in ['-h', '--help']:
482 usage()
483 elif key in ['-t', '--timeout']:
484 try:
485 timeout = int(value)
486 if timeout < 1:
487 raise TypeError
488 except TypeError:
489 raise error.Error("value %s on -t or --timeout is not at "
490 "least 1" % value)
491 signal.alarm(timeout)
492 else:
493 sys.exit(0)
494
495 if not args:
496 sys.stderr.write("%s: missing command argument "
497 "(use --help for help)\n" % ovs.util.PROGRAM_NAME)
498 sys.exit(1)
499
500 commands = {"default-atoms": (do_default_atoms, 0),
501 "default-data": (do_default_data, 0),
502 "parse-atomic-type": (do_parse_atomic_type, 1),
503 "parse-base-type": (do_parse_base_type, 1),
504 "parse-type": (do_parse_type, 1),
505 "parse-atoms": (do_parse_atoms, (2,)),
506 "parse-data": (do_parse_data, (2,)),
507 "sort-atoms": (do_sort_atoms, 2),
508 "parse-column": (do_parse_column, 2),
509 "parse-table": (do_parse_table, (2, 3)),
510 "parse-schema": (do_parse_schema, 1),
511 "idl": (do_idl, (2,))}
512
513 command_name = args[0]
514 args = args[1:]
515 if not command_name in commands:
516 sys.stderr.write("%s: unknown command \"%s\" "
517 "(use --help for help)\n" % (ovs.util.PROGRAM_NAME,
518 command_name))
519 sys.exit(1)
520
521 func, n_args = commands[command_name]
522 if type(n_args) == tuple:
523 if len(args) < n_args[0]:
524 sys.stderr.write("%s: \"%s\" requires at least %d arguments but "
525 "only %d provided\n"
526 % (ovs.util.PROGRAM_NAME, command_name,
527 n_args, len(args)))
528 sys.exit(1)
529 elif type(n_args) == int:
530 if len(args) != n_args:
531 sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
532 "provided\n"
533 % (ovs.util.PROGRAM_NAME, command_name,
534 n_args, len(args)))
535 sys.exit(1)
536 else:
537 assert False
538
539 func(*args)
540
541
542 if __name__ == '__main__':
543 try:
544 main(sys.argv)
545 except error.Error, e:
546 sys.stderr.write("%s\n" % e)
547 sys.exit(1)