Skip to content

Commit

Permalink
Merge pull request #167 from pkalever/interactive-mode
Browse files Browse the repository at this point in the history
daemonized-mode: add interactive shell support
  • Loading branch information
maurizio-lombardi authored Apr 9, 2020
2 parents e09fa8c + 534c475 commit 48fb5a3
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 25 deletions.
102 changes: 79 additions & 23 deletions scripts/targetcli
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class TargetCLI(ConfigShell):
'max_backup_files': '10',
'auto_add_default_portal': True,
'auto_use_daemon': False,
'daemon_use_batch_mode': False,
}

def usage():
Expand Down Expand Up @@ -121,7 +122,7 @@ def completer(text, state):
except IndexError:
return None

def call_daemon(shell, req):
def call_daemon(shell, req, interactive):
try:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
except socket.error as err:
Expand All @@ -139,9 +140,23 @@ def call_daemon(shell, req):
"then run '#targetcli --disable-daemon'", 'red'))
sys.exit(1)

# Two cases where we want to get pwd:
# 1. Before starting shell in interactive mode, needed for setting terminal
# 2. And only in Interactive mode, having command 'cd'
get_pwd = False
if interactive:
if not req:
req = "pwd"
get_pwd = True
elif "cd " in req:
req += "%pwd"
get_pwd = True
else:
req = "cd /%" + req # Non-interactive modes always consider start at '/'

try:
# send request
sock.sendall(req)
sock.sendall(req.encode())
except socket.error as err:
shell.con.display(shell.con.render_text(err, 'red'))
sys.exit(1)
Expand All @@ -152,17 +167,31 @@ def call_daemon(shell, req):
amount_received = 0

# get the actual data in chunks
output = ""
path = ""
while amount_received < amount_expected:
data = sock.recv(1024)
data = data.decode()
amount_received += len(data)
print(data, end ="")
output += data

if get_pwd:
output_split = output.splitlines()
lines = len(output_split)
for i in range(0, lines):
if i == lines-1:
path = str(output_split[i])
else:
print(str(output_split[i]), end ="\n")
else:
print(output, end ="")

sock.send(b'-END@OF@DATA-')
sock.close()
sys.exit(0)

def get_arguments(shell):
return path

def switch_to_daemon(shell, interactive):
readline.set_completer(completer)
readline.set_completer_delims('')

Expand All @@ -173,27 +202,50 @@ def get_arguments(shell):

if len(sys.argv) > 1:
command = " ".join(sys.argv[1:])
call_daemon(shell, command, False)
sys.exit(0)

if interactive:
shell.con.display("targetcli shell version %s\n"
"Entering targetcli interactive mode for daemonized approach.\n"
"Type 'exit' to quit.\n"
% targetcli_version)
else:
inputs = []
shell.con.display("targetcli shell version %s\n"
"Entering targetcli batch mode for daemonized approach.\n"
"Enter multiple commands separated by newline and "
"type 'exit' to run them all in one go.\n"
% targetcli_version)
while True:
shell.con.raw_write("/> ")
command = six.moves.input()
if command.lower() == "exit":
break
"Entering targetcli batch mode for daemonized approach.\n"
"Enter multiple commands separated by newline and "
"type 'exit' to run them all in one go.\n"
% targetcli_version)

prompt_path = "/"
if interactive:
prompt_path = call_daemon(shell, None, interactive) # get the initial path

inputs = []
real_exit=False
while True:
command = six.moves.input("%s> " %prompt_path)
if command.lower() == "exit":
real_exit=True
elif not command:
continue
if not interactive:
inputs.append(command)
command = '%'.join(inputs) # delimit multiple commands with '%'

if not command:
sys.exit(1)

usage_version(command);
if real_exit:
command = '%'.join(inputs) # delimit multiple commands with '%'
call_daemon(shell, command, interactive)
break
else:
if real_exit:
break
path = call_daemon(shell, command, interactive)
if path:
if path[0] == "/":
prompt_path = path
else:
print(path) # Error No Path ...

return command
sys.exit(0)

def main():
'''
Expand Down Expand Up @@ -225,8 +277,12 @@ def main():
if sys.argv[1] in ("disable-daemon", "--disable-daemon"):
disable_daemon=True

interactive_mode = True
if shell.prefs['daemon_use_batch_mode']:
interactive_mode = False

if use_daemon and not disable_daemon:
call_daemon(shell, get_arguments(shell).encode())
switch_to_daemon(shell, interactive_mode)
# does not return

try:
Expand Down
3 changes: 3 additions & 0 deletions targetcli/ui_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ def __init__(self, name, parent=None, shell=None):
self.define_config_group_param(
'global', 'auto_use_daemon', 'bool',
'If true, commands will be sent to targetclid.')
self.define_config_group_param(
'global', 'daemon_use_batch_mode', 'bool',
'If true, use batch mode for daemonized approach.')

def assert_root(self):
'''
Expand Down
31 changes: 29 additions & 2 deletions targetclid.8
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,38 @@ $ targetcli set global auto_use_daemon=true
.br
$ targetcli ls
.TP
You can use batch mode for sending multiple commands in one go,
You can use interactive mode,
.br
$ targetcli <hit-enter>
.br
targetcli shell version 2.1.50
targetcli shell version 2.1.51
.br
Entering targetcli interactive mode for daemonized approach.
.br
Type 'exit' to quit.
.br
/> pwd
.br
/
.br
/> cd /iscsi
.br
/> pwd
.br
/iscsi
.br
/> exit
.br
.TP
You can also use batch mode for sending multiple commands in one go,
.br
$ targetcli set global daemon_use_batch_mode=true
.br
Parameter daemon_use_batch_mode is now 'true'.
.br
$ targetcli <hit-enter>
.br
targetcli shell version 2.1.51
.br
Entering targetcli batch mode for daemonized approach.
.br
Expand Down

0 comments on commit 48fb5a3

Please sign in to comment.