Soft Patch Panel
 help / color / mirror / Atom feed
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


  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).