]> git.proxmox.com Git - ovs.git/blame - tests/test-jsonrpc.py
dpif-netdev: Incremental addition/deletion of PMD threads.
[ovs.git] / tests / test-jsonrpc.py
CommitLineData
e0edde6f 1# Copyright (c) 2009, 2010, 2011 Nicira, Inc.
99155935
BP
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
8ea171ab
RB
15from __future__ import print_function
16
b153e667 17import argparse
99155935 18import errno
99155935
BP
19import os
20import sys
21
22import ovs.daemon
23import ovs.json
24import ovs.jsonrpc
25import ovs.poller
26import ovs.stream
27
e60a5e26 28
99155935
BP
29def 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")
e60a5e26 49
99155935
BP
50 if reply:
51 rpc.send(reply)
52 return done
53
e60a5e26 54
99155935 55def do_listen(name):
03947eb7
AB
56 if sys.platform != 'win32' or (
57 ovs.daemon._detach and ovs.daemon._detached):
58 # On Windows the child is a new process created which should be the
59 # one that creates the PassiveStream. Without this check, the new
60 # child process will create a new PassiveStream overwriting the one
61 # that the parent process created.
62 error, pstream = ovs.stream.PassiveStream.open(name)
63 if error:
64 sys.stderr.write("could not listen on \"%s\": %s\n"
65 % (name, os.strerror(error)))
66 sys.exit(1)
99155935
BP
67
68 ovs.daemon.daemonize()
69
70 rpcs = []
71 done = False
72 while True:
73 # Accept new connections.
74 error, stream = pstream.accept()
75 if stream:
76 rpcs.append(ovs.jsonrpc.Connection(stream))
77 elif error != errno.EAGAIN:
78 sys.stderr.write("PassiveStream.accept() failed\n")
79 sys.exit(1)
80
81 # Service existing connections.
82 dead_rpcs = []
83 for rpc in rpcs:
84 rpc.run()
85
86 error = 0
87 if not rpc.get_backlog():
88 error, msg = rpc.recv()
89 if not error:
90 if handle_rpc(rpc, msg):
91 done = True
92
93 error = rpc.get_status()
94 if error:
95 rpc.close()
96 dead_rpcs.append(rpc)
603e325f 97 rpcs = [rpc for rpc in rpcs if rpc not in dead_rpcs]
99155935
BP
98
99 if done and not rpcs:
100 break
101
102 poller = ovs.poller.Poller()
103 pstream.wait(poller)
104 for rpc in rpcs:
105 rpc.wait(poller)
106 if not rpc.get_backlog():
107 rpc.recv_wait(poller)
108 poller.block()
109 pstream.close()
110
e60a5e26 111
99155935
BP
112def do_request(name, method, params_string):
113 params = ovs.json.from_string(params_string)
114 msg = ovs.jsonrpc.Message.create_request(method, params)
115 s = msg.is_valid()
116 if s:
117 sys.stderr.write("not a valid JSON-RPC request: %s\n" % s)
118 sys.exit(1)
119
120 error, stream = ovs.stream.Stream.open_block(ovs.stream.Stream.open(name))
121 if error:
122 sys.stderr.write("could not open \"%s\": %s\n"
123 % (name, os.strerror(error)))
124 sys.exit(1)
125
126 rpc = ovs.jsonrpc.Connection(stream)
127
128 error = rpc.send(msg)
129 if error:
130 sys.stderr.write("could not send request: %s\n" % os.strerror(error))
131 sys.exit(1)
132
133 error, msg = rpc.recv_block()
134 if error:
135 sys.stderr.write("error waiting for reply: %s\n" % os.strerror(error))
136 sys.exit(1)
e60a5e26 137
8ea171ab 138 print(ovs.json.to_string(msg.to_json()))
99155935
BP
139
140 rpc.close()
e60a5e26
EJ
141
142
99155935
BP
143def do_notify(name, method, params_string):
144 params = ovs.json.from_string(params_string)
145 msg = ovs.jsonrpc.Message.create_notify(method, params)
146 s = msg.is_valid()
147 if s:
148 sys.stderr.write("not a valid JSON-RPC notification: %s\n" % s)
149 sys.exit(1)
150
151 error, stream = ovs.stream.Stream.open_block(ovs.stream.Stream.open(name))
152 if error:
153 sys.stderr.write("could not open \"%s\": %s\n"
154 % (name, os.strerror(error)))
155 sys.exit(1)
156
157 rpc = ovs.jsonrpc.Connection(stream)
158
159 error = rpc.send_block(msg)
160 if error:
161 sys.stderr.write("could not send notification: %s\n"
162 % os.strerror(error))
163 sys.exit(1)
164
165 rpc.close()
166
e60a5e26 167
99155935 168def main(argv):
99155935 169
b153e667
EJ
170 parser = argparse.ArgumentParser(
171 description="JSON-RPC test utility for Python.",
172 formatter_class=argparse.RawDescriptionHelpFormatter)
99155935
BP
173
174 commands = {"listen": (do_listen, 1),
175 "request": (do_request, 3),
176 "notify": (do_notify, 3),
b153e667
EJ
177 "help": (parser.print_help, (0,))}
178
179 group_description = """\
180listen LOCAL listen for connections on LOCAL
181request REMOTE METHOD PARAMS send request, print reply
182notify REMOTE METHOD PARAMS send notification and exit
183""" + ovs.stream.usage("JSON-RPC")
184
185 group = parser.add_argument_group(title="Commands",
186 description=group_description)
187 group.add_argument('command', metavar="COMMAND", nargs=1,
188 choices=commands, help="Command to use.")
189 group.add_argument('command_args', metavar="ARG", nargs='*',
190 help="Arguments to COMMAND.")
191
192 ovs.daemon.add_args(parser)
193 args = parser.parse_args()
194 ovs.daemon.handle_args(args)
195
196 command_name = args.command[0]
197 args = args.command_args
603e325f 198 if command_name not in commands:
99155935 199 sys.stderr.write("%s: unknown command \"%s\" "
d2dc8f58 200 "(use --help for help)\n" % (argv[0], command_name))
99155935
BP
201 sys.exit(1)
202
203 func, n_args = commands[command_name]
204 if type(n_args) == tuple:
205 if len(args) < n_args[0]:
206 sys.stderr.write("%s: \"%s\" requires at least %d arguments but "
207 "only %d provided\n"
d2dc8f58 208 % (argv[0], command_name, n_args, len(args)))
99155935
BP
209 sys.exit(1)
210 elif type(n_args) == int:
211 if len(args) != n_args:
212 sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
213 "provided\n"
d2dc8f58 214 % (argv[0], command_name, n_args, len(args)))
99155935
BP
215 sys.exit(1)
216 else:
217 assert False
218
219 func(*args)
220
e60a5e26 221
99155935
BP
222if __name__ == '__main__':
223 main(sys.argv)