thanks for reviewing.

> On Mon, 16 Dec 2013 17:52:11 +0900
> YAMAMOTO Takashi <[email protected]> wrote:
> 
>> the placement (ryu/tests/bin) was suggested by FUJITA Tomonori.
>> 
>> Signed-off-by: YAMAMOTO Takashi <[email protected]>
>> ---
>>  ryu/cmd/of_config_cli.py    | 473 
>> ++++++++++++++++++++++++++++++++++++++++++++
>>  ryu/tests/bin/of-config-cli |  20 ++
>>  2 files changed, 493 insertions(+)
>>  create mode 100755 ryu/cmd/of_config_cli.py
>>  create mode 100755 ryu/tests/bin/of-config-cli
>> 
>> diff --git a/ryu/cmd/of_config_cli.py b/ryu/cmd/of_config_cli.py
>> new file mode 100755
>> index 0000000..1803849
>> --- /dev/null
>> +++ b/ryu/cmd/of_config_cli.py
>> @@ -0,0 +1,473 @@
>> +#!/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 OF-CONFIG client
>> +#
>> +# a usage example:
>> +#     % PYTHONPATH=. ./bin/of_config_cli \
>> +#      --peers=sw1=localhost:1830:username:password
>> +#     (Cmd) raw_get sw1
>> +
>> +import ryu.contrib
>> +
>> +from oslo.config import cfg
>> +
>> +import cmd
>> +import sys
>> +import lxml.etree as ET
>> +
>> +from ryu.lib import of_config
>> +from ryu.lib.of_config import capable_switch
>> +from ryu.lib.of_config import constants as consts
>> +from ncclient.operations.rpc import RPCError
>> +import ryu.lib.of_config.classes as ofc
>> +
>> +
>> +CONF = cfg.CONF
>> +CONF.register_cli_opts([
>> +    cfg.ListOpt('peers', default=[], help='list of peers')
>> +])
>> +
>> +
>> +class Peer(capable_switch.OFCapableSwitch):
>> +    def __init__(self, name, host, port, username, password):
>> +        self._name = name
>> +        super(Peer, self).__init__(
>> +            host=host, port=port, username=username, password=password,
>> +            unknown_host_cb=lambda host, fingeprint: True)
>> +
>> +
>> +peers = {}
>> +
>> +
>> +def add_peer(name, host, port, username, password):
>> +    peers[name] = Peer(name, host, port, username, password)
>> +
>> +
>> +def et_tostring_pp(tree):
>> +    # pretty_print is an lxml feature, not available in ElementTree
>> +    try:
>> +        return ET.tostring(tree, pretty_print=True)
>> +    except TypeError:
>> +        return ET.tostring(tree)
>> +
>> +
>> +def validate(tree):
>> +    schema = ET.XMLSchema(file=of_config.OF_CONFIG_1_1_1_XSD)
>> +    if not schema(tree):
>> +        print schema.error_log
>> +
>> +
>> +def _pythonify(name):
>> +    # XXX code duplication
>> +    return name.replace('-', '_')
> 
> Plans to add other functions here? Otherwise, I don't see any point to
> inventing a new function that wraps one liner.

it depends on what the future versions of of-config will use.

currently it seems that '-' is the only python-incompatible thing.

> 
> 
>> +class Cmd(cmd.Cmd):
>> +    def __init__(self, *args, **kwargs):
>> +        self._in_onecmd = False
>> +        cmd.Cmd.__init__(self, *args, **kwargs)
>> +
>> +    def _request(self, line, f):
>> +        args = line.split()
>> +        try:
>> +            peer = args[0]
>> +        except:
>> +            print "argument error"
>> +            return
>> +        try:
>> +            p = peers[peer]
>> +        except KeyError:
>> +            print "unknown peer", peer
>> +            return
>> +        try:
>> +            f(p, args[1:])
>> +        except 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_list_cap(self, line):
>> +        """list_cap <peer>
>> +        """
>> +
>> +        def f(p, args):
>> +            for i in p.netconf.server_capabilities:
>> +                print i
>> +
>> +        self._request(line, f)
>> +
>> +    def do_raw_get(self, line):
> 
> What 'raw_' means?

