From: ogawa.yasufumi@lab.ntt.co.jp
To: spp@dpdk.org, ferruh.yigit@intel.com, ogawa.yasufumi@lab.ntt.co.jp
Subject: [spp] [PATCH 6/9] controller: move sec command to SppSecondary
Date: Thu, 18 Oct 2018 20:25:15 +0900 [thread overview]
Message-ID: <20181018112518.77556-7-ogawa.yasufumi@lab.ntt.co.jp> (raw)
In-Reply-To: <20181018112518.77556-1-ogawa.yasufumi@lab.ntt.co.jp>
From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
SppSecondary defines 'sec' command and its completion as in a separated
module. It is intended to be used from Shell, which is derived from
'cmd.Cmd'.
Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
src/controller/commands/sec.py | 194 ++++++++++++++++++++++++++++++++++++++
src/controller/shell.py | 197 +++++----------------------------------
src/controller/spp_ctl_client.py | 2 +
3 files changed, 221 insertions(+), 172 deletions(-)
create mode 100644 src/controller/commands/sec.py
diff --git a/src/controller/commands/sec.py b/src/controller/commands/sec.py
new file mode 100644
index 0000000..77cfe62
--- /dev/null
+++ b/src/controller/commands/sec.py
@@ -0,0 +1,194 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Nippon Telegraph and Telephone Corporation
+
+
+class SppSecondary(object):
+ """Exec SPP secondary command.
+
+ SppSecondaryclass is intended to be used in Shell class as a delegator
+ for running 'sec' command.
+
+ 'self.command()' is called from do_sec() and 'self.complete()' is called
+ from complete_sec() of both of which is defined in Shell.
+ """
+
+ # All of commands and sub-commands used for validation and completion.
+ SEC_CMDS = ['status', 'exit', 'forward', 'stop', 'add', 'patch', 'del']
+ SEC_SUBCMDS = ['vhost', 'ring', 'pcap', 'nullpmd']
+
+ def __init__(self, spp_ctl_cli):
+ self.spp_ctl_cli = spp_ctl_cli
+
+ def run(self, sec_id, cmdline):
+ """Called from do_sec() to Send command to secondary process."""
+
+ cmd = cmdline.split(' ')[0]
+ params = cmdline.split(' ')[1:]
+
+ if cmd == 'status':
+ res = self.spp_ctl_cli.get('nfvs/%d' % sec_id)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 200:
+ self.print_sec_status(res.json())
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ elif cmd == 'add':
+ req_params = {'action': 'add', 'port': params[0]}
+ res = self.spp_ctl_cli.put('nfvs/%d/ports' % sec_id, req_params)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 204:
+ print('Add %s.' % params[0])
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ elif cmd == 'del':
+ req_params = {'action': 'del', 'port': params[0]}
+ res = self.spp_ctl_cli.put('nfvs/%d/ports' % sec_id, req_params)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 204:
+ print('Delete %s.' % params[0])
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ elif cmd == 'forward' or cmd == 'stop':
+ if cmd == 'forward':
+ req_params = {'action': 'start'}
+ elif cmd == 'stop':
+ req_params = {'action': 'stop'}
+ else:
+ print('Unknown command. "forward" or "stop"?')
+
+ res = self.spp_ctl_cli.put('nfvs/%d/forward' % sec_id, req_params)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 204:
+ if cmd == 'forward':
+ print('Start forwarding.')
+ else:
+ print('Stop forwarding.')
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ elif cmd == 'patch':
+ if params[0] == 'reset':
+ res = self.spp_ctl_cli.delete('nfvs/%d/patches' % sec_id)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 204:
+ print('Clear all of patches.')
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+ else:
+ req_params = {'src': params[0], 'dst': params[1]}
+ res = self.spp_ctl_cli.put(
+ 'nfvs/%d/patches' % sec_id, req_params)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 204:
+ print('Patch ports (%s -> %s).' % (
+ params[0], params[1]))
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ elif cmd == 'exit':
+ print('do nothing.')
+
+ else:
+ print('Invalid command "%s".' % cmd)
+
+ def print_sec_status(self, json_obj):
+ """Parse and print message from SPP secondary.
+
+ Print status received from secondary.
+
+ spp > sec 1;status
+ - status: idling
+ - ports:
+ - phy:0 -> ring:0
+ - phy:1
+
+ The format of the received message is JSON and ended with
+ series of null character "\x00".
+
+ {"client-id":1,...,"patches":[{"src":"phy:0"...},...]}'\x00..
+ """
+
+ sec_attr = json_obj
+ print('- status: %s' % sec_attr['status'])
+ print('- ports:')
+ for port in sec_attr['ports']:
+ dst = None
+ for patch in sec_attr['patches']:
+ if patch['src'] == port:
+ dst = patch['dst']
+
+ if dst is None:
+ print(' - %s' % port)
+ else:
+ print(' - %s -> %s' % (port, dst))
+
+ def complete(self, sec_ids, text, line, begidx, endidx):
+ """Completion for secondary process commands.
+
+ Called from complete_sec() to complete secondary command.
+ """
+
+ try:
+ cleaned_line = line
+
+ if len(cleaned_line.split()) == 1:
+ completions = [str(i)+";" for i in sec_ids]
+ elif len(cleaned_line.split()) == 2:
+ if not (";" in cleaned_line):
+ tmplist = [str(i) for i in sec_ids]
+ completions = [p+";"
+ for p in tmplist
+ if p.startswith(text)
+ ]
+ elif cleaned_line[-1] == ";":
+ completions = self.SEC_CMDS[:]
+ else:
+ seccmd = cleaned_line.split(";")[1]
+ if cleaned_line[-1] != " ":
+ completions = [p
+ for p in self.SEC_CMDS
+ if p.startswith(seccmd)
+ ]
+ elif ("add" in seccmd) or ("del" in seccmd):
+ completions = self.SEC_SUBCMDS[:]
+ else:
+ completions = []
+ elif len(cleaned_line.split()) == 3:
+ subcmd = cleaned_line.split()[-1]
+ if ("add" == subcmd) or ("del" == subcmd):
+ completions = self.SEC_SUBCMDS[:]
+ else:
+ if cleaned_line[-1] == " ":
+ completions = []
+ else:
+ completions = [p
+ for p in self.SEC_SUBCMDS
+ if p.startswith(subcmd)
+ ]
+ else:
+ completions = []
+ return completions
+ except Exception as e:
+ print(len(cleaned_line.split()))
+ print(e)
diff --git a/src/controller/shell.py b/src/controller/shell.py
index 9834df0..ca4775b 100644
--- a/src/controller/shell.py
+++ b/src/controller/shell.py
@@ -5,6 +5,7 @@ from __future__ import absolute_import
import cmd
from .commands import pri
+from .commands import sec
import os
import re
import readline
@@ -27,14 +28,10 @@ class Shell(cmd.Cmd, object):
PORT_TYPES = ['phy', 'ring', 'vhost', 'pcap', 'nullpmd']
- SEC_CMDS = ['status', 'exit', 'forward', 'stop', 'add', 'patch', 'del']
- SEC_SUBCMDS = ['vhost', 'ring', 'pcap', 'nullpmd']
BYE_CMDS = ['sec', 'all']
HIST_EXCEPT = ['bye', 'exit', 'history', 'redo']
- rest_common_error_codes = [400, 404, 500]
-
PLUGIN_DIR = 'command'
subgraphs = {}
topo_size = '60%'
@@ -49,6 +46,7 @@ class Shell(cmd.Cmd, object):
cmd.Cmd.__init__(self)
self.spp_ctl_cli = spp_ctl_cli
self.spp_primary = pri.SppPrimary(self.spp_ctl_cli)
+ self.spp_secondary = sec.SppSecondary(self.spp_ctl_cli)
def default(self, line):
"""Define defualt behaviour.
@@ -71,6 +69,20 @@ class Shell(cmd.Cmd, object):
"""
pass
+ def get_sec_ids(self, ptype):
+ """Return a list of IDs of running secondary processes.
+
+ 'ptype' is 'nfv' or 'vf'.
+ """
+
+ ids = []
+ res = self.spp_ctl_cli.get('processes')
+ if res.status_code == 200:
+ for ent in res.json():
+ if ent['type'] == ptype:
+ ids.append(ent['client-id'])
+ return ids
+
def clean_hist_file(self):
"""Remove useless entries in history file."""
@@ -126,129 +138,11 @@ class Shell(cmd.Cmd, object):
for obj in sec_obj['nfv']:
print(' %d: %s:%s' % (
obj['client-id'], obj['type'], obj['client-id']))
- elif res.status_code in self.rest_common_error_codes:
+ elif res.status_code in self.spp_ctl_cli.rest_common_error_codes:
pass
else:
print('Error: unknown response.')
- def print_sec_status(self, json_obj):
- """Parse and print message from SPP secondary.
-
- Print status received from secondary.
-
- spp > sec 1;status
- - status: idling
- - ports:
- - phy:0 -> ring:0
- - phy:1
-
- The format of the received message is JSON and ended with
- series of null character "\x00".
-
- {"client-id":1,...,"patches":[{"src":"phy:0"...},...]}'\x00..
- """
-
- sec_attr = json_obj
- print('- status: %s' % sec_attr['status'])
- print('- ports:')
- for port in sec_attr['ports']:
- dst = None
- for patch in sec_attr['patches']:
- if patch['src'] == port:
- dst = patch['dst']
-
- if dst is None:
- print(' - %s' % port)
- else:
- print(' - %s -> %s' % (port, dst))
-
- def command_secondary(self, sec_id, command):
- """Send command to secondary process."""
-
- cmd = command.split(' ')[0]
- params = command.split(' ')[1:]
-
- if cmd == 'status':
- res = self.spp_ctl_cli.get('nfvs/%d' % sec_id)
- if res is not None:
- if res.status_code == 200:
- self.print_sec_status(res.json())
- elif res.status_code in self.rest_common_error_codes:
- pass
- else:
- print('Error: unknown response.')
-
- elif cmd == 'add':
- req_params = {'action': 'add', 'port': params[0]}
- res = self.spp_ctl_cli.put('nfvs/%d/ports' % sec_id, req_params)
- if res is not None:
- if res.status_code == 204:
- print('Add %s.' % params[0])
- elif res.status_code in self.rest_common_error_codes:
- pass
- else:
- print('Error: unknown response.')
-
- elif cmd == 'del':
- req_params = {'action': 'del', 'port': params[0]}
- res = self.spp_ctl_cli.put('nfvs/%d/ports' % sec_id, req_params)
- if res is not None:
- if res.status_code == 204:
- print('Delete %s.' % params[0])
- elif res.status_code in self.rest_common_error_codes:
- pass
- else:
- print('Error: unknown response.')
-
- elif cmd == 'forward' or cmd == 'stop':
- if cmd == 'forward':
- req_params = {'action': 'start'}
- elif cmd == 'stop':
- req_params = {'action': 'stop'}
- else:
- print('Unknown command. "forward" or "stop"?')
-
- res = self.spp_ctl_cli.put('nfvs/%d/forward' % sec_id, req_params)
- if res is not None:
- if res.status_code == 204:
- if cmd == 'forward':
- print('Start forwarding.')
- else:
- print('Stop forwarding.')
- elif res.status_code in self.rest_common_error_codes:
- pass
- else:
- print('Error: unknown response.')
-
- elif cmd == 'patch':
- if params[0] == 'reset':
- res = self.spp_ctl_cli.delete('nfvs/%d/patches' % sec_id)
- if res is not None:
- if res.status_code == 204:
- print('Clear all of patches.')
- elif res.status_code in self.rest_common_error_codes:
- pass
- else:
- print('Error: unknown response.')
- else:
- req_params = {'src': params[0], 'dst': params[1]}
- res = self.spp_ctl_cli.put(
- 'nfvs/%d/patches' % sec_id, req_params)
- if res is not None:
- if res.status_code == 204:
- print('Patch ports (%s -> %s).' % (
- params[0], params[1]))
- elif res.status_code in self.rest_common_error_codes:
- pass
- else:
- print('Error: unknown response.')
-
- elif cmd == 'exit':
- print('do nothing.')
-
- else:
- print('Invalid command "%s".' % cmd)
-
def is_patched_ids_valid(self, id1, id2, delim=':'):
"""Check if port IDs are valid
@@ -364,7 +258,7 @@ class Shell(cmd.Cmd, object):
return self.spp_primary.complete(text, line, begidx, endidx)
- def do_sec(self, arg):
+ def do_sec(self, cmd):
"""Send a command to secondary process specified with ID.
SPP secondary process is specified with secondary ID and takes
@@ -382,18 +276,16 @@ class Shell(cmd.Cmd, object):
"""
# remove unwanted spaces to avoid invalid command error
- tmparg = self.clean_cmd(arg)
+ tmparg = self.clean_cmd(cmd)
cmds = tmparg.split(';')
if len(cmds) < 2:
- message = "'sec' requires an ID and ';' before command."
- print(message)
+ print("Required an ID and ';' before command.")
elif str.isdigit(cmds[0]):
sec_id = int(cmds[0])
if self.check_sec_cmds(cmds[1]):
- self.command_secondary(sec_id, cmds[1])
+ self.spp_secondary.run(sec_id, cmds[1])
else:
- message = "invalid cmd"
- print(message)
+ print("Invalid sec command")
else:
print(cmds[0])
print("first %s" % cmds[1])
@@ -401,48 +293,9 @@ class Shell(cmd.Cmd, object):
def complete_sec(self, text, line, begidx, endidx):
"""Completion for secondary process commands"""
- try:
- cleaned_line = self.clean_cmd(line)
- if len(cleaned_line.split()) == 1:
- completions = [str(i)+";" for i in spp_common.SECONDARY_LIST]
- elif len(cleaned_line.split()) == 2:
- if not (";" in cleaned_line):
- tmplist = [str(i) for i in spp_common.SECONDARY_LIST]
- completions = [p+";"
- for p in tmplist
- if p.startswith(text)
- ]
- elif cleaned_line[-1] == ";":
- completions = self.SEC_CMDS[:]
- else:
- seccmd = cleaned_line.split(";")[1]
- if cleaned_line[-1] != " ":
- completions = [p
- for p in self.SEC_CMDS
- if p.startswith(seccmd)
- ]
- elif ("add" in seccmd) or ("del" in seccmd):
- completions = self.SEC_SUBCMDS[:]
- else:
- completions = []
- elif len(cleaned_line.split()) == 3:
- subcmd = cleaned_line.split()[-1]
- if ("add" == subcmd) or ("del" == subcmd):
- completions = self.SEC_SUBCMDS[:]
- else:
- if cleaned_line[-1] == " ":
- completions = []
- else:
- completions = [p
- for p in self.SEC_SUBCMDS
- if p.startswith(subcmd)
- ]
- else:
- completions = []
- return completions
- except Exception as e:
- print(len(cleaned_line.split()))
- print(e)
+ line = self.clean_cmd(line)
+ return self.spp_secondary.complete(
+ self.get_sec_ids('nfv'), text, line, begidx, endidx)
def do_record(self, fname):
"""Save commands as a recipe file.
diff --git a/src/controller/spp_ctl_client.py b/src/controller/spp_ctl_client.py
index a1d6d93..8a88fa4 100644
--- a/src/controller/spp_ctl_client.py
+++ b/src/controller/spp_ctl_client.py
@@ -7,6 +7,8 @@ import requests
class SppCtlClient(object):
+ rest_common_error_codes = [400, 404, 500]
+
def __init__(self, ip_addr='localhost', port=7777):
api_ver = 'v1'
self.base_url = 'http://%s:%d/%s' % (ip_addr, port, api_ver)
--
2.13.1
next prev parent reply other threads:[~2018-10-18 11:25 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-10-18 11:25 [spp] [PATCH 0/9] Change SPP controller to use spp-ctl ogawa.yasufumi
2018-10-18 11:25 ` [spp] [PATCH 1/9] controller: add spp-ctl client for SPP controller ogawa.yasufumi
2018-10-18 11:25 ` [spp] [PATCH 2/9] controller: change controller to use spp-ctl ogawa.yasufumi
2018-10-18 11:25 ` [spp] [PATCH 3/9] spp-ctl: add IP address binding ogawa.yasufumi
2018-10-18 11:25 ` [spp] [PATCH 4/9] controller: add IP address and port binding ogawa.yasufumi
2018-10-18 11:25 ` [spp] [PATCH 5/9] controller: move pri command to SppPrimary ogawa.yasufumi
2018-10-18 11:25 ` ogawa.yasufumi [this message]
2018-10-18 11:25 ` [spp] [PATCH 7/9] controller: move topo command to SppTopo ogawa.yasufumi
2018-10-18 11:25 ` [spp] [PATCH 8/9] controller: move topo_resize " ogawa.yasufumi
2018-10-18 11:25 ` [spp] [PATCH 9/9] controller: move bye command to SppBye ogawa.yasufumi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20181018112518.77556-7-ogawa.yasufumi@lab.ntt.co.jp \
--to=ogawa.yasufumi@lab.ntt.co.jp \
--cc=ferruh.yigit@intel.com \
--cc=spp@dpdk.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).