Remove CLI parts from os-ken
It has been agreed on one of the Neutron team meetings [1] that we should remove those parts of os-ken which provides CLI scripts and make it as small as possible to just fit Neutron actual needs. The CLI bits were simply there from when os-ken was forked from Ryu but we actually never used those tools in OpenStack so it is better to remove them and keep os-ken as small as possible. [1] https://meetings.opendev.org/meetings/networking/2025/networking.2025-02-25-14.00.log.html#l-81 Closes-bug: #2100268 Change-Id: I40a60a3233718fcda2f0be25120ef92708ffcbd5 Signed-off-by: Slawek Kaplonski <skaplons@redhat.com>
This commit is contained in:
@@ -1,48 +0,0 @@
|
|||||||
:orphan:
|
|
||||||
|
|
||||||
os_ken manual page
|
|
||||||
==================
|
|
||||||
|
|
||||||
Synopsis
|
|
||||||
--------
|
|
||||||
**osken** [-h] [--config-dir DIR] [--config-file PATH] [--version] [subcommand] ...
|
|
||||||
|
|
||||||
Description
|
|
||||||
-----------
|
|
||||||
:program:`os_ken` is the executable for OS-Ken applications. os_ken loads a sub-module
|
|
||||||
corresponding to the sub-command and run it. 'run' sub-command is an
|
|
||||||
equivalent to osken-manager.
|
|
||||||
|
|
||||||
OS-Ken is a component-based software defined networking framework. OS-Ken
|
|
||||||
provides software components with well defined API that make it easy for
|
|
||||||
developers to create new network management and control applications.
|
|
||||||
OS-Ken supports various protocols for managing network devices, such as
|
|
||||||
OpenFlow, Netconf, OF-config, etc. About OpenFlow, OS-Ken supports fully
|
|
||||||
1.0, 1.2, 1.3, 1.4 and Nicira Extensions.
|
|
||||||
|
|
||||||
Options
|
|
||||||
-------
|
|
||||||
subcommand
|
|
||||||
[rpc-cli|run|of-config-cli]
|
|
||||||
|
|
||||||
subcommand_args
|
|
||||||
subcommand specific arguments
|
|
||||||
|
|
||||||
-h, --help
|
|
||||||
show this help message and exit
|
|
||||||
|
|
||||||
--config-dir DIR
|
|
||||||
Path to a config directory to pull \*.conf files from.
|
|
||||||
This file set is sorted, so as to provide a predictable
|
|
||||||
parse order if individual options are over-ridden. The
|
|
||||||
set is parsed after the file(s) specified via previous
|
|
||||||
--config-file, arguments hence over-ridden options in
|
|
||||||
the directory take precedence.
|
|
||||||
|
|
||||||
--config-file PATH
|
|
||||||
Path to a config file to use. Multiple config files can
|
|
||||||
be specified, with values in later files taking
|
|
||||||
precedence. The default files used are: None
|
|
||||||
|
|
||||||
--version
|
|
||||||
show program's version number and exit
|
|
@@ -1,184 +0,0 @@
|
|||||||
:orphan:
|
|
||||||
|
|
||||||
osken-manager manual page
|
|
||||||
==========================
|
|
||||||
|
|
||||||
|
|
||||||
Synopsis
|
|
||||||
--------
|
|
||||||
**osken-manager** [-h]
|
|
||||||
[--app-lists APP_LISTS] [--ca-certs CA_CERTS]
|
|
||||||
[--config-dir DIR] [--config-file PATH]
|
|
||||||
[--ctl-cert CTL_CERT] [--ctl-privkey CTL_PRIVKEY]
|
|
||||||
[--default-log-level DEFAULT_LOG_LEVEL] [--explicit-drop]
|
|
||||||
[--install-lldp-flow] [--log-config-file LOG_CONFIG_FILE]
|
|
||||||
[--log-dir LOG_DIR] [--log-file LOG_FILE]
|
|
||||||
[--log-file-mode LOG_FILE_MODE]
|
|
||||||
[--neutron-admin-auth-url NEUTRON_ADMIN_AUTH_URL]
|
|
||||||
[--neutron-admin-password NEUTRON_ADMIN_PASSWORD]
|
|
||||||
[--neutron-admin-tenant-name NEUTRON_ADMIN_TENANT_NAME]
|
|
||||||
[--neutron-admin-username NEUTRON_ADMIN_USERNAME]
|
|
||||||
[--neutron-auth-strategy NEUTRON_AUTH_STRATEGY]
|
|
||||||
[--neutron-controller-addr NEUTRON_CONTROLLER_ADDR]
|
|
||||||
[--neutron-url NEUTRON_URL]
|
|
||||||
[--neutron-url-timeout NEUTRON_URL_TIMEOUT]
|
|
||||||
[--noexplicit-drop] [--noinstall-lldp-flow]
|
|
||||||
[--noobserve-links] [--nouse-stderr] [--nouse-syslog]
|
|
||||||
[--noverbose] [--observe-links]
|
|
||||||
[--ofp-listen-host OFP_LISTEN_HOST]
|
|
||||||
[--ofp-ssl-listen-port OFP_SSL_LISTEN_PORT]
|
|
||||||
[--ofp-tcp-listen-port OFP_TCP_LISTEN_PORT] [--use-stderr]
|
|
||||||
[--use-syslog] [--verbose] [--version]
|
|
||||||
[--wsapi-host WSAPI_HOST] [--wsapi-port WSAPI_PORT]
|
|
||||||
[--test-switch-dir TEST-SWITCH_DIR]
|
|
||||||
[--test-switch-target TEST-SWITCH_TARGET]
|
|
||||||
[--test-switch-tester TEST-SWITCH_TESTER]
|
|
||||||
[app [app ...]]
|
|
||||||
|
|
||||||
Description
|
|
||||||
-----------
|
|
||||||
:program:`osken-manager` is the executable for OS-Ken applications. osken-manager
|
|
||||||
loads OS-Ken applications and run it.
|
|
||||||
|
|
||||||
OS-Ken is a component-based software defined networking framework. OS-Ken
|
|
||||||
provides software components with well defined API that make it easy for
|
|
||||||
developers to create new network management and control applications.
|
|
||||||
OS-Ken supports various protocols for managing network devices, such as
|
|
||||||
OpenFlow, Netconf, OF-config, etc. About OpenFlow, OS-Ken supports fully
|
|
||||||
1.0, 1.2, 1.3, 1.4 and Nicira Extensions.
|
|
||||||
|
|
||||||
Options
|
|
||||||
-------
|
|
||||||
app
|
|
||||||
application module name to run
|
|
||||||
|
|
||||||
-h, --help
|
|
||||||
show this help message and exit
|
|
||||||
|
|
||||||
--app-lists APP_LISTS
|
|
||||||
application module name to run
|
|
||||||
|
|
||||||
--ca-certs CA_CERTS
|
|
||||||
CA certificates
|
|
||||||
|
|
||||||
--config-dir DIR
|
|
||||||
Path to a config directory to pull \*.conf files from.
|
|
||||||
This file set is sorted, so as to provide a
|
|
||||||
predictable parse order if individual options are
|
|
||||||
over-ridden. The set is parsed after the file(s)
|
|
||||||
specified via previous --config-file, arguments hence
|
|
||||||
over-ridden options in the directory take precedence.
|
|
||||||
|
|
||||||
--config-file PATH
|
|
||||||
Path to a config file to use. Multiple config files
|
|
||||||
can be specified, with values in later files taking
|
|
||||||
precedence. The default files used are: None
|
|
||||||
|
|
||||||
--ctl-cert CTL_CERT
|
|
||||||
controller certificate
|
|
||||||
|
|
||||||
--ctl-privkey CTL_PRIVKEY
|
|
||||||
controller private key
|
|
||||||
|
|
||||||
--default-log-level DEFAULT_LOG_LEVEL
|
|
||||||
default log level
|
|
||||||
|
|
||||||
--explicit-drop
|
|
||||||
link discovery: explicitly drop lldp packet in
|
|
||||||
|
|
||||||
--install-lldp-flow
|
|
||||||
link discovery: explicitly install flow entry to send
|
|
||||||
lldp packet to controller
|
|
||||||
|
|
||||||
--log-config-file LOG_CONFIG_FILE
|
|
||||||
Path to a logging config file to use
|
|
||||||
|
|
||||||
--log-dir LOG_DIR
|
|
||||||
log file directory
|
|
||||||
|
|
||||||
--log-file LOG_FILE
|
|
||||||
log file name
|
|
||||||
|
|
||||||
--log-file-mode LOG_FILE_MODE
|
|
||||||
default log file permission
|
|
||||||
|
|
||||||
--neutron-admin-auth-url NEUTRON_ADMIN_AUTH_URL
|
|
||||||
auth url for connecting to neutron in admin context
|
|
||||||
|
|
||||||
--neutron-admin-password NEUTRON_ADMIN_PASSWORD
|
|
||||||
password for connecting to neutron in admin context
|
|
||||||
|
|
||||||
--neutron-admin-tenant-name NEUTRON_ADMIN_TENANT_NAME
|
|
||||||
tenant name for connecting to neutron in admin context
|
|
||||||
|
|
||||||
--neutron-admin-username NEUTRON_ADMIN_USERNAME
|
|
||||||
username for connecting to neutron in admin context
|
|
||||||
|
|
||||||
--neutron-auth-strategy NEUTRON_AUTH_STRATEGY
|
|
||||||
auth strategy for connecting to neutron in admincontext
|
|
||||||
|
|
||||||
--neutron-controller-addr NEUTRON_CONTROLLER_ADDR
|
|
||||||
openflow method:address:port to set controller ofovs bridge
|
|
||||||
|
|
||||||
--neutron-url NEUTRON_URL
|
|
||||||
URL for connecting to neutron
|
|
||||||
|
|
||||||
--neutron-url-timeout NEUTRON_URL_TIMEOUT
|
|
||||||
timeout value for connecting to neutron in seconds
|
|
||||||
|
|
||||||
--noexplicit-drop
|
|
||||||
The inverse of --explicit-drop
|
|
||||||
|
|
||||||
--noinstall-lldp-flow
|
|
||||||
The inverse of --install-lldp-flow
|
|
||||||
|
|
||||||
--noobserve-links
|
|
||||||
The inverse of --observe-links
|
|
||||||
|
|
||||||
--nouse-stderr
|
|
||||||
The inverse of --use-stderr
|
|
||||||
|
|
||||||
--nouse-syslog
|
|
||||||
The inverse of --use-syslog
|
|
||||||
|
|
||||||
--noverbose
|
|
||||||
The inverse of --verbose
|
|
||||||
|
|
||||||
--observe-links
|
|
||||||
observe link discovery events.
|
|
||||||
|
|
||||||
--ofp-listen-host OFP_LISTEN_HOST
|
|
||||||
openflow listen host
|
|
||||||
|
|
||||||
--ofp-ssl-listen-port OFP_SSL_LISTEN_PORT
|
|
||||||
openflow ssl listen port
|
|
||||||
|
|
||||||
--ofp-tcp-listen-port OFP_TCP_LISTEN_PORT
|
|
||||||
openflow tcp listen port
|
|
||||||
|
|
||||||
--use-stderr
|
|
||||||
log to standard error
|
|
||||||
|
|
||||||
--use-syslog
|
|
||||||
output to syslog
|
|
||||||
|
|
||||||
--verbose
|
|
||||||
show debug output
|
|
||||||
|
|
||||||
--version
|
|
||||||
show program's version number and exit
|
|
||||||
|
|
||||||
--wsapi-host WSAPI_HOST
|
|
||||||
webapp listen host
|
|
||||||
|
|
||||||
--wsapi-port WSAPI_PORT
|
|
||||||
webapp listen port
|
|
||||||
|
|
||||||
--test-switch-dir TEST-SWITCH_DIR
|
|
||||||
test files directory
|
|
||||||
|
|
||||||
--test-switch-target TEST-SWITCH_TARGET
|
|
||||||
target sw dp-id
|
|
||||||
|
|
||||||
--test-switch-tester TEST-SWITCH_TESTER
|
|
||||||
tester sw dp-id
|
|
@@ -1,112 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
#
|
|
||||||
# Copyright (C) 2011, 2012 Nippon Telegraph and Telephone Corporation.
|
|
||||||
# Copyright (C) 2011 Isaku Yamahata <yamahata 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.
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from os_ken.lib import hub
|
|
||||||
hub.patch(thread=False)
|
|
||||||
|
|
||||||
from os_ken import cfg
|
|
||||||
|
|
||||||
import logging
|
|
||||||
from os_ken import log
|
|
||||||
log.early_init_log(logging.DEBUG)
|
|
||||||
|
|
||||||
from os_ken import flags
|
|
||||||
from os_ken import __version__ as version
|
|
||||||
from os_ken.base.app_manager import AppManager
|
|
||||||
from os_ken.controller import controller
|
|
||||||
from os_ken.topology import switches
|
|
||||||
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
CONF.register_cli_opts([
|
|
||||||
cfg.ListOpt('app-lists', default=[],
|
|
||||||
help='application module name to run'),
|
|
||||||
cfg.MultiStrOpt('app', positional=True, default=[],
|
|
||||||
help='application module name to run'),
|
|
||||||
cfg.StrOpt('pid-file', default=None, help='pid file name'),
|
|
||||||
cfg.BoolOpt('enable-debugger', default=False,
|
|
||||||
help='don\'t overwrite Python standard threading library'
|
|
||||||
'(use only for debugging)'),
|
|
||||||
cfg.StrOpt('user-flags', default=None,
|
|
||||||
help='Additional flags file for user applications'),
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_user_flags():
|
|
||||||
"""
|
|
||||||
Parses user-flags file and loads it to register user defined options.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
idx = list(sys.argv).index('--user-flags')
|
|
||||||
user_flags_file = sys.argv[idx + 1]
|
|
||||||
except (ValueError, IndexError):
|
|
||||||
user_flags_file = ''
|
|
||||||
|
|
||||||
if user_flags_file and os.path.isfile(user_flags_file):
|
|
||||||
from os_ken.utils import _import_module_file
|
|
||||||
_import_module_file(user_flags_file)
|
|
||||||
|
|
||||||
|
|
||||||
def main(args=None, prog=None):
|
|
||||||
_parse_user_flags()
|
|
||||||
try:
|
|
||||||
CONF(args=args, prog=prog,
|
|
||||||
project='os_ken', version='osken-manager %s' % version,
|
|
||||||
default_config_files=['/usr/local/etc/os_ken/os_ken.conf'])
|
|
||||||
except cfg.ConfigFilesNotFoundError:
|
|
||||||
CONF(args=args, prog=prog,
|
|
||||||
project='os_ken', version='osken-manager %s' % version)
|
|
||||||
|
|
||||||
log.init_log()
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
if CONF.enable_debugger:
|
|
||||||
msg = 'debugging is available (--enable-debugger option is turned on)'
|
|
||||||
logger.info(msg)
|
|
||||||
else:
|
|
||||||
hub.patch(thread=True)
|
|
||||||
|
|
||||||
if CONF.pid_file:
|
|
||||||
with open(CONF.pid_file, 'w') as pid_file:
|
|
||||||
pid_file.write(str(os.getpid()))
|
|
||||||
|
|
||||||
app_lists = CONF.app_lists + CONF.app
|
|
||||||
# keep old behavior, run ofp if no application is specified.
|
|
||||||
if not app_lists:
|
|
||||||
app_lists = ['os_ken.controller.ofp_handler']
|
|
||||||
|
|
||||||
app_mgr = AppManager.get_instance()
|
|
||||||
app_mgr.load_apps(app_lists)
|
|
||||||
contexts = app_mgr.create_contexts()
|
|
||||||
services = []
|
|
||||||
services.extend(app_mgr.instantiate_apps(**contexts))
|
|
||||||
|
|
||||||
try:
|
|
||||||
hub.joinall(services)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
logger.debug("Keyboard Interrupt received. "
|
|
||||||
"Closing OSKen application manager...")
|
|
||||||
finally:
|
|
||||||
app_mgr.close()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@@ -1,559 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
#
|
|
||||||
# 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 cmd
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import lxml.etree as ET
|
|
||||||
from ncclient.operations.rpc import RPCError
|
|
||||||
|
|
||||||
from os_ken import cfg
|
|
||||||
from os_ken.lib import of_config
|
|
||||||
from os_ken.lib.of_config import capable_switch
|
|
||||||
import os_ken.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)
|
|
||||||
|
|
||||||
|
|
||||||
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 %s" % peer)
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
f(p, args[1:])
|
|
||||||
except RPCError as e:
|
|
||||||
print("RPC Error %s" % 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):
|
|
||||||
"""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 sw1
|
|
||||||
"""
|
|
||||||
|
|
||||||
def f(p, args):
|
|
||||||
print(p.get())
|
|
||||||
|
|
||||||
self._request(line, f)
|
|
||||||
|
|
||||||
def do_commit(self, line):
|
|
||||||
"""commit <peer>
|
|
||||||
eg. commit sw1
|
|
||||||
"""
|
|
||||||
|
|
||||||
def f(p, args):
|
|
||||||
print(p.commit())
|
|
||||||
|
|
||||||
self._request(line, f)
|
|
||||||
|
|
||||||
def do_discard(self, line):
|
|
||||||
"""discard <peer>
|
|
||||||
eg. discard sw1
|
|
||||||
"""
|
|
||||||
|
|
||||||
def f(p, args):
|
|
||||||
print(p.discard_changes())
|
|
||||||
|
|
||||||
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_delete_config(self, line):
|
|
||||||
"""delete_config <peer> <source>
|
|
||||||
eg. delete_config sw1 startup
|
|
||||||
"""
|
|
||||||
|
|
||||||
def f(p, args):
|
|
||||||
try:
|
|
||||||
source = args[0]
|
|
||||||
except:
|
|
||||||
print("argument error")
|
|
||||||
return
|
|
||||||
print(p.delete_config(source))
|
|
||||||
|
|
||||||
self._request(line, f)
|
|
||||||
|
|
||||||
def do_copy_config(self, line):
|
|
||||||
"""copy_config <peer> <source> <target>
|
|
||||||
eg. copy_config sw1 running startup
|
|
||||||
"""
|
|
||||||
|
|
||||||
def f(p, args):
|
|
||||||
try:
|
|
||||||
source, target = args
|
|
||||||
except:
|
|
||||||
print("argument error")
|
|
||||||
return
|
|
||||||
print(p.copy_config(source, target))
|
|
||||||
|
|
||||||
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('%s %s %s' % (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, k)
|
|
||||||
except AttributeError:
|
|
||||||
continue
|
|
||||||
print('%s %s' % (k, v))
|
|
||||||
|
|
||||||
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(
|
|
||||||
**{key: value}))
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
except TypeError:
|
|
||||||
print("argument error")
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
p.edit_config(target, capable_switch)
|
|
||||||
except Exception as 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('%s %s' % (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, k)
|
|
||||||
except AttributeError:
|
|
||||||
continue
|
|
||||||
print('%s %s' % (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(
|
|
||||||
**{key: value})),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
except TypeError:
|
|
||||||
print("argument error")
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
p.edit_config(target, capable_switch)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
|
|
||||||
self._request(line, f)
|
|
||||||
|
|
||||||
def do_add_queue(self, line):
|
|
||||||
"""add_queue <peer> <target> <logical-switch> <queue>
|
|
||||||
eg. add_queue sw1 running LogicalSwitch7 NameOfNewQueue
|
|
||||||
"""
|
|
||||||
|
|
||||||
def f(p, args):
|
|
||||||
try:
|
|
||||||
target, lsw, queue = 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)
|
|
||||||
]
|
|
||||||
),
|
|
||||||
logical_switches=ofc.OFCapableSwitchLogicalSwitchesType(
|
|
||||||
switch=[ofc.OFLogicalSwitchType(
|
|
||||||
id=lsw,
|
|
||||||
resources=ofc.OFLogicalSwitchResourcesType(
|
|
||||||
queue=[queue])
|
|
||||||
)]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
except TypeError:
|
|
||||||
print("argument error")
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
p.edit_config(target, capable_switch)
|
|
||||||
except Exception as 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 %s' % (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' % s.datapath_id)
|
|
||||||
if s.resources.queue:
|
|
||||||
print('queues:')
|
|
||||||
for q in s.resources.queue:
|
|
||||||
print('\t %s' % q)
|
|
||||||
if s.resources.port:
|
|
||||||
print('ports:')
|
|
||||||
for p in s.resources.port:
|
|
||||||
print('\t %s' % 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, k)
|
|
||||||
except AttributeError:
|
|
||||||
continue
|
|
||||||
print('%s %s' % (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,
|
|
||||||
**{key: value}
|
|
||||||
)]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
except TypeError:
|
|
||||||
print("argument error")
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
p.edit_config(target, capable_switch)
|
|
||||||
except Exception as 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(args=None, prog=None):
|
|
||||||
CONF(args=args, prog=prog,
|
|
||||||
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()
|
|
@@ -1,42 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
# Copyright (C) 2014 VA Linux Systems Japan K.K.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# @author: Fumihiko Kakuma, VA Linux Systems Japan K.K.
|
|
||||||
# @author: YAMAMOTO Takashi, VA Linux Systems Japan K.K.
|
|
||||||
|
|
||||||
# NOTE: This module is used by Neutron "ofagent" agent for
|
|
||||||
# IceHouse release. Juno and later releases do not use this.
|
|
||||||
# TODO: Remove this module when IceHouse is EOL'ed.
|
|
||||||
|
|
||||||
from os_ken.lib import hub
|
|
||||||
hub.patch()
|
|
||||||
|
|
||||||
from os_ken import cfg
|
|
||||||
|
|
||||||
from neutron.common import config as logging_config
|
|
||||||
|
|
||||||
from os_ken.base.app_manager import AppManager
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
cfg.CONF(project='os_ken')
|
|
||||||
logging_config.setup_logging(cfg.CONF)
|
|
||||||
AppManager.run_apps(['neutron.plugins.ofagent.agent.ofa_neutron_agent'])
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@@ -1,74 +0,0 @@
|
|||||||
# Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
|
|
||||||
# Copyright (C) 2014 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.
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os.path
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from os_ken import cfg
|
|
||||||
from os_ken import utils
|
|
||||||
from os_ken import __version__
|
|
||||||
|
|
||||||
|
|
||||||
subcommands = {
|
|
||||||
'run': 'os_ken.cmd.manager',
|
|
||||||
'of-config-cli': 'os_ken.cmd.of_config_cli',
|
|
||||||
'rpc-cli': 'os_ken.cmd.rpc_cli',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class RemainderOpt(cfg.MultiStrOpt):
|
|
||||||
def _get_argparse_kwargs(self, group, **kwargs):
|
|
||||||
kwargs = cfg.MultiStrOpt._get_argparse_kwargs(self, group, **kwargs)
|
|
||||||
kwargs['nargs'] = argparse.REMAINDER
|
|
||||||
return kwargs
|
|
||||||
|
|
||||||
|
|
||||||
base_conf = cfg.ConfigOpts()
|
|
||||||
base_conf.register_cli_opt(cfg.StrOpt('subcommand', positional=True,
|
|
||||||
required=True,
|
|
||||||
help='[%s]' % '|'.join(
|
|
||||||
list(subcommands.keys()))))
|
|
||||||
base_conf.register_cli_opt(RemainderOpt('subcommand_args', default=[],
|
|
||||||
positional=True,
|
|
||||||
help='subcommand specific arguments'))
|
|
||||||
|
|
||||||
|
|
||||||
class SubCommand(object):
|
|
||||||
def __init__(self, name, entry):
|
|
||||||
self.name = name
|
|
||||||
self.entry = entry
|
|
||||||
|
|
||||||
def run(self, args):
|
|
||||||
prog = '%s %s' % (os.path.basename(sys.argv[0]), self.name,)
|
|
||||||
self.entry(args=args, prog=prog)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
try:
|
|
||||||
base_conf(project='os_ken', version='os_ken %s' % __version__)
|
|
||||||
except cfg.RequiredOptError as e:
|
|
||||||
base_conf.print_help()
|
|
||||||
raise SystemExit(1)
|
|
||||||
subcmd_name = base_conf.subcommand
|
|
||||||
try:
|
|
||||||
subcmd_mod_name = subcommands[subcmd_name]
|
|
||||||
except KeyError:
|
|
||||||
base_conf.print_help()
|
|
||||||
raise SystemExit('Unknown subcommand %s' % subcmd_name)
|
|
||||||
subcmd_mod = utils.import_module(subcmd_mod_name)
|
|
||||||
subcmd = SubCommand(name=subcmd_name, entry=subcmd_mod.main)
|
|
||||||
subcmd.run(base_conf.subcommand_args)
|
|
@@ -1,263 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
#
|
|
||||||
# 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 ast
|
|
||||||
import cmd
|
|
||||||
import signal
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
import termios
|
|
||||||
|
|
||||||
from os_ken import cfg
|
|
||||||
from os_ken.lib import rpc
|
|
||||||
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
CONF.register_cli_opts([
|
|
||||||
cfg.ListOpt('peers', default=[],
|
|
||||||
help='List of peers, separated by commas. '
|
|
||||||
'(e.g., "hoge=localhost:9998,fuga=localhost:9999")'),
|
|
||||||
cfg.StrOpt('command', short='c', default=None,
|
|
||||||
help='Command to be executed as single command. '
|
|
||||||
'The default is None and opens interactive console.'),
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
class Peer(object):
|
|
||||||
def __init__(self, name, addr):
|
|
||||||
self._name = name
|
|
||||||
self._addr = addr
|
|
||||||
self.socket = None
|
|
||||||
self.client = None
|
|
||||||
try:
|
|
||||||
self.connect()
|
|
||||||
except ConnectionError as e:
|
|
||||||
print('Exception when connecting to peer "%s": %s' % (name, e))
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def connect(self):
|
|
||||||
self.socket = socket.create_connection(self._addr)
|
|
||||||
self.client = rpc.Client(self.socket,
|
|
||||||
notification_callback=self.notification)
|
|
||||||
|
|
||||||
def try_to_connect(self, verbose=False):
|
|
||||||
if self.client:
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
self.connect()
|
|
||||||
assert self.client
|
|
||||||
except Exception as e:
|
|
||||||
if verbose:
|
|
||||||
print("connection failure %s" % e)
|
|
||||||
raise EOFError
|
|
||||||
|
|
||||||
def notification(self, n):
|
|
||||||
print("NOTIFICATION from %s %s" % (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()
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.socket.close()
|
|
||||||
|
|
||||||
|
|
||||||
peers = {}
|
|
||||||
|
|
||||||
|
|
||||||
def add_peer(name, host, port):
|
|
||||||
try:
|
|
||||||
peer = Peer(name, (host, port))
|
|
||||||
except ConnectionError:
|
|
||||||
return
|
|
||||||
|
|
||||||
peers[name] = peer
|
|
||||||
|
|
||||||
|
|
||||||
def close_peers():
|
|
||||||
for peer in peers.values():
|
|
||||||
peer.socket.close()
|
|
||||||
|
|
||||||
|
|
||||||
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 = ast.literal_eval(args[2])
|
|
||||||
except (IndexError, ValueError) as e:
|
|
||||||
print("argument error: %s" % e)
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
p = peers[peer]
|
|
||||||
except KeyError:
|
|
||||||
print("unknown peer %s" % peer)
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
f(p, method, params)
|
|
||||||
except rpc.RPCError as e:
|
|
||||||
print("RPC ERROR %s" % 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 %s" % 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=None):
|
|
||||||
close_peers()
|
|
||||||
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.items():
|
|
||||||
if p.client:
|
|
||||||
try:
|
|
||||||
p.client.peek_notification()
|
|
||||||
except EOFError:
|
|
||||||
p.client = None
|
|
||||||
print("disconnected %s" % 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 postloop(self):
|
|
||||||
close_peers()
|
|
||||||
|
|
||||||
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(args=None, prog=None):
|
|
||||||
CONF(args=args, prog=prog, 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)
|
|
||||||
|
|
||||||
if CONF.command:
|
|
||||||
command = Cmd()
|
|
||||||
command.onecmd(CONF.command)
|
|
||||||
command.do_EOF()
|
|
||||||
|
|
||||||
Cmd().cmdloop()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@@ -1,15 +0,0 @@
|
|||||||
# 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.
|
|
@@ -1,21 +0,0 @@
|
|||||||
# 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 os_ken.base import app_manager
|
|
||||||
|
|
||||||
|
|
||||||
class DummyApp(app_manager.OSKenApp):
|
|
||||||
pass
|
|
@@ -1,22 +0,0 @@
|
|||||||
# Copyright (C) 2013,2014 Nippon Telegraph and Telephone Corporation.
|
|
||||||
# Copyright (C) 2013,2014 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 os_ken.base import app_manager
|
|
||||||
from os_ken.ofproto import ofproto_v1_3
|
|
||||||
|
|
||||||
|
|
||||||
class DummyOpenFlowApp(app_manager.OSKenApp):
|
|
||||||
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
|
|
@@ -1,68 +0,0 @@
|
|||||||
# Copyright (C) 2013,2014 Nippon Telegraph and Telephone Corporation.
|
|
||||||
# Copyright (C) 2013,2014 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.
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
from importlib import reload
|
|
||||||
|
|
||||||
from os_ken.cmd.manager import main
|
|
||||||
|
|
||||||
|
|
||||||
class Test_Manager(unittest.TestCase):
|
|
||||||
"""Test osken-manager command
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, methodName):
|
|
||||||
super(Test_Manager, self).__init__(methodName)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@mock.patch('sys.argv', new=['osken-manager', '--version'])
|
|
||||||
def test_version(self):
|
|
||||||
self.assertRaises(SystemExit, main)
|
|
||||||
|
|
||||||
@mock.patch('sys.argv', new=['osken-manager', '--help'])
|
|
||||||
def test_help(self):
|
|
||||||
self.assertRaises(SystemExit, main)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _reset_globals():
|
|
||||||
# hack to reset globals like SERVICE_BRICKS.
|
|
||||||
# assumption: this is the only test which actually starts OSKenApp.
|
|
||||||
import os_ken.base.app_manager
|
|
||||||
import os_ken.ofproto.ofproto_protocol
|
|
||||||
|
|
||||||
reload(os_ken.base.app_manager)
|
|
||||||
reload(os_ken.ofproto.ofproto_protocol)
|
|
||||||
|
|
||||||
@mock.patch('sys.argv', new=['osken-manager', '--verbose',
|
|
||||||
'os_ken.tests.unit.cmd.dummy_app'])
|
|
||||||
def test_no_services(self):
|
|
||||||
self._reset_globals()
|
|
||||||
main()
|
|
||||||
self._reset_globals()
|
|
||||||
|
|
||||||
@mock.patch('sys.argv', new=['osken-manager', '--verbose',
|
|
||||||
'os_ken.tests.unit.cmd.dummy_openflow_app'])
|
|
||||||
def test_openflow_app(self):
|
|
||||||
self._reset_globals()
|
|
||||||
main()
|
|
||||||
self._reset_globals()
|
|
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
other:
|
||||||
|
- |
|
||||||
|
CLI tools `osken` and `osken-manager` are removed completely.
|
||||||
|
|
Reference in New Issue
Block a user