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