From: yasufum.o@gmail.com
To: spp@dpdk.org, ferruh.yigit@intel.com, yasufum.o@gmail.com
Subject: [spp] [PATCH 1/2] cli: add compl for new commands in spp_primary
Date: Thu, 17 Oct 2019 21:58:35 +0900 [thread overview]
Message-ID: <20191017125836.29365-2-yasufum.o@gmail.com> (raw)
In-Reply-To: <20191017125836.29365-1-yasufum.o@gmail.com>
From: Yasufumi Ogawa <yasufum.o@gmail.com>
As `add`, `del` and `patch` are supported in spp_primary, add
completion for these commands. This update is also including misc
revises for maintenance.
Signed-off-by: Yasufumi Ogawa <yasufum.o@gmail.com>
---
src/cli/commands/nfv.py | 19 ++--
src/cli/commands/pri.py | 218 ++++++++++++++++++++++++++++++----------
2 files changed, 173 insertions(+), 64 deletions(-)
diff --git a/src/cli/commands/nfv.py b/src/cli/commands/nfv.py
index 1144eca..3bf4148 100644
--- a/src/cli/commands/nfv.py
+++ b/src/cli/commands/nfv.py
@@ -28,7 +28,7 @@ class SppNfv(object):
self.spp_ctl_cli = spp_ctl_cli
self.sec_id = sec_id
self.ports = [] # registered ports
- self.patchs = []
+ self.patches = []
# Call REST API each time of completion if it is True.
self.use_cache = use_cache
@@ -129,13 +129,13 @@ class SppNfv(object):
print('Error: unknown response.')
# TODO(yasufum) change name starts with '_' as private
- def get_ports_and_patches(self):
- """Get all of ports and patchs at once.
+ def _get_ports_and_patches(self):
+ """Get all of ports and patches at once.
This method is to execute `get_ports()` and `get_patches()` at
once to reduce request to spp-ctl. Returned value is a set of
lists. You use this method as following.
- ports, patches = get_ports_and_patches()
+ ports, patches = _get_ports_and_patches()
"""
res = self.spp_ctl_cli.get('nfvs/%d' % self.sec_id)
@@ -150,8 +150,7 @@ class SppNfv(object):
else:
print('Error: unknown response.')
- # TODO(yasufum) change name starts with '_' as private
- def get_patched_ports(self):
+ def _get_patched_ports(self):
"""Get all of patched ports as a list.
This method is to get a list of patched ports instead of a dict.
@@ -234,10 +233,10 @@ class SppNfv(object):
res = []
if self.use_cache is False:
- self.ports, self.patches = self.get_ports_and_patches()
+ self.ports, self.patches = self._get_ports_and_patches()
# Patched ports should not be included in the candidate of del.
- patched_ports = self.get_patched_ports()
+ patched_ports = self._get_patched_ports()
# Remove ports already used from candidate.
for kw in self.ports:
@@ -264,7 +263,7 @@ class SppNfv(object):
res = []
if self.use_cache is False:
- self.ports, self.patches = self.get_ports_and_patches()
+ self.ports, self.patches = self._get_ports_and_patches()
# Get patched ports of src and dst to be used for completion.
src_ports = []
@@ -354,7 +353,7 @@ class SppNfv(object):
self.patches = self.get_patches()
# Patched ports should not be deleted.
- patched_ports = self.get_patched_ports()
+ patched_ports = self._get_patched_ports()
if params[0] in patched_ports:
print("Cannot delete patched port '%s'." % params[0])
diff --git a/src/cli/commands/pri.py b/src/cli/commands/pri.py
index 32c632c..f4cda74 100644
--- a/src/cli/commands/pri.py
+++ b/src/cli/commands/pri.py
@@ -25,7 +25,7 @@ class SppPrimary(object):
self.spp_ctl_cli = spp_ctl_cli
self.ports = [] # registered ports
- self.patchs = []
+ self.patches = []
# Default args for `pri; launch`, used if given cli_config is invalid
@@ -248,7 +248,7 @@ class SppPrimary(object):
print('Error: unknown response for get_patches.')
def _get_ports_and_patches(self):
- """Get all of ports and patchs at once.
+ """Get all of ports and patches at once.
This method is to execute `_get_ports()` and `_get_patches()` at
once to reduce request to spp-ctl. Returned value is a set of
@@ -357,16 +357,16 @@ class SppPrimary(object):
return sockets
- def _setup_launch_opts(self, tokens, cli_config):
+ def _setup_launch_opts(self, sub_tokens, cli_config):
"""Make options for launch cmd from config params."""
if 'max_secondary' in cli_config.keys():
max_secondary = int(cli_config['max_secondary']['val'])
- if (tokens[2] in spp_common.SEC_TYPES) and \
- (int(tokens[3])-1 in range(max_secondary)):
- ptype = tokens[2]
- sid = tokens[3]
+ if (sub_tokens[1] in spp_common.SEC_TYPES) and \
+ (int(sub_tokens[2])-1 in range(max_secondary)):
+ ptype = sub_tokens[1]
+ sid = sub_tokens[2]
# Option of secondary ID is different between spp_nfv
# and others.
@@ -481,56 +481,166 @@ class SppPrimary(object):
Called from complete_pri() to complete primary command.
"""
- candidates = []
- tokens = line.split(' ')
-
- # Parse command line
- if tokens[0].endswith(';'):
-
- # Show sub commands
- if len(tokens) == 2:
- # Add sub commands
- candidates = candidates + self.PRI_CMDS[:]
-
- # Show args of `launch` sub command.
- elif len(tokens) == 3 and tokens[1] == 'launch':
- for pt in spp_common.SEC_TYPES:
- candidates.append('{}'.format(pt))
-
- elif len(tokens) == 4 and tokens[1] == 'launch':
- if 'max_secondary' in cli_config.keys():
- max_secondary = int(
- cli_config['max_secondary']['val'])
-
- if tokens[2] in spp_common.SEC_TYPES:
- used_sec_ids = [str(i) for i in self._get_sec_ids()]
- candidates = [
- str(i+1) for i in range(max_secondary)
- if str(i+1) not in used_sec_ids]
- logger.debug(candidates)
+ try:
+ candidates = []
+ tokens = line.split(' ')
+
+ # Parse command line
+ if tokens[0].endswith(';'):
+
+ # Show sub commands
+ if len(tokens) == 2:
+ # Add sub commands
+ candidates = candidates + self.PRI_CMDS[:]
+
else:
- logger.error(
- 'Error: max_secondary is not defined in config')
- candidates = []
+ # Show args of `launch` sub command.
+ if tokens[1] == 'launch':
+ candidates = self._compl_launch(tokens[1:], cli_config)
+ elif tokens[1] == 'add':
+ candidates = self._compl_add(tokens[1:])
+ elif tokens[1] == 'del':
+ candidates = self._compl_del(tokens[1:])
+ elif tokens[1] == 'patch':
+ candidates = self._compl_patch(tokens[1:])
+
+ if not text:
+ completions = candidates
+ else:
+ completions = [p for p in candidates
+ if p.startswith(text)
+ ]
- elif len(tokens) == 5 and tokens[1] == 'launch':
- # Do not show candidate if given sec ID is already used.
- # Sec ID is contained as the third entry in tokens. Here is an
- # example of tokens.
- # ['pri;', 'launch', 'nfv', '1', '']
- used_sec_ids = [str(i) for i in self._get_sec_ids()]
- if tokens[3] not in used_sec_ids:
- candidates = self._setup_launch_opts(
- tokens, cli_config)
-
- if not text:
- completions = candidates
- else:
- completions = [p for p in candidates
- if p.startswith(text)
- ]
+ return completions
+
+ except Exception as e:
+ print(e)
+
+ def _compl_launch(self, sub_tokens, cli_config):
+ candidates = []
+ if len(sub_tokens) == 2:
+ for pt in spp_common.SEC_TYPES:
+ candidates.append('{}'.format(pt))
+
+ elif len(sub_tokens) == 3:
+ if 'max_secondary' in cli_config.keys():
+ max_secondary = int(
+ cli_config['max_secondary']['val'])
+
+ if sub_tokens[1] in spp_common.SEC_TYPES:
+ used_sec_ids = [str(i) for i in self._get_sec_ids()]
+ candidates = [
+ str(i+1) for i in range(max_secondary)
+ if str(i+1) not in used_sec_ids]
+ logger.debug(candidates)
+ else:
+ logger.error(
+ 'Error: max_secondary is not defined in config')
+ candidates = []
+
+ elif len(sub_tokens) == 4:
+ # Do not show candidate if given sec ID is already used.
+ # Sec ID is contained as the 2nd entry in sub_tokens. Here is an
+ # example of sub_tokens.
+ # ['launch', 'nfv', '1', '']
+ used_sec_ids = [str(i) for i in self._get_sec_ids()]
+ if sub_tokens[1] not in used_sec_ids:
+ candidates = self._setup_launch_opts(
+ sub_tokens, cli_config)
+
+ return candidates
+
+ # TODO(yasufum): consider to merge nfv's.
+ def _compl_add(self, sub_tokens):
+ """Complete `add` command."""
+
+ if len(sub_tokens) < 3:
+ res = []
+
+ port_types = spp_common.PORT_TYPES[:]
+ port_types.remove('phy')
+
+ for kw in port_types:
+ if kw.startswith(sub_tokens[1]):
+ res.append(kw + ':')
+ return res
+
+ # TODO(yasufum): consider to merge nfv's.
+ def _compl_del(self, sub_tokens):
+ """Complete `del` command."""
+
+ # Del command consists of two tokens max, for instance,
+ # `nfv 1; del ring:1`.
+ if len(sub_tokens) < 3:
+ res = []
+
+ self.ports, self.patches = self._get_ports_and_patches()
+
+ # Patched ports should not be included in the candidate of del.
+ patched_ports = self._get_patched_ports()
+
+ # Remove ports already used from candidate.
+ for kw in self.ports:
+ if not (kw in patched_ports):
+ if kw.startswith(sub_tokens[1]):
+ if ':' in sub_tokens[1]: # exp, 'ring:' or 'ring:0'
+ res.append(kw.split(':')[1])
+ else:
+ res.append(kw)
+
+ # Physical port cannot be removed.
+ for p in res:
+ if p.startswith('phy:'):
+ res.remove(p)
+
+ return res
+
+ # TODO(yasufum): consider to merge nfv's.
+ def _compl_patch(self, sub_tokens):
+ """Complete `patch` command."""
+
+ # Patch command consists of three tokens max, for instance,
+ # `nfv 1; patch phy:0 ring:1`.
+ if len(sub_tokens) < 4:
+ res = []
+
+ self.ports, self.patches = self._get_ports_and_patches()
+
+ # Get patched ports of src and dst to be used for completion.
+ src_ports = []
+ dst_ports = []
+ for pt in self.patches:
+ src_ports.append(pt['src'])
+ dst_ports.append(pt['dst'])
+
+ # Remove patched ports from candidates.
+ target_idx = len(sub_tokens) - 1 # target is src or dst
+ tmp_ports = self.ports[:] # candidates
+ if target_idx == 1: # find src port
+ # If some of ports are patched, `reset` should be included.
+ if self.patches != []:
+ tmp_ports.append('reset')
+ for pt in src_ports:
+ tmp_ports.remove(pt) # remove patched ports
+ else: # find dst port
+ # If `reset` is given, no need to show dst ports.
+ if sub_tokens[target_idx - 1] == 'reset':
+ tmp_ports = []
+ else:
+ for pt in dst_ports:
+ tmp_ports.remove(pt)
+
+ # Return candidates.
+ for kw in tmp_ports:
+ if kw.startswith(sub_tokens[target_idx]):
+ # Completion does not work correctly if `:` is included in
+ # tokens. Required to create keyword only after `:`.
+ if ':' in sub_tokens[target_idx]: # 'ring:' or 'ring:0'
+ res.append(kw.split(':')[1]) # add only after `:`
+ else:
+ res.append(kw)
- return completions
+ return res
def _get_sec_ids(self):
sec_ids = []
--
2.17.1
next prev parent reply other threads:[~2019-10-17 12:58 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-17 12:58 [spp] [PATCH 0/2] Add completion for forwarder in primary yasufum.o
2019-10-17 12:58 ` yasufum.o [this message]
2019-10-17 12:58 ` [spp] [PATCH 2/2] cli: fix bug of completion in del command yasufum.o
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=20191017125836.29365-2-yasufum.o@gmail.com \
--to=yasufum.o@gmail.com \
--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).