test-ovsdb.py: Remove unused import.
[cascardo/ovs.git] / tests / test-ovsdb.py
1 # Copyright (c) 2009, 2010, 2011 Nicira Networks
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import getopt
16 import re
17 import os
18 import signal
19 import sys
20 import uuid
21
22 from ovs.db import error
23 import ovs.db.idl
24 import ovs.db.schema
25 from ovs.db import data
26 from ovs.db import types
27 import ovs.ovsuuid
28 import ovs.poller
29 import ovs.util
30
31 def unbox_json(json):
32     if type(json) == list and len(json) == 1:
33         return json[0]
34     else:
35         return json
36
37 def do_default_atoms():
38     for type_ in types.ATOMIC_TYPES:
39         if type_ == types.VoidType:
40             continue
41
42         sys.stdout.write("%s: " % type_.to_string())
43
44         atom = data.Atom.default(type_)
45         if atom != data.Atom.default(type_):
46             sys.stdout.write("wrong\n")
47             sys.exit(1)
48
49         sys.stdout.write("OK\n")
50
51 def do_default_data():
52     any_errors = False
53     for n_min in 0, 1:
54         for key in types.ATOMIC_TYPES:
55             if key == types.VoidType:
56                 continue
57             for value in types.ATOMIC_TYPES:
58                 if value == types.VoidType:
59                     valueBase = None
60                 else:
61                     valueBase = types.BaseType(value)
62                 type_ = types.Type(types.BaseType(key), valueBase, n_min, 1)
63                 assert type_.is_valid()
64
65                 sys.stdout.write("key %s, value %s, n_min %d: "
66                                  % (key.to_string(), value.to_string(), n_min))
67
68                 datum = data.Datum.default(type_)
69                 if datum != data.Datum.default(type_):
70                     sys.stdout.write("wrong\n")
71                     any_errors = True
72                 else:
73                     sys.stdout.write("OK\n")
74     if any_errors:
75         sys.exit(1)
76
77 def do_parse_atomic_type(type_string):
78     type_json = unbox_json(ovs.json.from_string(type_string))
79     atomic_type = types.AtomicType.from_json(type_json)
80     print ovs.json.to_string(atomic_type.to_json(), sort_keys=True)
81
82 def do_parse_base_type(type_string):
83     type_json = unbox_json(ovs.json.from_string(type_string))
84     base_type = types.BaseType.from_json(type_json)
85     print ovs.json.to_string(base_type.to_json(), sort_keys=True)
86
87 def do_parse_type(type_string):
88     type_json = unbox_json(ovs.json.from_string(type_string))
89     type_ = types.Type.from_json(type_json)
90     print ovs.json.to_string(type_.to_json(), sort_keys=True)
91
92 def do_parse_atoms(type_string, *atom_strings):
93     type_json = unbox_json(ovs.json.from_string(type_string))
94     base = types.BaseType.from_json(type_json)
95     for atom_string in atom_strings:
96         atom_json = unbox_json(ovs.json.from_string(atom_string))
97         try:
98             atom = data.Atom.from_json(base, atom_json)
99             print ovs.json.to_string(atom.to_json())
100         except error.Error, e:
101             print unicode(e)
102
103 def do_parse_data(type_string, *data_strings):
104     type_json = unbox_json(ovs.json.from_string(type_string))
105     type_ = types.Type.from_json(type_json)
106     for datum_string in data_strings:
107         datum_json = unbox_json(ovs.json.from_string(datum_string))
108         datum = data.Datum.from_json(type_, datum_json)
109         print ovs.json.to_string(datum.to_json())
110
111 def do_sort_atoms(type_string, atom_strings):
112     type_json = unbox_json(ovs.json.from_string(type_string))
113     base = types.BaseType.from_json(type_json)
114     atoms = [data.Atom.from_json(base, atom_json)
115              for atom_json in unbox_json(ovs.json.from_string(atom_strings))]
116     print ovs.json.to_string([data.Atom.to_json(atom)
117                               for atom in sorted(atoms)])
118
119 def do_parse_column(name, column_string):
120     column_json = unbox_json(ovs.json.from_string(column_string))
121     column = ovs.db.schema.ColumnSchema.from_json(column_json, name)
122     print ovs.json.to_string(column.to_json(), sort_keys=True)
123
124 def do_parse_table(name, table_string, default_is_root_string='false'):
125     default_is_root = default_is_root_string == 'true'
126     table_json = unbox_json(ovs.json.from_string(table_string))
127     table = ovs.db.schema.TableSchema.from_json(table_json, name)
128     print ovs.json.to_string(table.to_json(default_is_root), sort_keys=True)
129
130 def do_parse_schema(schema_string):
131     schema_json = unbox_json(ovs.json.from_string(schema_string))
132     schema = ovs.db.schema.DbSchema.from_json(schema_json)
133     print ovs.json.to_string(schema.to_json(), sort_keys=True)
134
135 def print_idl(idl, step):
136     simple = idl.tables["simple"].rows
137     l1 = idl.tables["link1"].rows
138     l2 = idl.tables["link2"].rows
139
140     n = 0
141     for row in simple.itervalues():
142         s = ("%03d: i=%s r=%s b=%s s=%s u=%s "
143              "ia=%s ra=%s ba=%s sa=%s ua=%s uuid=%s"
144              % (step, row.i, row.r, row.b, row.s, row.u,
145                 row.ia, row.ra, row.ba, row.sa, row.ua, row.uuid))
146         s = re.sub('""|,|u?\'', "", s)
147         s = re.sub('UUID\(([^)]+)\)', r'\1', s)
148         s = re.sub('False', 'false', s)
149         s = re.sub('True', 'true', s)
150         s = re.sub(r'(ba)=([^[][^ ]*) ', r'\1=[\2] ', s)
151         print(s)
152         n += 1
153
154     for row in l1.itervalues():
155         s = ["%03d: i=%s k=" % (step, row.i)]
156         if row.k:
157             s.append(str(row.k.i))
158         s.append(" ka=[")
159         s.append(' '.join(sorted(str(ka.i) for ka in row.ka)))
160         s.append("] l2=")
161         if row.l2:
162             s.append(str(row.l2[0].i))
163         s.append(" uuid=%s" % row.uuid)
164         print(''.join(s))
165         n += 1
166
167     for row in l2.itervalues():
168         s = ["%03d: i=%s l1=" % (step, row.i)]
169         if row.l1:
170             s.append(str(row.l1.i))
171         s.append(" uuid=%s" % row.uuid)
172         print(''.join(s))
173         n += 1
174
175     if not n:
176         print("%03d: empty" % step)
177     sys.stdout.flush()
178
179 def substitute_uuids(json, symtab):
180     if type(json) in [str, unicode]:
181         symbol = symtab.get(json)
182         if symbol:
183             return str(symbol)
184     elif type(json) == list:
185         return [substitute_uuids(element, symtab) for element in json]
186     elif type(json) == dict:
187         d = {}
188         for key, value in json.iteritems():
189             d[key] = substitute_uuids(value, symtab)
190         return d
191     return json
192
193 def parse_uuids(json, symtab):
194     if type(json) in [str, unicode] and ovs.ovsuuid.is_valid_string(json):
195         name = "#%d#" % len(symtab)
196         sys.stderr.write("%s = %s\n" % (name, json))
197         symtab[name] = json
198     elif type(json) == list:
199         for element in json:
200             parse_uuids(element, symtab)
201     elif type(json) == dict:
202         for value in json.itervalues():
203             parse_uuids(value, symtab)
204
205 def idltest_find_simple(idl, i):
206     for row in idl.tables["simple"].rows.itervalues():
207         if row.i == i:
208             return row
209     return None
210
211 def idl_set(idl, commands, step):
212     txn = ovs.db.idl.Transaction(idl)
213     increment = False
214     for command in commands.split(','):
215         words = command.split()
216         name = words[0]
217         args = words[1:]
218
219         if name == "set":
220             if len(args) != 3:
221                 sys.stderr.write('"set" command requires 3 arguments\n')
222                 sys.exit(1)
223
224             s = idltest_find_simple(idl, int(args[0]))
225             if not s:
226                 sys.stderr.write('"set" command asks for nonexistent i=%d\n'
227                                  % int(args[0]))
228                 sys.exit(1)
229
230             if args[1] == "b":
231                 s.b = args[2] == "1"
232             elif args[1] == "s":
233                 s.s = args[2]
234             elif args[1] == "u":
235                 s.u = uuid.UUID(args[2])
236             elif args[1] == "r":
237                 s.r = float(args[2])
238             else:
239                 sys.stderr.write('"set" comamnd asks for unknown column %s\n'
240                                  % args[2])
241                 sys.stderr.exit(1)
242         elif name == "insert":
243             if len(args) != 1:
244                 sys.stderr.write('"set" command requires 1 argument\n')
245                 sys.exit(1)
246
247             s = txn.insert(idl.tables["simple"])
248             s.i = int(args[0])
249         elif name == "delete":
250             if len(args) != 1:
251                 sys.stderr.write('"delete" command requires 1 argument\n')
252                 sys.exit(1)
253
254             s = idltest_find_simple(idl, int(args[0]))
255             if not s:
256                 sys.stderr.write('"delete" command asks for nonexistent i=%d\n'
257                                  % int(args[0]))
258                 sys.exit(1)
259             s.delete()
260         elif name == "verify":
261             if len(args) != 2:
262                 sys.stderr.write('"verify" command requires 2 arguments\n')
263                 sys.exit(1)
264
265             s = idltest_find_simple(idl, int(args[0]))
266             if not s:
267                 sys.stderr.write('"verify" command asks for nonexistent i=%d\n'
268                                  % int(args[0]))
269                 sys.exit(1)
270
271             if args[1] in ("i", "b", "s", "u", "r"):
272                 s.verify(args[1])
273             else:
274                 sys.stderr.write('"verify" command asks for unknown column '
275                                  '"%s"\n' % args[1])
276                 sys.exit(1)
277         elif name == "increment":
278             if len(args) != 2:
279                 sys.stderr.write('"increment" command requires 2 arguments\n')
280                 sys.exit(1)
281
282             txn.increment(args[0], args[1], [])
283             increment = True
284         elif name == "abort":
285             txn.abort()
286             break
287         elif name == "destroy":
288             print "%03d: destroy" % step
289             sys.stdout.flush()
290             txn.abort()
291             return
292         else:
293             sys.stderr.write("unknown command %s\n" % name)
294             sys.exit(1)
295
296     status = txn.commit_block()
297     sys.stdout.write("%03d: commit, status=%s"
298                      % (step, ovs.db.idl.Transaction.status_to_string(status)))
299     if increment and status == ovs.db.idl.Transaction.SUCCESS:
300         sys.stdout.write(", increment=%d" % txn.get_increment_new_value())
301     sys.stdout.write("\n")
302     sys.stdout.flush()
303
304 def do_idl(schema_file, remote, *commands):
305     schema = ovs.db.schema.DbSchema.from_json(ovs.json.from_file(schema_file))
306     idl = ovs.db.idl.Idl(remote, schema)
307
308     if commands:
309         error, stream = ovs.stream.Stream.open_block(
310             ovs.stream.Stream.open(remote))
311         if error:
312             sys.stderr.write("failed to connect to \"%s\"" % remote)
313             sys.exit(1)
314         rpc = ovs.jsonrpc.Connection(stream)
315     else:
316         rpc = None
317
318     symtab = {}
319     seqno = 0
320     step = 0
321     for command in commands:
322         if command.startswith("+"):
323             # The previous transaction didn't change anything.
324             command = command[1:]
325         else:
326             # Wait for update.
327             while idl.change_seqno == seqno and not idl.run():
328                 rpc.run()
329
330                 poller = ovs.poller.Poller()
331                 idl.wait(poller)
332                 rpc.wait(poller)
333                 poller.block()
334                 
335             print_idl(idl, step)
336             step += 1
337
338         seqno = idl.change_seqno
339
340         if command == "reconnect":
341             print("%03d: reconnect" % step)
342             sys.stdout.flush()
343             step += 1
344             idl.force_reconnect()
345         elif not command.startswith("["):
346             idl_set(idl, command, step)
347             step += 1
348         else:
349             json = ovs.json.from_string(command)
350             if type(json) in [str, unicode]:
351                 sys.stderr.write("\"%s\": %s\n" % (command, json))
352                 sys.exit(1)
353             json = substitute_uuids(json, symtab)
354             request = ovs.jsonrpc.Message.create_request("transact", json)
355             error, reply = rpc.transact_block(request)
356             if error:
357                 sys.stderr.write("jsonrpc transaction failed: %s"
358                                  % os.strerror(error))
359                 sys.exit(1)
360             sys.stdout.write("%03d: " % step)
361             sys.stdout.flush()
362             step += 1
363             if reply.result is not None:
364                 parse_uuids(reply.result, symtab)
365             reply.id = None
366             sys.stdout.write("%s\n" % ovs.json.to_string(reply.to_json()))
367             sys.stdout.flush()
368
369     if rpc:
370         rpc.close()
371     while idl.change_seqno == seqno and not idl.run():
372         poller = ovs.poller.Poller()
373         idl.wait(poller)
374         poller.block()
375     print_idl(idl, step)
376     step += 1
377     idl.close()
378     print("%03d: done" % step)
379
380 def usage():
381     print """\
382 %(program_name)s: test utility for Open vSwitch database Python bindings
383 usage: %(program_name)s [OPTIONS] COMMAND ARG...
384
385 The following commands are supported:
386 default-atoms
387   test ovsdb_atom_default()
388 default-data
389   test ovsdb_datum_default()
390 parse-atomic-type TYPE
391   parse TYPE as OVSDB atomic type, and re-serialize
392 parse-base-type TYPE
393   parse TYPE as OVSDB base type, and re-serialize
394 parse-type JSON
395   parse JSON as OVSDB type, and re-serialize
396 parse-atoms TYPE ATOM...
397   parse JSON ATOMs as atoms of TYPE, and re-serialize
398 parse-atom-strings TYPE ATOM...
399   parse string ATOMs as atoms of given TYPE, and re-serialize
400 sort-atoms TYPE ATOM...
401   print JSON ATOMs in sorted order
402 parse-data TYPE DATUM...
403   parse JSON DATUMs as data of given TYPE, and re-serialize
404 parse-column NAME OBJECT
405   parse column NAME with info OBJECT, and re-serialize
406 parse-table NAME OBJECT [DEFAULT-IS-ROOT]
407   parse table NAME with info OBJECT
408 parse-schema JSON
409   parse JSON as an OVSDB schema, and re-serialize
410 idl SCHEMA SERVER [TRANSACTION...]
411   connect to SERVER (which has the specified SCHEMA) and dump the
412   contents of the database as seen initially by the IDL implementation
413   and after executing each TRANSACTION.  (Each TRANSACTION must modify
414   the database or this command will hang.)
415
416 The following options are also available:
417   -t, --timeout=SECS          give up after SECS seconds
418   -h, --help                  display this help message\
419 """ % {'program_name': ovs.util.PROGRAM_NAME}
420     sys.exit(0)
421
422 def main(argv):
423     try:
424         options, args = getopt.gnu_getopt(argv[1:], 't:h',
425                                           ['timeout',
426                                            'help'])
427     except getopt.GetoptError, geo:
428         sys.stderr.write("%s: %s\n" % (ovs.util.PROGRAM_NAME, geo.msg))
429         sys.exit(1)
430
431     for key, value in options:
432         if key in ['-h', '--help']:
433             usage()
434         elif key in ['-t', '--timeout']:
435             try:
436                 timeout = int(value)
437                 if timeout < 1:
438                     raise TypeError
439             except TypeError:
440                 raise error.Error("value %s on -t or --timeout is not at "
441                                   "least 1" % value)
442             signal.alarm(timeout)
443         else:
444             sys.exit(0)
445
446     if not args:
447         sys.stderr.write("%s: missing command argument "
448                          "(use --help for help)\n" % ovs.util.PROGRAM_NAME)
449         sys.exit(1)
450
451     commands = {"default-atoms": (do_default_atoms, 0),
452                 "default-data": (do_default_data, 0),
453                 "parse-atomic-type": (do_parse_atomic_type, 1),
454                 "parse-base-type": (do_parse_base_type, 1),
455                 "parse-type": (do_parse_type, 1),
456                 "parse-atoms": (do_parse_atoms, (2,)),
457                 "parse-data": (do_parse_data, (2,)),
458                 "sort-atoms": (do_sort_atoms, 2),
459                 "parse-column": (do_parse_column, 2),
460                 "parse-table": (do_parse_table, (2, 3)),
461                 "parse-schema": (do_parse_schema, 1),
462                 "idl": (do_idl, (2,))}
463
464     command_name = args[0]
465     args = args[1:]
466     if not command_name in commands:
467         sys.stderr.write("%s: unknown command \"%s\" "
468                          "(use --help for help)\n" % (ovs.util.PROGRAM_NAME,
469                                                       command_name))
470         sys.exit(1)
471
472     func, n_args = commands[command_name]
473     if type(n_args) == tuple:
474         if len(args) < n_args[0]:
475             sys.stderr.write("%s: \"%s\" requires at least %d arguments but "
476                              "only %d provided\n"
477                              % (ovs.util.PROGRAM_NAME, command_name,
478                                 n_args, len(args)))
479             sys.exit(1)
480     elif type(n_args) == int:
481         if len(args) != n_args:
482             sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
483                              "provided\n"
484                              % (ovs.util.PROGRAM_NAME, command_name,
485                                 n_args, len(args)))
486             sys.exit(1)
487     else:
488         assert False
489
490     func(*args)
491
492 if __name__ == '__main__':
493     try:
494         main(sys.argv)
495     except error.Error, e:
496         sys.stderr.write("%s\n" % e)
497         sys.exit(1)