XML.

> 
>> +        """raw_get <peer>
>> +        """
>> +
>> +        def f(p, args):
>> +            result = p.raw_get()
>> +            tree = ET.fromstring(result)
>> +            validate(tree)
>> +            print et_tostring_pp(tree)
>> +
>> +        self._request(line, f)
>> +
>> +    def do_raw_get_config(self, line):
>> +        """raw_get_config <peer> <source>
>> +        """
>> +
>> +        def f(p, args):
>> +            try:
>> +                source = args[0]
>> +            except:
>> +                print "argument error"
>> +                return
>> +            result = p.raw_get_config(source)
>> +            tree = ET.fromstring(result)
>> +            validate(tree)
>> +            print et_tostring_pp(tree)
>> +
>> +        self._request(line, f)
>> +
>> +    def do_get(self, line):
>> +        """get <peer>
>> +        eg. get_config sw1
>> +        """
>> +
>> +        def f(p, args):
>> +            print p.get()
>> +
>> +        self._request(line, f)
>> +
>> +    def do_get_config(self, line):
>> +        """get_config <peer> <source>
>> +        eg. get_config sw1 startup
>> +        """
>> +
>> +        def f(p, args):
>> +            try:
>> +                source = args[0]
>> +            except:
>> +                print "argument error"
>> +                return
>> +            print p.get_config(source)
>> +
>> +        self._request(line, f)
>> +
>> +    def do_list_port(self, line):
>> +        """list_port <peer>
>> +        """
>> +
>> +        def f(p, args):
>> +            o = p.get()
>> +            for p in o.resources.port:
>> +                print p.resource_id, p.name, p.number
>> +
>> +        self._request(line, f)
>> +
>> +    _port_settings = [
>> +        'admin-state',
>> +        'no-forward',
>> +        'no-packet-in',
>> +        'no-receive',
>> +    ]
>> +
>> +    def do_get_port_config(self, line):
>> +        """get_config_port <peer> <source> <port>
>> +        eg. get_port_config sw1 running LogicalSwitch7-Port2
>> +        """
>> +
>> +        def f(p, args):
>> +            try:
>> +                source, port = args
>> +            except:
>> +                print "argument error"
>> +                return
>> +            o = p.get_config(source)
>> +            for p in o.resources.port:
>> +                if p.resource_id != port:
>> +                    continue
>> +                print p.resource_id
>> +                conf = p.configuration
>> +                for k in self._port_settings:
>> +                    try:
>> +                        v = getattr(conf, _pythonify(k))
>> +                    except AttributeError:
>> +                        continue
>> +                    print k, v
> 
> The above is only for debugging?

which 'The above'?

i added get_port_config merely for symmetry to set_port_config.
it's redundant as you can get the same info with get_config command.

