]>
Commit | Line | Data |
---|---|---|
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 |
15 | from __future__ import print_function |
16 | ||
b153e667 | 17 | import argparse |
99155935 | 18 | import errno |
99155935 BP |
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 | ||
e60a5e26 | 28 | |
99155935 BP |
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") | |
e60a5e26 | 49 | |
99155935 BP |
50 | if reply: |
51 | rpc.send(reply) | |
52 | return done | |
53 | ||
e60a5e26 | 54 | |
99155935 | 55 | def 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 |
112 | def 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 |
143 | def 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 | 168 | def 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 = """\ | |
180 | listen LOCAL listen for connections on LOCAL | |
181 | request REMOTE METHOD PARAMS send request, print reply | |
182 | notify 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 |
222 | if __name__ == '__main__': |
223 | main(sys.argv) |