]>
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): |
99155935 BP |
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) | |
603e325f | 91 | rpcs = [rpc for rpc in rpcs if rpc not in dead_rpcs] |
99155935 BP |
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 | ||
e60a5e26 | 105 | |
99155935 BP |
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) | |
e60a5e26 | 131 | |
8ea171ab | 132 | print(ovs.json.to_string(msg.to_json())) |
99155935 BP |
133 | |
134 | rpc.close() | |
e60a5e26 EJ |
135 | |
136 | ||
99155935 BP |
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 | ||
e60a5e26 | 161 | |
99155935 | 162 | def main(argv): |
99155935 | 163 | |
b153e667 EJ |
164 | parser = argparse.ArgumentParser( |
165 | description="JSON-RPC test utility for Python.", | |
166 | formatter_class=argparse.RawDescriptionHelpFormatter) | |
99155935 BP |
167 | |
168 | commands = {"listen": (do_listen, 1), | |
169 | "request": (do_request, 3), | |
170 | "notify": (do_notify, 3), | |
b153e667 EJ |
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 | |
603e325f | 192 | if command_name not in commands: |
99155935 | 193 | sys.stderr.write("%s: unknown command \"%s\" " |
d2dc8f58 | 194 | "(use --help for help)\n" % (argv[0], command_name)) |
99155935 BP |
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" | |
d2dc8f58 | 202 | % (argv[0], command_name, n_args, len(args))) |
99155935 BP |
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" | |
d2dc8f58 | 208 | % (argv[0], command_name, n_args, len(args))) |
99155935 BP |
209 | sys.exit(1) |
210 | else: | |
211 | assert False | |
212 | ||
213 | func(*args) | |
214 | ||
e60a5e26 | 215 | |
99155935 BP |
216 | if __name__ == '__main__': |
217 | main(sys.argv) |