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

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