multiSSH3 4.99__tar.gz → 5.0__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: multiSSH3
3
- Version: 4.99
3
+ Version: 5.0
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: multiSSH3
3
- Version: 4.99
3
+ Version: 5.0
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
@@ -18,6 +18,7 @@ import glob
18
18
  import shutil
19
19
  import getpass
20
20
  import uuid
21
+ import tempfile
21
22
 
22
23
  try:
23
24
  # Check if functiools.cache is available
@@ -30,7 +31,7 @@ except AttributeError:
30
31
  # If neither is available, use a dummy decorator
31
32
  def cache_decorator(func):
32
33
  return func
33
- version = '4.99'
34
+ version = '5.00'
34
35
  VERSION = version
35
36
 
36
37
  CONFIG_FILE = '/etc/multiSSH3.config.json'
@@ -94,7 +95,7 @@ __build_in_default_config = {
94
95
  'DEFAULT_JSON_MODE': False,
95
96
  'DEFAULT_PRINT_SUCCESS_HOSTS': False,
96
97
  'DEFAULT_GREPPABLE_MODE': False,
97
- 'DEFAULT_SKIP_UNREACHABLE': False,
98
+ 'DEFAULT_SKIP_UNREACHABLE': True,
98
99
  'DEFAULT_SKIP_HOSTS': '',
99
100
  'SSH_STRICT_HOST_KEY_CHECKING': False,
100
101
  'ERROR_MESSAGES_TO_IGNORE': [
@@ -179,7 +180,7 @@ __DEBUG_MODE = __configs_from_file.get('__DEBUG_MODE', __build_in_default_config
179
180
 
180
181
 
181
182
 
182
- __global_suppress_printout = True
183
+ __global_suppress_printout = False
183
184
 
184
185
  __mainReturnCode = 0
185
186
  __failedHosts = set()
@@ -1302,9 +1303,10 @@ def print_output(hosts,usejson = False,quiet = False,greppable = False):
1302
1303
  outputs[hostPrintOut] = [host['name']]
1303
1304
  else:
1304
1305
  outputs[hostPrintOut].append(host['name'])
1305
- rtnStr = ''
1306
+ rtnStr = '*'*80+'\n'
1306
1307
  for output, hosts in outputs.items():
1307
1308
  rtnStr += f"{','.join(hosts)}{output}\n"
1309
+ rtnStr += '*'*80+'\n'
1308
1310
  if __keyPressesIn[-1]:
1309
1311
  CMDsOut = [''.join(cmd).encode('unicode_escape').decode().replace('\\n', '↵') for cmd in __keyPressesIn if cmd]
1310
1312
  rtnStr += 'User Inputs: '+ '\nUser Inputs: '.join(CMDsOut)
@@ -1420,9 +1422,25 @@ def processRunOnHosts(timeout, password, max_connections, hosts, returnUnfinishe
1420
1422
  if __DEBUG_MODE:
1421
1423
  print(f'Unreachable hosts: {unavailableHosts}')
1422
1424
  __globalUnavailableHosts.update(unavailableHosts)
1423
- # update the os environment variable if not _no_env
1424
- if not _no_env:
1425
- os.environ['__multiSSH3_UNAVAILABLE_HOSTS'] = ','.join(unavailableHosts)
1425
+
1426
+ # os.environ['__multiSSH3_UNAVAILABLE_HOSTS'] = ','.join(unavailableHosts)
1427
+ # create a temporary file to store the unavailable hosts
1428
+ try:
1429
+ # check for the old content, only update if the new content is different
1430
+ if not os.path.exists(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS')):
1431
+ with open(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS'),'w') as f:
1432
+ f.write(','.join(unavailableHosts))
1433
+ else:
1434
+ try:
1435
+ with open(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS'),'r') as f:
1436
+ oldSet = set(f.read().strip().split(','))
1437
+ except:
1438
+ oldSet = None
1439
+ if not oldSet or set(oldSet) != unavailableHosts:
1440
+ with open(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS'),'w') as f:
1441
+ f.write(','.join(unavailableHosts))
1442
+ except Exception as e:
1443
+ eprint(f'Error writing to temporary file: {e}')
1426
1444
 
1427
1445
  # print the output, if the output of multiple hosts are the same, we aggragate them
1428
1446
  if not called:
@@ -1555,10 +1573,26 @@ def run_command_on_hosts(hosts = DEFAULT_HOSTS,commands = None,oneonone = DEFAUL
1555
1573
  global __DEBUG_MODE
1556
1574
  _emo = False
1557
1575
  _no_env = no_env
1558
- if not no_env and '__multiSSH3_UNAVAILABLE_HOSTS' in os.environ:
1559
- __globalUnavailableHosts = set(os.environ['__multiSSH3_UNAVAILABLE_HOSTS'].split(','))
1576
+ if os.path.exists(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS')):
1577
+ if timeout <= 0:
1578
+ checkTime = DEFAULT_TIMEOUT
1579
+ else:
1580
+ checkTime = timeout
1581
+ if checkTime <= 0:
1582
+ checkTime = 60
1583
+ try:
1584
+ if 0 < time.time() - os.path.getmtime(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS')) < checkTime:
1585
+ if not __global_suppress_printout:
1586
+ eprint(f"Reading unavailable hosts from the file {os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS')}")
1587
+ with open(os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS'),'r') as f:
1588
+ __globalUnavailableHosts.update(f.read().strip().split(','))
1589
+ if __DEBUG_MODE:
1590
+ eprint(f"Unavailable hosts: {__globalUnavailableHosts}")
1591
+ except Exception as e:
1592
+ eprint(f"Warning: Unable to read the unavailable hosts from the file {os.path.join(tempfile.gettempdir(),'__multiSSH3_UNAVAILABLE_HOSTS')}")
1593
+ eprint(str(e))
1560
1594
  elif '__multiSSH3_UNAVAILABLE_HOSTS' in readEnvFromFile():
1561
- __globalUnavailableHosts = set(readEnvFromFile()['__multiSSH3_UNAVAILABLE_HOSTS'].split(','))
1595
+ __globalUnavailableHosts.update(readEnvFromFile()['__multiSSH3_UNAVAILABLE_HOSTS'].split(','))
1562
1596
  if not max_connections:
1563
1597
  max_connections = 4 * os.cpu_count()
1564
1598
  elif max_connections == 0:
@@ -1842,7 +1876,7 @@ def main():
1842
1876
  parser.add_argument("-j","--json", action='store_true', help=F"Output in json format. (default: {DEFAULT_JSON_MODE})", default=DEFAULT_JSON_MODE)
1843
1877
  parser.add_argument("--success_hosts", action='store_true', help=f"Output the hosts that succeeded in summary as wells. (default: {DEFAULT_PRINT_SUCCESS_HOSTS})", default=DEFAULT_PRINT_SUCCESS_HOSTS)
1844
1878
  parser.add_argument("-g","--greppable", action='store_true', help=f"Output in greppable format. (default: {DEFAULT_GREPPABLE_MODE})", default=DEFAULT_GREPPABLE_MODE)
1845
- parser.add_argument("-su","--skip_unreachable", action='store_true', help=f"Skip unreachable hosts while using --repeat. Note: Timedout Hosts are considered unreachable. Note: multiple command sequence will still auto skip unreachable hosts. (default: {DEFAULT_SKIP_UNREACHABLE})", default=DEFAULT_SKIP_UNREACHABLE)
1879
+ parser.add_argument("-su","--skip_unreachable", action='store_true', help=f"Skip unreachable hosts. Note: Timedout Hosts are considered unreachable. Note: multiple command sequence will still auto skip unreachable hosts. (default: {DEFAULT_SKIP_UNREACHABLE})", default=DEFAULT_SKIP_UNREACHABLE)
1846
1880
  parser.add_argument("-sh","--skip_hosts", type=str, help=f"Skip the hosts in the list. (default: {DEFAULT_SKIP_HOSTS if DEFAULT_SKIP_HOSTS else 'None'})", default=DEFAULT_SKIP_HOSTS)
1847
1881
  parser.add_argument('--store_config_file', action='store_true', help=f'Store / generate the default config file from command line argument and current config at {CONFIG_FILE}')
1848
1882
  parser.add_argument('--debug', action='store_true', help='Print debug information')
@@ -1940,15 +1974,16 @@ def main():
1940
1974
 
1941
1975
  __ipmiiInterfaceIPPrefix = args.ipmi_interface_ip_prefix
1942
1976
 
1943
- if not args.greppable and not args.json and not args.no_output:
1944
- __global_suppress_printout = False
1977
+ if args.no_output:
1978
+ __global_suppress_printout = True
1945
1979
 
1946
1980
  if not __global_suppress_printout:
1947
- eprint('> ' + getStrCommand(args.hosts,args.commands,oneonone=args.oneonone,timeout=args.timeout,password=args.password,
1981
+ cmdStr = getStrCommand(args.hosts,args.commands,oneonone=args.oneonone,timeout=args.timeout,password=args.password,
1948
1982
  nowatch=args.nowatch,json=args.json,called=args.no_output,max_connections=args.max_connections,
1949
1983
  files=args.file,file_sync=args.file_sync,ipmi=args.ipmi,interface_ip_prefix=args.interface_ip_prefix,scp=args.scp,gather_mode = args.gather_mode,username=args.username,
1950
1984
  extraargs=args.extraargs,skipUnreachable=args.skip_unreachable,no_env=args.no_env,greppable=args.greppable,skip_hosts = args.skip_hosts,
1951
- curses_min_char_len = args.window_width, curses_min_line_len = args.window_height,single_window=args.single_window,error_only=args.error_only,identity_file=args.key))
1985
+ curses_min_char_len = args.window_width, curses_min_line_len = args.window_height,single_window=args.single_window,error_only=args.error_only,identity_file=args.key)
1986
+ eprint('> ' + cmdStr)
1952
1987
  if args.error_only:
1953
1988
  __global_suppress_printout = True
1954
1989
 
@@ -2,7 +2,7 @@ from setuptools import setup
2
2
 
3
3
  setup(
4
4
  name='multiSSH3',
5
- version='4.99',
5
+ version='5.00',
6
6
  description='Run commands on multiple hosts via SSH',
7
7
  long_description=open('README.md').read(),
8
8
  long_description_content_type='text/markdown',
File without changes
File without changes
File without changes