> Sorry for late response. > Can you please add man page for rpc-cli? The contents of man page can > be mostly trivial/empty because it's necessary for satisfying rpmlint of > Fedora. > > add ryu/doc/source/man/msgpack-rpc.rst > update ryu/doc/source/conf.py
ok, i will. YAMAMOTO Takashi > > thanks, > > On Mon, Jul 01, 2013 at 02:37:08PM +0900, YAMAMOTO Takashi wrote: >> >> Signed-off-by: YAMAMOTO Takashi <yamam...@valinux.co.jp> >> --- >> bin/rpc-cli | 237 >> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> run_tests.sh | 2 +- >> setup.py | 3 +- >> 3 files changed, 240 insertions(+), 2 deletions(-) >> create mode 100755 bin/rpc-cli >> >> diff --git a/bin/rpc-cli b/bin/rpc-cli >> new file mode 100755 >> index 0000000..05696b3 >> --- /dev/null >> +++ b/bin/rpc-cli >> @@ -0,0 +1,237 @@ >> +#!/usr/bin/env python >> +# >> +# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. >> +# Copyright (C) 2013 YAMAMOTO Takashi <yamamoto at valinux co jp> >> +# >> +# Licensed under the Apache License, Version 2.0 (the "License"); >> +# you may not use this file except in compliance with the License. >> +# You may obtain a copy of the License at >> +# >> +# http://www.apache.org/licenses/LICENSE-2.0 >> +# >> +# Unless required by applicable law or agreed to in writing, software >> +# distributed under the License is distributed on an "AS IS" BASIS, >> +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or >> +# implied. >> +# See the License for the specific language governing permissions and >> +# limitations under the License. >> + >> +# a simple command line msgpack-rpc client >> +# >> +# a usage example: >> +# % PYTHONPATH=. ./bin/rpc-cli \ >> +# --peers=echo-server=localhost:9999,hoge=localhost:9998 >> +# (Cmd) request echo-server echo ["hoge"] >> +# RESULT hoge >> +# (Cmd) request echo-server notify ["notify-method", >> ["param1","param2"]] >> +# RESULT notify-method >> +# (Cmd) >> +# NOTIFICATION from echo-server ['notify-method', ['param1', 'param2']] >> +# (Cmd) >> + >> +import ryu.contrib >> + >> +from oslo.config import cfg >> + >> +import cmd >> +import signal >> +import socket >> +import sys >> +import termios >> + >> +from ryu.lib import rpc >> + >> + >> +CONF = cfg.CONF >> +CONF.register_cli_opts([ >> + # eg. rpc-cli --peers=hoge=localhost:9998,fuga=localhost:9999 >> + cfg.ListOpt('peers', default=[], help='list of peers') >> +]) >> + >> + >> +class Peer(object): >> + def __init__(self, name, addr): >> + self._name = name >> + self._addr = addr >> + self.client = None >> + try: >> + self.connect() >> + except: >> + pass >> + >> + def connect(self): >> + self.client = None >> + s = socket.create_connection(self._addr) >> + self.client = rpc.Client(s, notification_callback=self.notification) >> + >> + def try_to_connect(self, verbose=False): >> + if self.client: >> + return >> + try: >> + self.connect() >> + assert self.client >> + except Exception, e: >> + if verbose: >> + print "connection failure", e >> + raise EOFError >> + >> + def notification(self, n): >> + print "NOTIFICATION from", self._name, n >> + >> + def call(self, method, params): >> + return self._do(lambda: self.client.call(method, params)) >> + >> + def send_notification(self, method, params): >> + self._do(lambda: self.client.send_notification(method, params)) >> + >> + def _do(self, f): >> + def g(): >> + try: >> + return f() >> + except EOFError: >> + self.client = None >> + raise >> + >> + self.try_to_connect(verbose=True) >> + try: >> + return g() >> + except EOFError: >> + print "disconnected. trying to connect..." >> + self.try_to_connect(verbose=True) >> + print "connected. retrying the request..." >> + return g() >> + >> + >> +peers = {} >> + >> + >> +def add_peer(name, host, port): >> + peers[name] = Peer(name, (host, port)) >> + >> + >> +class Cmd(cmd.Cmd): >> + def __init__(self, *args, **kwargs): >> + self._in_onecmd = False >> + self._notification_check_interval = 1 # worth to be configurable? >> + self._saved_termios = None >> + cmd.Cmd.__init__(self, *args, **kwargs) >> + >> + def _request(self, line, f): >> + args = line.split(None, 2) >> + try: >> + peer = args[0] >> + method = args[1] >> + params = eval(args[2]) >> + except: >> + print "argument error" >> + return >> + try: >> + p = peers[peer] >> + except KeyError: >> + print "unknown peer", peer >> + return >> + try: >> + f(p, method, params) >> + except rpc.RPCError, e: >> + print "RPC ERROR", e >> + except EOFError: >> + print "disconnected" >> + >> + def _complete_peer(self, text, line, _begidx, _endidx): >> + if len((line + 'x').split()) >= 3: >> + return [] >> + return [name for name in peers if name.startswith(text)] >> + >> + def do_request(self, line): >> + """request <peer> <method> <params> >> + send a msgpack-rpc request and print a response. >> + <params> is a python code snippet, it should be eval'ed to a list. >> + """ >> + >> + def f(p, method, params): >> + result = p.call(method, params) >> + print "RESULT", result >> + >> + self._request(line, f) >> + >> + def do_notify(self, line): >> + """notify <peer> <method> <params> >> + send a msgpack-rpc notification. >> + <params> is a python code snippet, it should be eval'ed to a list. >> + """ >> + >> + def f(p, method, params): >> + p.send_notification(method, params) >> + >> + self._request(line, f) >> + >> + def complete_request(self, text, line, begidx, endidx): >> + return self._complete_peer(text, line, begidx, endidx) >> + >> + def complete_notify(self, text, line, begidx, endidx): >> + return self._complete_peer(text, line, begidx, endidx) >> + >> + def do_EOF(self, _line): >> + sys.exit(0) >> + >> + def emptyline(self): >> + self._peek_notification() >> + >> + def postcmd(self, _stop, _line): >> + self._peek_notification() >> + >> + def _peek_notification(self): >> + for k, p in peers.iteritems(): >> + if p.client: >> + try: >> + p.client.peek_notification() >> + except EOFError: >> + p.client = None >> + print "disconnected", k >> + >> + @staticmethod >> + def _save_termios(): >> + return termios.tcgetattr(sys.stdin.fileno()) >> + >> + @staticmethod >> + def _restore_termios(t): >> + termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, t) >> + >> + def preloop(self): >> + self._saved_termios = self._save_termios() >> + signal.signal(signal.SIGALRM, self._timeout) >> + signal.alarm(1) >> + >> + def onecmd(self, string): >> + self._in_onecmd = True >> + try: >> + return cmd.Cmd.onecmd(self, string) >> + finally: >> + self._in_onecmd = False >> + >> + def _timeout(self, _sig, _frame): >> + if not self._in_onecmd: >> + # restore terminal settings. (cooked/raw, ...) >> + # required for pypy at least. >> + # this doesn't seem to be needed for cpython readline >> + # module but i'm not sure if it's by spec or luck. >> + o = self._save_termios() >> + self._restore_termios(self._saved_termios) >> + self._peek_notification() >> + self._restore_termios(o) >> + signal.alarm(self._notification_check_interval) >> + >> + >> +def main(): >> + CONF(project='rpc-cli', version='rpc-cli') >> + >> + for p_str in CONF.peers: >> + name, addr = p_str.split('=') >> + host, port = addr.rsplit(':', 1) >> + add_peer(name, host, port) >> + >> + Cmd().cmdloop() >> + >> + >> +if __name__ == "__main__": >> + main() >> diff --git a/run_tests.sh b/run_tests.sh >> index 5e0d631..0551fe1 100755 >> --- a/run_tests.sh >> +++ b/run_tests.sh >> @@ -90,7 +90,7 @@ run_tests() { >> run_pylint() { >> echo "Running pylint ..." >> PYLINT_OPTIONS="--rcfile=.pylintrc --output-format=parseable" >> - PYLINT_INCLUDE="ryu bin/ryu-manager ryu/tests/bin/ryu-client" >> + PYLINT_INCLUDE="ryu bin/ryu-manager bin/rpc-cli ryu/tests/bin/ryu-client" >> export PYTHONPATH=$PYTHONPATH:.ryu >> PYLINT_LOG=pylint.log >> >> diff --git a/setup.py b/setup.py >> index efbb550..3f855b6 100644 >> --- a/setup.py >> +++ b/setup.py >> @@ -59,7 +59,8 @@ setup(name='ryu', >> install_requires=requires, >> license='Apache License 2.0', >> packages=find_packages(), >> - scripts=['bin/ryu-manager', ], >> + scripts=['bin/ryu-manager', >> + 'bin/rpc-cli'], >> data_files=data_files, >> include_package_data=True, >> ) >> -- >> 1.8.1.5 >> >> >> ------------------------------------------------------------------------------ >> This SF.net email is sponsored by Windows: >> >> Build for Windows Store. >> >> http://p.sf.net/sfu/windows-dev2dev >> _______________________________________________ >> Ryu-devel mailing list >> Ryu-devel@lists.sourceforge.net >> https://lists.sourceforge.net/lists/listinfo/ryu-devel >> > > -- > yamahata > > ------------------------------------------------------------------------------ > See everything from the browser to the database with AppDynamics > Get end-to-end visibility with application monitoring from AppDynamics > Isolate bottlenecks and diagnose root cause in seconds. > Start your free trial of AppDynamics Pro today! > http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk > _______________________________________________ > Ryu-devel mailing list > Ryu-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/ryu-devel ------------------------------------------------------------------------------ See everything from the browser to the database with AppDynamics Get end-to-end visibility with application monitoring from AppDynamics Isolate bottlenecks and diagnose root cause in seconds. Start your free trial of AppDynamics Pro today! http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk _______________________________________________ Ryu-devel mailing list Ryu-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/ryu-devel