]> git.proxmox.com Git - mirror_ovs.git/blob - tests/test-ovsdb.py
ovsdb-idl: Return correct seqno from ovsdb_idl_db_set_condition().
[mirror_ovs.git] / tests / test-ovsdb.py
1 # Copyright (c) 2009, 2010, 2011, 2012, 2016 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 os
17 import re
18 import sys
19 import uuid
20
21 import ovs.db.idl
22 import ovs.db.schema
23 import ovs.db.types
24 import ovs.ovsuuid
25 import ovs.poller
26 import ovs.stream
27 import ovs.util
28 import ovs.vlog
29 from ovs.db import data
30 from ovs.db import error
31 from ovs.db.idl import _row_to_uuid as row_to_uuid
32 from ovs.fatal_signal import signal_alarm
33
34 vlog = ovs.vlog.Vlog("test-ovsdb")
35 vlog.set_levels_from_string("console:dbg")
36 vlog.init(None)
37
38
39 def unbox_json(json):
40 if type(json) == list and len(json) == 1:
41 return json[0]
42 else:
43 return json
44
45
46 def do_default_atoms():
47 for type_ in ovs.db.types.ATOMIC_TYPES:
48 if type_ == ovs.db.types.VoidType:
49 continue
50
51 sys.stdout.write("%s: " % type_.to_string())
52
53 atom = data.Atom.default(type_)
54 if atom != data.Atom.default(type_):
55 sys.stdout.write("wrong\n")
56 sys.exit(1)
57
58 sys.stdout.write("OK\n")
59
60
61 def do_default_data():
62 any_errors = False
63 for n_min in 0, 1:
64 for key in ovs.db.types.ATOMIC_TYPES:
65 if key == ovs.db.types.VoidType:
66 continue
67 for value in ovs.db.types.ATOMIC_TYPES:
68 if value == ovs.db.types.VoidType:
69 valueBase = None
70 else:
71 valueBase = ovs.db.types.BaseType(value)
72 type_ = ovs.db.types.Type(ovs.db.types.BaseType(key),
73 valueBase, n_min, 1)
74 assert type_.is_valid()
75
76 sys.stdout.write("key %s, value %s, n_min %d: "
77 % (key.to_string(), value.to_string(), n_min))
78
79 datum = data.Datum.default(type_)
80 if datum != data.Datum.default(type_):
81 sys.stdout.write("wrong\n")
82 any_errors = True
83 else:
84 sys.stdout.write("OK\n")
85 if any_errors:
86 sys.exit(1)
87
88
89 def do_parse_atomic_type(type_string):
90 type_json = unbox_json(ovs.json.from_string(type_string))
91 atomic_type = ovs.db.types.AtomicType.from_json(type_json)
92 print(ovs.json.to_string(atomic_type.to_json(), sort_keys=True))
93
94
95 def do_parse_base_type(type_string):
96 type_json = unbox_json(ovs.json.from_string(type_string))
97 base_type = ovs.db.types.BaseType.from_json(type_json)
98 print(ovs.json.to_string(base_type.to_json(), sort_keys=True))
99
100
101 def do_parse_type(type_string):
102 type_json = unbox_json(ovs.json.from_string(type_string))
103 type_ = ovs.db.types.Type.from_json(type_json)
104 print(ovs.json.to_string(type_.to_json(), sort_keys=True))
105
106
107 def do_parse_atoms(type_string, *atom_strings):
108 type_json = unbox_json(ovs.json.from_string(type_string))
109 base = ovs.db.types.BaseType.from_json(type_json)
110 for atom_string in atom_strings:
111 atom_json = unbox_json(ovs.json.from_string(atom_string))
112 try:
113 atom = data.Atom.from_json(base, atom_json)
114 print(ovs.json.to_string(atom.to_json()))
115 except error.Error as e:
116 print(e.args[0])
117
118
119 def do_parse_data(type_string, *data_strings):
120 type_json = unbox_json(ovs.json.from_string(type_string))
121 type_ = ovs.db.types.Type.from_json(type_json)
122 for datum_string in data_strings:
123 datum_json = unbox_json(ovs.json.from_string(datum_string))
124 datum = data.Datum.from_json(type_, datum_json)
125 print(ovs.json.to_string(datum.to_json()))
126
127
128 def do_sort_atoms(type_string, atom_strings):
129 type_json = unbox_json(ovs.json.from_string(type_string))
130 base = ovs.db.types.BaseType.from_json(type_json)
131 atoms = [data.Atom.from_json(base, atom_json)
132 for atom_json in unbox_json(ovs.json.from_string(atom_strings))]
133 print(ovs.json.to_string([data.Atom.to_json(atom)
134 for atom in sorted(atoms)]))
135
136
137 def do_parse_column(name, column_string):
138 column_json = unbox_json(ovs.json.from_string(column_string))
139 column = ovs.db.schema.ColumnSchema.from_json(column_json, name)
140 print(ovs.json.to_string(column.to_json(), sort_keys=True))
141
142
143 def do_parse_table(name, table_string, default_is_root_string='false'):
144 default_is_root = default_is_root_string == 'true'
145 table_json = unbox_json(ovs.json.from_string(table_string))
146 table = ovs.db.schema.TableSchema.from_json(table_json, name)
147 print(ovs.json.to_string(table.to_json(default_is_root), sort_keys=True))
148
149
150 def do_parse_schema(schema_string):
151 schema_json = unbox_json(ovs.json.from_string(schema_string))
152 schema = ovs.db.schema.DbSchema.from_json(schema_json)
153 print(ovs.json.to_string(schema.to_json(), sort_keys=True))
154
155
156 def get_simple_printable_row_string(row, columns):
157 s = ""
158 for column in columns:
159 if hasattr(row, column) and not (type(getattr(row, column))
160 is ovs.db.data.Atom):
161 value = getattr(row, column)
162 if isinstance(value, dict):
163 value = sorted((row_to_uuid(k), row_to_uuid(v))
164 for k, v in value.items())
165 s += "%s=%s " % (column, value)
166 s = s.strip()
167 s = re.sub('""|,|u?\'', "", s)
168 s = re.sub(r'UUID\(([^)]+)\)', r'\1', s)
169 s = re.sub('False', 'false', s)
170 s = re.sub('True', 'true', s)
171 s = re.sub(r'(ba)=([^[][^ ]*) ', r'\1=[\2] ', s)
172 return s
173
174
175 def get_simple_table_printable_row(row):
176 simple_columns = ["i", "r", "b", "s", "u", "ia",
177 "ra", "ba", "sa", "ua", "uuid"]
178 return get_simple_printable_row_string(row, simple_columns)
179
180
181 def get_simple2_table_printable_row(row):
182 simple2_columns = ["name", "smap", "imap"]
183 return get_simple_printable_row_string(row, simple2_columns)
184
185
186 def get_simple3_table_printable_row(row):
187 simple3_columns = ["name", "uset"]
188 return get_simple_printable_row_string(row, simple3_columns)
189
190
191 def print_idl(idl, step):
192 n = 0
193 if "simple" in idl.tables:
194 simple = idl.tables["simple"].rows
195 for row in simple.values():
196 s = "%03d: " % step
197 s += get_simple_table_printable_row(row)
198 print(s)
199 n += 1
200
201 if "simple2" in idl.tables:
202 simple2 = idl.tables["simple2"].rows
203 for row in simple2.values():
204 s = "%03d: " % step
205 s += get_simple2_table_printable_row(row)
206 print(s)
207 n += 1
208
209 if "simple3" in idl.tables:
210 simple3 = idl.tables["simple3"].rows
211 for row in simple3.values():
212 s = "%03d: " % step
213 s += get_simple3_table_printable_row(row)
214 print(s)
215 n += 1
216
217 if "simple5" in idl.tables:
218 simple5 = idl.tables["simple5"].rows
219 for row in simple5.values():
220 s = "%03d: " % step
221 s += get_simple_printable_row_string(row, ["name", "irefmap"])
222 print(s)
223 n += 1
224
225 if "link1" in idl.tables:
226 l1 = idl.tables["link1"].rows
227 for row in l1.values():
228 s = ["%03d: i=%s k=" % (step, row.i)]
229 if hasattr(row, "k") and row.k:
230 s.append(str(row.k.i))
231 if hasattr(row, "ka"):
232 s.append(" ka=[")
233 s.append(' '.join(sorted(str(ka.i) for ka in row.ka)))
234 s.append("] l2=")
235 if hasattr(row, "l2") and row.l2:
236 s.append(str(row.l2[0].i))
237 if hasattr(row, "uuid"):
238 s.append(" uuid=%s" % row.uuid)
239 print(''.join(s))
240 n += 1
241
242 if "link2" in idl.tables:
243 l2 = idl.tables["link2"].rows
244 for row in l2.values():
245 s = ["%03d:" % step]
246 s.append(" i=%s l1=" % row.i)
247 if hasattr(row, "l1") and row.l1:
248 s.append(str(row.l1[0].i))
249 if hasattr(row, "uuid"):
250 s.append(" uuid=%s" % row.uuid)
251 print(''.join(s))
252 n += 1
253
254 if "singleton" in idl.tables:
255 sng = idl.tables["singleton"].rows
256 for row in sng.values():
257 s = ["%03d:" % step]
258 s.append(" name=%s" % row.name)
259 if hasattr(row, "uuid"):
260 s.append(" uuid=%s" % row.uuid)
261 print(''.join(s))
262 n += 1
263
264 if not n:
265 print("%03d: empty" % step)
266 sys.stdout.flush()
267
268
269 def substitute_uuids(json, symtab):
270 if isinstance(json, str):
271 symbol = symtab.get(json)
272 if symbol:
273 return str(symbol)
274 elif type(json) == list:
275 return [substitute_uuids(element, symtab) for element in json]
276 elif type(json) == dict:
277 d = {}
278 for key, value in json.items():
279 d[key] = substitute_uuids(value, symtab)
280 return d
281 return json
282
283
284 def parse_uuids(json, symtab):
285 if (isinstance(json, str)
286 and ovs.ovsuuid.is_valid_string(json)):
287 name = "#%d#" % len(symtab)
288 sys.stderr.write("%s = %s\n" % (name, json))
289 symtab[name] = json
290 elif type(json) == list:
291 for element in json:
292 parse_uuids(element, symtab)
293 elif type(json) == dict:
294 for value in json.values():
295 parse_uuids(value, symtab)
296
297
298 def idltest_find_simple(idl, i):
299 for row in idl.tables["simple"].rows.values():
300 if row.i == i:
301 return row
302 return None
303
304
305 def idltest_find_simple2(idl, i):
306 for row in idl.tables["simple2"].rows.values():
307 if row.name == i:
308 return row
309 return None
310
311
312 def idltest_find_simple3(idl, i):
313 return next(idl.index_equal("simple3", "simple3_by_name", i), None)
314
315
316 def idltest_find(idl, table, col, match):
317 return next((r for r in idl.tables[table].rows.values() if
318 getattr(r, col) == match), None)
319
320
321 def idl_set(idl, commands, step):
322 txn = ovs.db.idl.Transaction(idl)
323 increment = False
324 fetch_cmds = []
325 events = []
326 for command in commands.split(','):
327 words = command.split()
328 name = words[0]
329 args = words[1:]
330
331 if name == "notifytest":
332 name = args[0]
333 args = args[1:]
334 old_notify = idl.notify
335
336 def notify(event, row, updates=None):
337 if updates:
338 upcol = list(updates._data.keys())[0]
339 else:
340 upcol = None
341 events.append("%s|%s|%s" % (event, row.i, upcol))
342 idl.notify = old_notify
343
344 idl.notify = notify
345
346 if name == "set":
347 if len(args) != 3:
348 sys.stderr.write('"set" command requires 3 arguments\n')
349 sys.exit(1)
350
351 s = idltest_find_simple(idl, int(args[0]))
352 if not s:
353 sys.stderr.write('"set" command asks for nonexistent i=%d\n'
354 % int(args[0]))
355 sys.exit(1)
356
357 if args[1] == "b":
358 s.b = args[2] == "1"
359 elif args[1] == "s":
360 s.s = args[2].encode(sys.getfilesystemencoding(),
361 'surrogateescape') \
362 .decode('utf-8', 'replace')
363 elif args[1] == "u":
364 s.u = uuid.UUID(args[2])
365 elif args[1] == "r":
366 s.r = float(args[2])
367 else:
368 sys.stderr.write('"set" comamnd asks for unknown column %s\n'
369 % args[2])
370 sys.stderr.exit(1)
371 elif name == "insert":
372 if len(args) != 1:
373 sys.stderr.write('"set" command requires 1 argument\n')
374 sys.exit(1)
375
376 s = txn.insert(idl.tables["simple"])
377 s.i = int(args[0])
378 elif name == "delete":
379 if len(args) != 1:
380 sys.stderr.write('"delete" command requires 1 argument\n')
381 sys.exit(1)
382
383 s = idltest_find_simple(idl, int(args[0]))
384 if not s:
385 sys.stderr.write('"delete" command asks for nonexistent i=%d\n'
386 % int(args[0]))
387 sys.exit(1)
388 s.delete()
389 elif name == "verify":
390 if len(args) != 2:
391 sys.stderr.write('"verify" command requires 2 arguments\n')
392 sys.exit(1)
393
394 s = idltest_find_simple(idl, int(args[0]))
395 if not s:
396 sys.stderr.write('"verify" command asks for nonexistent i=%d\n'
397 % int(args[0]))
398 sys.exit(1)
399
400 if args[1] in ("i", "b", "s", "u", "r"):
401 s.verify(args[1])
402 else:
403 sys.stderr.write('"verify" command asks for unknown column '
404 '"%s"\n' % args[1])
405 sys.exit(1)
406 elif name == "fetch":
407 if len(args) != 2:
408 sys.stderr.write('"fetch" command requires 2 argument\n')
409 sys.exit(1)
410
411 row = idltest_find_simple(idl, int(args[0]))
412 if not row:
413 sys.stderr.write('"fetch" command asks for nonexistent i=%d\n'
414 % int(args[0]))
415 sys.exit(1)
416
417 column = args[1]
418 row.fetch(column)
419 fetch_cmds.append([row, column])
420 elif name == "increment":
421 if len(args) != 1:
422 sys.stderr.write('"increment" command requires 1 argument\n')
423 sys.exit(1)
424
425 s = idltest_find_simple(idl, int(args[0]))
426 if not s:
427 sys.stderr.write('"set" command asks for nonexistent i=%d\n'
428 % int(args[0]))
429 sys.exit(1)
430
431 s.increment("i")
432 increment = True
433 elif name == "abort":
434 txn.abort()
435 break
436 elif name == "destroy":
437 print("%03d: destroy" % step)
438 sys.stdout.flush()
439 txn.abort()
440 return
441 elif name == "linktest":
442 l1_0 = txn.insert(idl.tables["link1"])
443 l1_0.i = 1
444 l1_0.k = [l1_0]
445 l1_0.ka = [l1_0]
446 l1_1 = txn.insert(idl.tables["link1"])
447 l1_1.i = 2
448 l1_1.k = [l1_0]
449 l1_1.ka = [l1_0, l1_1]
450 elif name == 'getattrtest':
451 l1 = txn.insert(idl.tables["link1"])
452 i = getattr(l1, 'i', 1)
453 assert i == 1
454 l1.i = 2
455 i = getattr(l1, 'i', 1)
456 assert i == 2
457 l1.k = [l1]
458 elif name == 'partialmapinsertelement':
459 row = idltest_find_simple2(idl, 'myString1')
460 len_smap = len(getattr(row, 'smap'))
461 row.setkey('smap', 'key1', 'myList1')
462 len_imap = len(getattr(row, 'imap'))
463 row.setkey('imap', 3, 'myids2')
464 row.__setattr__('name', 'String2')
465 assert len(getattr(row, 'smap')) == len_smap
466 assert len(getattr(row, 'imap')) == len_imap + 1
467 elif name == 'partialmapinsertmultipleelements':
468 row = idltest_find_simple2(idl, 'String2')
469 len_smap = len(getattr(row, 'smap'))
470 row.setkey('smap', 'key2', 'myList2')
471 row.setkey('smap', 'key3', 'myList3')
472 row.setkey('smap', 'key4', 'myList4')
473 assert len(getattr(row, 'smap')) == len_smap + 2
474 elif name == 'partialmapdelelements':
475 row = idltest_find_simple2(idl, 'String2')
476 len_smap = len(getattr(row, 'smap'))
477 row.delkey('smap', 'key1', 'myList1')
478 row.delkey('smap', 'key2', 'wrongvalue')
479 row.delkey('smap', 'key3')
480 row.delkey('smap', 'key4')
481 assert len(getattr(row, 'smap')) == len_smap - 3
482 elif name == 'partialmapmutatenew':
483 new_row2 = txn.insert(idl.tables["simple2"])
484 setattr(new_row2, 'name', 'String2New')
485 new_row2.setkey('smap', 'key1', 'newList1')
486 assert len(getattr(new_row2, 'smap')) == 1
487 new_row2.setkey('smap', 'key2', 'newList2')
488 assert len(getattr(new_row2, 'smap')) == 2
489 elif name == 'partialrenamesetadd':
490 row = idltest_find_simple3(idl, 'mySet1')
491 old_size = len(getattr(row, 'uset', []))
492 row.addvalue('uset',
493 uuid.UUID("001e43d2-dd3f-4616-ab6a-83a490bb0991"))
494 row.__setattr__('name', 'String2')
495 assert len(getattr(row, 'uset', [])) == old_size + 1
496 elif name == 'partialduplicateadd':
497 row = idltest_find_simple3(idl, 'String2')
498 old_size = len(getattr(row, 'uset', []))
499 row.addvalue('uset',
500 uuid.UUID("0026b3ba-571b-4729-8227-d860a5210ab8"))
501 row.addvalue('uset',
502 uuid.UUID("0026b3ba-571b-4729-8227-d860a5210ab8"))
503 assert len(getattr(row, 'uset', [])) == old_size + 1
504 elif name == 'partialsetdel':
505 row = idltest_find_simple3(idl, 'String2')
506 old_size = len(getattr(row, 'uset', []))
507 row.delvalue('uset',
508 uuid.UUID("001e43d2-dd3f-4616-ab6a-83a490bb0991"))
509 assert len(getattr(row, 'uset', [])) == old_size - 1
510 elif name == 'partialsetref':
511 new_row = txn.insert(idl.tables["simple4"])
512 new_row.__setattr__('name', 'test')
513 row = idltest_find_simple3(idl, 'String2')
514 old_size = len(getattr(row, 'uref', []))
515 row.addvalue('uref', new_row.uuid)
516 assert len(getattr(row, 'uref', [])) == old_size + 1
517 elif name == 'partialsetoverrideops':
518 row = idltest_find_simple3(idl, 'String2')
519 row.addvalue('uset',
520 uuid.UUID("579e978d-776c-4f19-a225-268e5890e670"))
521 row.delvalue('uset',
522 uuid.UUID("0026b3ba-571b-4729-8227-d860a5210ab8"))
523 row.__setattr__('uset',
524 [uuid.UUID("0026b3ba-571b-4729-8227-d860a5210ab8")])
525 assert len(getattr(row, 'uset', [])) == 1
526 elif name == 'partialsetadddelete':
527 row = idltest_find_simple3(idl, 'String2')
528 row.addvalue('uset',
529 uuid.UUID('b6272353-af9c-40b7-90fe-32a43e6518a1'))
530 row.addvalue('uset',
531 uuid.UUID('1d6a71a2-dffb-426e-b2fa-b727091f9901'))
532 row.delvalue('uset',
533 uuid.UUID('0026b3ba-571b-4729-8227-d860a5210ab8'))
534 assert len(getattr(row, 'uset', [])) == 2
535 elif name == 'partialsetmutatenew':
536 new_row41 = txn.insert(idl.tables["simple4"])
537 new_row41.__setattr__('name', 'new_row41')
538 new_row3 = txn.insert(idl.tables["simple3"])
539 setattr(new_row3, 'name', 'String3')
540 new_row3.addvalue('uset', new_row41.uuid)
541 assert len(getattr(new_row3, 'uset', [])) == 1
542 elif name == 'partialmapmutateirefmap':
543 row3 = idltest_find_simple3(idl, "myString1")
544 row5 = idltest_find(idl, "simple5", "name", "myString2")
545 row5.setkey('irefmap', 1, row3.uuid)
546 maplen = len(row5.irefmap)
547 assert maplen == 1, "expected 1, got %d" % maplen
548 else:
549 sys.stderr.write("unknown command %s\n" % name)
550 sys.exit(1)
551
552 status = txn.commit_block()
553 sys.stdout.write("%03d: commit, status=%s"
554 % (step, ovs.db.idl.Transaction.status_to_string(status)))
555 if increment and status == ovs.db.idl.Transaction.SUCCESS:
556 sys.stdout.write(", increment=%d" % txn.get_increment_new_value())
557 if events:
558 # Event notifications from operations in a single transaction are
559 # not in a gauranteed order due to update messages being dicts
560 sys.stdout.write(", events=" + ", ".join(sorted(events)))
561 sys.stdout.write("\n")
562 sys.stdout.flush()
563
564
565 def update_condition(idl, commands):
566 commands = commands[len("condition "):].split(";")
567 for command in commands:
568 command = command.split(" ")
569 if(len(command) != 2):
570 sys.stderr.write("Error parsing condition %s\n" % command)
571 sys.exit(1)
572
573 table = command[0]
574 cond = ovs.json.from_string(command[1])
575
576 idl.cond_change(table, cond)
577
578
579 def do_idl(schema_file, remote, *commands):
580 schema_helper = ovs.db.idl.SchemaHelper(schema_file)
581 track_notify = False
582
583 if remote.startswith("ssl:"):
584 if len(commands) < 3:
585 sys.stderr.write("SSL connection requires private key, "
586 "certificate for private key, and peer CA "
587 "certificate as arguments\n")
588 sys.exit(1)
589 ovs.stream.Stream.ssl_set_private_key_file(commands[0])
590 ovs.stream.Stream.ssl_set_certificate_file(commands[1])
591 ovs.stream.Stream.ssl_set_ca_cert_file(commands[2])
592 commands = commands[3:]
593
594 if commands and commands[0] == "track-notify":
595 commands = commands[1:]
596 track_notify = True
597
598 if commands and commands[0].startswith("?"):
599 readonly = {}
600 for x in commands[0][1:].split("?"):
601 readonly = []
602 table, columns = x.split(":")
603 columns = columns.split(",")
604 for index, column in enumerate(columns):
605 if column[-1] == '!':
606 columns[index] = columns[index][:-1]
607 readonly.append(columns[index])
608 schema_helper.register_columns(table, columns, readonly)
609 commands = commands[1:]
610 else:
611 schema_helper.register_all()
612 idl = ovs.db.idl.Idl(remote, schema_helper)
613 if "simple3" in idl.tables:
614 idl.index_create("simple3", "simple3_by_name")
615
616 if commands:
617 remotes = remote.split(',')
618 stream = None
619 for r in remotes:
620 error, stream = ovs.stream.Stream.open_block(
621 ovs.stream.Stream.open(r), 2000)
622 if not error and stream:
623 break
624 stream = None
625
626 if not stream:
627 sys.stderr.write("failed to connect to \"%s\"" % remote)
628 sys.exit(1)
629 rpc = ovs.jsonrpc.Connection(stream)
630 else:
631 rpc = None
632
633 symtab = {}
634 seqno = 0
635 step = 0
636
637 def mock_notify(event, row, updates=None):
638 output = "%03d: " % step
639 output += "event:" + str(event) + ", row={"
640 output += get_simple_table_printable_row(row) + "}, updates="
641 if updates is None:
642 output += "None"
643 else:
644 output += "{" + get_simple_table_printable_row(updates) + "}"
645
646 output += '\n'
647 sys.stdout.write(output)
648 sys.stdout.flush()
649
650 if track_notify and "simple" in idl.tables:
651 idl.notify = mock_notify
652
653 commands = list(commands)
654 if len(commands) >= 1 and "condition" in commands[0]:
655 update_condition(idl, commands.pop(0))
656 sys.stdout.write("%03d: change conditions\n" % step)
657 sys.stdout.flush()
658 step += 1
659
660 for command in commands:
661 if command.startswith("+"):
662 # The previous transaction didn't change anything.
663 command = command[1:]
664 else:
665 # Wait for update.
666 while idl.change_seqno == seqno and not idl.run():
667 rpc.run()
668
669 poller = ovs.poller.Poller()
670 idl.wait(poller)
671 rpc.wait(poller)
672 poller.block()
673
674 print_idl(idl, step)
675 step += 1
676
677 seqno = idl.change_seqno
678
679 if command == "reconnect":
680 print("%03d: reconnect" % step)
681 sys.stdout.flush()
682 step += 1
683 idl.force_reconnect()
684 elif "condition" in command:
685 update_condition(idl, command)
686 sys.stdout.write("%03d: change conditions\n" % step)
687 sys.stdout.flush()
688 step += 1
689 elif not command.startswith("["):
690 idl_set(idl, command, step)
691 step += 1
692 else:
693 json = ovs.json.from_string(command)
694 if isinstance(json, str):
695 sys.stderr.write("\"%s\": %s\n" % (command, json))
696 sys.exit(1)
697 json = substitute_uuids(json, symtab)
698 request = ovs.jsonrpc.Message.create_request("transact", json)
699 error, reply = rpc.transact_block(request)
700 if error:
701 sys.stderr.write("jsonrpc transaction failed: %s\n"
702 % os.strerror(error))
703 sys.exit(1)
704 elif reply.error is not None:
705 sys.stderr.write("jsonrpc transaction failed: %s\n"
706 % reply.error)
707 sys.exit(1)
708
709 sys.stdout.write("%03d: " % step)
710 sys.stdout.flush()
711 step += 1
712 if reply.result is not None:
713 parse_uuids(reply.result, symtab)
714 reply.id = None
715 sys.stdout.write("%s\n" % ovs.json.to_string(reply.to_json()))
716 sys.stdout.flush()
717
718 if rpc:
719 rpc.close()
720 while idl.change_seqno == seqno and not idl.run():
721 poller = ovs.poller.Poller()
722 idl.wait(poller)
723 poller.block()
724 print_idl(idl, step)
725 step += 1
726 idl.close()
727 print("%03d: done" % step)
728
729
730 def do_idl_passive(schema_file, remote, *commands):
731 symtab = {}
732 step = 0
733 schema_helper = ovs.db.idl.SchemaHelper(schema_file)
734 schema_helper.register_all()
735 idl = ovs.db.idl.Idl(remote, schema_helper)
736
737 while idl._session.rpc is None:
738 idl.run()
739
740 rpc = idl._session.rpc
741
742 print_idl(idl, step)
743 step += 1
744
745 for command in commands:
746 json = ovs.json.from_string(command)
747 if isinstance(json, str):
748 sys.stderr.write("\"%s\": %s\n" % (command, json))
749 sys.exit(1)
750 json = substitute_uuids(json, symtab)
751 request = ovs.jsonrpc.Message.create_request("transact", json)
752 error, reply = rpc.transact_block(request)
753 if error:
754 sys.stderr.write("jsonrpc transaction failed: %s\n"
755 % os.strerror(error))
756 sys.exit(1)
757 elif reply.error is not None:
758 sys.stderr.write("jsonrpc transaction failed: %s\n"
759 % reply.error)
760 sys.exit(1)
761
762 sys.stdout.write("%03d: " % step)
763 sys.stdout.flush()
764 step += 1
765 if reply.result is not None:
766 parse_uuids(reply.result, symtab)
767 reply.id = None
768 sys.stdout.write("%s\n" % ovs.json.to_string(reply.to_json()))
769 sys.stdout.flush()
770
771 idl.close()
772 print("%03d: done" % step)
773
774
775 def do_idl_cluster(schema_file, remote, pid, *commands):
776 schema_helper = ovs.db.idl.SchemaHelper(schema_file)
777
778 if remote.startswith("ssl:"):
779 if len(commands) < 3:
780 sys.stderr.write("SSL connection requires private key, "
781 "certificate for private key, and peer CA "
782 "certificate as arguments\n")
783 sys.exit(1)
784 ovs.stream.Stream.ssl_set_private_key_file(commands[0])
785 ovs.stream.Stream.ssl_set_certificate_file(commands[1])
786 ovs.stream.Stream.ssl_set_ca_cert_file(commands[2])
787 commands = commands[3:]
788
789 schema_helper.register_all()
790 idl = ovs.db.idl.Idl(remote, schema_helper)
791
792 step = 0
793 seqno = 0
794 commands = list(commands)
795 for command in commands:
796 if command.startswith("+"):
797 # The previous transaction didn't change anything.
798 command = command[1:]
799 else:
800 # Wait for update.
801 while idl.change_seqno == seqno and not idl.run():
802 poller = ovs.poller.Poller()
803 idl.wait(poller)
804 poller.block()
805 step += 1
806
807 seqno = idl.change_seqno
808
809 if command == "reconnect":
810 print("%03d: reconnect" % step)
811 sys.stdout.flush()
812 step += 1
813 idl.force_reconnect()
814 elif command == "remote":
815 print("%03d: %s" % (step, idl.session_name()))
816 sys.stdout.flush()
817 step += 1
818 elif command == "remotestop":
819 r = idl.session_name()
820 remotes = remote.split(',')
821 i = remotes.index(r)
822 pids = pid.split(',')
823 command = None
824 try:
825 command = "kill %s" % pids[i]
826 except ValueError as error:
827 sys.stderr.write("Cannot find pid of remote: %s\n"
828 % os.strerror(error))
829 sys.exit(1)
830 os.popen(command)
831 print("%03d: stop %s" % (step, pids[i]))
832 sys.stdout.flush()
833 step += 1
834
835 idl.close()
836 print("%03d: done" % step)
837
838
839 def usage():
840 print("""\
841 %(program_name)s: test utility for Open vSwitch database Python bindings
842 usage: %(program_name)s [OPTIONS] COMMAND ARG...
843
844 The following commands are supported:
845 default-atoms
846 test ovsdb_atom_default()
847 default-data
848 test ovsdb_datum_default()
849 parse-atomic-type TYPE
850 parse TYPE as OVSDB atomic type, and re-serialize
851 parse-base-type TYPE
852 parse TYPE as OVSDB base type, and re-serialize
853 parse-type JSON
854 parse JSON as OVSDB type, and re-serialize
855 parse-atoms TYPE ATOM...
856 parse JSON ATOMs as atoms of TYPE, and re-serialize
857 parse-atom-strings TYPE ATOM...
858 parse string ATOMs as atoms of given TYPE, and re-serialize
859 sort-atoms TYPE ATOM...
860 print JSON ATOMs in sorted order
861 parse-data TYPE DATUM...
862 parse JSON DATUMs as data of given TYPE, and re-serialize
863 parse-column NAME OBJECT
864 parse column NAME with info OBJECT, and re-serialize
865 parse-table NAME OBJECT [DEFAULT-IS-ROOT]
866 parse table NAME with info OBJECT
867 parse-schema JSON
868 parse JSON as an OVSDB schema, and re-serialize
869 idl SCHEMA SERVER [?T1:C1,C2...[?T2:C1,C2,...]...] [TRANSACTION...]
870 connect to SERVER (which has the specified SCHEMA) and dump the
871 contents of the database as seen initially by the IDL implementation
872 and after executing each TRANSACTION. (Each TRANSACTION must modify
873 the database or this command will hang.)
874 By default, all columns of all tables are monitored. The "?" option
875 can be used to monitor specific Table:Column(s). The table and their
876 columns are listed as a string of the form starting with "?":
877 ?<table-name>:<column-name>,<column-name>,...
878 e.g.:
879 ?simple:b - Monitor column "b" in table "simple"
880 Entries for multiple tables are seperated by "?":
881 ?<table-name>:<column-name>,...?<table-name>:<column-name>,...
882 e.g.:
883 ?simple:b?link1:i,k - Monitor column "b" in table "simple",
884 and column "i", "k" in table "link1"
885 Readonly columns: Suffixing a "!" after a column indicates that the
886 column is to be registered "readonly".
887 e.g.:
888 ?simple:i,b! - Register interest in column "i" (monitoring) and
889 column "b" (readonly).
890
891
892 The following options are also available:
893 -t, --timeout=SECS give up after SECS seconds
894 -h, --help display this help message\
895 """ % {'program_name': ovs.util.PROGRAM_NAME})
896 sys.exit(0)
897
898
899 def main(argv):
900 try:
901 options, args = getopt.gnu_getopt(argv[1:], 't:h',
902 ['timeout',
903 'help'])
904 except getopt.GetoptError as geo:
905 sys.stderr.write("%s: %s\n" % (ovs.util.PROGRAM_NAME, geo.msg))
906 sys.exit(1)
907
908 timeout = None
909 for key, value in options:
910 if key in ['-h', '--help']:
911 usage()
912 elif key in ['-t', '--timeout']:
913 try:
914 timeout = int(value)
915 if timeout < 1:
916 raise TypeError
917 except TypeError:
918 raise error.Error("value %s on -t or --timeout is not at "
919 "least 1" % value)
920 else:
921 sys.exit(0)
922
923 signal_alarm(timeout)
924
925 if not args:
926 sys.stderr.write("%s: missing command argument "
927 "(use --help for help)\n" % ovs.util.PROGRAM_NAME)
928 sys.exit(1)
929
930 commands = {"default-atoms": (do_default_atoms, 0),
931 "default-data": (do_default_data, 0),
932 "parse-atomic-type": (do_parse_atomic_type, 1),
933 "parse-base-type": (do_parse_base_type, 1),
934 "parse-type": (do_parse_type, 1),
935 "parse-atoms": (do_parse_atoms, (2,)),
936 "parse-data": (do_parse_data, (2,)),
937 "sort-atoms": (do_sort_atoms, 2),
938 "parse-column": (do_parse_column, 2),
939 "parse-table": (do_parse_table, (2, 3)),
940 "parse-schema": (do_parse_schema, 1),
941 "idl": (do_idl, (2,)),
942 "idl_passive": (do_idl_passive, (2,)),
943 "idl-cluster": (do_idl_cluster, (3,))}
944
945 command_name = args[0]
946 args = args[1:]
947 if command_name not in commands:
948 sys.stderr.write("%s: unknown command \"%s\" "
949 "(use --help for help)\n" % (ovs.util.PROGRAM_NAME,
950 command_name))
951 sys.exit(1)
952
953 func, n_args = commands[command_name]
954 if type(n_args) == tuple:
955 if len(args) < n_args[0]:
956 sys.stderr.write("%s: \"%s\" requires at least %d arguments but "
957 "only %d provided\n"
958 % (ovs.util.PROGRAM_NAME, command_name,
959 n_args[0], len(args)))
960 sys.exit(1)
961 elif type(n_args) == int:
962 if len(args) != n_args:
963 sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
964 "provided\n"
965 % (ovs.util.PROGRAM_NAME, command_name,
966 n_args, len(args)))
967 sys.exit(1)
968 else:
969 assert False
970
971 func(*args)
972
973
974 if __name__ == '__main__':
975 try:
976 main(sys.argv)
977 except error.Error as e:
978 sys.stderr.write("%s\n" % e)
979 sys.exit(1)