From b965f9b75879065a3bc3cefa4ec7c2cb55a15f13 Mon Sep 17 00:00:00 2001 From: Tinashe Date: Fri, 20 Jan 2023 16:41:56 -0500 Subject: [PATCH 1/6] nodeconsole windowed and tiled functionality --- confluent_client/bin/nodeconsole | 102 ++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/confluent_client/bin/nodeconsole b/confluent_client/bin/nodeconsole index 3b5afa51..d2b09d88 100755 --- a/confluent_client/bin/nodeconsole +++ b/confluent_client/bin/nodeconsole @@ -72,13 +72,36 @@ if options.log: logreader.replay_to_console(logname) sys.exit(0) #added functionality for wcons - if options.windowed: + result=subprocess.Popen(['xwininfo', '-root'], stdout=subprocess.PIPE) + rootinfo=result.communicate()[0] + result.wait() + for line in rootinfo.decode('utf-8').split('\n'): + if 'Width' in line: + screenwidth = int(line.split(':')[1]) + if 'Height' in line: + screenheight = int(line.split(':')[1]) + envstring=os.environ.get('NODECONSOLE_WINDOWED_COMMAND') if not envstring: - envlist=["xterm", "-e"] + sizegeometry='75x30' + envlist=['xterm', '-bg', 'black', '-fg', 'white', '-geometry', '{sizegeometry}+0+0'.format(sizegeometry=sizegeometry), '-e'] else: envlist=os.environ.get('NODECONSOLE_WINDOWED_COMMAND').split(' ') + if envlist[0] == 'xterm': + if '-geometry' in envlist: + g_index = envlist.index('-geometry') + elif '-g' in envlist: + g_index = envlist.index('-g') + else: + g_index = 0 + if g_index: + envlist[g_index+1] = envlist[g_index+1] + '+0+0' + + else: + envlist.insert(1, '-geometry') + envlist.insert(2, '75x30+0+0') + g_index = 1 nodes = [] sess = client.Command() for res in sess.read('/noderange/{0}/nodes/'.format(args[0])): @@ -87,9 +110,82 @@ if options.windowed: sys.stderr.write(res.get('error', repr(res)) + '\n') sys.exit(1) nodes.append(node) + if options.tile and not envlist[0] == 'xterm': + sys.stderr.write('[ERROR] UNSUPPORTED OPTIONS. \nWindowed and tiled consoles are only supported when using xterm \n') + sys.exit(1) + firstnode=nodes[0] + nodes.pop(0) + with open(os.devnull, 'wb') as devnull: + xopen=subprocess.Popen(envlist + [confettypath, '-c', '/tmp/controlpath-{0}'.format(firstnode), '-m', '5', 'start', '/nodes/{0}/console/session'.format(firstnode) ] , stdin=devnull) + time.sleep(2) + s=socket.socket(socket.AF_UNIX) + winid='' + try: + s.connect('/tmp/controlpath-{firstnode}'.format(firstnode=firstnode)) + s.recv(64) + s.send(b'GETWINID') + winid=s.recv(64).decode('utf-8') + except: + time.sleep(2) + # try to get id of first panel/xterm window using name + win=subprocess.Popen(['xwininfo', '-tree', '-root'], stdout=subprocess.PIPE) + wintr=win.communicate()[0] + for line in wintr.decode('utf-8').split('\n'): + if 'console: {firstnode}'.format(firstnode=firstnode) in line or 'confetty' in line: + win_obj = [ele for ele in line.split(' ') if ele.strip()] + winid = win_obj[0] + if winid: + firstnode_window=subprocess.Popen(['xwininfo', '-id', '{winid}'.format(winid=winid)], stdout=subprocess.PIPE) + xinfo=firstnode_window.communicate()[0] + xinfl = xinfo.decode('utf-8').split('\n') + for line in xinfl: + if 'Absolute upper-left X:' in line: + side_pad = int(line.split(':')[1]) + elif 'Absolute upper-left Y:' in line: + top_pad = int(line.split(':')[1]) + elif 'Width:' in line: + window_width = int(line.split(':')[1]) + elif 'Height' in line: + window_height = int(line.split(':')[1]) + elif '-geometry' in line: + l = re.split(' |x|\+', line) + l_nosp = [ele for ele in l if ele.strip()] + wmxo = int(l_nosp[1]) + wmyo = int(l_nosp[2]) + sizegeometry = str(wmxo) + 'x' + str(wmyo) + else: + pass + window_width += side_pad*2 + window_height += side_pad+top_pad + screenwidth -= wmxo + screenheight -= wmyo + currx = window_width + curry = 0 + maxcol = int(screenwidth/window_width) for node in sortutil.natural_sort(nodes): + if options.tile and envlist[0] == 'xterm': + corrected_x = currx + corrected_y = curry + xgeometry = '{0}+{1}+{2}'.format(sizegeometry, corrected_x, corrected_y) + currx += window_width + if currx >= screenwidth: + currx=0 + curry += window_height + if curry > screenheight: + curry =top_pad + if not envstring: + envlist=['xterm','-bg', 'black', '-fg', 'white', '-geometry', '{0}'.format(xgeometry), '-e'] + else: + if g_index: + envlist[g_index+1] = xgeometry + elif envlist[0] == 'xterm': + envlist=['xterm','-bg', 'black', '-fg', 'white', '-geometry', '75x30+{0}+{1}'.format(side_pad, top_pad), '-e'] + side_pad+=side_pad + top_pad+=top_pad + else: + pass with open(os.devnull, 'wb') as devnull: - subprocess.Popen(envlist + [confettypath, '-m', '5', 'start', '/nodes/{0}/console/session'.format(node)], stdin=devnull) + xopen=subprocess.Popen(envlist + [confettypath, '-m', '5', 'start', '/nodes/{0}/console/session'.format(node)] , stdin=devnull) sys.exit(0) #end of wcons if options.tile: From 23ea53ab5506928e16c3fbc0638230a1a7f41dbe Mon Sep 17 00:00:00 2001 From: Tinashe Date: Tue, 24 Jan 2023 11:18:21 -0500 Subject: [PATCH 2/6] console geometry 100x31 --- confluent_client/bin/nodeconsole | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/confluent_client/bin/nodeconsole b/confluent_client/bin/nodeconsole index d2b09d88..e317220f 100755 --- a/confluent_client/bin/nodeconsole +++ b/confluent_client/bin/nodeconsole @@ -84,7 +84,7 @@ if options.windowed: envstring=os.environ.get('NODECONSOLE_WINDOWED_COMMAND') if not envstring: - sizegeometry='75x30' + sizegeometry='100x31' envlist=['xterm', '-bg', 'black', '-fg', 'white', '-geometry', '{sizegeometry}+0+0'.format(sizegeometry=sizegeometry), '-e'] else: envlist=os.environ.get('NODECONSOLE_WINDOWED_COMMAND').split(' ') @@ -100,7 +100,7 @@ if options.windowed: else: envlist.insert(1, '-geometry') - envlist.insert(2, '75x30+0+0') + envlist.insert(2, '100x31+0+0') g_index = 1 nodes = [] sess = client.Command() @@ -179,7 +179,7 @@ if options.windowed: if g_index: envlist[g_index+1] = xgeometry elif envlist[0] == 'xterm': - envlist=['xterm','-bg', 'black', '-fg', 'white', '-geometry', '75x30+{0}+{1}'.format(side_pad, top_pad), '-e'] + envlist=['xterm','-bg', 'black', '-fg', 'white', '-geometry', '100x31+{0}+{1}'.format(side_pad, top_pad), '-e'] side_pad+=side_pad top_pad+=top_pad else: From f176a836ae440f2075efa14e38fc80cc90de25ce Mon Sep 17 00:00:00 2001 From: Tinashe Date: Thu, 26 Jan 2023 10:01:02 -0500 Subject: [PATCH 3/6] nodeecentlog: add timeframe option --- confluent_client/bin/nodeeventlog | 38 +++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/confluent_client/bin/nodeeventlog b/confluent_client/bin/nodeeventlog index afe2a2fe..0a0686f6 100755 --- a/confluent_client/bin/nodeeventlog +++ b/confluent_client/bin/nodeeventlog @@ -17,6 +17,7 @@ import codecs from datetime import datetime as dt +from datetime import timedelta import optparse import os import signal @@ -45,7 +46,14 @@ argparser.add_option('-m', '--maxnodes', type='int', argparser.add_option('-l', '--lines', type='int', help='return the last entries ' 'for each node in the eventlog. ' - ) + ) +argparser.add_option('-t', '--timeframe', type='string', + help='return entries within a specified timeframe ' + 'for each node in the eventlog. This will return ' + 'entries from the last hours or days. ' + '1h would be one hour, 4d would be four days. ' + 'format h or d' + ) (options, args) = argparser.parse_args() try: noderange = args[0] @@ -93,13 +101,27 @@ def format_event(evt): msg = '' return ' '.join(retparts) + msg - if deletemode: func = session.delete session.stop_if_noderange_over(noderange, options.maxnodes) else: func = session.read +if options.timeframe: + try: + delta = int(options.timeframe[:-1]) + except ValueError: + argparser.print_help() + sys.exit(1) + if options.timeframe[-1].lower() == 'd': + tdelta = timedelta(days=delta) + elif options.timeframe[-1].lower() == 'h': + tdelta = timedelta(hours=delta) + else: + argparser.print_help() + sys.exit(1) + timeframe = dt.now() - tdelta + event_dict = {} nodes = [] for res in session.read('/noderange/{0}/nodes/'.format(args[0])): @@ -124,7 +146,14 @@ for rsp in func('/noderange/{0}/events/hardware/log'.format(noderange)): event_dict[node].extend(evtdata) else: for evt in evtdata: - print('{0}: {1}'.format(node, format_event(evt))) + if options.timeframe: + # check if line is in timeframe + if 'timestamp' in evt and evt['timestamp'] is not None: + display = dt.strptime(evt['timestamp'], '%Y-%m-%dT%H:%M:%S') + if display > timeframe: + print('{0}: {1}'.format(node, format_event(evt))) + else: + print('{0}: {1}'.format(node, format_event(evt))) if options.lines: for node in nodes: @@ -133,5 +162,6 @@ if options.lines: if len(evtdata_list) > options.lines: evtdata_list = evtdata_list[-abs(options.lines):] for evt in evtdata_list: + if options.timeframe: + pass print('{0}: {1}'.format(node, format_event(evt))) - \ No newline at end of file From 3433635e9b1b5ba8ae94da94623048da0819bd7b Mon Sep 17 00:00:00 2001 From: Tinashe Date: Thu, 26 Jan 2023 10:16:33 -0500 Subject: [PATCH 4/6] nodeeventlog: timeframe option --- confluent_client/bin/nodeeventlog | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/confluent_client/bin/nodeeventlog b/confluent_client/bin/nodeeventlog index 0a0686f6..680ea400 100755 --- a/confluent_client/bin/nodeeventlog +++ b/confluent_client/bin/nodeeventlog @@ -163,5 +163,9 @@ if options.lines: evtdata_list = evtdata_list[-abs(options.lines):] for evt in evtdata_list: if options.timeframe: - pass - print('{0}: {1}'.format(node, format_event(evt))) + if 'timestamp' in evt and evt['timestamp'] is not None: + display = dt.strptime(evt['timestamp'], '%Y-%m-%dT%H:%M:%S') + if display > timeframe: + print('{0}: {1}'.format(node, format_event(evt))) + else: + print('{0}: {1}'.format(node, format_event(evt))) From c9b72225a967568bfb2acf65fe6a3ac6b0432630 Mon Sep 17 00:00:00 2001 From: Tinashe Date: Thu, 26 Jan 2023 10:37:30 -0500 Subject: [PATCH 5/6] nodeeventlog timeframe documentation --- confluent_client/doc/man/nodeeventlog.ronn | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/confluent_client/doc/man/nodeeventlog.ronn b/confluent_client/doc/man/nodeeventlog.ronn index 2e76ecf3..c1d5b1b7 100644 --- a/confluent_client/doc/man/nodeeventlog.ronn +++ b/confluent_client/doc/man/nodeeventlog.ronn @@ -18,6 +18,11 @@ noderange. * `-l LINES`, `--lines=LINES`: return the last entries for each node in the eventlog. + +* `-t TIMEFRAME`, `--timeframe=TIMEFRAME`: + return entries within a specified timeframe for each node's event log. + This will return entries from the last hours or days. 1h would be + entries from with the last one hour. * `-h`, `--help`: From 2cc134adeb8c68a3343203b8a1b225d5f16cea4e Mon Sep 17 00:00:00 2001 From: Tinashe Date: Fri, 27 Jan 2023 09:30:46 -0500 Subject: [PATCH 6/6] nodeconsole: allow for passthrough args --- confluent_client/bin/nodeconsole | 48 +++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/confluent_client/bin/nodeconsole b/confluent_client/bin/nodeconsole index e317220f..f90127fc 100755 --- a/confluent_client/bin/nodeconsole +++ b/confluent_client/bin/nodeconsole @@ -58,7 +58,14 @@ argparser.add_option('-w','--windowed', action='store_true', default=False, '--shell-type login". If the NODECONSOLE_WINDOWED_COMMAND ' 'environment variable isn\'t set, xterm will be used by' 'default.') + (options, args) = argparser.parse_args() + +pass_through_args = [] +if len(args) > 1: + pass_through_args = args[1:] + args = args[:1] + if len(args) != 1: argparser.print_help() sys.exit(1) @@ -71,6 +78,26 @@ if options.log: sys.exit(1) logreader.replay_to_console(logname) sys.exit(0) + + +def handle_geometry(envlist, sizegeometry, side_pad=0, top_pad=0, first=False): + if '-geometry' in envlist: + g_index = envlist.index('-geometry') + elif '-g' in envlist: + g_index = envlist.index('-g') + else: + g_index = 0 + if g_index: + if first: + envlist[g_index+1] = '{0}+{1}+{2}'.format(envlist[g_index+1],side_pad, top_pad) + else: + envlist[g_index+1] = '{0}+{1}+{2}'.format(sizegeometry,side_pad, top_pad) + else: + envlist.insert(1, '-geometry') + envlist.insert(2, '{0}+{1}+{2}'.format(sizegeometry,side_pad, top_pad)) + g_index = 1 + return envlist + #added functionality for wcons if options.windowed: result=subprocess.Popen(['xwininfo', '-root'], stdout=subprocess.PIPE) @@ -85,7 +112,8 @@ if options.windowed: envstring=os.environ.get('NODECONSOLE_WINDOWED_COMMAND') if not envstring: sizegeometry='100x31' - envlist=['xterm', '-bg', 'black', '-fg', 'white', '-geometry', '{sizegeometry}+0+0'.format(sizegeometry=sizegeometry), '-e'] + corrected_x, corrected_y = (13,84) + envlist = handle_geometry(['xterm'] + pass_through_args + ['-e'],sizegeometry, first=True) else: envlist=os.environ.get('NODECONSOLE_WINDOWED_COMMAND').split(' ') if envlist[0] == 'xterm': @@ -101,7 +129,8 @@ if options.windowed: else: envlist.insert(1, '-geometry') envlist.insert(2, '100x31+0+0') - g_index = 1 + g_index = 1 + nodes = [] sess = client.Command() for res in sess.read('/noderange/{0}/nodes/'.format(args[0])): @@ -110,6 +139,7 @@ if options.windowed: sys.stderr.write(res.get('error', repr(res)) + '\n') sys.exit(1) nodes.append(node) + if options.tile and not envlist[0] == 'xterm': sys.stderr.write('[ERROR] UNSUPPORTED OPTIONS. \nWindowed and tiled consoles are only supported when using xterm \n') sys.exit(1) @@ -125,6 +155,7 @@ if options.windowed: s.recv(64) s.send(b'GETWINID') winid=s.recv(64).decode('utf-8') + except: time.sleep(2) # try to get id of first panel/xterm window using name @@ -143,6 +174,7 @@ if options.windowed: side_pad = int(line.split(':')[1]) elif 'Absolute upper-left Y:' in line: top_pad = int(line.split(':')[1]) + elif 'Width:' in line: window_width = int(line.split(':')[1]) elif 'Height' in line: @@ -155,6 +187,7 @@ if options.windowed: sizegeometry = str(wmxo) + 'x' + str(wmyo) else: pass + window_width += side_pad*2 window_height += side_pad+top_pad screenwidth -= wmxo @@ -162,6 +195,7 @@ if options.windowed: currx = window_width curry = 0 maxcol = int(screenwidth/window_width) + for node in sortutil.natural_sort(nodes): if options.tile and envlist[0] == 'xterm': corrected_x = currx @@ -174,14 +208,14 @@ if options.windowed: if curry > screenheight: curry =top_pad if not envstring: - envlist=['xterm','-bg', 'black', '-fg', 'white', '-geometry', '{0}'.format(xgeometry), '-e'] + envlist= handle_geometry(envlist, sizegeometry, corrected_x, corrected_y) else: if g_index: envlist[g_index+1] = xgeometry elif envlist[0] == 'xterm': - envlist=['xterm','-bg', 'black', '-fg', 'white', '-geometry', '100x31+{0}+{1}'.format(side_pad, top_pad), '-e'] - side_pad+=side_pad - top_pad+=top_pad + envlist=handle_geometry(envlist, sizegeometry, side_pad, top_pad) + side_pad+=(side_pad+1) + top_pad+=(top_pad+30) else: pass with open(os.devnull, 'wb') as devnull: @@ -224,4 +258,4 @@ if options.tile: os.execlp('tmux', 'tmux', 'attach', '-t', sessname) else: os.execl(confettypath, confettypath, 'start', - '/nodes/{0}/console/session'.format(args[0])) + '/nodes/{0}/console/session'.format(args[0])) \ No newline at end of file