Skip to content

Commit

Permalink
[consutil] Remove actual baud and refactor lib for future change (#1130)
Browse files Browse the repository at this point in the history
* [update] removed actual baud from consutil show result table
* [refine] ensure only 1 db querying per command
* [refine] refactor code for better reusing in future
* [new] add a new return value ERR_CFG for indicating configuration issue

Signed-off-by: jika@microsoft.com
  • Loading branch information
Blueve committed Sep 25, 2020
1 parent 2f79ac1 commit 49f1634
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 91 deletions.
94 changes: 33 additions & 61 deletions consutil/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

ERR_CMD = 1
ERR_DEV = 2
ERR_CFG = 3

CONSOLE_PORT_TABLE = "CONSOLE_PORT"
LINE_KEY = "LINE"
Expand Down Expand Up @@ -47,48 +48,34 @@ def run_command(cmd):
sys.exit(ERR_CMD)
return output

# returns a sorted list of all devices
def getAllDevices():
# returns a list of all lines
def getAllLines():
config_db = ConfigDBConnector()
config_db.connect()

# Querying CONFIG_DB to get configured console ports
keys = config_db.get_keys(CONSOLE_PORT_TABLE)
devices = []
lines = []
for k in keys:
device = config_db.get_entry(CONSOLE_PORT_TABLE, k)
device[LINE_KEY] = k
devices.append(device)
line = config_db.get_entry(CONSOLE_PORT_TABLE, k)
line[LINE_KEY] = k
lines.append(line)

# Querying device directory to get all available console ports
cmd = "ls " + DEVICE_PREFIX + "*"
output = run_command(cmd)

availableTtys = output.split('\n')
availableTtys = list(filter(lambda dev: re.match(DEVICE_PREFIX + r"\d+", dev) != None, availableTtys))
for tty in availableTtys:
k = tty[len(DEVICE_PREFIX):]
if k not in keys:
device = { LINE_KEY: k }
devices.append(device)

devices.sort(key=lambda dev: int(dev[LINE_KEY]))
return devices

# exits if inputted line number does not correspond to a device
# input: linenum
def checkDevice(linenum):
config_db = ConfigDBConnector()
config_db.connect()

entry = config_db.get_entry(CONSOLE_PORT_TABLE, str(linenum))
if not entry:
click.echo("Line number {} does not exist".format(linenum))
sys.exit(ERR_DEV)
line = { LINE_KEY: k }
lines.append(line)
return lines

# returns a dictionary of busy devices and their info
# returns a dictionary of busy lines and their info
# maps line number to (pid, process start time)
def getBusyDevices():
def getBusyLines():
cmd = 'ps -eo pid,lstart,cmd | grep -E "(mini|pico)com"'
output = run_command(cmd)
processes = output.split('\n')
Expand All @@ -103,48 +90,33 @@ def getBusyDevices():
regexCmd = r"\S*(?:(?:mini)|(?:pico))com .*" + DEVICE_PREFIX + r"(\d+)(?: .*)?"
regexProcess = re.compile(r"^"+regexPid+r" "+regexDate+r" "+regexCmd+r"$")

busyDevices = {}
busyLines = {}
for process in processes:
match = regexProcess.match(process)
if match != None:
pid = match.group(1)
date = match.group(2)
linenum_key = match.group(3)
busyDevices[linenum_key] = (pid, date)
return busyDevices

# returns actual baud rate, configured baud rate,
# and flow control settings of device corresponding to line number
# input: linenum (str), output: (actual baud (str), configured baud (str), flow control (bool))
def getConnectionInfo(linenum):
config_db = ConfigDBConnector()
config_db.connect()
entry = config_db.get_entry(CONSOLE_PORT_TABLE, str(linenum))
busyLines[linenum_key] = (pid, date)
return busyLines

conf_baud = "-" if BAUD_KEY not in entry else entry[BAUD_KEY]
act_baud = DEFAULT_BAUD if conf_baud == "-" else conf_baud
flow_control = False
if FLOW_KEY in entry and entry[FLOW_KEY] == "1":
flow_control = True

return (act_baud, conf_baud, flow_control)

# returns the line number corresponding to target, or exits if line number cannot be found
# returns the target device corresponding to target, or None if line number connot be found
# if deviceBool, interprets target as device name
# otherwise interprets target as line number
# input: target (str), deviceBool (bool), output: linenum (str)
def getLineNumber(target, deviceBool):
if not deviceBool:
return target

config_db = ConfigDBConnector()
config_db.connect()

devices = getAllDevices()
for device in devices:
if DEVICE_KEY in device and device[DEVICE_KEY] == target:
return device[LINE_KEY]

click.echo("Device {} does not exist".format(target))
sys.exit(ERR_DEV)
return ""
# input: target (str), deviceBool (bool), output: device (dict)
def getLine(target, deviceBool=False):
lines = getAllLines()

# figure out the search key
searchKey = LINE_KEY
if deviceBool:
searchKey = DEVICE_KEY

# identify the line number by searching configuration
lineNumber = None
for line in lines:
if searchKey in line and line[searchKey] == target:
lineNumber = line[LINE_KEY]
targetLine = line

return targetLine if lineNumber else None
74 changes: 44 additions & 30 deletions consutil/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,66 +21,80 @@ def consutil():

if os.geteuid() != 0:
click.echo("Root privileges are required for this operation")
sys.exit(1)
sys.exit(ERR_CMD)

# 'show' subcommand
@consutil.command()
def show():
"""Show all /dev/ttyUSB lines and their info"""
devices = getAllDevices()
busyDevices = getBusyDevices()
"""Show all lines and their info"""
lines = getAllLines()
busyLines = getBusyLines()

header = ["Line", "Actual/Configured Baud", "PID", "Start Time", "Device"]
# sort lines for table rendering
lines.sort(key=lambda dev: int(dev[LINE_KEY]))

# set table header style
header = ["Line", "Baud", "PID", "Start Time", "Device"]
body = []
for device in devices:
lineNum = device[LINE_KEY]
for line in lines:
# configured information
lineNum = line[LINE_KEY]
baud = '-' if BAUD_KEY not in line else line[BAUD_KEY]
remoteDevice = '-' if DEVICE_KEY not in line else line[DEVICE_KEY]

# runtime information
busy = " "
pid = ""
date = ""
remoteDevice = '-' if DEVICE_KEY not in device else device[DEVICE_KEY]
if lineNum in busyDevices:
pid, date = busyDevices[lineNum]
if lineNum in busyLines:
pid, date = busyLines[lineNum]
busy = "*"
actBaud, confBaud, _ = getConnectionInfo(lineNum)
# repeated "~" will be replaced by spaces - hacky way to align the "/"s
baud = "{}/{}{}".format(actBaud, confBaud, "~"*(15-len(confBaud)))
body.append([busy+lineNum, baud, pid, date, remoteDevice])

# replace repeated "~" with spaces - hacky way to align the "/"s
click.echo(tabulate(body, header, stralign="right").replace('~', ' '))
click.echo(tabulate(body, header, stralign='right'))

# 'clear' subcommand
@consutil.command()
@click.argument('linenum')
def clear(linenum):
@click.argument('target')
def clear(target):
"""Clear preexisting connection to line"""
checkDevice(linenum)
linenum = str(linenum)
targetLine = getLine(target)
if not targetLine:
click.echo("Target [{}] does not exist".format(linenum))
sys.exit(ERR_DEV)
lineNumber = targetLine[LINE_KEY]

busyDevices = getBusyDevices()
if linenum in busyDevices:
pid, _ = busyDevices[linenum]
busyLines = getBusyLines()
if lineNumber in busyLines:
pid, _ = busyLines[lineNumber]
cmd = "sudo kill -SIGTERM " + pid
click.echo("Sending SIGTERM to process " + pid)
run_command(cmd)
else:
click.echo("No process is connected to line " + linenum)
click.echo("No process is connected to line " + lineNumber)

# 'connect' subcommand
@consutil.command()
@click.argument('target')
@click.option('--devicename', '-d', is_flag=True, help="connect by name - if flag is set, interpret linenum as device name instead")
def connect(target, devicename):
"""Connect to switch via console device - TARGET is line number or device name of switch"""
lineNumber = getLineNumber(target, devicename)
checkDevice(lineNumber)
lineNumber = str(lineNumber)
# identify the target line
targetLine = getLine(target, devicename)
if not targetLine:
click.echo("Cannot connect: target [{}] does not exist".format(target))
sys.exit(ERR_DEV)
lineNumber = targetLine[LINE_KEY]

# build and start picocom command
actBaud, _, flowBool = getConnectionInfo(lineNumber)
if BAUD_KEY in targetLine:
baud = targetLine[BAUD_KEY]
else:
click.echo("Cannot connect: line [{}] has no baud rate".format(lineNumber))
sys.exit(ERR_CFG)
flowBool = True if FLOW_KEY in targetLine and targetLine[FLOW_KEY] == "1" else False
flowCmd = "h" if flowBool else "n"
quietCmd = "-q" if QUIET else ""
cmd = "sudo picocom -b {} -f {} {} {}{}".format(actBaud, flowCmd, quietCmd, DEVICE_PREFIX, lineNumber)
cmd = "sudo picocom -b {} -f {} {} {}{}".format(baud, flowCmd, quietCmd, DEVICE_PREFIX, lineNumber)
proc = pexpect.spawn(cmd)
proc.send("\n")

Expand All @@ -106,4 +120,4 @@ def connect(target, devicename):
click.echo("Cannot connect: unable to open picocom process")

if __name__ == '__main__':
consutil()
consutil()

0 comments on commit 49f1634

Please sign in to comment.