]>
Commit | Line | Data |
---|---|---|
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 |
15 | import getopt |
16 | import re | |
17 | import os | |
18 | import signal | |
19 | import sys | |
8cdf0349 | 20 | import uuid |
99155935 BP |
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 | ||
26bb0f31 | 31 | |
99155935 BP |
32 | def 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 | 39 | def 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 |
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) | |
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 |
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 | ||
26bb0f31 | 86 | |
99155935 BP |
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 | ||
26bb0f31 | 92 | |
99155935 BP |
93 | def 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 |
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: | |
be44585c | 108 | print unicode(e) |
99155935 | 109 | |
26bb0f31 | 110 | |
99155935 BP |
111 | def 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 |
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 | ||
26bb0f31 | 128 | |
99155935 BP |
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 | ||
26bb0f31 | 134 | |
c5f341ab BP |
135 | def 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 |
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 | ||
26bb0f31 | 147 | |
99155935 | 148 | def 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 |
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 | ||
26bb0f31 | 207 | |
99155935 | 208 | def 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 |
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 | ||
26bb0f31 | 227 | |
8cdf0349 BP |
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 | ||
26bb0f31 | 321 | |
8cdf0349 | 322 | def 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 |
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 | |
c5f341ab | 431 | parse-table NAME OBJECT [DEFAULT-IS-ROOT] |
99155935 BP |
432 | parse table NAME with info OBJECT |
433 | parse-schema JSON | |
434 | parse JSON as an OVSDB schema, and re-serialize | |
8cdf0349 BP |
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 | |
99155935 BP |
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 | ||
26bb0f31 | 447 | |
99155935 | 448 | def 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 |
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) |