* [spp] [PATCH 0/5] update SPP CLI
@ 2018-12-12 2:03 ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 1/5] controller: change sec command to nfv ogawa.yasufumi
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: ogawa.yasufumi @ 2018-12-12 2:03 UTC (permalink / raw)
To: ferruh.yigit, spp, ogawa.yasufumi
From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
Hi,
This series of patches is for three updates for SPP CLI. It also include
other misc upates for refactoring.
1. Change sec command to nfv
As suggested in [1], there are several commands in SPP CLI for managing
secondary processes, `sec`, `vf` and `mirror`, and `sec` should be
changed to `nfv`.
[1] https://mails.dpdk.org/archives/spp/2018-November/000990.html
2. Add checking for add and del commands
To avoid invalid operations for ports, add checking for the operations.
If you add a port which is already registered actually, it might cause
a problem.
3. Update bye command to support spp_vf and spp_mirror
Bye command is available ony for spp_nfv because spp_vf and spp_mirror
does not provide `exit` command for graceful termination. This update is
to add exiting spp_vf and spp_mirror with `bye` command for graceful
shutdown.
Thanks,
Yasufumi
Yasufumi Ogawa (5):
controller: change sec command to nfv
controller: change to exclude used port from del
controller: add checking for add and del cmds
controller: refactor SppNfv class
controller: update SppBye class
src/controller/commands/bye.py | 27 +--
src/controller/commands/nfv.py | 435 +++++++++++++++++++++++++++++++++++++++++
src/controller/commands/sec.py | 202 -------------------
src/controller/shell.py | 153 ++++++++++-----
4 files changed, 551 insertions(+), 266 deletions(-)
create mode 100644 src/controller/commands/nfv.py
delete mode 100644 src/controller/commands/sec.py
--
2.7.4
^ permalink raw reply [flat|nested] 6+ messages in thread
* [spp] [PATCH 1/5] controller: change sec command to nfv
2018-12-12 2:03 [spp] [PATCH 0/5] update SPP CLI ogawa.yasufumi
@ 2018-12-12 2:03 ` ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 2/5] controller: change to exclude used port from del ogawa.yasufumi
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: ogawa.yasufumi @ 2018-12-12 2:03 UTC (permalink / raw)
To: ferruh.yigit, spp, ogawa.yasufumi
From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
This update is to change `sec` command to `nfv` and correct completion
of patch sub command. Completion of `patch` command should not show
ports already used, and should not show dst port after `reset`.
Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
src/controller/commands/bye.py | 8 +-
src/controller/commands/nfv.py | 314 +++++++++++++++++++++++++++++++++++++++++
src/controller/commands/sec.py | 202 --------------------------
src/controller/shell.py | 80 +++++++----
4 files changed, 372 insertions(+), 232 deletions(-)
create mode 100644 src/controller/commands/nfv.py
delete mode 100644 src/controller/commands/sec.py
diff --git a/src/controller/commands/bye.py b/src/controller/commands/bye.py
index 3ffc259..dfbd048 100644
--- a/src/controller/commands/bye.py
+++ b/src/controller/commands/bye.py
@@ -14,10 +14,10 @@ class SppBye(object):
BYE_CMDS = ['sec', 'all']
- def __init__(self, spp_ctl_cli, spp_primary, spp_secondary):
+ def __init__(self, spp_ctl_cli, spp_primary, spp_nfvs):
self.spp_ctl_cli = spp_ctl_cli
self.spp_primary = spp_primary
- self.spp_secondary = spp_secondary
+ self.spp_nfvs = spp_nfvs
def run(self, args, sec_ids):
@@ -44,5 +44,5 @@ class SppBye(object):
def close_all_secondary(self, sec_ids):
"""Terminate all secondary processes."""
- for i in sec_ids:
- self.spp_secondary.run(i, 'exit')
+ for i, nfv in self.spp_nfvs.items():
+ nfv.run(i, 'exit')
diff --git a/src/controller/commands/nfv.py b/src/controller/commands/nfv.py
new file mode 100644
index 0000000..9af4449
--- /dev/null
+++ b/src/controller/commands/nfv.py
@@ -0,0 +1,314 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2018 Nippon Telegraph and Telephone Corporation
+
+from .. import spp_common
+
+
+class SppNfv(object):
+ """Exec spp_nfv command.
+
+ SppNfv lass is intended to be used in Shell class as a delegator for
+ running 'nfv' command.
+
+ 'self.command()' is called from do_nfv() and 'self.complete()' is called
+ from complete_nfv() of both of which is defined in Shell.
+ """
+
+ # All of commands and sub-commands used for validation and completion.
+ NFV_CMDS = ['status', 'exit', 'forward', 'stop', 'add', 'patch', 'del']
+
+ def __init__(self, spp_ctl_cli, sec_id, use_cache=False):
+ self.spp_ctl_cli = spp_ctl_cli
+ self.sec_id = sec_id
+ self.ports = [] # registered ports
+ self.patchs = []
+
+ # Call REST API each time of completion if it is True.
+ self.use_cache = use_cache
+
+ def run(self, cmdline):
+ """Called from do_nfv() 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' % self.sec_id)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 200:
+ self.print_nfv_status(res.json())
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ elif cmd == 'add':
+ if self.use_cache is True:
+ self.ports.append(params[0])
+
+ req_params = {'action': 'add', 'port': params[0]}
+
+ res = self.spp_ctl_cli.put('nfvs/%d/ports' %
+ self.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':
+ if self.use_cache is True:
+ if params[0] in self.ports:
+ self.ports.remove(params[0])
+
+ req_params = {'action': 'del', 'port': params[0]}
+ res = self.spp_ctl_cli.put('nfvs/%d/ports' %
+ self.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' %
+ self.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' % self.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' % self.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':
+ res = self.spp_ctl_cli.delete('nfvs/%d' % self.sec_id)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 204:
+ print('Exit nfv %d' % self.sec_id)
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ else:
+ print('Invalid command "%s".' % cmd)
+
+ def print_nfv_status(self, json_obj):
+ """Parse and print message from SPP secondary.
+
+ Print status received from secondary.
+
+ spp > nfv 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..
+ """
+
+ nfv_attr = json_obj
+ print('- status: %s' % nfv_attr['status'])
+ print('- ports:')
+ for port in nfv_attr['ports']:
+ dst = None
+ for patch in nfv_attr['patches']:
+ if patch['src'] == port:
+ dst = patch['dst']
+
+ if dst is None:
+ print(' - %s' % port)
+ else:
+ print(' - %s -> %s' % (port, dst))
+
+ def get_registered_ports(self):
+ res = self.spp_ctl_cli.get('nfvs/%d' % self.sec_id)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 200:
+ return res.json()['ports']
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ def get_registered_patches(self):
+ res = self.spp_ctl_cli.get('nfvs/%d' % self.sec_id)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 200:
+ return res.json()['patches']
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ def complete(self, sec_ids, text, line, begidx, endidx):
+ """Completion for spp_nfv commands.
+
+ Called from complete_nfv() to complete secondary command.
+ """
+
+ try:
+ completions = []
+ tokens = line.split(';')
+
+ if len(tokens) == 2:
+ sub_tokens = tokens[1].split(' ')
+
+ if len(sub_tokens) == 1:
+ if not (sub_tokens[0] in self.NFV_CMDS):
+ completions = self._compl_first_tokens(sub_tokens[0])
+
+ else:
+ if sub_tokens[0] in ['status', 'exit', 'forward', 'stop']:
+ if len(sub_tokens) < 2:
+ if sub_tokens[0].startswith(sub_tokens[1]):
+ completions = [sub_tokens[0]]
+
+ elif sub_tokens[0] == 'add':
+ completions = self._compl_add(sub_tokens)
+
+ elif sub_tokens[0] == 'del':
+ completions = self._compl_del(sub_tokens)
+
+ elif sub_tokens[0] == 'patch':
+ completions = self._compl_patch(sub_tokens)
+
+ return completions
+
+ except Exception as e:
+ print(e)
+
+ def _compl_first_tokens(self, token):
+ res = []
+ for kw in self.NFV_CMDS:
+ if kw.startswith(token):
+ res.append(kw)
+ return res
+
+ def _compl_add(self, sub_tokens):
+ 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
+
+ def _compl_del(self, sub_tokens):
+ if len(sub_tokens) < 3:
+ res = []
+
+ if self.use_cache is False:
+ self.ports = self.get_registered_ports()
+
+ for kw in self.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)
+
+ for p in res:
+ if p.startswith('phy:'):
+ res.remove(p)
+
+ return res
+
+ def _compl_patch(self, sub_tokens):
+ # Patch command consists of three tokens max, for instance,
+ # `nfv 1; patch phy:0 ring:1`.
+ if len(sub_tokens) < 4:
+ res = []
+
+ if self.use_cache is False:
+ self.ports = self.get_registered_ports()
+ self.patches = self.get_registered_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 res
diff --git a/src/controller/commands/sec.py b/src/controller/commands/sec.py
deleted file mode 100644
index ec1da58..0000000
--- a/src/controller/commands/sec.py
+++ /dev/null
@@ -1,202 +0,0 @@
-# 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':
- res = self.spp_ctl_cli.delete('nfvs/%d' % sec_id)
- if res is not None:
- error_codes = self.spp_ctl_cli.rest_common_error_codes
- if res.status_code == 204:
- print('Exit sec %d' % sec_id)
- elif res.status_code in error_codes:
- pass
- else:
- print('Error: unknown response.')
-
- 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 84d4e2f..eafc5de 100644
--- a/src/controller/shell.py
+++ b/src/controller/shell.py
@@ -6,7 +6,7 @@ from __future__ import absolute_import
import cmd
from .commands import bye
from .commands import pri
-from .commands import sec
+from .commands import nfv
from .commands import topo
from .commands import vf
from .commands import mirror
@@ -42,7 +42,10 @@ 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)
+
+ self.spp_nfvs = {}
+ for sec_id in self.get_sec_ids('nfv'):
+ self.spp_nfvs[sec_id] = nfv.SppNfv(self.spp_ctl_cli, sec_id)
self.spp_vfs = {}
for sec_id in self.get_sec_ids('vf'):
@@ -55,7 +58,7 @@ class Shell(cmd.Cmd, object):
self.spp_topo = topo.SppTopo(self.spp_ctl_cli, {}, self.topo_size)
self.spp_bye = bye.SppBye(self.spp_ctl_cli, self.spp_primary,
- self.spp_secondary)
+ self.spp_nfvs)
def default(self, line):
"""Define defualt behaviour.
@@ -141,7 +144,8 @@ class Shell(cmd.Cmd, object):
cnt = 1
for pt in ['nfv', 'vf', 'mirror']:
for obj in sec_obj[pt]:
- print(' %d: %s:%s' % (cnt, obj['type'], obj['client-id']))
+ print(' %d: %s:%s' %
+ (cnt, obj['type'], obj['client-id']))
cnt += 1
elif res.status_code in self.spp_ctl_cli.rest_common_error_codes:
pass
@@ -264,20 +268,19 @@ class Shell(cmd.Cmd, object):
return self.spp_primary.complete(text, line, begidx, endidx)
- def do_sec(self, cmd):
- """Send a command to secondary process specified with ID.
+ def do_nfv(self, cmd):
+ """Send a command to spp_nfv specified with ID.
- SPP secondary process is specified with secondary ID and takes
- sub commands.
+ Spp_nfv is specified with secondary ID and takes sub commands.
- spp > sec 1; status
- spp > sec 1; add ring:0
- spp > sec 1; patch phy:0 ring:0
+ spp > nfv 1; status
+ spp > nfv 1; add ring:0
+ spp > nfv 1; patch phy:0 ring:0
You can refer all of sub commands by pressing TAB after
- 'sec 1;'.
+ 'nfv 1;'.
- spp > sec 1; # press TAB
+ spp > nfv 1; # press TAB
add del exit forward patch status stop
"""
@@ -287,21 +290,44 @@ class Shell(cmd.Cmd, object):
if len(cmds) < 2:
print("Required an ID and ';' before the command.")
elif str.isdigit(cmds[0]):
- sec_id = int(cmds[0])
- if self.check_sec_cmds(cmds[1]):
- self.spp_secondary.run(sec_id, cmds[1])
- else:
- print("Invalid sec command")
+ self.spp_nfvs[int(cmds[0])].run(cmds[1])
else:
- print(cmds[0])
- print("first %s" % cmds[1])
+ print('Invalid command: %s' % tmparg)
- def complete_sec(self, text, line, begidx, endidx):
- """Completion for secondary process commands"""
+ def complete_nfv(self, text, line, begidx, endidx):
+ """Completion for nfv command"""
line = self.clean_cmd(line)
- return self.spp_secondary.complete(
- self.get_sec_ids('nfv'), text, line, begidx, endidx)
+
+ tokens = line.split(';')
+ if len(tokens) == 1:
+ # Add SppNfv of sec_id if it is not exist
+ sec_ids = self.get_sec_ids('nfv')
+ for idx in sec_ids:
+ if self.spp_nfvs[idx] is None:
+ self.spp_nfvs[idx] = nfv.SppNfv(self.spp_ctl_cli, idx)
+
+ if len(line.split()) == 1:
+ res = [str(i)+';' for i in sec_ids]
+ else:
+ if not (';' in line):
+ res = [str(i)+';'
+ for i in sec_ids
+ if (str(i)+';').startswith(text)]
+ return res
+ elif len(tokens) == 2:
+ first_tokens = tokens[0].split(' ') # 'nfv 1' => ['nfv', '1']
+ if len(first_tokens) == 2:
+ idx = int(first_tokens[1])
+
+ # Add SppVf of sec_id if it is not exist
+ if self.spp_nfvs[idx] is None:
+ self.spp_nfvs[idx] = nfv.SppNfv(self.spp_ctl_cli, idx)
+
+ res = self.spp_nfvs[idx].complete(self.get_sec_ids('nfv'),
+ text, line, begidx, endidx)
+ # logger.info(res)
+ return res
def do_vf(self, cmd):
"""Send a command to spp_vf.
@@ -451,7 +477,8 @@ class Shell(cmd.Cmd, object):
sec_ids = self.get_sec_ids('mirror')
for idx in sec_ids:
if self.spp_mirrors[idx] is None:
- self.spp_mirrors[idx] = mirror.SppMirror(self.spp_ctl_cli, idx)
+ self.spp_mirrors[idx] = mirror.SppMirror(
+ self.spp_ctl_cli, idx)
if len(line.split()) == 1:
res = [str(i)+';' for i in sec_ids]
@@ -469,7 +496,8 @@ class Shell(cmd.Cmd, object):
# Add SppMirror of sec_id if it is not exist
if self.spp_mirrors[idx] is None:
- self.spp_mirrors[idx] = mirror.SppMirror(self.spp_ctl_cli, idx)
+ self.spp_mirrors[idx] = mirror.SppMirror(
+ self.spp_ctl_cli, idx)
return self.spp_mirrors[idx].complete(
self.get_sec_ids('mirror'), text, line, begidx, endidx)
--
2.7.4
^ permalink raw reply [flat|nested] 6+ messages in thread
* [spp] [PATCH 2/5] controller: change to exclude used port from del
2018-12-12 2:03 [spp] [PATCH 0/5] update SPP CLI ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 1/5] controller: change sec command to nfv ogawa.yasufumi
@ 2018-12-12 2:03 ` ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 3/5] controller: add checking for add and del cmds ogawa.yasufumi
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: ogawa.yasufumi @ 2018-12-12 2:03 UTC (permalink / raw)
To: ferruh.yigit, spp, ogawa.yasufumi
From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
In completion of `del`, exclude ports already used.
Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
src/controller/commands/nfv.py | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/src/controller/commands/nfv.py b/src/controller/commands/nfv.py
index 9af4449..7a8d073 100644
--- a/src/controller/commands/nfv.py
+++ b/src/controller/commands/nfv.py
@@ -248,19 +248,33 @@ class SppNfv(object):
return res
def _compl_del(self, sub_tokens):
+ # Del command consists of two tokens max, for instance,
+ # `nfv 1; del ring:1`.
if len(sub_tokens) < 3:
res = []
if self.use_cache is False:
self.ports = self.get_registered_ports()
+ self.patches = self.get_registered_patches()
- for kw in self.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)
+ # Used ports should not be included in the candidate of del.
+ used_ports = []
+ for pt in self.ports:
+ for ppt in self.patches:
+ if ((pt in ppt['src']) or (pt in ppt['dst'])):
+ used_ports.append(pt)
+ used_ports = list(set(used_ports))
+ # Remove ports already used from candidate.
+ for kw in self.ports:
+ if not (kw in used_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)
--
2.7.4
^ permalink raw reply [flat|nested] 6+ messages in thread
* [spp] [PATCH 3/5] controller: add checking for add and del cmds
2018-12-12 2:03 [spp] [PATCH 0/5] update SPP CLI ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 1/5] controller: change sec command to nfv ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 2/5] controller: change to exclude used port from del ogawa.yasufumi
@ 2018-12-12 2:03 ` ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 4/5] controller: refactor SppNfv class ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 5/5] controller: update SppBye class ogawa.yasufumi
4 siblings, 0 replies; 6+ messages in thread
From: ogawa.yasufumi @ 2018-12-12 2:03 UTC (permalink / raw)
To: ferruh.yigit, spp, ogawa.yasufumi
From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
To check invalid port, add checking for `add` and `del` commands.
`add` should not accept if assigned port is already added, and `patch`
should not accept if assigned is patched.
Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
src/controller/commands/nfv.py | 88 +++++++++++++++++++++++++-----------------
1 file changed, 53 insertions(+), 35 deletions(-)
diff --git a/src/controller/commands/nfv.py b/src/controller/commands/nfv.py
index 7a8d073..646cdc0 100644
--- a/src/controller/commands/nfv.py
+++ b/src/controller/commands/nfv.py
@@ -44,38 +44,57 @@ class SppNfv(object):
print('Error: unknown response.')
elif cmd == 'add':
- if self.use_cache is True:
- self.ports.append(params[0])
+ if self.use_cache is False:
+ self.ports = self.get_registered_ports()
- req_params = {'action': 'add', 'port': params[0]}
+ if params[0] in self.ports:
+ print("'%s' is already added." % params[0])
+ else:
+ if self.use_cache is True:
+ self.ports.append(params[0])
- res = self.spp_ctl_cli.put('nfvs/%d/ports' %
- self.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.')
+ req_params = {'action': 'add', 'port': params[0]}
+
+ res = self.spp_ctl_cli.put('nfvs/%d/ports' %
+ self.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':
- if self.use_cache is True:
- if params[0] in self.ports:
- self.ports.remove(params[0])
+ if self.use_cache is False:
+ self.patches = self.get_registered_patches()
- req_params = {'action': 'del', 'port': params[0]}
- res = self.spp_ctl_cli.put('nfvs/%d/ports' %
- self.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.')
+ # Patched ports should not be deleted.
+ patched_ports = []
+ for pport in self.patches:
+ patched_ports.append(pport['src'])
+ patched_ports.append(pport['dst'])
+ patched_ports = list(set(patched_ports))
+
+ if params[0] in patched_ports:
+ print("Cannot delete patched port '%s'." % params[0])
+ else:
+ if self.use_cache is True:
+ if params[0] in self.ports:
+ self.ports.remove(params[0])
+
+ req_params = {'action': 'del', 'port': params[0]}
+ res = self.spp_ctl_cli.put('nfvs/%d/ports' %
+ self.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':
@@ -257,17 +276,16 @@ class SppNfv(object):
self.ports = self.get_registered_ports()
self.patches = self.get_registered_patches()
- # Used ports should not be included in the candidate of del.
- used_ports = []
- for pt in self.ports:
- for ppt in self.patches:
- if ((pt in ppt['src']) or (pt in ppt['dst'])):
- used_ports.append(pt)
- used_ports = list(set(used_ports))
+ # Patched ports should not be included in the candidate of del.
+ patched_ports = []
+ for pport in self.patches:
+ patched_ports.append(pport['src'])
+ patched_ports.append(pport['dst'])
+ patched_ports = list(set(patched_ports))
# Remove ports already used from candidate.
for kw in self.ports:
- if not (kw in used_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])
--
2.7.4
^ permalink raw reply [flat|nested] 6+ messages in thread
* [spp] [PATCH 4/5] controller: refactor SppNfv class
2018-12-12 2:03 [spp] [PATCH 0/5] update SPP CLI ogawa.yasufumi
` (2 preceding siblings ...)
2018-12-12 2:03 ` [spp] [PATCH 3/5] controller: add checking for add and del cmds ogawa.yasufumi
@ 2018-12-12 2:03 ` ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 5/5] controller: update SppBye class ogawa.yasufumi
4 siblings, 0 replies; 6+ messages in thread
From: ogawa.yasufumi @ 2018-12-12 2:03 UTC (permalink / raw)
To: ferruh.yigit, spp, ogawa.yasufumi
From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
* To become maintainance easier, define methods for each of sub command
which starts from `_run`.
* Add `get_ports_and_patches()` for getting both of attributes at once
to reduce the number of requests to spp-ctl.
* Add descriptions for all of methods.
* Revise names of variables and methods.
Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
src/controller/commands/nfv.py | 349 ++++++++++++++++++++++++++---------------
1 file changed, 219 insertions(+), 130 deletions(-)
diff --git a/src/controller/commands/nfv.py b/src/controller/commands/nfv.py
index 646cdc0..e6f95d0 100644
--- a/src/controller/commands/nfv.py
+++ b/src/controller/commands/nfv.py
@@ -10,14 +10,21 @@ class SppNfv(object):
SppNfv lass is intended to be used in Shell class as a delegator for
running 'nfv' command.
- 'self.command()' is called from do_nfv() and 'self.complete()' is called
- from complete_nfv() of both of which is defined in Shell.
+ 'self.command()' is called from do_nfv() and 'self.complete()' is
+ called from complete_nfv() of both of which is defined in Shell.
"""
- # All of commands and sub-commands used for validation and completion.
- NFV_CMDS = ['status', 'exit', 'forward', 'stop', 'add', 'patch', 'del']
+ # All of spp_nfv commands used for validation and completion.
+ NFV_CMDS = ['status', 'exit', 'forward', 'stop', 'add', 'patch',
+ 'del']
def __init__(self, spp_ctl_cli, sec_id, use_cache=False):
+ """Initialize SppNfv.
+
+ Turn use_cache `True` if you do not request to spp-ctl each
+ time.
+ """
+
self.spp_ctl_cli = spp_ctl_cli
self.sec_id = sec_id
self.ports = [] # registered ports
@@ -33,126 +40,22 @@ class SppNfv(object):
params = cmdline.split(' ')[1:]
if cmd == 'status':
- res = self.spp_ctl_cli.get('nfvs/%d' % self.sec_id)
- if res is not None:
- error_codes = self.spp_ctl_cli.rest_common_error_codes
- if res.status_code == 200:
- self.print_nfv_status(res.json())
- elif res.status_code in error_codes:
- pass
- else:
- print('Error: unknown response.')
+ self._run_status()
elif cmd == 'add':
- if self.use_cache is False:
- self.ports = self.get_registered_ports()
-
- if params[0] in self.ports:
- print("'%s' is already added." % params[0])
- else:
- if self.use_cache is True:
- self.ports.append(params[0])
-
- req_params = {'action': 'add', 'port': params[0]}
-
- res = self.spp_ctl_cli.put('nfvs/%d/ports' %
- self.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.')
+ self._run_add(params)
elif cmd == 'del':
- if self.use_cache is False:
- self.patches = self.get_registered_patches()
-
- # Patched ports should not be deleted.
- patched_ports = []
- for pport in self.patches:
- patched_ports.append(pport['src'])
- patched_ports.append(pport['dst'])
- patched_ports = list(set(patched_ports))
-
- if params[0] in patched_ports:
- print("Cannot delete patched port '%s'." % params[0])
- else:
- if self.use_cache is True:
- if params[0] in self.ports:
- self.ports.remove(params[0])
-
- req_params = {'action': 'del', 'port': params[0]}
- res = self.spp_ctl_cli.put('nfvs/%d/ports' %
- self.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.')
+ self._run_del(params)
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' %
- self.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.')
+ self._run_forward_or_stop(cmd)
elif cmd == 'patch':
- if params[0] == 'reset':
- res = self.spp_ctl_cli.delete('nfvs/%d/patches' % self.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' % self.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.')
+ self._run_patch(params)
elif cmd == 'exit':
- res = self.spp_ctl_cli.delete('nfvs/%d' % self.sec_id)
- if res is not None:
- error_codes = self.spp_ctl_cli.rest_common_error_codes
- if res.status_code == 204:
- print('Exit nfv %d' % self.sec_id)
- elif res.status_code in error_codes:
- pass
- else:
- print('Error: unknown response.')
+ self._run_exit()
else:
print('Invalid command "%s".' % cmd)
@@ -167,11 +70,6 @@ class SppNfv(object):
- 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..
"""
nfv_attr = json_obj
@@ -188,7 +86,9 @@ class SppNfv(object):
else:
print(' - %s -> %s' % (port, dst))
- def get_registered_ports(self):
+ def get_ports(self):
+ """Get all of ports as a list."""
+
res = self.spp_ctl_cli.get('nfvs/%d' % self.sec_id)
if res is not None:
error_codes = self.spp_ctl_cli.rest_common_error_codes
@@ -199,7 +99,14 @@ class SppNfv(object):
else:
print('Error: unknown response.')
- def get_registered_patches(self):
+ def get_patches(self):
+ """Get all of patched ports as a list of dicts.
+
+ Returned value is like as
+ [{'src': 'phy:0', 'dst': 'ring:0'},
+ {'src': 'ring:1', 'dst':'vhost:1'}, ...]
+ """
+
res = self.spp_ctl_cli.get('nfvs/%d' % self.sec_id)
if res is not None:
error_codes = self.spp_ctl_cli.rest_common_error_codes
@@ -210,6 +117,41 @@ class SppNfv(object):
else:
print('Error: unknown response.')
+ def get_ports_and_patches(self):
+ """Get all of ports and patchs 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()
+ """
+
+ res = self.spp_ctl_cli.get('nfvs/%d' % self.sec_id)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 200:
+ ports = res.json()['ports']
+ patches = res.json()['patches']
+ return ports, patches
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ 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.
+ You use this method if you simply get patches without `src` and
+ `dst`.
+ """
+
+ patched_ports = []
+ for pport in self.patches:
+ patched_ports.append(pport['src'])
+ patched_ports.append(pport['dst'])
+ return list(set(patched_ports))
+
def complete(self, sec_ids, text, line, begidx, endidx):
"""Completion for spp_nfv commands.
@@ -248,6 +190,8 @@ class SppNfv(object):
print(e)
def _compl_first_tokens(self, token):
+ """Complete spp_nfv command."""
+
res = []
for kw in self.NFV_CMDS:
if kw.startswith(token):
@@ -255,6 +199,8 @@ class SppNfv(object):
return res
def _compl_add(self, sub_tokens):
+ """Complete `add` command."""
+
if len(sub_tokens) < 3:
res = []
@@ -267,21 +213,18 @@ class SppNfv(object):
return res
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 = []
if self.use_cache is False:
- self.ports = self.get_registered_ports()
- self.patches = self.get_registered_patches()
+ self.ports, self.patches = self.get_ports_and_patches()
# Patched ports should not be included in the candidate of del.
- patched_ports = []
- for pport in self.patches:
- patched_ports.append(pport['src'])
- patched_ports.append(pport['dst'])
- patched_ports = list(set(patched_ports))
+ patched_ports = self.get_patched_ports()
# Remove ports already used from candidate.
for kw in self.ports:
@@ -300,14 +243,15 @@ class SppNfv(object):
return res
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 = []
if self.use_cache is False:
- self.ports = self.get_registered_ports()
- self.patches = self.get_registered_patches()
+ self.ports, self.patches = self.get_ports_and_patches()
# Get patched ports of src and dst to be used for completion.
src_ports = []
@@ -344,3 +288,148 @@ class SppNfv(object):
res.append(kw)
return res
+
+ def _run_status(self):
+ """Run `status` command."""
+
+ res = self.spp_ctl_cli.get('nfvs/%d' % self.sec_id)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 200:
+ self.print_nfv_status(res.json())
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ def _run_add(self, params):
+ """Run `add` command."""
+
+ if len(params) == 0:
+ print('Port is required!')
+ elif params[0] in self.ports:
+ print("'%s' is already added." % params[0])
+ else:
+ if self.use_cache is False:
+ self.ports = self.get_ports()
+
+ req_params = {'action': 'add', 'port': params[0]}
+
+ res = self.spp_ctl_cli.put('nfvs/%d/ports' %
+ self.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 self.use_cache is True:
+ if not (params[0] in self.ports):
+ self.ports.append(params[0])
+ print('Add %s.' % params[0])
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ def _run_del(self, params):
+ """Run `del` command."""
+
+ if len(params) == 0:
+ print('Port is required!')
+ elif 'phy:' in params[0]:
+ print("Cannot delete phy port '%s'." % params[0])
+ else:
+ if self.use_cache is False:
+ self.patches = self.get_patches()
+
+ # Patched ports should not be deleted.
+ patched_ports = self.get_patched_ports()
+
+ if params[0] in patched_ports:
+ print("Cannot delete patched port '%s'." % params[0])
+ else:
+ req_params = {'action': 'del', 'port': params[0]}
+ res = self.spp_ctl_cli.put('nfvs/%d/ports' %
+ self.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 self.use_cache is True:
+ if params[0] in self.ports:
+ self.ports.remove(params[0])
+ print('Delete %s.' % params[0])
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
+
+ def _run_forward_or_stop(self, cmd):
+ """Run `forward` or `stop` command.
+
+ Spp-ctl accepts this two commands via single API, so this method
+ runs one of which commands by referring `cmd` param.
+ """
+
+ 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' %
+ self.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.')
+
+ def _run_patch(self, params):
+ """Run `patch` command."""
+
+ if len(params) == 0:
+ print('Params are required!')
+ elif params[0] == 'reset':
+ res = self.spp_ctl_cli.delete('nfvs/%d/patches' % self.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:
+ if len(params) < 2:
+ print('Dst port is required!')
+ else:
+ req_params = {'src': params[0], 'dst': params[1]}
+ res = self.spp_ctl_cli.put(
+ 'nfvs/%d/patches' % self.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.')
+
+ def _run_exit(self):
+ """Run `exit` command."""
+
+ res = self.spp_ctl_cli.delete('nfvs/%d' % self.sec_id)
+ if res is not None:
+ error_codes = self.spp_ctl_cli.rest_common_error_codes
+ if res.status_code == 204:
+ print('Exit nfv %d' % self.sec_id)
+ elif res.status_code in error_codes:
+ pass
+ else:
+ print('Error: unknown response.')
--
2.7.4
^ permalink raw reply [flat|nested] 6+ messages in thread
* [spp] [PATCH 5/5] controller: update SppBye class
2018-12-12 2:03 [spp] [PATCH 0/5] update SPP CLI ogawa.yasufumi
` (3 preceding siblings ...)
2018-12-12 2:03 ` [spp] [PATCH 4/5] controller: refactor SppNfv class ogawa.yasufumi
@ 2018-12-12 2:03 ` ogawa.yasufumi
4 siblings, 0 replies; 6+ messages in thread
From: ogawa.yasufumi @ 2018-12-12 2:03 UTC (permalink / raw)
To: ferruh.yigit, spp, ogawa.yasufumi
From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
This update is to support `bye` command other than spp_nfv. Although
spp_vf and spp_mirror do not support this command currently, SPP CLI
is updadted first. SPP CLI does not send `exit` command to spp_vf and
spp_mirror because it is not supported currently, so still need to be
upadated after implementation of the command.
Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
src/controller/commands/bye.py | 27 ++++++------
src/controller/shell.py | 97 +++++++++++++++++++++++++-----------------
2 files changed, 74 insertions(+), 50 deletions(-)
diff --git a/src/controller/commands/bye.py b/src/controller/commands/bye.py
index dfbd048..af77b08 100644
--- a/src/controller/commands/bye.py
+++ b/src/controller/commands/bye.py
@@ -3,7 +3,7 @@
class SppBye(object):
- """Exec SPP bye command.
+ """Run SPP bye command.
SppBye class is intended to be used in Shell class as a delegator
for running 'bye' command.
@@ -14,21 +14,21 @@ class SppBye(object):
BYE_CMDS = ['sec', 'all']
- def __init__(self, spp_ctl_cli, spp_primary, spp_nfvs):
- self.spp_ctl_cli = spp_ctl_cli
- self.spp_primary = spp_primary
- self.spp_nfvs = spp_nfvs
+ def __init__(self):
+ pass
- def run(self, args, sec_ids):
+ def run(self, args, spp_primary, spp_secondaries):
cmds = args.split(' ')
if cmds[0] == 'sec':
- self.close_all_secondary(sec_ids)
+ print('Closing secondary ...')
+ self.close_all_secondary(spp_secondaries)
+
elif cmds[0] == 'all':
print('Closing secondary ...')
- self.close_all_secondary(sec_ids)
+ self.close_all_secondary(spp_secondaries)
print('Closing primary ...')
- self.spp_primary.do_exit()
+ spp_primary.do_exit()
def complete(self, text, line, begidx, endidx):
@@ -41,8 +41,11 @@ class SppBye(object):
]
return completions
- def close_all_secondary(self, sec_ids):
+ def close_all_secondary(self, spp_secondaries):
"""Terminate all secondary processes."""
- for i, nfv in self.spp_nfvs.items():
- nfv.run(i, 'exit')
+ for sec_type, spp_procs in spp_secondaries.items():
+ # TODO(yasufum) Remove if they support exit command.
+ if not (sec_type in ['vf', 'mirror']):
+ for sec in spp_procs.values():
+ sec.run('exit')
diff --git a/src/controller/shell.py b/src/controller/shell.py
index eafc5de..615b9a1 100644
--- a/src/controller/shell.py
+++ b/src/controller/shell.py
@@ -38,28 +38,39 @@ class Shell(cmd.Cmd, object):
else:
readline.write_history_file(hist_file)
- def __init__(self, spp_ctl_cli):
+ def __init__(self, spp_ctl_cli, use_cache=False):
cmd.Cmd.__init__(self)
self.spp_ctl_cli = spp_ctl_cli
- self.spp_primary = pri.SppPrimary(self.spp_ctl_cli)
+ self.use_cache = use_cache
+ self.init_spp_procs()
+ self.spp_topo = topo.SppTopo(self.spp_ctl_cli, {}, self.topo_size)
+
+ def init_spp_procs(self):
+ """Initialize delegators of SPP processes.
+
+ Delegators accept a command and sent it to SPP proesses. This method
+ is also called from `precmd()` method to update it to the latest
+ status.
+ """
- self.spp_nfvs = {}
+ self.primary = pri.SppPrimary(self.spp_ctl_cli)
+
+ self.secondaries = {}
+ self.secondaries['nfv'] = {}
for sec_id in self.get_sec_ids('nfv'):
- self.spp_nfvs[sec_id] = nfv.SppNfv(self.spp_ctl_cli, sec_id)
+ self.secondaries['nfv'][sec_id] = nfv.SppNfv(
+ self.spp_ctl_cli, sec_id)
- self.spp_vfs = {}
+ self.secondaries['vf'] = {}
for sec_id in self.get_sec_ids('vf'):
- self.spp_vfs[sec_id] = vf.SppVf(self.spp_ctl_cli, sec_id)
+ self.secondaries['vf'][sec_id] = vf.SppVf(
+ self.spp_ctl_cli, sec_id)
- self.spp_mirrors = {}
+ self.secondaries['mirror'] = {}
for sec_id in self.get_sec_ids('mirror'):
- self.spp_mirrors[sec_id] = mirror.SppMirror(
+ self.secondaries['mirror'][sec_id] = mirror.SppMirror(
self.spp_ctl_cli, sec_id)
- self.spp_topo = topo.SppTopo(self.spp_ctl_cli, {}, self.topo_size)
- self.spp_bye = bye.SppBye(self.spp_ctl_cli, self.spp_primary,
- self.spp_nfvs)
-
def default(self, line):
"""Define defualt behaviour.
@@ -222,6 +233,9 @@ class Shell(cmd.Cmd, object):
It is called for checking a contents of command line.
"""
+ if self.use_cache is False:
+ self.init_spp_procs()
+
if self.recorded_file:
if not (
('playback' in line) or
@@ -261,12 +275,12 @@ class Shell(cmd.Cmd, object):
if logger is not None:
logger.info("Receive pri command: '%s'" % command)
- self.spp_primary.run(command)
+ self.primary.run(command)
def complete_pri(self, text, line, begidx, endidx):
"""Completion for primary process commands."""
- return self.spp_primary.complete(text, line, begidx, endidx)
+ return self.primary.complete(text, line, begidx, endidx)
def do_nfv(self, cmd):
"""Send a command to spp_nfv specified with ID.
@@ -290,7 +304,7 @@ class Shell(cmd.Cmd, object):
if len(cmds) < 2:
print("Required an ID and ';' before the command.")
elif str.isdigit(cmds[0]):
- self.spp_nfvs[int(cmds[0])].run(cmds[1])
+ self.secondaries['nfv'][int(cmds[0])].run(cmds[1])
else:
print('Invalid command: %s' % tmparg)
@@ -304,8 +318,9 @@ class Shell(cmd.Cmd, object):
# Add SppNfv of sec_id if it is not exist
sec_ids = self.get_sec_ids('nfv')
for idx in sec_ids:
- if self.spp_nfvs[idx] is None:
- self.spp_nfvs[idx] = nfv.SppNfv(self.spp_ctl_cli, idx)
+ if self.secondaries['nfv'][idx] is None:
+ self.secondaries['nfv'][idx] = nfv.SppNfv(
+ self.spp_ctl_cli, idx)
if len(line.split()) == 1:
res = [str(i)+';' for i in sec_ids]
@@ -321,11 +336,13 @@ class Shell(cmd.Cmd, object):
idx = int(first_tokens[1])
# Add SppVf of sec_id if it is not exist
- if self.spp_nfvs[idx] is None:
- self.spp_nfvs[idx] = nfv.SppNfv(self.spp_ctl_cli, idx)
+ if self.secondaries['nfv'][idx] is None:
+ self.secondaries['nfv'][idx] = nfv.SppNfv(
+ self.spp_ctl_cli, idx)
+
+ res = self.secondaries['nfv'][idx].complete(
+ self.get_sec_ids('nfv'), text, line, begidx, endidx)
- res = self.spp_nfvs[idx].complete(self.get_sec_ids('nfv'),
- text, line, begidx, endidx)
# logger.info(res)
return res
@@ -386,7 +403,7 @@ class Shell(cmd.Cmd, object):
if len(cmds) < 2:
print("Required an ID and ';' before the command.")
elif str.isdigit(cmds[0]):
- self.spp_vfs[int(cmds[0])].run(cmds[1])
+ self.secondaries['vf'][int(cmds[0])].run(cmds[1])
else:
print('Invalid command: %s' % tmparg)
@@ -400,8 +417,9 @@ class Shell(cmd.Cmd, object):
# Add SppVf of sec_id if it is not exist
sec_ids = self.get_sec_ids('vf')
for idx in sec_ids:
- if self.spp_vfs[idx] is None:
- self.spp_vfs[idx] = vf.SppVf(self.spp_ctl_cli, idx)
+ if self.secondaries['vf'][idx] is None:
+ self.secondaries['vf'][idx] = vf.SppVf(
+ self.spp_ctl_cli, idx)
if len(line.split()) == 1:
res = [str(i)+';' for i in sec_ids]
@@ -417,11 +435,12 @@ class Shell(cmd.Cmd, object):
idx = int(first_tokens[1])
# Add SppVf of sec_id if it is not exist
- if self.spp_vfs[idx] is None:
- self.spp_vfs[idx] = vf.SppVf(self.spp_ctl_cli, idx)
+ if self.secondaries['vf'][idx] is None:
+ self.secondaries['vf'][idx] = vf.SppVf(
+ self.spp_ctl_cli, idx)
- return self.spp_vfs[idx].complete(self.get_sec_ids('vf'),
- text, line, begidx, endidx)
+ return self.secondaries['vf'][idx].complete(
+ self.get_sec_ids('vf'), text, line, begidx, endidx)
def do_mirror(self, cmd):
"""Send a command to spp_mirror.
@@ -462,7 +481,7 @@ class Shell(cmd.Cmd, object):
if len(cmds) < 2:
print("Required an ID and ';' before the command.")
elif str.isdigit(cmds[0]):
- self.spp_mirrors[int(cmds[0])].run(cmds[1])
+ self.secondaries['mirror'][int(cmds[0])].run(cmds[1])
else:
print('Invalid command: %s' % tmparg)
@@ -476,8 +495,8 @@ class Shell(cmd.Cmd, object):
# Add SppMirror of sec_id if it is not exist
sec_ids = self.get_sec_ids('mirror')
for idx in sec_ids:
- if self.spp_mirrors[idx] is None:
- self.spp_mirrors[idx] = mirror.SppMirror(
+ if self.secondaries['mirror'][idx] is None:
+ self.secondaries['mirror'][idx] = mirror.SppMirror(
self.spp_ctl_cli, idx)
if len(line.split()) == 1:
@@ -495,11 +514,11 @@ class Shell(cmd.Cmd, object):
idx = int(first_tokens[1])
# Add SppMirror of sec_id if it is not exist
- if self.spp_mirrors[idx] is None:
- self.spp_mirrors[idx] = mirror.SppMirror(
+ if self.secondaries['mirror'][idx] is None:
+ self.secondaries['mirror'][idx] = mirror.SppMirror(
self.spp_ctl_cli, idx)
- return self.spp_mirrors[idx].complete(
+ return self.secondaries['mirror'][idx].complete(
self.get_sec_ids('mirror'), text, line, begidx, endidx)
def do_record(self, fname):
@@ -622,16 +641,18 @@ class Shell(cmd.Cmd, object):
"""
cmds = args.split(' ')
- if cmds[0] == '':
+ if cmds[0] == '': # terminate SPP CLI itself
self.do_exit('')
return True
- else: # 'all' or 'sec'
- self.spp_bye.run(args, self.get_sec_ids('nfv'))
+ else: # terminate other SPP processes
+ spp_bye = bye.SppBye()
+ spp_bye.run(args, self.primary, self.secondaries)
def complete_bye(self, text, line, begidx, endidx):
"""Completion for bye commands"""
- return self.spp_bye.complete(text, line, begidx, endidx)
+ spp_bye = bye.SppBye()
+ return spp_bye.complete(text, line, begidx, endidx)
def do_cat(self, arg):
"""View contents of a file.
--
2.7.4
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2018-12-12 2:05 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-12 2:03 [spp] [PATCH 0/5] update SPP CLI ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 1/5] controller: change sec command to nfv ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 2/5] controller: change to exclude used port from del ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 3/5] controller: add checking for add and del cmds ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 4/5] controller: refactor SppNfv class ogawa.yasufumi
2018-12-12 2:03 ` [spp] [PATCH 5/5] controller: update SppBye class ogawa.yasufumi
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).