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

thanks,

On Mon, Jul 01, 2013 at 02:37:08PM +0900, YAMAMOTO Takashi wrote:
> 
> Signed-off-by: YAMAMOTO Takashi <[email protected]>
> ---
>  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
> [email protected]
> 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
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to