]> git.proxmox.com Git - ovs.git/blob - tests/test-ovsdb.py
idl: Convert python daemons to utilize SchemaHelper.
[ovs.git] / tests / test-ovsdb.py
1 # Copyright (c) 2009, 2010, 2011 Nicira Networks
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 unicode(e)
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.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) != 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
321
322 def do_idl(schema_file, remote, *commands):
323 schema_helper = ovs.db.idl.SchemaHelper(schema_file)
324 schema_helper.register_all()
325 idl = ovs.db.idl.Idl(remote, schema_helper)
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.
346 while idl.change_seqno == seqno and not idl.run():
347 rpc.run()
348
349 poller = ovs.poller.Poller()
350 idl.wait(poller)
351 rpc.wait(poller)
352 poller.block()
353
354 print_idl(idl, step)
355 step += 1
356
357 seqno = idl.change_seqno
358
359 if command == "reconnect":
360 print("%03d: reconnect" % step)
361 sys.stdout.flush()
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)
379 elif reply.error is not None:
380 sys.stderr.write("jsonrpc transaction failed: %s"
381 % reply.error)
382 sys.exit(1)
383
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()))
391 sys.stdout.flush()
392
393 if rpc:
394 rpc.close()
395 while idl.change_seqno == seqno and not idl.run():
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
404
405 def usage():
406 print """\
407 %(program_name)s: test utility for Open vSwitch database Python bindings
408 usage: %(program_name)s [OPTIONS] COMMAND ARG...
409
410 The following commands are supported:
411 default-atoms
412 test ovsdb_atom_default()
413 default-data
414 test ovsdb_datum_default()
415 parse-atomic-type TYPE
416 parse TYPE as OVSDB atomic type, and re-serialize
417 parse-base-type TYPE
418 parse TYPE as OVSDB base type, and re-serialize
419 parse-type JSON
420 parse JSON as OVSDB type, and re-serialize
421 parse-atoms TYPE ATOM...
422 parse JSON ATOMs as atoms of TYPE, and re-serialize
423 parse-atom-strings TYPE ATOM...
424 parse string ATOMs as atoms of given TYPE, and re-serialize
425 sort-atoms TYPE ATOM...
426 print JSON ATOMs in sorted order
427 parse-data TYPE DATUM...
428 parse JSON DATUMs as data of given TYPE, and re-serialize
429 parse-column NAME OBJECT
430 parse column NAME with info OBJECT, and re-serialize
431 parse-table NAME OBJECT [DEFAULT-IS-ROOT]
432 parse table NAME with info OBJECT
433 parse-schema JSON
434 parse JSON as an OVSDB schema, and re-serialize
435 idl 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
439 the database or this command will hang.)
440
441 The 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
447
448 def main(argv):
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
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),
486 "parse-table": (do_parse_table, (2, 3)),
487 "parse-schema": (do_parse_schema, 1),
488 "idl": (do_idl, (2,))}
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
518
519 if __name__ == '__main__':
520 try:
521 main(sys.argv)
522 except error.Error, e:
523 sys.stderr.write("%s\n" % e)
524 sys.exit(1)