ssm-cli 1.1.0.dev3__tar.gz → 1.1.0.dev4__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.
Files changed (31) hide show
  1. {ssm_cli-1.1.0.dev3/ssm_cli.egg-info → ssm_cli-1.1.0.dev4}/PKG-INFO +2 -1
  2. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/pyproject.toml +2 -1
  3. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/ssh_proxy/forwarding.py +88 -5
  4. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4/ssm_cli.egg-info}/PKG-INFO +2 -1
  5. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli.egg-info/requires.txt +1 -0
  6. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/LICENCE +0 -0
  7. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/README.md +0 -0
  8. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/setup.cfg +0 -0
  9. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/__init__.py +0 -0
  10. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/__main__.py +0 -0
  11. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/app.py +0 -0
  12. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/aws.py +0 -0
  13. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/cli.py +0 -0
  14. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/click.py +0 -0
  15. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/config.py +0 -0
  16. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/instances.py +0 -0
  17. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/logging.py +0 -0
  18. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/selectors/__init__.py +0 -0
  19. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/selectors/first.py +0 -0
  20. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/selectors/tui.py +0 -0
  21. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/ssh_proxy/__init__.py +0 -0
  22. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/ssh_proxy/channels.py +0 -0
  23. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/ssh_proxy/server.py +0 -0
  24. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/ssh_proxy/shell.py +0 -0
  25. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/ssh_proxy/socket.py +0 -0
  26. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/ui.py +0 -0
  27. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli/xdg.py +0 -0
  28. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli.egg-info/SOURCES.txt +0 -0
  29. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli.egg-info/dependency_links.txt +0 -0
  30. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli.egg-info/entry_points.txt +0 -0
  31. {ssm_cli-1.1.0.dev3 → ssm_cli-1.1.0.dev4}/ssm_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ssm-cli
3
- Version: 1.1.0.dev3
3
+ Version: 1.1.0.dev4
4
4
  Summary: CLI tool to help with SSM functionality, aimed at adminstrators
5
5
  Author-email: Simon Fletcher <simon.fletcher@lexisnexisrisk.com>
6
6
  License: MIT License
@@ -39,6 +39,7 @@ Requires-Dist: rich
39
39
  Requires-Dist: confclasses>=0.3.2
40
40
  Requires-Dist: xdg_base_dirs
41
41
  Requires-Dist: rich-click
42
+ Requires-Dist: psutil
42
43
  Dynamic: license-file
43
44
 
44
45
  # SSM CLI
@@ -22,7 +22,8 @@ dependencies = [
22
22
  "rich",
23
23
  "confclasses>=0.3.2",
24
24
  "xdg_base_dirs",
25
- "rich-click"
25
+ "rich-click",
26
+ "psutil"
26
27
  ]
27
28
  dynamic = ["version"]
28
29
 
