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