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