]>
Commit | Line | Data |
---|---|---|
99155935 BP |
1 | # Copyright (c) 2009, 2010 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 codecs | |
16 | import getopt | |
17 | import re | |
18 | import os | |
19 | import signal | |
20 | import sys | |
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 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): | |
125 | table_json = unbox_json(ovs.json.from_string(table_string)) | |
126 | table = ovs.db.schema.TableSchema.from_json(table_json, name) | |
127 | print ovs.json.to_string(table.to_json(), sort_keys=True) | |
128 | ||
129 | def do_parse_rows(table_string, *rows): | |
130 | table_json = unbox_json(ovs.json.from_string(table_string)) | |
131 | table = ovs.db.schema.TableSchema.from_json(table_json, name) | |
132 | ||
133 | def do_parse_schema(schema_string): | |
134 | schema_json = unbox_json(ovs.json.from_string(schema_string)) | |
135 | schema = ovs.db.schema.DbSchema.from_json(schema_json) | |
136 | print ovs.json.to_string(schema.to_json(), sort_keys=True) | |
137 | ||
138 | def print_idl(idl, step): | |
139 | n = 0 | |
140 | for uuid, row in idl.data["simple"].iteritems(): | |
141 | s = ("%03d: i=%s r=%s b=%s s=%s u=%s " | |
142 | "ia=%s ra=%s ba=%s sa=%s ua=%s uuid=%s" | |
143 | % (step, row.i, row.r, row.b, row.s, row.u, | |
144 | row.ia, row.ra, row.ba, row.sa, row.ua, uuid)) | |
145 | print(re.sub('""|,', "", s)) | |
146 | n += 1 | |
147 | if not n: | |
148 | print("%03d: empty" % step) | |
149 | ||
150 | def substitute_uuids(json, symtab): | |
151 | if type(json) in [str, unicode]: | |
152 | symbol = symtab.get(json) | |
153 | if symbol: | |
154 | return str(symbol) | |
155 | elif type(json) == list: | |
156 | return [substitute_uuids(element, symtab) for element in json] | |
157 | elif type(json) == dict: | |
158 | d = {} | |
159 | for key, value in json.iteritems(): | |
160 | d[key] = substitute_uuids(value, symtab) | |
161 | return d | |
162 | return json | |
163 | ||
164 | def parse_uuids(json, symtab): | |
165 | if type(json) in [str, unicode] and ovs.ovsuuid.UUID.is_valid_string(json): | |
166 | name = "#%d#" % len(symtab) | |
167 | sys.stderr.write("%s = %s\n" % (name, json)) | |
168 | symtab[name] = json | |
169 | elif type(json) == list: | |
170 | for element in json: | |
171 | parse_uuids(element, symtab) | |
172 | elif type(json) == dict: | |
173 | for value in json.itervalues(): | |
174 | parse_uuids(value, symtab) | |
175 | ||
176 | def do_idl(remote, *commands): | |
177 | idl = ovs.db.idl.Idl(remote, "idltest") | |
178 | ||
179 | if commands: | |
180 | error, stream = ovs.stream.Stream.open_block( | |
181 | ovs.stream.Stream.open(remote)) | |
182 | if error: | |
183 | sys.stderr.write("failed to connect to \"%s\"" % remote) | |
184 | sys.exit(1) | |
185 | rpc = ovs.jsonrpc.Connection(stream) | |
186 | else: | |
187 | rpc = None | |
188 | ||
189 | symtab = {} | |
190 | seqno = 0 | |
191 | step = 0 | |
192 | for command in commands: | |
193 | if command.startswith("+"): | |
194 | # The previous transaction didn't change anything. | |
195 | command = command[1:] | |
196 | else: | |
197 | # Wait for update. | |
198 | while idl.get_seqno() == seqno and not idl.run(): | |
199 | rpc.run() | |
200 | ||
201 | poller = ovs.poller.Poller() | |
202 | idl.wait(poller) | |
203 | rpc.wait(poller) | |
204 | poller.block() | |
205 | ||
206 | print_idl(idl, step) | |
207 | step += 1 | |
208 | ||
209 | seqno = idl.get_seqno() | |
210 | ||
211 | if command == "reconnect": | |
212 | print("%03d: reconnect" % step) | |
213 | step += 1 | |
214 | idl.force_reconnect() | |
215 | elif not command.startswith("["): | |
216 | idl_set(idl, command, step) | |
217 | step += 1 | |
218 | else: | |
219 | json = ovs.json.from_string(command) | |
220 | if type(json) in [str, unicode]: | |
221 | sys.stderr.write("\"%s\": %s\n" % (command, json)) | |
222 | sys.exit(1) | |
223 | json = substitute_uuids(json, symtab) | |
224 | request = ovs.jsonrpc.Message.create_request("transact", json) | |
225 | error, reply = rpc.transact_block(request) | |
226 | if error: | |
227 | sys.stderr.write("jsonrpc transaction failed: %s" | |
228 | % os.strerror(error)) | |
229 | sys.exit(1) | |
230 | sys.stdout.write("%03d: " % step) | |
231 | sys.stdout.flush() | |
232 | step += 1 | |
233 | if reply.result is not None: | |
234 | parse_uuids(reply.result, symtab) | |
235 | reply.id = None | |
236 | sys.stdout.write("%s\n" % ovs.json.to_string(reply.to_json())) | |
237 | ||
238 | if rpc: | |
239 | rpc.close() | |
240 | while idl.get_seqno() == seqno and not idl.run(): | |
241 | poller = ovs.poller.Poller() | |
242 | idl.wait(poller) | |
243 | poller.block() | |
244 | print_idl(idl, step) | |
245 | step += 1 | |
246 | idl.close() | |
247 | print("%03d: done" % step) | |
248 | ||
249 | def usage(): | |
250 | print """\ | |
251 | %(program_name)s: test utility for Open vSwitch database Python bindings | |
252 | usage: %(program_name)s [OPTIONS] COMMAND ARG... | |
253 | ||
254 | The following commands are supported: | |
255 | default-atoms | |
256 | test ovsdb_atom_default() | |
257 | default-data | |
258 | test ovsdb_datum_default() | |
259 | parse-atomic-type TYPE | |
260 | parse TYPE as OVSDB atomic type, and re-serialize | |
261 | parse-base-type TYPE | |
262 | parse TYPE as OVSDB base type, and re-serialize | |
263 | parse-type JSON | |
264 | parse JSON as OVSDB type, and re-serialize | |
265 | parse-atoms TYPE ATOM... | |
266 | parse JSON ATOMs as atoms of TYPE, and re-serialize | |
267 | parse-atom-strings TYPE ATOM... | |
268 | parse string ATOMs as atoms of given TYPE, and re-serialize | |
269 | sort-atoms TYPE ATOM... | |
270 | print JSON ATOMs in sorted order | |
271 | parse-data TYPE DATUM... | |
272 | parse JSON DATUMs as data of given TYPE, and re-serialize | |
273 | parse-column NAME OBJECT | |
274 | parse column NAME with info OBJECT, and re-serialize | |
275 | parse-table NAME OBJECT | |
276 | parse table NAME with info OBJECT | |
277 | parse-schema JSON | |
278 | parse JSON as an OVSDB schema, and re-serialize | |
279 | idl SERVER [TRANSACTION...] | |
280 | connect to SERVER and dump the contents of the database | |
281 | as seen initially by the IDL implementation and after | |
282 | executing each TRANSACTION. (Each TRANSACTION must modify | |
283 | the database or this command will hang.) | |
284 | ||
285 | The following options are also available: | |
286 | -t, --timeout=SECS give up after SECS seconds | |
287 | -h, --help display this help message\ | |
288 | """ % {'program_name': ovs.util.PROGRAM_NAME} | |
289 | sys.exit(0) | |
290 | ||
291 | def main(argv): | |
292 | # Make stdout and stderr UTF-8, even if they are redirected to a file. | |
293 | sys.stdout = codecs.getwriter("utf-8")(sys.stdout) | |
294 | sys.stderr = codecs.getwriter("utf-8")(sys.stderr) | |
295 | ||
296 | try: | |
297 | options, args = getopt.gnu_getopt(argv[1:], 't:h', | |
298 | ['timeout', | |
299 | 'help']) | |
300 | except getopt.GetoptError, geo: | |
301 | sys.stderr.write("%s: %s\n" % (ovs.util.PROGRAM_NAME, geo.msg)) | |
302 | sys.exit(1) | |
303 | ||
304 | for key, value in options: | |
305 | if key in ['-h', '--help']: | |
306 | usage() | |
307 | elif key in ['-t', '--timeout']: | |
308 | try: | |
309 | timeout = int(value) | |
310 | if timeout < 1: | |
311 | raise TypeError | |
312 | except TypeError: | |
313 | raise error.Error("value %s on -t or --timeout is not at " | |
314 | "least 1" % value) | |
315 | signal.alarm(timeout) | |
316 | else: | |
317 | sys.exit(0) | |
318 | ||
319 | optKeys = [key for key, value in options] | |
320 | ||
321 | if not args: | |
322 | sys.stderr.write("%s: missing command argument " | |
323 | "(use --help for help)\n" % ovs.util.PROGRAM_NAME) | |
324 | sys.exit(1) | |
325 | ||
326 | commands = {"default-atoms": (do_default_atoms, 0), | |
327 | "default-data": (do_default_data, 0), | |
328 | "parse-atomic-type": (do_parse_atomic_type, 1), | |
329 | "parse-base-type": (do_parse_base_type, 1), | |
330 | "parse-type": (do_parse_type, 1), | |
331 | "parse-atoms": (do_parse_atoms, (2,)), | |
332 | "parse-data": (do_parse_data, (2,)), | |
333 | "sort-atoms": (do_sort_atoms, 2), | |
334 | "parse-column": (do_parse_column, 2), | |
335 | "parse-table": (do_parse_table, 2), | |
336 | "parse-schema": (do_parse_schema, 1), | |
337 | "idl": (do_idl, (1,))} | |
338 | ||
339 | command_name = args[0] | |
340 | args = args[1:] | |
341 | if not command_name in commands: | |
342 | sys.stderr.write("%s: unknown command \"%s\" " | |
343 | "(use --help for help)\n" % (ovs.util.PROGRAM_NAME, | |
344 | command_name)) | |
345 | sys.exit(1) | |
346 | ||
347 | func, n_args = commands[command_name] | |
348 | if type(n_args) == tuple: | |
349 | if len(args) < n_args[0]: | |
350 | sys.stderr.write("%s: \"%s\" requires at least %d arguments but " | |
351 | "only %d provided\n" | |
352 | % (ovs.util.PROGRAM_NAME, command_name, | |
353 | n_args, len(args))) | |
354 | sys.exit(1) | |
355 | elif type(n_args) == int: | |
356 | if len(args) != n_args: | |
357 | sys.stderr.write("%s: \"%s\" requires %d arguments but %d " | |
358 | "provided\n" | |
359 | % (ovs.util.PROGRAM_NAME, command_name, | |
360 | n_args, len(args))) | |
361 | sys.exit(1) | |
362 | else: | |
363 | assert False | |
364 | ||
365 | func(*args) | |
366 | ||
367 | if __name__ == '__main__': | |
368 | try: | |
369 | main(sys.argv) | |
370 | except error.Error, e: | |
371 | sys.stderr.write("%s\n" % e) | |
372 | sys.exit(1) |