]> git.proxmox.com Git - ovs.git/blame - tests/test-ovsdb.py
ovsdb-idl: Simplify transaction retry.
[ovs.git] / tests / test-ovsdb.py
CommitLineData
c5f341ab 1# Copyright (c) 2009, 2010, 2011 Nicira Networks
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:
be44585c 108 print unicode(e)
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:
183 s.append(str(row.l1.i))
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
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) != 2:
296 sys.stderr.write('"increment" command requires 2 arguments\n')
297 sys.exit(1)
298
299 txn.increment(args[0], args[1], [])
300 increment = True
301 elif name == "abort":
302 txn.abort()
303 break
304 elif name == "destroy":
305 print "%03d: destroy" % step
306 sys.stdout.flush()
307 txn.abort()
308 return
309 else:
310 sys.stderr.write("unknown command %s\n" % name)
311 sys.exit(1)
312
313 status = txn.commit_block()
314 sys.stdout.write("%03d: commit, status=%s"
315 % (step, ovs.db.idl.Transaction.status_to_string(status)))
316 if increment and status == ovs.db.idl.Transaction.SUCCESS:
317 sys.stdout.write(", increment=%d" % txn.get_increment_new_value())
318 sys.stdout.write("\n")
319 sys.stdout.flush()
320
26bb0f31 321
8cdf0349 322def do_idl(schema_file, remote, *commands):
bf42f674
EJ
323 schema_helper = ovs.db.idl.SchemaHelper(schema_file)
324 schema_helper.register_all()
325 idl = ovs.db.idl.Idl(remote, schema_helper)
99155935
BP
326
327 if commands:
328 error, stream = ovs.stream.Stream.open_block(
329 ovs.stream.Stream.open(remote))
330 if error:
331 sys.stderr.write("failed to connect to \"%s\"" % remote)
332 sys.exit(1)
333 rpc = ovs.jsonrpc.Connection(stream)
334 else:
335 rpc = None
336
337 symtab = {}
338 seqno = 0
339 step = 0
340 for command in commands:
341 if command.startswith("+"):
342 # The previous transaction didn't change anything.
343 command = command[1:]
344 else:
345 # Wait for update.
8cdf0349 346 while idl.change_seqno == seqno and not idl.run():
99155935
BP
347 rpc.run()
348
349 poller = ovs.poller.Poller()
350 idl.wait(poller)
351 rpc.wait(poller)
352 poller.block()
26bb0f31 353
99155935
BP
354 print_idl(idl, step)
355 step += 1
356
8cdf0349 357 seqno = idl.change_seqno
99155935
BP
358
359 if command == "reconnect":
360 print("%03d: reconnect" % step)
8cdf0349 361 sys.stdout.flush()
99155935
BP
362 step += 1
363 idl.force_reconnect()
364 elif not command.startswith("["):
365 idl_set(idl, command, step)
366 step += 1
367 else:
368 json = ovs.json.from_string(command)
369 if type(json) in [str, unicode]:
370 sys.stderr.write("\"%s\": %s\n" % (command, json))
371 sys.exit(1)
372 json = substitute_uuids(json, symtab)
373 request = ovs.jsonrpc.Message.create_request("transact", json)
374 error, reply = rpc.transact_block(request)
375 if error:
376 sys.stderr.write("jsonrpc transaction failed: %s"
377 % os.strerror(error))
378 sys.exit(1)
66eb76d0
EJ
379 elif reply.error is not None:
380 sys.stderr.write("jsonrpc transaction failed: %s"
381 % reply.error)
382 sys.exit(1)
383
99155935
BP
384 sys.stdout.write("%03d: " % step)
385 sys.stdout.flush()
386 step += 1
387 if reply.result is not None:
388 parse_uuids(reply.result, symtab)
389 reply.id = None
390 sys.stdout.write("%s\n" % ovs.json.to_string(reply.to_json()))
8cdf0349 391 sys.stdout.flush()
99155935
BP
392
393 if rpc:
394 rpc.close()
8cdf0349 395 while idl.change_seqno == seqno and not idl.run():
99155935
BP
396 poller = ovs.poller.Poller()
397 idl.wait(poller)
398 poller.block()
399 print_idl(idl, step)
400 step += 1
401 idl.close()
402 print("%03d: done" % step)
403
26bb0f31 404
99155935
BP
405def usage():
406 print """\
407%(program_name)s: test utility for Open vSwitch database Python bindings
408usage: %(program_name)s [OPTIONS] COMMAND ARG...
409
410The following commands are supported:
411default-atoms
412 test ovsdb_atom_default()
413default-data
414 test ovsdb_datum_default()
415parse-atomic-type TYPE
416 parse TYPE as OVSDB atomic type, and re-serialize
417parse-base-type TYPE
418 parse TYPE as OVSDB base type, and re-serialize
419parse-type JSON
420 parse JSON as OVSDB type, and re-serialize
421parse-atoms TYPE ATOM...
422 parse JSON ATOMs as atoms of TYPE, and re-serialize
423parse-atom-strings TYPE ATOM...
424 parse string ATOMs as atoms of given TYPE, and re-serialize
425sort-atoms TYPE ATOM...
426 print JSON ATOMs in sorted order
427parse-data TYPE DATUM...
428 parse JSON DATUMs as data of given TYPE, and re-serialize
429parse-column NAME OBJECT
430 parse column NAME with info OBJECT, and re-serialize
c5f341ab 431parse-table NAME OBJECT [DEFAULT-IS-ROOT]
99155935
BP
432 parse table NAME with info OBJECT
433parse-schema JSON
434 parse JSON as an OVSDB schema, and re-serialize
8cdf0349
BP
435idl SCHEMA SERVER [TRANSACTION...]
436 connect to SERVER (which has the specified SCHEMA) and dump the
437 contents of the database as seen initially by the IDL implementation
438 and after executing each TRANSACTION. (Each TRANSACTION must modify
99155935
BP
439 the database or this command will hang.)
440
441The following options are also available:
442 -t, --timeout=SECS give up after SECS seconds
443 -h, --help display this help message\
444""" % {'program_name': ovs.util.PROGRAM_NAME}
445 sys.exit(0)
446
26bb0f31 447
99155935 448def main(argv):
99155935
BP
449 try:
450 options, args = getopt.gnu_getopt(argv[1:], 't:h',
451 ['timeout',
452 'help'])
453 except getopt.GetoptError, geo:
454 sys.stderr.write("%s: %s\n" % (ovs.util.PROGRAM_NAME, geo.msg))
455 sys.exit(1)
456
457 for key, value in options:
458 if key in ['-h', '--help']:
459 usage()
460 elif key in ['-t', '--timeout']:
461 try:
462 timeout = int(value)
463 if timeout < 1:
464 raise TypeError
465 except TypeError:
466 raise error.Error("value %s on -t or --timeout is not at "
467 "least 1" % value)
468 signal.alarm(timeout)
469 else:
470 sys.exit(0)
471
99155935
BP
472 if not args:
473 sys.stderr.write("%s: missing command argument "
474 "(use --help for help)\n" % ovs.util.PROGRAM_NAME)
475 sys.exit(1)
476
477 commands = {"default-atoms": (do_default_atoms, 0),
478 "default-data": (do_default_data, 0),
479 "parse-atomic-type": (do_parse_atomic_type, 1),
480 "parse-base-type": (do_parse_base_type, 1),
481 "parse-type": (do_parse_type, 1),
482 "parse-atoms": (do_parse_atoms, (2,)),
483 "parse-data": (do_parse_data, (2,)),
484 "sort-atoms": (do_sort_atoms, 2),
485 "parse-column": (do_parse_column, 2),
c5f341ab 486 "parse-table": (do_parse_table, (2, 3)),
99155935 487 "parse-schema": (do_parse_schema, 1),
8cdf0349 488 "idl": (do_idl, (2,))}
99155935
BP
489
490 command_name = args[0]
491 args = args[1:]
492 if not command_name in commands:
493 sys.stderr.write("%s: unknown command \"%s\" "
494 "(use --help for help)\n" % (ovs.util.PROGRAM_NAME,
495 command_name))
496 sys.exit(1)
497
498 func, n_args = commands[command_name]
499 if type(n_args) == tuple:
500 if len(args) < n_args[0]:
501 sys.stderr.write("%s: \"%s\" requires at least %d arguments but "
502 "only %d provided\n"
503 % (ovs.util.PROGRAM_NAME, command_name,
504 n_args, len(args)))
505 sys.exit(1)
506 elif type(n_args) == int:
507 if len(args) != n_args:
508 sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
509 "provided\n"
510 % (ovs.util.PROGRAM_NAME, command_name,
511 n_args, len(args)))
512 sys.exit(1)
513 else:
514 assert False
515
516 func(*args)
517
26bb0f31 518
99155935
BP
519if __name__ == '__main__':
520 try:
521 main(sys.argv)
522 except error.Error, e:
523 sys.stderr.write("%s\n" % e)
524 sys.exit(1)