> 
> 
>> +        self._request(line, f)
>> +
>> +    def do_set_port_config(self, line):
>> +        """set_port_config <peer> <target> <port> <key> <value>
>> +        eg. set_port_config sw1 running LogicalSwitch7-Port2 admin-state 
>> down
>> +        eg. set_port_config sw1 running LogicalSwitch7-Port2 no-forward 
>> false
>> +        """
>> +
>> +        def f(p, args):
>> +            try:
>> +                target, port, key, value = args
>> +            except:
>> +                print "argument error"
>> +                print args
>> +                return
>> +
>> +            # get switch id
>> +            o = p.get()
>> +            capable_switch_id = o.id
>> +
>> +            try:
>> +                capable_switch = ofc.OFCapableSwitchType(
>> +                    id=capable_switch_id,
>> +                    resources=ofc.OFCapableSwitchResourcesType(
>> +                        port=[
>> +                            ofc.OFPortType(
>> +                                resource_id=port,
>> +                                configuration=ofc.OFPortConfigurationType(
>> +                                    **{_pythonify(key): value}))
> 
> Can Ryu hide '_pythonify' stuff from the consumers of this library?

i'll try.

YAMAMOTO Takashi

> 
>> +                        ]
>> +                    )
>> +                )
>> +            except TypeError:
>> +                print "argument error"
>> +                return
>> +            try:
>> +                p.edit_config(target, capable_switch)
>> +            except Exception, e:
>> +                print e
>> +
>> +        self._request(line, f)
>> +
>> +    def do_list_queue(self, line):
>> +        """list_queue <peer>
>> +        """
>> +
>> +        def f(p, args):
>> +            o = p.get()
>> +            if o.resources.queue:
>> +                for q in o.resources.queue:
>> +                    print q.resource_id, q.port
>> +
>> +        self._request(line, f)
>> +
>> +    _queue_settings = [
>> +        'max-rate',
>> +        'min-rate',
>> +        'experimenter',
>> +    ]
>> +
>> +    def do_get_queue_config(self, line):
>> +        """get_queue_port <peer> <source> <queue>
>> +        eg. get_queue_config sw1 running LogicalSwitch7-Port1-Queue922
>> +        """
>> +
>> +        def f(p, args):
>> +            try:
>> +                source, queue = args
>> +            except:
>> +                print "argument error"
>> +                return
>> +            o = p.get_config(source)
>> +            for q in o.resources.queue:
>> +                if q.resource_id != queue:
>> +                    continue
>> +                print q.resource_id
>> +                conf = q.properties
>> +                for k in self._queue_settings:
>> +                    try:
>> +                        v = getattr(conf, _pythonify(k))
>> +                    except AttributeError:
>> +                        continue
>> +                    print k, v
>> +
>> +        self._request(line, f)
>> +
>> +    def do_set_queue_config(self, line):
>> +        """set_queue_config <peer> <target> <queue> <key> <value>
>> +        eg. set_queue_config sw1 running LogicalSwitch7-Port1-Queue922 \
>> +max-rate 100
>> +        """
>> +
>> +        def f(p, args):
>> +            try:
>> +                target, queue, key, value = args
>> +            except:
>> +                print "argument error"
>> +                print args
>> +                return
>> +
>> +            # get switch id
>> +            o = p.get()
>> +            capable_switch_id = o.id
>> +
>> +            try:
>> +                capable_switch = ofc.OFCapableSwitchType(
>> +                    id=capable_switch_id,
>> +                    resources=ofc.OFCapableSwitchResourcesType(
>> +                        queue=[
>> +                            ofc.OFQueueType(
>> +                                resource_id=queue,
>> +                                properties=ofc.OFQueuePropertiesType(
>> +                                    **{_pythonify(key): value})),
>> +                        ]
>> +                    )
>> +                )
>> +            except TypeError:
>> +                print "argument error"
>> +                return
>> +            try:
>> +                p.edit_config(target, capable_switch)
>> +            except Exception, e:
>> +                print e
>> +
>> +        self._request(line, f)
>> +
>> +    def do_list_logical_switch(self, line):
>> +        """list_logical_switch <peer>
>> +        """
>> +
>> +        def f(p, args):
>> +            o = p.get()
>> +            for s in o.logical_switches.switch:
>> +                print s.id, s.datapath_id
>> +
>> +        self._request(line, f)
>> +
>> +    def do_show_logical_switch(self, line):
>> +        """show_logical_switch <peer> <logical switch>
>> +        """
>> +
>> +        def f(p, args):
>> +            try:
>> +                (lsw,) = args
>> +            except:
>> +                print "argument error"
>> +                return
>> +            o = p.get()
>> +            for s in o.logical_switches.switch:
>> +                if s.id != lsw:
>> +                    continue
>> +                print s.id
>> +                print 'datapath-id', s.datapath_id
>> +                if s.resources.queue:
>> +                    print 'queues:'
>> +                    for q in s.resources.queue:
>> +                        print '\t', q
>> +                if s.resources.port:
>> +                    print 'ports:'
>> +                    for p in s.resources.port:
>> +                        print '\t', p
>> +
>> +        self._request(line, f)
>> +
>> +    _lsw_settings = [
>> +        'lost-connection-behavior',
>> +    ]
>> +
>> +    def do_get_logical_switch_config(self, line):
>> +        """get_logical_switch_config <peer> <source> <logical switch>
>> +        """
>> +
>> +        def f(p, args):
>> +            try:
>> +                source, lsw = args
>> +            except:
>> +                print "argument error"
>> +                return
>> +            o = p.get_config(source)
>> +            for l in o.logical_switches.switch:
>> +                if l.id != lsw:
>> +                    continue
>> +                print l.id
>> +                for k in self._lsw_settings:
>> +                    try:
>> +                        v = getattr(l, _pythonify(k))
>> +                    except AttributeError:
>> +                        continue
>> +                    print k, v
>> +
>> +        self._request(line, f)
>> +
>> +    def do_set_logical_switch_config(self, line):
>> +        """set_logical_switch_config <peer> <logical switch> <key> <value>
>> +        eg. set_logical_switch_config sw1 running LogicalSwitch7 \
>> +lost-connection-behavior failStandaloneMode
>> +        """
>> +
>> +        def f(p, args):
>> +            try:
>> +                target, lsw, key, value = args
>> +            except:
>> +                print "argument error"
>> +                return
>> +
>> +            # get switch id
>> +            o = p.get_config(target)
>> +            capable_switch_id = o.id
>> +
>> +            try:
>> +                capable_switch = ofc.OFCapableSwitchType(
>> +                    id=capable_switch_id,
>> +                    logical_switches=ofc.OFCapableSwitchLogicalSwitchesType(
>> +                        switch=[ofc.OFLogicalSwitchType(
>> +                            id=lsw,
>> +                            **{_pythonify(key): value}
>> +                        )]
>> +                    )
>> +                )
>> +            except TypeError:
>> +                print "argument error"
>> +                return
>> +            try:
>> +                p.edit_config(target, capable_switch)
>> +            except Exception, e:
>> +                print e
>> +
>> +        self._request(line, f)
>> +
>> +    completedefault = _complete_peer
>> +
>> +    def complete_EOF(self, _text, _line, _begidx, _endidx):
>> +        return []
>> +
>> +    def do_EOF(self, _line):
>> +        sys.exit(0)
>> +
>> +    def onecmd(self, string):
>> +        self._in_onecmd = True
>> +        try:
>> +            return cmd.Cmd.onecmd(self, string)
>> +        finally:
>> +            self._in_onecmd = False
>> +
>> +
>> +def main():
>> +    CONF(project='of-config-cli', version='of-config-cli')
>> +
>> +    for p_str in CONF.peers:
>> +        name, addr = p_str.split('=')
>> +        host, port, username, password = addr.rsplit(':', 3)
>> +        add_peer(name, host, port, username, password)
>> +
>> +    Cmd().cmdloop()
>> +
>> +
>> +if __name__ == "__main__":
>> +    main()
>> diff --git a/ryu/tests/bin/of-config-cli b/ryu/tests/bin/of-config-cli
>> new file mode 100755
>> index 0000000..c076ee8
>> --- /dev/null
>> +++ b/ryu/tests/bin/of-config-cli
>> @@ -0,0 +1,20 @@
>> +#!/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.
>> +
>> +from ryu.cmd.of_config_cli import main
>> +main()
>> -- 
>> 1.8.3.1
>> 
>> 
>> ------------------------------------------------------------------------------
>> Rapidly troubleshoot problems before they affect your business. Most IT 
>> organizations don't have a clear picture of how application performance 
>> affects their revenue. With AppDynamics, you get 100% visibility into your 
>> Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics 
>> Pro!
>> http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk
>> _______________________________________________
>> Ryu-devel mailing list
>> [email protected]
>> https://lists.sourceforge.net/lists/listinfo/ryu-devel
> 
> ------------------------------------------------------------------------------
> Rapidly troubleshoot problems before they affect your business. Most IT 
> organizations don't have a clear picture of how application performance 
> affects their revenue. With AppDynamics, you get 100% visibility into your 
> Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro!
> http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk
> _______________________________________________
> Ryu-devel mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/ryu-devel

------------------------------------------------------------------------------
Rapidly troubleshoot problems before they affect your business. Most IT 
organizations don't have a clear picture of how application performance 
affects their revenue. With AppDynamics, you get 100% visibility into your 
Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro!
http://pubads.g.doubleclick.net/gampad/clk?id=84349831&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to