@@ -15,6 +15,7 @@ The manager side is the code that runs in a separate process and is responsible
15
15
  """
16
16
 
17
17
  import io
18
+ import os
18
19
  import socket
19
20
  from typing import Dict, Any, List
20
21
  import time
@@ -209,6 +210,7 @@ class PortForwardingManagerProcess(multiprocessing.Process):
209
210
  def __init__(self, pipe: Connection, instance: Instance):
210
211
  self.pipe = pipe
211
212
  self.instance = instance
213
+ self.parent_pid = os.getppid()
212
214
 
213
215
  with io.StringIO() as f:
214
216
  save(CONFIG, f)
@@ -230,12 +232,54 @@ class PortForwardingManagerProcess(multiprocessing.Process):
230
232
  for logger_name, level in CONFIG.log.loggers.items():
231
233
  set_log_level(level, name=logger_name)
232
234
 
235
+
233
236
  logger.info("manager process started")
234
-
237
+
238
+ # get parent process object
239
+ import psutil
240
+ try:
241
+ self.parent = psutil.Process(self.parent_pid)
242
+ except (psutil.NoSuchProcess, psutil.AccessDenied) as e:
243
+ logger.warning(f"Could not get parent process object: {e}")
244
+
245
+ # detaching from parent
246
+ try:
247
+ self.detatch_from_proxy()
248
+ except Exception as e:
249
+ logger.error(f"failed to detatch from proxy: {e}")
250
+
251
+ # cleanup handlers
252
+ import atexit
253
+ self.cleanup_called = False
254
+ atexit.register(self.safe_cleanup)
255
+
235
256
  self.sessions = []
236
257
  self.pipe.send("ready")
237
258
  while True:
238
- try:
259
+ if not self.parent.is_running():
260
+ logger.info("proxy process is no longer running, exiting manager process")
261
+ break
262
+ if not self.process_messages():
263
+ logger.info("proxy pipe closed, exiting manager process")
264
+ break
265
+
266
+ self.safe_cleanup()
267
+
268
+ def safe_cleanup(self):
269
+ """ Used to ensure cleanup only called once """
270
+ if self.cleanup_called:
271
+ return
272
+ self.cleanup_called = True
273
+ self.cleanup()
274
+
275
+ def cleanup(self):
276
+ """ Any cleanup tasks go here """
277
+ logger.info("cleaning up")
278
+ self.close_all_sessions()
279
+
280
+ def process_messages(self):
281
+ try:
282
+ if self.pipe.poll(timeout=1.0):
239
283
  msg, data = self.pipe.recv()
240
284
  logger.debug(f"received {msg} {data} from proxy")
241
285
  reply = None
@@ -249,9 +293,12 @@ class PortForwardingManagerProcess(multiprocessing.Process):
249
293
  if reply is not None:
250
294
  logger.debug(f"sending {reply} to proxy")
251
295
  self.pipe.send(reply)
252
- except EOFError:
253
- break
254
-
296
+
297
+ return True
298
+ except (EOFError, OSError) as e:
299
+ logger.warning(f"pipe to proxy closed: {e}")
300
+ return False
301
+
255
302
  def open_session(self, host: str, remote_port: int):
256
303
  session = None
257
304
  for s in self.sessions:
@@ -274,6 +321,12 @@ class PortForwardingManagerProcess(multiprocessing.Process):
274
321
  if session.session_id == session_id:
275
322
  session.close()
276
323
  self.sessions.remove(session)
324
+ break
325
+
326
+ def close_all_sessions(self):
327
+ for session in self.sessions:
328
+ session.close()
329
+ self.sessions = []
277
330
 
278
331
  def is_open(self, session_id: str) -> bool:
279
332
  for session in self.sessions:
@@ -284,6 +337,36 @@ class PortForwardingManagerProcess(multiprocessing.Process):
284
337
  self.sessions.remove(session)
285
338
  break
286
339
  return False
340
+
341
+ def detatch_from_proxy(self):
342
+ """Detach from the parent process to avoid zombies on unix like systems, this will need refining after more testing"""
343
+ if os.name != 'nt':
344
+ os.setsid()
345
+ else:
346
+ import ctypes
347
+ kernel32 = ctypes.windll.kernel32
348
+
349
+ # Set up independent console control handler
350
+ kernel32.SetConsoleCtrlHandler(None, True)
351
+
352
+ # Set independent process priority
353
+ current_process = kernel32.GetCurrentProcess()
354
+ NORMAL_PRIORITY_CLASS = 0x00000020
355
+ kernel32.SetPriorityClass(current_process, NORMAL_PRIORITY_CLASS)
356
+
357
+ # Detach from console if present
358
+ console_window = kernel32.GetConsoleWindow()
359
+ if console_window:
360
+ kernel32.FreeConsole()
361
+
362
+ # Break out of job object (most important)
363
+ ntdll = ctypes.windll.ntdll
364
+ ntdll.NtSetInformationProcess(
365
+ kernel32.GetCurrentProcess(),
366
+ 0x11,
367
+ ctypes.byref(ctypes.c_ulong(0)),
368
+ ctypes.sizeof(ctypes.c_ulong)
369
+ )
287
370
 
288
371
  def get_free_port(bind_host="127.0.0.1"):
289
372
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ssm-cli
3
- Version: 1.1.0.dev3
3
+ Version: 1.1.0.dev4
4
4
  Summary: CLI tool to help with SSM functionality, aimed at adminstrators
5
5
  Author-email: Simon Fletcher <simon.fletcher@lexisnexisrisk.com>
6
6
  License: MIT License
@@ -39,6 +39,7 @@ Requires-Dist: rich
39
39
  Requires-Dist: confclasses>=0.3.2
40
40
  Requires-Dist: xdg_base_dirs
41
41
  Requires-Dist: rich-click
42
+ Requires-Dist: psutil
42
43
  Dynamic: license-file
43
44
 
44
45
  # SSM CLI
@@ -4,3 +4,4 @@ rich
4
4
  confclasses>=0.3.2
5
5
  xdg_base_dirs
6
6
  rich-click
7
+ psutil
File without changes
File without changes
File without changes
File without changes