multiSSH3 5.48__tar.gz → 5.51__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.48 → multissh3-5.51}/PKG-INFO +3 -1
- {multissh3-5.48 → multissh3-5.51}/multiSSH3.egg-info/PKG-INFO +3 -1
- {multissh3-5.48 → multissh3-5.51}/multiSSH3.py +46 -17
- {multissh3-5.48 → multissh3-5.51}/setup.py +2 -0
- {multissh3-5.48 → multissh3-5.51}/README.md +0 -0
- {multissh3-5.48 → multissh3-5.51}/multiSSH3.egg-info/SOURCES.txt +0 -0
- {multissh3-5.48 → multissh3-5.51}/multiSSH3.egg-info/dependency_links.txt +0 -0
- {multissh3-5.48 → multissh3-5.51}/multiSSH3.egg-info/entry_points.txt +0 -0
- {multissh3-5.48 → multissh3-5.51}/multiSSH3.egg-info/requires.txt +0 -0
- {multissh3-5.48 → multissh3-5.51}/multiSSH3.egg-info/top_level.txt +0 -0
- {multissh3-5.48 → multissh3-5.51}/setup.cfg +0 -0
- {multissh3-5.48 → multissh3-5.51}/test/test.py +0 -0
- {multissh3-5.48 → multissh3-5.51}/test/testCurses.py +0 -0
- {multissh3-5.48 → multissh3-5.51}/test/testCursesOld.py +0 -0
- {multissh3-5.48 → multissh3-5.51}/test/testPerfCompact.py +0 -0
- {multissh3-5.48 → multissh3-5.51}/test/testPerfExpand.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: multiSSH3
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.51
|
|
4
4
|
Summary: Run commands on multiple hosts via SSH
|
|
5
5
|
Home-page: https://github.com/yufei-pan/multiSSH3
|
|
6
6
|
Author: Yufei Pan
|
|
@@ -9,6 +9,8 @@ License: GPLv3+
|
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
11
11
|
Classifier: Operating System :: POSIX :: Linux
|
|
12
|
+
Classifier: Operating System :: MacOS
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
12
14
|
Requires-Python: >=3.6
|
|
13
15
|
Description-Content-Type: text/markdown
|
|
14
16
|
Requires-Dist: argparse
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: multiSSH3
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.51
|
|
4
4
|
Summary: Run commands on multiple hosts via SSH
|
|
5
5
|
Home-page: https://github.com/yufei-pan/multiSSH3
|
|
6
6
|
Author: Yufei Pan
|
|
@@ -9,6 +9,8 @@ License: GPLv3+
|
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
11
11
|
Classifier: Operating System :: POSIX :: Linux
|
|
12
|
+
Classifier: Operating System :: MacOS
|
|
13
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
12
14
|
Requires-Python: >=3.6
|
|
13
15
|
Description-Content-Type: text/markdown
|
|
14
16
|
Requires-Dist: argparse
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
+
# /// script
|
|
3
|
+
# requires-python = ">=3.6"
|
|
4
|
+
# dependencies = [
|
|
5
|
+
# "argparse",
|
|
6
|
+
# "ipaddress",
|
|
7
|
+
# ]
|
|
8
|
+
# ///
|
|
2
9
|
__curses_available = False
|
|
3
10
|
__resource_lib_available = False
|
|
4
11
|
try:
|
|
@@ -47,8 +54,9 @@ except AttributeError:
|
|
|
47
54
|
# If neither is available, use a dummy decorator
|
|
48
55
|
def cache_decorator(func):
|
|
49
56
|
return func
|
|
50
|
-
version = '5.
|
|
57
|
+
version = '5.51'
|
|
51
58
|
VERSION = version
|
|
59
|
+
__version__ = version
|
|
52
60
|
COMMIT_DATE = '2025-01-30'
|
|
53
61
|
|
|
54
62
|
CONFIG_FILE_CHAIN = ['./multiSSH3.config.json',
|
|
@@ -1358,7 +1366,7 @@ def run_command(host, sem, timeout=60,passwds=None, retry_limit = 5):
|
|
|
1358
1366
|
# Monitor the subprocess and terminate it after the timeout
|
|
1359
1367
|
host.lastUpdateTime = time.time()
|
|
1360
1368
|
timeoutLineAppended = False
|
|
1361
|
-
sleep_interval = 1.0e-
|
|
1369
|
+
sleep_interval = 1.0e-7 # 100 nanoseconds
|
|
1362
1370
|
while proc.poll() is None: # while the process is still running
|
|
1363
1371
|
if timeout > 0:
|
|
1364
1372
|
if time.time() - host.lastUpdateTime > timeout:
|
|
@@ -2175,18 +2183,7 @@ def curses_print(stdscr, hosts, threads, min_char_len = DEFAULT_CURSES_MINIMUM_C
|
|
|
2175
2183
|
#time.sleep(0.25)
|
|
2176
2184
|
|
|
2177
2185
|
# ------------ Generate Output Block ----------------
|
|
2178
|
-
def
|
|
2179
|
-
'''
|
|
2180
|
-
Print / generate the output of the hosts to the terminal
|
|
2181
|
-
|
|
2182
|
-
Args:
|
|
2183
|
-
hosts (list): A list of Host objects
|
|
2184
|
-
usejson (bool, optional): Whether to print the output in JSON format. Defaults to False.
|
|
2185
|
-
quiet (bool, optional): Whether to print the output. Defaults to False.
|
|
2186
|
-
|
|
2187
|
-
Returns:
|
|
2188
|
-
str: The pretty output generated
|
|
2189
|
-
'''
|
|
2186
|
+
def generate_output(hosts, usejson = False, greppable = False):
|
|
2190
2187
|
global __keyPressesIn
|
|
2191
2188
|
global __global_suppress_printout
|
|
2192
2189
|
hosts = [dict(host) for host in hosts]
|
|
@@ -2251,6 +2248,21 @@ def print_output(hosts,usejson = False,quiet = False,greppable = False):
|
|
|
2251
2248
|
__keyPressesIn = [[]]
|
|
2252
2249
|
if __global_suppress_printout and not outputs:
|
|
2253
2250
|
rtnStr += 'Success'
|
|
2251
|
+
return rtnStr
|
|
2252
|
+
|
|
2253
|
+
def print_output(hosts,usejson = False,quiet = False,greppable = False):
|
|
2254
|
+
'''
|
|
2255
|
+
Print / generate the output of the hosts to the terminal
|
|
2256
|
+
|
|
2257
|
+
Args:
|
|
2258
|
+
hosts (list): A list of Host objects
|
|
2259
|
+
usejson (bool, optional): Whether to print the output in JSON format. Defaults to False.
|
|
2260
|
+
quiet (bool, optional): Whether to print the output. Defaults to False.
|
|
2261
|
+
|
|
2262
|
+
Returns:
|
|
2263
|
+
str: The pretty output generated
|
|
2264
|
+
'''
|
|
2265
|
+
rtnStr = generate_output(hosts,usejson,greppable)
|
|
2254
2266
|
if not quiet:
|
|
2255
2267
|
print(rtnStr)
|
|
2256
2268
|
return rtnStr
|
|
@@ -2259,13 +2271,27 @@ def print_output(hosts,usejson = False,quiet = False,greppable = False):
|
|
|
2259
2271
|
def processRunOnHosts(timeout, password, max_connections, hosts, returnUnfinished, nowatch, json, called, greppable,unavailableHosts,willUpdateUnreachableHosts,curses_min_char_len = DEFAULT_CURSES_MINIMUM_CHAR_LEN, curses_min_line_len = DEFAULT_CURSES_MINIMUM_LINE_LEN,single_window = DEFAULT_SINGLE_WINDOW):
|
|
2260
2272
|
global __globalUnavailableHosts
|
|
2261
2273
|
global _no_env
|
|
2274
|
+
sleep_interval = 1.0e-7 # 0.1 microseconds
|
|
2262
2275
|
threads = start_run_on_hosts(hosts, timeout=timeout,password=password,max_connections=max_connections)
|
|
2263
|
-
if __curses_available and not nowatch and threads and not returnUnfinished
|
|
2264
|
-
|
|
2276
|
+
if __curses_available and not nowatch and threads and not returnUnfinished and sys.stdout.isatty() and os.get_terminal_size() and os.get_terminal_size().columns > 10:
|
|
2277
|
+
total_sleeped = 0
|
|
2278
|
+
while any([host.returncode is None for host in hosts]):
|
|
2279
|
+
time.sleep(sleep_interval) # avoid busy-waiting
|
|
2280
|
+
total_sleeped += sleep_interval
|
|
2281
|
+
if sleep_interval < 0.001:
|
|
2282
|
+
sleep_interval *= 2
|
|
2283
|
+
elif sleep_interval < 0.01:
|
|
2284
|
+
sleep_interval *= 1.1
|
|
2285
|
+
if total_sleeped > 0.1:
|
|
2286
|
+
break
|
|
2287
|
+
if any([host.returncode is None for host in hosts]):
|
|
2288
|
+
curses.wrapper(curses_print, hosts, threads, min_char_len = curses_min_char_len, min_line_len = curses_min_line_len, single_window = single_window)
|
|
2265
2289
|
if not returnUnfinished:
|
|
2266
2290
|
# wait until all hosts have a return code
|
|
2267
2291
|
while any([host.returncode is None for host in hosts]):
|
|
2268
|
-
time.sleep(
|
|
2292
|
+
time.sleep(sleep_interval) # avoid busy-waiting
|
|
2293
|
+
if sleep_interval < 0.01:
|
|
2294
|
+
sleep_interval *= 1.1
|
|
2269
2295
|
for thread in threads:
|
|
2270
2296
|
thread.join(timeout=3)
|
|
2271
2297
|
# update the unavailable hosts and global unavailable hosts
|
|
@@ -2448,6 +2474,7 @@ def run_command_on_hosts(hosts = DEFAULT_HOSTS,commands = None,oneonone = DEFAUL
|
|
|
2448
2474
|
global __DEBUG_MODE
|
|
2449
2475
|
global __thread_start_delay
|
|
2450
2476
|
global __max_connections_nofile_limit_supported
|
|
2477
|
+
global __keyPressesIn
|
|
2451
2478
|
_emo = False
|
|
2452
2479
|
_no_env = no_env
|
|
2453
2480
|
if os.path.exists(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS.csv')):
|
|
@@ -2511,6 +2538,8 @@ def run_command_on_hosts(hosts = DEFAULT_HOSTS,commands = None,oneonone = DEFAUL
|
|
|
2511
2538
|
unavailableHosts = __globalUnavailableHosts
|
|
2512
2539
|
else:
|
|
2513
2540
|
unavailableHosts = set()
|
|
2541
|
+
# set global input to empty
|
|
2542
|
+
__keyPressesIn = [[]]
|
|
2514
2543
|
else:
|
|
2515
2544
|
# if run in command line ( or emulating running in command line, we default to skip unreachable hosts within one command call )
|
|
2516
2545
|
if skipUnreachable:
|
|
@@ -28,6 +28,8 @@ setup(
|
|
|
28
28
|
'Programming Language :: Python :: 3',
|
|
29
29
|
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
|
|
30
30
|
'Operating System :: POSIX :: Linux',
|
|
31
|
+
'Operating System :: MacOS',
|
|
32
|
+
'Operating System :: Microsoft :: Windows',
|
|
31
33
|
],
|
|
32
34
|
python_requires='>=3.6',
|
|
33
35
|
license='GPLv3+',
|
|
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
|