summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorPrasanna Kumar Kalever <prasanna.kalever@redhat.com>2019-04-10 14:09:58 +0530
committerPrasanna Kumar Kalever <prasanna.kalever@redhat.com>2019-06-11 15:17:40 +0530
commit7917ef55f6279fa28519d2160c4ec49453c275ec (patch)
treea7cb45ae99afe8dad93ed204ecc24b7efadbb87c /scripts
parente84b89ed709f4f291fbdd8c42b48e2ca187a57ba (diff)
downloadtargetcli-7917ef55f6279fa28519d2160c4ec49453c275ec.tar.gz
targetclid: add daemonize component for targetcli
Problem: ------- Overall creation time of a block using targetcli is raising linearly as the block count increase. This is because of the recurring issue involving refresh(reload) at multiple objects/places, as the LIO's configfs is deeply nested. Earlier discussion of the problem statement with stats and graphs about delays: http://bit.ly/targetcli-create-delay Solution: -------- Introduce a daemon component for targetcli[d] which will retain state of Configshell object in memory, so that any new requests can directly use it, instead of loading the storageObjects/targetObjects again. Details about "how to use it ?": ------------------------------- $ systemctl start targetclid $ systemctl status targetclid ● targetclid.service - Targetcli daemon Loaded: loaded (/usr/lib/systemd/system/targetclid.service; disabled; vendor preset: disabled) Active: active (running) since Wed 2019-04-10 12:19:51 IST; 2h 17min ago Main PID: 3950 (targetclid) Tasks: 3 (limit: 4915) CGroup: /system.slice/targetclid.service └─3950 /usr/bin/python /usr/bin/targetclid Apr 10 12:19:51 localhost.localdomain systemd[1]: Started Targetcli daemon. $ targetcli help Usage: /usr/bin/targetcli [--version|--help|CMD|--tcp] --version Print version --help Print this information CMD Run targetcli shell command and exit <nothing> Enter configuration shell --tcp CMD Pass targetcli command to targetclid --tcp <nothing> Enter multi-line command mode for targetclid See man page for more information. One line command usage: ---------------------- $ targetcli --tcp CMD Eg: $ targetcli --tcp pwd / Multiple line commands usage: ---------------------------- $ targetcli --tcp CMD1 CMD2 . . CMDN exit Eg: $ targetcli --tcp ^Tab / backstores/ iscsi/ loopback/ vhost/ xen-pvscsi/ cd clearconfig exit get help ls pwd refresh restoreconfig saveconfig set status pwd get global logfile get global auto_save_on_exit / saveconfig exit output follows: / logfile=/var/log/gluster-block/gluster-block-configshell.log auto_save_on_exit=false Configuration saved to /etc/target/saveconfig.json Stats with and without changes: ------------------------------ Running simple 'pwd' command after creating 1000 blocks on a node: Without this change: $ time targetcli pwd / real 0m8.963s user 0m7.775s sys 0m1.103s with daemonize changes: $ time targetcli --tcp "pwd" / real 0m0.126s user 0m0.099s sys 0m0.024s Thanks to Maurizio for hangingout with me for all the discussions involved. Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/targetcli102
1 files changed, 94 insertions, 8 deletions
diff --git a/scripts/targetcli b/scripts/targetcli
index b042ad9..92d3378 100755
--- a/scripts/targetcli
+++ b/scripts/targetcli
@@ -24,10 +24,19 @@ from os import getuid, getenv
from targetcli import UIRoot
from rtslib_fb import RTSLibError
from configshell_fb import ConfigShell, ExecutionError
-import sys
from targetcli import __version__ as targetcli_version
+import sys
+import socket
+import struct
+import readline
+import six
+
err = sys.stderr
+socket_path = '/var/run/targetclid.sock'
+hints = ['/', 'backstores/', 'iscsi/', 'loopback/', 'vhost/', 'xen-pvscsi/',
+ 'cd', 'pwd', 'ls', 'set', 'get', 'help', 'refresh', 'status',
+ 'clearconfig', 'restoreconfig', 'saveconfig', 'exit']
class TargetCLI(ConfigShell):
default_prefs = {'color_path': 'magenta',
@@ -54,11 +63,13 @@ class TargetCLI(ConfigShell):
}
def usage():
- print("Usage: %s [--version|--help|CMD]" % sys.argv[0], file=err)
+ print("Usage: %s [--version|--help|CMD|--tcp]" % sys.argv[0], file=err)
print(" --version\t\tPrint version", file=err)
print(" --help\t\tPrint this information", file=err)
print(" CMD\t\t\tRun targetcli shell command and exit", file=err)
print(" <nothing>\t\tEnter configuration shell", file=err)
+ print(" --tcp CMD\t\tPass targetcli command to targetclid", file=err)
+ print(" --tcp <nothing>\tEnter multi-line command mode for targetclid", file=err)
print("See man page for more information.", file=err)
sys.exit(-1)
@@ -66,6 +77,76 @@ def version():
print("%s version %s" % (sys.argv[0], targetcli_version), file=err)
sys.exit(0)
+def usage_version(cmd):
+ if cmd in ("help", "--help", "-h"):
+ usage()
+
+ if cmd in ("version", "--version", "-v"):
+ version()
+
+def completer(text, state):
+ options = [x for x in hints if x.startswith(text)]
+ try:
+ return options[state]
+ except IndexError:
+ return None
+
+def call_daemon(shell, req):
+ try:
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ except socket.error as err:
+ shell.con.display(shell.con.render_text(err, 'red'))
+ sys.exit(1)
+
+ try:
+ sock.connect(socket_path)
+ except socket.error as err:
+ shell.con.display(shell.con.render_text(err, 'red'))
+ sys.exit(1)
+
+ try:
+ # send request
+ sock.sendall(req)
+ except socket.error as err:
+ shell.con.display(shell.con.render_text(err, 'red'))
+ sys.exit(1)
+
+ var = sock.recv(4) # get length of data
+ sending = struct.unpack('i', var)
+ amount_expected = sending[0]
+ amount_received = 0
+
+ # get the actual data in chunks
+ while amount_received < amount_expected:
+ data = sock.recv(1024)
+ amount_received += len(data)
+ print(data, end ="")
+
+ sock.send(b'-END@OF@DATA-')
+ sock.close()
+ sys.exit(0)
+
+def get_arguments():
+ readline.set_completer(completer)
+ readline.set_completer_delims('')
+
+ if 'libedit' in readline.__doc__:
+ readline.parse_and_bind("bind ^I rl_complete")
+ else:
+ readline.parse_and_bind("tab: complete")
+
+ if len(sys.argv[1:]) > 1:
+ command = " ".join(sys.argv[2:])
+ else:
+ inputs = []
+ while True:
+ command = six.moves.input()
+ if command.lower() == "exit":
+ break
+ inputs.append(command)
+ command = '%'.join(inputs) # delimit multiple commands with '%'
+ return command
+
def main():
'''
Start the targetcli shell.
@@ -77,6 +158,17 @@ def main():
shell = TargetCLI(getenv("TARGETCLI_HOME", '~/.targetcli'))
+ if len(sys.argv) > 1:
+ usage_version(sys.argv[1])
+ if sys.argv[1] in ("tcp", "--tcp", "-t"):
+ if len(sys.argv) > 2:
+ usage_version(sys.argv[2])
+ args = get_arguments()
+ if not args:
+ sys.exit(1)
+ usage_version(args);
+ call_daemon(shell, args)
+
try:
root_node = UIRoot(shell, as_root=is_root)
root_node.refresh()
@@ -87,12 +179,6 @@ def main():
sys.exit(-1)
if len(sys.argv) > 1:
- if sys.argv[1] in ("--help", "-h"):
- usage()
-
- if sys.argv[1] in ("--version", "-v"):
- version()
-
try:
shell.run_cmdline(" ".join(sys.argv[1:]))
except Exception as e: