From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id AE743A317C for ; Thu, 17 Oct 2019 14:58:45 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id A7E101E97F; Thu, 17 Oct 2019 14:58:45 +0200 (CEST) Received: from mail-pf1-f194.google.com (mail-pf1-f194.google.com [209.85.210.194]) by dpdk.org (Postfix) with ESMTP id E95511E97F for ; Thu, 17 Oct 2019 14:58:43 +0200 (CEST) Received: by mail-pf1-f194.google.com with SMTP id v4so1618857pff.6 for ; Thu, 17 Oct 2019 05:58:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=nRlx63/RNG6HqVA1geusB/J5tp9X8Fw6LmZ86dODuC4=; b=hBEwh8DRS4B1SO046F1HDAHLIbceOCzjveg/pptUk5dd4lRjq0ywI+8n5+54yo560y TneEMidQR7wmHa7aJB0bF3FJBmoOkCSbwJdG+MqQ9QI83LDN8PvhAAPPRjOLyYY/p0Aa CU/GZLVfSqDhX4nbq3GFmZeJwPwQ1Y+3A8efQd0H5Vy8vUT97ZtFXr4LSpahaq3L0G/Q RIfhJZx2qa0/6VB6Kr0XngRVuba0ORrZmoDzCifcvTx2rmprKPX2G3O1HdnVEiYF3nqk puOrTYYylgplYDwz31RhxVfujg/3JtB/cjUFIANV9bZXSAuFLpL16hJmzRKJq2aP1cMU E7TQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=nRlx63/RNG6HqVA1geusB/J5tp9X8Fw6LmZ86dODuC4=; b=OhDfQCcUHeE46zghWDA6NWbXd4+/ONTSMYO9aQ+XJSaGc2Tc2PVkqKeab70ywHZehm 3gVgZguvRgjh0eYgFc4vrrUtc854LglJ6+mx9h4ZzZIAlzQzPZMvOSGxiAB8j3uPRKgc TuxQsI/gU9fj2YmHE0QPSFya1Lp6tmfL2monwLuzpr2Fo6Ni8Y/de5Or64lkUcl/JZUz tfzGlAs5Zq5mN5FvhvR6RJd6lTsT9sYrnMv1ODteTVdbPl10x4Cu4xiI1VpfnfycrC5r CvuCtPnTyHfpuh5FdXvDPxwDN9nWMnhvK4PagbP/mEWDnECgemsnkfOxcsT1liCRwfbL WWLw== X-Gm-Message-State: APjAAAV3HyEMmhwm94UKX6pv82tT79kWUOjGTojymDNWMZVHYat1spue MDp/zaEfNt5eqSG1n4M5GNvafKIc7WE= X-Google-Smtp-Source: APXvYqyT0hFCDEIdXrLVilMfg7vNz1p/6o5PAJXLiCmAeg1KkrV2d+duFwb2HXoi9rD5WMCsyW1PQw== X-Received: by 2002:a17:90a:86c2:: with SMTP id y2mr4088916pjv.105.1571317122708; Thu, 17 Oct 2019 05:58:42 -0700 (PDT) Received: from localhost.localdomain ([192.47.164.146]) by smtp.gmail.com with ESMTPSA id b4sm2352585pju.16.2019.10.17.05.58.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 17 Oct 2019 05:58:41 -0700 (PDT) From: yasufum.o@gmail.com To: spp@dpdk.org, ferruh.yigit@intel.com, yasufum.o@gmail.com Date: Thu, 17 Oct 2019 21:58:35 +0900 Message-Id: <20191017125836.29365-2-yasufum.o@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191017125836.29365-1-yasufum.o@gmail.com> References: <20191017125836.29365-1-yasufum.o@gmail.com> Subject: [spp] [PATCH 1/2] cli: add compl for new commands in spp_primary 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: , Errors-To: spp-bounces@dpdk.org Sender: "spp" From: Yasufumi Ogawa 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 --- 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