Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

modify cli_sample to use control tree method #101

Merged
merged 1 commit into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The Application Developmers Guide is the best document to read first.
- **cp_shell**
- Web interface for running linux shell commands.
- **cli_sample**
- Includes cppxssh module that enables SSH access to local CLI to send commands and return output.
- Includes csterm module that enables access to local CLI to send commands and return output.
- **ipverify_custom_action**
- Create a custom action in a function to be called when an IPverify test status changes.
- **cpu_usage**
Expand Down
41 changes: 10 additions & 31 deletions cli_sample/cli_sample.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,16 @@
# cli - execute CLI command and return output

from csclient import EventingCSClient


def cli(username, password, cmd):
"""
:param username: string
username for SSH login
:param password: string
user password for SSH login
:param cmd: string
CLI command to execute
Example: "sms 2081234567 'hello world' int1"
Example: "arpdump"
:return: string
Text output returned from CLI command
"""
import cppxssh
ssh_tunnel = cppxssh.cppxssh()
ssh_tunnel.login('localhost', username, password, auto_prompt_reset=False)
ssh_tunnel.PROMPT = '\[[0-9A-Za-z_]+@.+\]\$ '
ssh_tunnel.sendline(cmd)
ssh_tunnel.prompt()
output = ssh_tunnel.before.decode()
del ssh_tunnel
try:
# try to remove the command echo
return output.split(cmd + '\r\n')[1]
except IndexError:
# for some reason we failed to remove so return original
return output
import time

from csclient import EventingCSClient
from csterm import CSTerm

cp = EventingCSClient('cli_sample')
ct = CSTerm(cp)
cp.log('Starting...')
cp.log('Output:\n' + cli('admin', '11', 'arpdump'))
while True:
# use ct.exec followed by CLI command to execute
# Example: "sms 2081234567 'hello world' int1"
# Example: "arpdump"
cp.log('Output:\n' + ct.exec('arpdump'))
time.sleep(10)
83 changes: 83 additions & 0 deletions cli_sample/csterm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import random
import time
import re


class CSTerm:
INTERVAL = 0.3 # how often to poll for output, faster can sometimes miss output

def __init__(self, csclient, timeout=10, soft_timeout=5, user=None):
"""
:param csclient: csclient.EventingCSClient
csclient object to use for communication
:param timeout: int
absolute maximum number of seconds to wait for output (default 10)
:param soft_timeout: int
number of seconds to wait for output before sending interrupt (default 5)
"""
self.c = csclient
self.timeout = timeout
self.soft_timeout = soft_timeout
self.s_id = "term-%s" % random.randint(100000000, 999999999)
self.user = user

def exec(self, cmds, clean=True):
"""
:param cmds: list or string
list of commands to execute or single command to execute
:param clean: bool
if True, remove terminal escape sequences from output
:return: string
Text output returned from CLI command
"""
cmds = cmds if isinstance(cmds, list) else [cmds]
cmds = [c + '\n' for c in cmds]
timeout = self.timeout * (1 / self.INTERVAL)
soft_timeout = self.soft_timeout * (1 / self.INTERVAL)

k = iter(cmds)
kp = next(k)
r = ''
while timeout > 0:

self.c.put("/control/csterm/%s" % self.s_id, self._k(kp))
rp = self.c.get("/control/csterm/%s" % self.s_id)

r += rp['k']
# the output generally will end with a prompt and no newline, so we can check for that
# after we've sent all our commands
if kp == "" and not r.endswith('\n'):
break

kp = next(k, None) or ""
timeout-=1
time.sleep(self.INTERVAL)
if timeout < soft_timeout:
self.c.put("/control/csterm/%s" % self.s_id, self._k('\x03'))
rp = self.c.get("/control/csterm/%s" % self.s_id)
r += rp['k']
soft_timeout = 0

# remove the prompt and any terminal escape sequences
if clean:
r = re.sub(r'(?:\x1B[@-Z\\-_]|[\x80-\x9A\x9C-\x9F]|(?:\x1B\[|\x9B)[0-?]*[ -/]*[@-~])','', r)
r = r.split('\n')
prompt = r[-1]
r = [l for l in r if not l.startswith(prompt)]
r = "\n".join(r)

return r

def _k(self, v):
r = {"k": v}
if self.user:
r["u"] = self.user
return r

if __name__ == '__main__':
import sys
from csclient import EventingCSClient

c = EventingCSClient('cli_sample')
ct = CSTerm(c, user="admin")
print(ct.exec(sys.argv[1:]))
1 change: 1 addition & 0 deletions cli_sample/package.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ reboot = true
auto_start = true
version_major = 1
version_minor = 0
version_patch = 1
36 changes: 34 additions & 2 deletions cli_sample/readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cli_sample

Application Version
===================
1.0
1.0.1


NCOS Devices Supported
Expand All @@ -20,7 +20,7 @@ None

Application Purpose
===================
Includes cppxssh module that enables SSH access to local CLI to send commands and return output. Example sends "arpdump".
Includes a csterm.py library that uses csclient control tree access to local CLI to send commands and return output. Example sends "arpdump".

Expected Output
===============
Expand All @@ -32,4 +32,36 @@ Expected Output
ethernet primarylan1 STALE 14:b1:c8:01:59:09 fe80::1cd1:9ffa:135:3ed4
ethernet primarylan1 STALE 14:b1:c8:01:59:09 fe80::18d5:408e:d760:2e39

Notes
====
csterm.py is a useful utility for interacting with the NCOS CLI. The usage is straight forward:
To run a single command:
c = EventingCSClient('cli_sample')
ct = CSTerm(c)
ct.exec("arpdump")

Multiple commands can be run by passing a list of commands:
ct.exec(["clients", "arpdump"])

An instance of CSTerm invokes a single CLI session, similar to SSHing into the device. Besides
sending a list of commands into exec, you can execute exec multiple times to send multiple commands

ct.exec("clients")
ct.exec("wan")
ct.exec("arpdump")

Intuitively, it's then possible to automate a workflow. Here's an example using NCOS ssh client
to SSH into a local machine and run a command:

ct.exec(["ssh user@host", # ssh into host
"yes", # respond 'yes' to accept host key
"password", # respond with password
"cd workflow", # change directory
"ls", # list files
"exit"]) # exit ssh session to return back to NCOS cli

You can adjust some of the timers for CSTerm:
ct = CSTerm(c, timeout=10, soft_timeout=5)
Timeout is the absolute timeout when running a command, soft_timeout is the timeout for sending
a "ctrl+c" to the console to terminate the running command. The default values are
10 and 5 seconds respectively.
Loading