multiSSH3 5.81__tar.gz → 5.83__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of multiSSH3 might be problematic. Click here for more details.
- {multissh3-5.81 → multissh3-5.83}/PKG-INFO +1 -1
- {multissh3-5.81 → multissh3-5.83}/multiSSH3.egg-info/PKG-INFO +1 -1
- {multissh3-5.81 → multissh3-5.83}/multiSSH3.py +60 -62
- {multissh3-5.81 → multissh3-5.83}/README.md +0 -0
- {multissh3-5.81 → multissh3-5.83}/multiSSH3.egg-info/SOURCES.txt +0 -0
- {multissh3-5.81 → multissh3-5.83}/multiSSH3.egg-info/dependency_links.txt +0 -0
- {multissh3-5.81 → multissh3-5.83}/multiSSH3.egg-info/entry_points.txt +0 -0
- {multissh3-5.81 → multissh3-5.83}/multiSSH3.egg-info/requires.txt +0 -0
- {multissh3-5.81 → multissh3-5.83}/multiSSH3.egg-info/top_level.txt +0 -0
- {multissh3-5.81 → multissh3-5.83}/setup.cfg +0 -0
- {multissh3-5.81 → multissh3-5.83}/setup.py +0 -0
- {multissh3-5.81 → multissh3-5.83}/test/test.py +0 -0
- {multissh3-5.81 → multissh3-5.83}/test/testCurses.py +0 -0
- {multissh3-5.81 → multissh3-5.83}/test/testCursesOld.py +0 -0
- {multissh3-5.81 → multissh3-5.83}/test/testPerfCompact.py +0 -0
- {multissh3-5.81 → multissh3-5.83}/test/testPerfExpand.py +0 -0
|
@@ -55,10 +55,10 @@ except AttributeError:
|
|
|
55
55
|
# If neither is available, use a dummy decorator
|
|
56
56
|
def cache_decorator(func):
|
|
57
57
|
return func
|
|
58
|
-
version = '5.
|
|
58
|
+
version = '5.83'
|
|
59
59
|
VERSION = version
|
|
60
60
|
__version__ = version
|
|
61
|
-
COMMIT_DATE = '2025-07-
|
|
61
|
+
COMMIT_DATE = '2025-07-21'
|
|
62
62
|
|
|
63
63
|
CONFIG_FILE_CHAIN = ['./multiSSH3.config.json',
|
|
64
64
|
'~/multiSSH3.config.json',
|
|
@@ -2298,11 +2298,8 @@ def curses_print(stdscr, hosts, threads, min_char_len = DEFAULT_CURSES_MINIMUM_C
|
|
|
2298
2298
|
#time.sleep(0.25)
|
|
2299
2299
|
|
|
2300
2300
|
#%% ------------ Generate Output Block ----------------
|
|
2301
|
-
def generate_output(hosts, usejson = False, greppable = False):
|
|
2302
|
-
|
|
2303
|
-
global __global_suppress_printout
|
|
2304
|
-
global __encoding
|
|
2305
|
-
if __global_suppress_printout:
|
|
2301
|
+
def generate_output(hosts, usejson = False, greppable = False,quiet = False,encoding = _encoding,keyPressesIn = [[]]):
|
|
2302
|
+
if quiet:
|
|
2306
2303
|
# remove hosts with returncode 0
|
|
2307
2304
|
hosts = [dict(host) for host in hosts if host.returncode != 0]
|
|
2308
2305
|
if not hosts:
|
|
@@ -2334,8 +2331,8 @@ def generate_output(hosts, usejson = False, greppable = False):
|
|
|
2334
2331
|
rtnList.append(['','','',''])
|
|
2335
2332
|
rtnStr += pretty_format_table(rtnList)
|
|
2336
2333
|
rtnStr += '*'*80+'\n'
|
|
2337
|
-
if
|
|
2338
|
-
CMDsOut = [''.join(cmd).encode(encoding=
|
|
2334
|
+
if keyPressesIn[-1]:
|
|
2335
|
+
CMDsOut = [''.join(cmd).encode(encoding=encoding,errors='backslashreplace').decode(encoding=encoding,errors='backslashreplace').replace('\\n', '↵') for cmd in keyPressesIn if cmd]
|
|
2339
2336
|
rtnStr += 'User Inputs: '+ '\nUser Inputs: '.join(CMDsOut)
|
|
2340
2337
|
#rtnStr += '\n'
|
|
2341
2338
|
else:
|
|
@@ -2357,23 +2354,21 @@ def generate_output(hosts, usejson = False, greppable = False):
|
|
|
2357
2354
|
for output, hostSet in outputs.items():
|
|
2358
2355
|
compact_hosts = compact_hostnames(hostSet)
|
|
2359
2356
|
rtnStr += '*'*80+'\n'
|
|
2360
|
-
if
|
|
2357
|
+
if quiet:
|
|
2361
2358
|
rtnStr += f'Abnormal returncode produced by {",".join(compact_hosts)}:\n'
|
|
2362
2359
|
rtnStr += output+'\n'
|
|
2363
2360
|
else:
|
|
2364
2361
|
rtnStr += f'These hosts: "{",".join(compact_hosts)}" have a response of:\n'
|
|
2365
2362
|
rtnStr += output+'\n'
|
|
2366
|
-
if not
|
|
2363
|
+
if not quiet or outputs:
|
|
2367
2364
|
rtnStr += '*'*80+'\n'
|
|
2368
|
-
if
|
|
2369
|
-
CMDsOut = [''.join(cmd).encode(encoding=
|
|
2370
|
-
#rtnStr += f"Key presses: {''.join(__keyPressesIn).encode('unicode_escape').decode()}\n"
|
|
2371
|
-
#rtnStr += f"Key presses: {__keyPressesIn}\n"
|
|
2365
|
+
if keyPressesIn[-1]:
|
|
2366
|
+
CMDsOut = [''.join(cmd).encode(encoding=encoding,errors='backslashreplace').decode(encoding=encoding,errors='backslashreplace').replace('\\n', '↵') for cmd in keyPressesIn if cmd]
|
|
2372
2367
|
rtnStr += "User Inputs: \n "
|
|
2373
2368
|
rtnStr += '\n '.join(CMDsOut)
|
|
2374
2369
|
rtnStr += '\n'
|
|
2375
|
-
|
|
2376
|
-
if
|
|
2370
|
+
keyPressesIn[-1].clear()
|
|
2371
|
+
if quiet and not outputs:
|
|
2377
2372
|
rtnStr += 'Success'
|
|
2378
2373
|
return rtnStr
|
|
2379
2374
|
|
|
@@ -2389,7 +2384,10 @@ def print_output(hosts,usejson = False,quiet = False,greppable = False):
|
|
|
2389
2384
|
Returns:
|
|
2390
2385
|
str: The pretty output generated
|
|
2391
2386
|
'''
|
|
2392
|
-
|
|
2387
|
+
global __global_suppress_printout
|
|
2388
|
+
global _encoding
|
|
2389
|
+
global __keyPressesIn
|
|
2390
|
+
rtnStr = generate_output(hosts,usejson,greppable,quiet=__global_suppress_printout,encoding=_encoding,keyPressesIn=__keyPressesIn)
|
|
2393
2391
|
if not quiet:
|
|
2394
2392
|
print(rtnStr)
|
|
2395
2393
|
return rtnStr
|
|
@@ -2424,56 +2422,56 @@ def processRunOnHosts(timeout, password, max_connections, hosts, returnUnfinishe
|
|
|
2424
2422
|
sleep_interval *= 1.1
|
|
2425
2423
|
for thread in threads:
|
|
2426
2424
|
thread.join(timeout=3)
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2425
|
+
# update the unavailable hosts and global unavailable hosts
|
|
2426
|
+
if willUpdateUnreachableHosts:
|
|
2427
|
+
availableHosts = set()
|
|
2428
|
+
for host in hosts:
|
|
2429
|
+
if host.stderr and ('No route to host' in host.stderr[0].strip() or 'Connection timed out' in host.stderr[0].strip() or (host.stderr[-1].strip().startswith('Timeout!') and host.returncode == 124)):
|
|
2430
|
+
unavailableHosts[host.name] = int(time.monotonic())
|
|
2431
|
+
__globalUnavailableHosts[host.name] = int(time.monotonic())
|
|
2432
|
+
else:
|
|
2433
|
+
availableHosts.add(host.name)
|
|
2434
|
+
if host.name in unavailableHosts:
|
|
2435
|
+
del unavailableHosts[host.name]
|
|
2436
|
+
if host.name in __globalUnavailableHosts:
|
|
2437
|
+
del __globalUnavailableHosts[host.name]
|
|
2438
|
+
if __DEBUG_MODE:
|
|
2439
|
+
print(f'Unreachable hosts: {unavailableHosts}')
|
|
2440
|
+
try:
|
|
2441
|
+
# check for the old content, only update if the new content is different
|
|
2442
|
+
if not os.path.exists(os.path.join(tempfile.gettempdir(),f'__{getpass.getuser()}_multiSSH3_UNAVAILABLE_HOSTS.csv')):
|
|
2443
|
+
with open(os.path.join(tempfile.gettempdir(),f'__{getpass.getuser()}_multiSSH3_UNAVAILABLE_HOSTS.csv'),'w') as f:
|
|
2444
|
+
f.writelines(f'{host},{expTime}' for host,expTime in unavailableHosts.items())
|
|
2445
|
+
else:
|
|
2446
|
+
oldDic = {}
|
|
2447
|
+
try:
|
|
2448
|
+
with open(os.path.join(tempfile.gettempdir(),f'__{getpass.getuser()}_multiSSH3_UNAVAILABLE_HOSTS.csv'),'r') as f:
|
|
2449
|
+
for line in f:
|
|
2450
|
+
line = line.strip()
|
|
2451
|
+
if line and ',' in line and len(line.split(',')) >= 2 and line.split(',')[0] and line.split(',')[1].isdigit():
|
|
2452
|
+
hostname = line.split(',')[0]
|
|
2453
|
+
expireTime = int(line.split(',')[1])
|
|
2454
|
+
if expireTime < time.monotonic() and hostname not in availableHosts:
|
|
2455
|
+
oldDic[hostname] = expireTime
|
|
2456
|
+
except:
|
|
2457
|
+
pass
|
|
2458
|
+
# add new entries
|
|
2459
|
+
oldDic.update(unavailableHosts)
|
|
2460
|
+
with open(os.path.join(tempfile.gettempdir(),getpass.getuser()+'__multiSSH3_UNAVAILABLE_HOSTS.csv.new'),'w') as f:
|
|
2461
|
+
for key, value in oldDic.items():
|
|
2462
|
+
f.write(f'{key},{value}\n')
|
|
2463
|
+
os.replace(os.path.join(tempfile.gettempdir(),getpass.getuser()+'__multiSSH3_UNAVAILABLE_HOSTS.csv.new'),os.path.join(tempfile.gettempdir(),f'__{getpass.getuser()}_multiSSH3_UNAVAILABLE_HOSTS.csv'))
|
|
2464
|
+
except Exception as e:
|
|
2465
|
+
eprint(f'Error writing to temporary file: {e!r}')
|
|
2466
|
+
import traceback
|
|
2467
|
+
eprint(traceback.format_exc())
|
|
2470
2468
|
|
|
2471
2469
|
# print the output, if the output of multiple hosts are the same, we aggragate them
|
|
2472
2470
|
if not called:
|
|
2473
2471
|
print_output(hosts,json,greppable=greppable)
|
|
2474
2472
|
|
|
2475
2473
|
#%% ------------ Stringfy Block ----------------
|
|
2476
|
-
|
|
2474
|
+
|
|
2477
2475
|
def formHostStr(host) -> str:
|
|
2478
2476
|
"""
|
|
2479
2477
|
Forms a comma-separated string of hosts.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|