netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / tests / test-jsonrpc.py
1 # Copyright (c) 2009, 2010, 2011 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 argparse
18 import errno
19 import os
20 import sys
21
22 import ovs.daemon
23 import ovs.json
24 import ovs.jsonrpc
25 import ovs.poller
26 import ovs.stream
27
28
29 def handle_rpc(rpc, msg):
30     done = False
31     reply = None
32
33     if msg.type == ovs.jsonrpc.Message.T_REQUEST:
34         if msg.method == "echo":
35             reply = ovs.jsonrpc.Message.create_reply(msg.params, msg.id)
36         else:
37             reply = ovs.jsonrpc.Message.create_error(
38                 {"error": "unknown method"}, msg.id)
39             sys.stderr.write("unknown request %s" % msg.method)
40     elif msg.type == ovs.jsonrpc.Message.T_NOTIFY:
41         if msg.method == "shutdown":
42             done = True
43         else:
44             rpc.error(errno.ENOTTY)
45             sys.stderr.write("unknown notification %s" % msg.method)
46     else:
47         rpc.error(errno.EPROTO)
48         sys.stderr.write("unsolicited JSON-RPC reply or error\n")
49
50     if reply:
51         rpc.send(reply)
52     return done
53
54
55 def do_listen(name):
56     error, pstream = ovs.stream.PassiveStream.open(name)
57     if error:
58         sys.stderr.write("could not listen on \"%s\": %s\n"
59                          % (name, os.strerror(error)))
60         sys.exit(1)
61
62     ovs.daemon.daemonize()
63
64     rpcs = []
65     done = False
66     while True:
67         # Accept new connections.
68         error, stream = pstream.accept()
69         if stream:
70             rpcs.append(ovs.jsonrpc.Connection(stream))
71         elif error != errno.EAGAIN:
72             sys.stderr.write("PassiveStream.accept() failed\n")
73             sys.exit(1)
74
75         # Service existing connections.
76         dead_rpcs = []
77         for rpc in rpcs:
78             rpc.run()
79
80             error = 0
81             if not rpc.get_backlog():
82                 error, msg = rpc.recv()
83                 if not error:
84                     if handle_rpc(rpc, msg):
85                         done = True
86
87             error = rpc.get_status()
88             if error:
89                 rpc.close()
90                 dead_rpcs.append(rpc)
91         rpcs = [rpc for rpc in rpcs if rpc not in dead_rpcs]
92
93         if done and not rpcs:
94             break
95
96         poller = ovs.poller.Poller()
97         pstream.wait(poller)
98         for rpc in rpcs:
99             rpc.wait(poller)
100             if not rpc.get_backlog():
101                 rpc.recv_wait(poller)
102         poller.block()
103     pstream.close()
104
105
106 def do_request(name, method, params_string):
107     params = ovs.json.from_string(params_string)
108     msg = ovs.jsonrpc.Message.create_request(method, params)
109     s = msg.is_valid()
110     if s:
111         sys.stderr.write("not a valid JSON-RPC request: %s\n" % s)
112         sys.exit(1)
113
114     error, stream = ovs.stream.Stream.open_block(ovs.stream.Stream.open(name))
115     if error:
116         sys.stderr.write("could not open \"%s\": %s\n"
117                          % (name, os.strerror(error)))
118         sys.exit(1)
119
120     rpc = ovs.jsonrpc.Connection(stream)
121
122     error = rpc.send(msg)
123     if error:
124         sys.stderr.write("could not send request: %s\n" % os.strerror(error))
125         sys.exit(1)
126
127     error, msg = rpc.recv_block()
128     if error:
129         sys.stderr.write("error waiting for reply: %s\n" % os.strerror(error))
130         sys.exit(1)
131
132     print(ovs.json.to_string(msg.to_json()))
133
134     rpc.close()
135
136
137 def do_notify(name, method, params_string):
138     params = ovs.json.from_string(params_string)
139     msg = ovs.jsonrpc.Message.create_notify(method, params)
140     s = msg.is_valid()
141     if s:
142         sys.stderr.write("not a valid JSON-RPC notification: %s\n" % s)
143         sys.exit(1)
144
145     error, stream = ovs.stream.Stream.open_block(ovs.stream.Stream.open(name))
146     if error:
147         sys.stderr.write("could not open \"%s\": %s\n"
148                          % (name, os.strerror(error)))
149         sys.exit(1)
150
151     rpc = ovs.jsonrpc.Connection(stream)
152
153     error = rpc.send_block(msg)
154     if error:
155         sys.stderr.write("could not send notification: %s\n"
156                          % os.strerror(error))
157         sys.exit(1)
158
159     rpc.close()
160
161
162 def main(argv):
163
164     parser = argparse.ArgumentParser(
165             description="JSON-RPC test utility for Python.",
166             formatter_class=argparse.RawDescriptionHelpFormatter)
167
168     commands = {"listen": (do_listen, 1),
169                 "request": (do_request, 3),
170                 "notify": (do_notify, 3),
171                 "help": (parser.print_help, (0,))}
172
173     group_description = """\
174 listen LOCAL             listen for connections on LOCAL
175 request REMOTE METHOD PARAMS   send request, print reply
176 notify REMOTE METHOD PARAMS  send notification and exit
177 """ + ovs.stream.usage("JSON-RPC")
178
179     group = parser.add_argument_group(title="Commands",
180                                       description=group_description)
181     group.add_argument('command', metavar="COMMAND", nargs=1,
182                         choices=commands, help="Command to use.")
183     group.add_argument('command_args', metavar="ARG", nargs='*',
184                        help="Arguments to COMMAND.")
185
186     ovs.daemon.add_args(parser)
187     args = parser.parse_args()
188     ovs.daemon.handle_args(args)
189
190     command_name = args.command[0]
191     args = args.command_args
192     if command_name not in commands:
193         sys.stderr.write("%s: unknown command \"%s\" "
194                          "(use --help for help)\n" % (argv[0], command_name))
195         sys.exit(1)
196
197     func, n_args = commands[command_name]
198     if type(n_args) == tuple:
199         if len(args) < n_args[0]:
200             sys.stderr.write("%s: \"%s\" requires at least %d arguments but "
201                              "only %d provided\n"
202                              % (argv[0], command_name, n_args, len(args)))
203             sys.exit(1)
204     elif type(n_args) == int:
205         if len(args) != n_args:
206             sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
207                              "provided\n"
208                              % (argv[0], command_name, n_args, len(args)))
209             sys.exit(1)
210     else:
211         assert False
212
213     func(*args)
214
215
216 if __name__ == '__main__':
217     main(sys.argv)