mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 18:07:40 +00:00
373 lines
13 KiB
Python
373 lines
13 KiB
Python
|
# Copyright (c) 2009, 2010 Nicira Networks
|
||
|
#
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at:
|
||
|
#
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
#
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
|
||
|
import codecs
|
||
|
import getopt
|
||
|
import re
|
||
|
import os
|
||
|
import signal
|
||
|
import sys
|
||
|
|
||
|
from ovs.db import error
|
||
|
import ovs.db.idl
|
||
|
import ovs.db.schema
|
||
|
from ovs.db import data
|
||
|
from ovs.db import types
|
||
|
import ovs.ovsuuid
|
||
|
import ovs.poller
|
||
|
import ovs.util
|
||
|
|
||
|
def unbox_json(json):
|
||
|
if type(json) == list and len(json) == 1:
|
||
|
return json[0]
|
||
|
else:
|
||
|
return json
|
||
|
|
||
|
def do_default_atoms():
|
||
|
for type in types.ATOMIC_TYPES:
|
||
|
if type == types.VoidType:
|
||
|
continue
|
||
|
|
||
|
sys.stdout.write("%s: " % type.to_string())
|
||
|
|
||
|
atom = data.Atom.default(type)
|
||
|
if atom != data.Atom.default(type):
|
||
|
sys.stdout.write("wrong\n")
|
||
|
sys.exit(1)
|
||
|
|
||
|
sys.stdout.write("OK\n")
|
||
|
|
||
|
def do_default_data():
|
||
|
any_errors = False
|
||
|
for n_min in 0, 1:
|
||
|
for key in types.ATOMIC_TYPES:
|
||
|
if key == types.VoidType:
|
||
|
continue
|
||
|
for value in types.ATOMIC_TYPES:
|
||
|
if value == types.VoidType:
|
||
|
valueBase = None
|
||
|
else:
|
||
|
valueBase = types.BaseType(value)
|
||
|
type = types.Type(types.BaseType(key), valueBase, n_min, 1)
|
||
|
assert type.is_valid()
|
||
|
|
||
|
sys.stdout.write("key %s, value %s, n_min %d: "
|
||
|
% (key.to_string(), value.to_string(), n_min))
|
||
|
|
||
|
datum = data.Datum.default(type)
|
||
|
if datum != data.Datum.default(type):
|
||
|
sys.stdout.write("wrong\n")
|
||
|
any_errors = True
|
||
|
else:
|
||
|
sys.stdout.write("OK\n")
|
||
|
if any_errors:
|
||
|
sys.exit(1)
|
||
|
|
||
|
def do_parse_atomic_type(type_string):
|
||
|
type_json = unbox_json(ovs.json.from_string(type_string))
|
||
|
atomic_type = types.AtomicType.from_json(type_json)
|
||
|
print ovs.json.to_string(atomic_type.to_json(), sort_keys=True)
|
||
|
|
||
|
def do_parse_base_type(type_string):
|
||
|
type_json = unbox_json(ovs.json.from_string(type_string))
|
||
|
base_type = types.BaseType.from_json(type_json)
|
||
|
print ovs.json.to_string(base_type.to_json(), sort_keys=True)
|
||
|
|
||
|
def do_parse_type(type_string):
|
||
|
type_json = unbox_json(ovs.json.from_string(type_string))
|
||
|
type = types.Type.from_json(type_json)
|
||
|
print ovs.json.to_string(type.to_json(), sort_keys=True)
|
||
|
|
||
|
def do_parse_atoms(type_string, *atom_strings):
|
||
|
type_json = unbox_json(ovs.json.from_string(type_string))
|
||
|
base = types.BaseType.from_json(type_json)
|
||
|
for atom_string in atom_strings:
|
||
|
atom_json = unbox_json(ovs.json.from_string(atom_string))
|
||
|
try:
|
||
|
atom = data.Atom.from_json(base, atom_json)
|
||
|
print ovs.json.to_string(atom.to_json())
|
||
|
except error.Error, e:
|
||
|
print e
|
||
|
|
||
|
def do_parse_data(type_string, *data_strings):
|
||
|
type_json = unbox_json(ovs.json.from_string(type_string))
|
||
|
type = types.Type.from_json(type_json)
|
||
|
for datum_string in data_strings:
|
||
|
datum_json = unbox_json(ovs.json.from_string(datum_string))
|
||
|
datum = data.Datum.from_json(type, datum_json)
|
||
|
print ovs.json.to_string(datum.to_json())
|
||
|
|
||
|
def do_sort_atoms(type_string, atom_strings):
|
||
|
type_json = unbox_json(ovs.json.from_string(type_string))
|
||
|
base = types.BaseType.from_json(type_json)
|
||
|
atoms = [data.Atom.from_json(base, atom_json)
|
||
|
for atom_json in unbox_json(ovs.json.from_string(atom_strings))]
|
||
|
print ovs.json.to_string([data.Atom.to_json(atom)
|
||
|
for atom in sorted(atoms)])
|
||
|
|
||
|
def do_parse_column(name, column_string):
|
||
|
column_json = unbox_json(ovs.json.from_string(column_string))
|
||
|
column = ovs.db.schema.ColumnSchema.from_json(column_json, name)
|
||
|
print ovs.json.to_string(column.to_json(), sort_keys=True)
|
||
|
|
||
|
def do_parse_table(name, table_string):
|
||
|
table_json = unbox_json(ovs.json.from_string(table_string))
|
||
|
table = ovs.db.schema.TableSchema.from_json(table_json, name)
|
||
|
print ovs.json.to_string(table.to_json(), sort_keys=True)
|
||
|
|
||
|
def do_parse_rows(table_string, *rows):
|
||
|
table_json = unbox_json(ovs.json.from_string(table_string))
|
||
|
table = ovs.db.schema.TableSchema.from_json(table_json, name)
|
||
|
|
||
|
def do_parse_schema(schema_string):
|
||
|
schema_json = unbox_json(ovs.json.from_string(schema_string))
|
||
|
schema = ovs.db.schema.DbSchema.from_json(schema_json)
|
||
|
print ovs.json.to_string(schema.to_json(), sort_keys=True)
|
||
|
|
||
|
def print_idl(idl, step):
|
||
|
n = 0
|
||
|
for uuid, row in idl.data["simple"].iteritems():
|
||
|
s = ("%03d: i=%s r=%s b=%s s=%s u=%s "
|
||
|
"ia=%s ra=%s ba=%s sa=%s ua=%s uuid=%s"
|
||
|
% (step, row.i, row.r, row.b, row.s, row.u,
|
||
|
row.ia, row.ra, row.ba, row.sa, row.ua, uuid))
|
||
|
print(re.sub('""|,', "", s))
|
||
|
n += 1
|
||
|
if not n:
|
||
|
print("%03d: empty" % step)
|
||
|
|
||
|
def substitute_uuids(json, symtab):
|
||
|
if type(json) in [str, unicode]:
|
||
|
symbol = symtab.get(json)
|
||
|
if symbol:
|
||
|
return str(symbol)
|
||
|
elif type(json) == list:
|
||
|
return [substitute_uuids(element, symtab) for element in json]
|
||
|
elif type(json) == dict:
|
||
|
d = {}
|
||
|
for key, value in json.iteritems():
|
||
|
d[key] = substitute_uuids(value, symtab)
|
||
|
return d
|
||
|
return json
|
||
|
|
||
|
def parse_uuids(json, symtab):
|
||
|
if type(json) in [str, unicode] and ovs.ovsuuid.UUID.is_valid_string(json):
|
||
|
name = "#%d#" % len(symtab)
|
||
|
sys.stderr.write("%s = %s\n" % (name, json))
|
||
|
symtab[name] = json
|
||
|
elif type(json) == list:
|
||
|
for element in json:
|
||
|
parse_uuids(element, symtab)
|
||
|
elif type(json) == dict:
|
||
|
for value in json.itervalues():
|
||
|
parse_uuids(value, symtab)
|
||
|
|
||
|
def do_idl(remote, *commands):
|
||
|
idl = ovs.db.idl.Idl(remote, "idltest")
|
||
|
|
||
|
if commands:
|
||
|
error, stream = ovs.stream.Stream.open_block(
|
||
|
ovs.stream.Stream.open(remote))
|
||
|
if error:
|
||
|
sys.stderr.write("failed to connect to \"%s\"" % remote)
|
||
|
sys.exit(1)
|
||
|
rpc = ovs.jsonrpc.Connection(stream)
|
||
|
else:
|
||
|
rpc = None
|
||
|
|
||
|
symtab = {}
|
||
|
seqno = 0
|
||
|
step = 0
|
||
|
for command in commands:
|
||
|
if command.startswith("+"):
|
||
|
# The previous transaction didn't change anything.
|
||
|
command = command[1:]
|
||
|
else:
|
||
|
# Wait for update.
|
||
|
while idl.get_seqno() == seqno and not idl.run():
|
||
|
rpc.run()
|
||
|
|
||
|
poller = ovs.poller.Poller()
|
||
|
idl.wait(poller)
|
||
|
rpc.wait(poller)
|
||
|
poller.block()
|
||
|
|
||
|
print_idl(idl, step)
|
||
|
step += 1
|
||
|
|
||
|
seqno = idl.get_seqno()
|
||
|
|
||
|
if command == "reconnect":
|
||
|
print("%03d: reconnect" % step)
|
||
|
step += 1
|
||
|
idl.force_reconnect()
|
||
|
elif not command.startswith("["):
|
||
|
idl_set(idl, command, step)
|
||
|
step += 1
|
||
|
else:
|
||
|
json = ovs.json.from_string(command)
|
||
|
if type(json) in [str, unicode]:
|
||
|
sys.stderr.write("\"%s\": %s\n" % (command, json))
|
||
|
sys.exit(1)
|
||
|
json = substitute_uuids(json, symtab)
|
||
|
request = ovs.jsonrpc.Message.create_request("transact", json)
|
||
|
error, reply = rpc.transact_block(request)
|
||
|
if error:
|
||
|
sys.stderr.write("jsonrpc transaction failed: %s"
|
||
|
% os.strerror(error))
|
||
|
sys.exit(1)
|
||
|
sys.stdout.write("%03d: " % step)
|
||
|
sys.stdout.flush()
|
||
|
step += 1
|
||
|
if reply.result is not None:
|
||
|
parse_uuids(reply.result, symtab)
|
||
|
reply.id = None
|
||
|
sys.stdout.write("%s\n" % ovs.json.to_string(reply.to_json()))
|
||
|
|
||
|
if rpc:
|
||
|
rpc.close()
|
||
|
while idl.get_seqno() == seqno and not idl.run():
|
||
|
poller = ovs.poller.Poller()
|
||
|
idl.wait(poller)
|
||
|
poller.block()
|
||
|
print_idl(idl, step)
|
||
|
step += 1
|
||
|
idl.close()
|
||
|
print("%03d: done" % step)
|
||
|
|
||
|
def usage():
|
||
|
print """\
|
||
|
%(program_name)s: test utility for Open vSwitch database Python bindings
|
||
|
usage: %(program_name)s [OPTIONS] COMMAND ARG...
|
||
|
|
||
|
The following commands are supported:
|
||
|
default-atoms
|
||
|
test ovsdb_atom_default()
|
||
|
default-data
|
||
|
test ovsdb_datum_default()
|
||
|
parse-atomic-type TYPE
|
||
|
parse TYPE as OVSDB atomic type, and re-serialize
|
||
|
parse-base-type TYPE
|
||
|
parse TYPE as OVSDB base type, and re-serialize
|
||
|
parse-type JSON
|
||
|
parse JSON as OVSDB type, and re-serialize
|
||
|
parse-atoms TYPE ATOM...
|
||
|
parse JSON ATOMs as atoms of TYPE, and re-serialize
|
||
|
parse-atom-strings TYPE ATOM...
|
||
|
parse string ATOMs as atoms of given TYPE, and re-serialize
|
||
|
sort-atoms TYPE ATOM...
|
||
|
print JSON ATOMs in sorted order
|
||
|
parse-data TYPE DATUM...
|
||
|
parse JSON DATUMs as data of given TYPE, and re-serialize
|
||
|
parse-column NAME OBJECT
|
||
|
parse column NAME with info OBJECT, and re-serialize
|
||
|
parse-table NAME OBJECT
|
||
|
parse table NAME with info OBJECT
|
||
|
parse-schema JSON
|
||
|
parse JSON as an OVSDB schema, and re-serialize
|
||
|
idl SERVER [TRANSACTION...]
|
||
|
connect to SERVER and dump the contents of the database
|
||
|
as seen initially by the IDL implementation and after
|
||
|
executing each TRANSACTION. (Each TRANSACTION must modify
|
||
|
the database or this command will hang.)
|
||
|
|
||
|
The following options are also available:
|
||
|
-t, --timeout=SECS give up after SECS seconds
|
||
|
-h, --help display this help message\
|
||
|
""" % {'program_name': ovs.util.PROGRAM_NAME}
|
||
|
sys.exit(0)
|
||
|
|
||
|
def main(argv):
|
||
|
# Make stdout and stderr UTF-8, even if they are redirected to a file.
|
||
|
sys.stdout = codecs.getwriter("utf-8")(sys.stdout)
|
||
|
sys.stderr = codecs.getwriter("utf-8")(sys.stderr)
|
||
|
|
||
|
try:
|
||
|
options, args = getopt.gnu_getopt(argv[1:], 't:h',
|
||
|
['timeout',
|
||
|
'help'])
|
||
|
except getopt.GetoptError, geo:
|
||
|
sys.stderr.write("%s: %s\n" % (ovs.util.PROGRAM_NAME, geo.msg))
|
||
|
sys.exit(1)
|
||
|
|
||
|
for key, value in options:
|
||
|
if key in ['-h', '--help']:
|
||
|
usage()
|
||
|
elif key in ['-t', '--timeout']:
|
||
|
try:
|
||
|
timeout = int(value)
|
||
|
if timeout < 1:
|
||
|
raise TypeError
|
||
|
except TypeError:
|
||
|
raise error.Error("value %s on -t or --timeout is not at "
|
||
|
"least 1" % value)
|
||
|
signal.alarm(timeout)
|
||
|
else:
|
||
|
sys.exit(0)
|
||
|
|
||
|
optKeys = [key for key, value in options]
|
||
|
|
||
|
if not args:
|
||
|
sys.stderr.write("%s: missing command argument "
|
||
|
"(use --help for help)\n" % ovs.util.PROGRAM_NAME)
|
||
|
sys.exit(1)
|
||
|
|
||
|
commands = {"default-atoms": (do_default_atoms, 0),
|
||
|
"default-data": (do_default_data, 0),
|
||
|
"parse-atomic-type": (do_parse_atomic_type, 1),
|
||
|
"parse-base-type": (do_parse_base_type, 1),
|
||
|
"parse-type": (do_parse_type, 1),
|
||
|
"parse-atoms": (do_parse_atoms, (2,)),
|
||
|
"parse-data": (do_parse_data, (2,)),
|
||
|
"sort-atoms": (do_sort_atoms, 2),
|
||
|
"parse-column": (do_parse_column, 2),
|
||
|
"parse-table": (do_parse_table, 2),
|
||
|
"parse-schema": (do_parse_schema, 1),
|
||
|
"idl": (do_idl, (1,))}
|
||
|
|
||
|
command_name = args[0]
|
||
|
args = args[1:]
|
||
|
if not command_name in commands:
|
||
|
sys.stderr.write("%s: unknown command \"%s\" "
|
||
|
"(use --help for help)\n" % (ovs.util.PROGRAM_NAME,
|
||
|
command_name))
|
||
|
sys.exit(1)
|
||
|
|
||
|
func, n_args = commands[command_name]
|
||
|
if type(n_args) == tuple:
|
||
|
if len(args) < n_args[0]:
|
||
|
sys.stderr.write("%s: \"%s\" requires at least %d arguments but "
|
||
|
"only %d provided\n"
|
||
|
% (ovs.util.PROGRAM_NAME, command_name,
|
||
|
n_args, len(args)))
|
||
|
sys.exit(1)
|
||
|
elif type(n_args) == int:
|
||
|
if len(args) != n_args:
|
||
|
sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
|
||
|
"provided\n"
|
||
|
% (ovs.util.PROGRAM_NAME, command_name,
|
||
|
n_args, len(args)))
|
||
|
sys.exit(1)
|
||
|
else:
|
||
|
assert False
|
||
|
|
||
|
func(*args)
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
try:
|
||
|
main(sys.argv)
|
||
|
except error.Error, e:
|
||
|
sys.stderr.write("%s\n" % e)
|
||
|
sys.exit(1)
|