From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from tama500.ecl.ntt.co.jp (tama500.ecl.ntt.co.jp [129.60.39.148]) by dpdk.org (Postfix) with ESMTP id 0F8121B864 for ; Mon, 17 Dec 2018 04:34:49 +0100 (CET) Received: from vc1.ecl.ntt.co.jp (vc1.ecl.ntt.co.jp [129.60.86.153]) by tama500.ecl.ntt.co.jp (8.13.8/8.13.8) with ESMTP id wBH3Ym4v019846; Mon, 17 Dec 2018 12:34:48 +0900 Received: from vc1.ecl.ntt.co.jp (localhost [127.0.0.1]) by vc1.ecl.ntt.co.jp (Postfix) with ESMTP id 28D7FEA7A87; Mon, 17 Dec 2018 12:34:48 +0900 (JST) Received: from localhost.localdomain (lobster.nslab.ecl.ntt.co.jp [129.60.13.95]) by vc1.ecl.ntt.co.jp (Postfix) with ESMTP id 16BA1EA77F7; Mon, 17 Dec 2018 12:34:48 +0900 (JST) From: ogawa.yasufumi@lab.ntt.co.jp To: ferruh.yigit@intel.com, spp@dpdk.org, ogawa.yasufumi@lab.ntt.co.jp Date: Mon, 17 Dec 2018 12:32:32 +0900 Message-Id: <1545017552-30059-1-git-send-email-ogawa.yasufumi@lab.ntt.co.jp> X-Mailer: git-send-email 2.7.4 X-TM-AS-MML: disable Subject: [spp] [PATCH] controller: add multi-node support X-BeenThere: spp@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Soft Patch Panel List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 17 Dec 2018 03:34:50 -0000 From: Yasufumi Ogawa This update is to manage multiple nodes of SPP from SPP CLI. To add several nodes, give several address of spp-ctl with `-b` option. Default address is `127.0.0.1:7777` and it is able to be overwritten. If port number is not given, default value `7777` is remained. # Use two spp-ctl running on "192.168.1.101:7777" and # "192.168.1.102:7777". $ python src/spp.py -b 192.168.1.101 -b 192.168.1.102 `server` command is provided for switching spp-ctl under the management of SPP CLI. # Show all of spp-ctl nodes. spp > server # or 'server list' 1: 192.168.1.101:7777 * 2: 192.168.1.102:7777 # Switch to second node. spp > server 2 Switch spp-ctl to "2: 192.168.1.102:7777". Signed-off-by: Yasufumi Ogawa --- src/controller/commands/pri.py | 2 +- src/controller/commands/server.py | 79 +++++++++++++++++++++++++++++++++++++++ src/controller/shell.py | 29 +++++++++++++- src/controller/spp.py | 42 ++++++++++++++++----- src/controller/spp_ctl_client.py | 5 ++- 5 files changed, 142 insertions(+), 15 deletions(-) create mode 100644 src/controller/commands/server.py diff --git a/src/controller/commands/pri.py b/src/controller/commands/pri.py index 51da7ab..750d355 100644 --- a/src/controller/commands/pri.py +++ b/src/controller/commands/pri.py @@ -8,7 +8,7 @@ class SppPrimary(object): SppPrimary class is intended to be used in Shell class as a delegator for running 'pri' command. - 'self.command()' is called from do_pri() and 'self.complete()' is called + 'self.run()' is called from do_pri() and 'self.complete()' is called from complete_pri() of both of which is defined in Shell. """ diff --git a/src/controller/commands/server.py b/src/controller/commands/server.py new file mode 100644 index 0000000..ca362ab --- /dev/null +++ b/src/controller/commands/server.py @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2017-2018 Nippon Telegraph and Telephone Corporation + +import re +from ..spp_common import logger + + +class SppCtlServer(object): + """Execute server command for switching spp-ctl. + + SppCtlServer class is intended to be used in Shell class as a delegator + for running 'server' command. + + 'self.run()' is called from do_pri() and 'self.complete()' is called + from complete_pri() of both of which is defined in Shell. + """ + + SERVER_CMDS = ['list'] + + def __init__(self, spp_cli_objs): + self.spp_cli_objs = spp_cli_objs + self.current_idx = 0 + + def run(self, commands): + args = re.sub(r'\s+', ' ', commands).split(' ') + if '' in args: + args.remove('') + + if len(args) == 0 or args[0] == 'list': + self._show_list() + else: + idx = int(args[0]) - 1 + self._switch_to(idx) + + def complete(self, text, line, begidx, endidx): + """Completion for server command. + + Called from complete_server() to complete server command. + """ + + candidates = [] + for i in range(len(self.spp_cli_objs)): + candidates.append(str(i)) + candidates = candidates + self.SERVER_CMDS[:] + + if not text: + completions = candidates + else: + completions = [p for p in candidates + if p.startswith(text) + ] + + return completions + + def get_current_server(self): + return self.spp_cli_objs[self.current_idx] + + def _show_list(self): + cnt = 1 + for cli_obj in self.spp_cli_objs: + # Put a mark to current server. + if cnt == self.current_idx + 1: + current = '*' + else: + current = '' + + print(' %d: %s:%s %s' % ( + cnt, cli_obj.ip_addr, cli_obj.port, current)) + cnt += 1 + + def _switch_to(self, idx): + if len(self.spp_cli_objs) > idx: + self.current_idx = idx + cli_obj = self.spp_cli_objs[self.current_idx] + print('Switch spp-ctl to "%d: %s:%d"' % + (idx+1, cli_obj.ip_addr, cli_obj.port)) + else: + print('Index should be less than %d!' % + (len(self.spp_cli_objs) + 1)) diff --git a/src/controller/shell.py b/src/controller/shell.py index 615b9a1..6ce4dca 100644 --- a/src/controller/shell.py +++ b/src/controller/shell.py @@ -7,6 +7,7 @@ import cmd from .commands import bye from .commands import pri from .commands import nfv +from .commands import server from .commands import topo from .commands import vf from .commands import mirror @@ -38,9 +39,10 @@ class Shell(cmd.Cmd, object): else: readline.write_history_file(hist_file) - def __init__(self, spp_ctl_cli, use_cache=False): + def __init__(self, spp_cli_objs, use_cache=False): cmd.Cmd.__init__(self) - self.spp_ctl_cli = spp_ctl_cli + self.spp_ctl_server = server.SppCtlServer(spp_cli_objs) + self.spp_ctl_cli = spp_cli_objs[0] self.use_cache = use_cache self.init_spp_procs() self.spp_topo = topo.SppTopo(self.spp_ctl_cli, {}, self.topo_size) @@ -128,6 +130,9 @@ class Shell(cmd.Cmd, object): def print_status(self): """Display information about connected clients.""" + print('- spp-ctl:') + print(' - address: %s:%s' % (self.spp_ctl_cli.ip_addr, + self.spp_ctl_cli.port)) res = self.spp_ctl_cli.get('processes') if res is not None: if res.status_code == 200: @@ -252,6 +257,26 @@ class Shell(cmd.Cmd, object): self.recorded_file.close() self.recorded_file = None + def do_server(self, commands): + """Switch SPP REST API server. + + spp > server # or 'server list' + 1: 192.168.1.101:7777 * + 2: 192.168.1.102:7777 + + spp > server 2 + Switch spp-ctl to "2: 192.168.1.102:7777". + """ + + self.spp_ctl_server.run(commands) + self.spp_ctl_cli = self.spp_ctl_server.get_current_server() + + def complete_server(self, text, line, begidx, endidx): + """Completion for server command.""" + + res = self.spp_ctl_server.complete(text, line, begidx, endidx) + return res + def do_status(self, _): """Display status info of SPP processes diff --git a/src/controller/spp.py b/src/controller/spp.py index 2e1c173..7b7316c 100644 --- a/src/controller/spp.py +++ b/src/controller/spp.py @@ -5,6 +5,7 @@ from __future__ import absolute_import import argparse +import re from .shell import Shell from . import spp_ctl_client import sys @@ -12,19 +13,40 @@ import sys def main(argv): + # Default + api_ipaddr = '127.0.0.1' + api_port = 7777 + parser = argparse.ArgumentParser(description="SPP Controller") - parser.add_argument('-b', '--bind-addr', type=str, default='127.0.0.1', - help='bind address, default=127.0.0.1') - parser.add_argument('-a', '--api-port', type=int, default=7777, - help='bind address, default=7777') + parser.add_argument('-b', '--bind-addr', action='append', + default=['%s:%s' % (api_ipaddr, api_port)], + help='bind address, default=127.0.0.1:7777') args = parser.parse_args() - spp_ctl_cli = spp_ctl_client.SppCtlClient(args.bind_addr, - args.api_port) - if spp_ctl_cli.is_server_running() is False: - print('Is not spp-ctl running, nor correct IP address?') - exit() - shell = Shell(spp_ctl_cli) + if len(args.bind_addr) > 1: + args.bind_addr.pop(0) + + spp_cli_objs = [] + for addr in args.bind_addr: + if ':' in addr: + api_ipaddr, api_port = addr.split(':') + else: + api_ipaddr = addr + + if not re.match(r'\d*\.\d*\.\d*\.\d*', addr): + print('Invalid address "%s"' % args.bind_addr) + exit() + + spp_ctl_cli = spp_ctl_client.SppCtlClient(api_ipaddr, int(api_port)) + + if spp_ctl_cli.is_server_running() is False: + print('Is not spp-ctl running on %s, nor correct IP address?' % + api_ipaddr) + exit() + + spp_cli_objs.append(spp_ctl_cli) + + shell = Shell(spp_cli_objs) shell.cmdloop() shell = None diff --git a/src/controller/spp_ctl_client.py b/src/controller/spp_ctl_client.py index 3713326..f04173b 100644 --- a/src/controller/spp_ctl_client.py +++ b/src/controller/spp_ctl_client.py @@ -9,9 +9,10 @@ class SppCtlClient(object): rest_common_error_codes = [400, 404, 500] - def __init__(self, ip_addr='localhost', port=7777): - api_ver = 'v1' + def __init__(self, ip_addr='localhost', port=7777, api_ver='v1'): self.base_url = 'http://%s:%d/%s' % (ip_addr, port, api_ver) + self.ip_addr = ip_addr + self.port = port def request_handler(func): """Request handler for spp-ctl. -- 2.7.4