pywebexec 1.4.13__py3-none-any.whl → 1.4.15__py3-none-any.whl

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.
pywebexec/pywebexec.py CHANGED
@@ -13,7 +13,7 @@ import time
13
13
  import shlex
14
14
  from gunicorn.app.base import Application
15
15
  import ipaddress
16
- from socket import gethostname, gethostbyname_ex, gethostbyaddr, inet_aton, inet_ntoa
16
+ from socket import socket, gethostname, gethostbyname_ex, gethostbyaddr, inet_aton, inet_ntoa, AF_INET, SOCK_STREAM
17
17
  import ssl
18
18
  import re
19
19
  import pwd
@@ -223,7 +223,7 @@ def start_gunicorn(daemonized=False, baselog=None):
223
223
  if daemonized:
224
224
  if daemon_d('status', pidfilepath=baselog, silent=True):
225
225
  print(f"Error: pywebexec already running on {args.listen}:{args.port}", file=sys.stderr)
226
- sys.exit(1)
226
+ return 1
227
227
 
228
228
  if sys.stdout.isatty():
229
229
  errorlog = "-"
@@ -244,6 +244,7 @@ def start_gunicorn(daemonized=False, baselog=None):
244
244
  'pidfile': pidfile,
245
245
  }
246
246
  PyWebExec(app, options=options).run()
247
+ return 0
247
248
 
248
249
  def daemon_d(action, pidfilepath, silent=False, hostname=None, args=None):
249
250
  """start/stop daemon"""
@@ -254,10 +255,15 @@ def daemon_d(action, pidfilepath, silent=False, hostname=None, args=None):
254
255
  if pidfile.is_locked():
255
256
  pid = pidfile.read_pid()
256
257
  print(f"Stopping server pid {pid}")
257
- try:
258
- os.kill(pid, signal.SIGINT)
259
- except:
260
- return False
258
+ n = 20
259
+ while n > 0:
260
+ try:
261
+ os.kill(pid, signal.SIGINT)
262
+ time.sleep(0.25)
263
+ n -= 1
264
+ except ProcessLookupError:
265
+ return True
266
+ print("Failed to stop server", file=sys.stderr)
261
267
  return True
262
268
  elif action == "status":
263
269
  status = pidfile.is_locked()
@@ -285,21 +291,42 @@ def daemon_d(action, pidfilepath, silent=False, hostname=None, args=None):
285
291
  except Exception as e:
286
292
  print(e)
287
293
 
288
- def start_term():
294
+ def start_term(command_id):
289
295
  os.environ["PYWEBEXEC"] = " (shared)"
290
296
  os.chdir(CWD)
291
- command_id = str(uuid.uuid4())
292
297
  start_time = datetime.now().isoformat()
293
298
  user = pwd.getpwuid(os.getuid())[0]
299
+ print(f"Starting terminal session for {user} : {command_id}")
294
300
  update_command_status(command_id, 'running', command="term", params=[user,os.ttyname(sys.stdout.fileno())], start_time=start_time, user=user)
295
301
  output_file_path = get_output_file_path(command_id)
296
302
  res = script(output_file_path)
297
303
  end_time = datetime.now().isoformat()
298
304
  update_command_status(command_id, status="success", end_time=end_time, exit_code=res)
305
+ print("Terminal session ended")
299
306
  return res
300
307
 
308
+
309
+ def print_urls(command_id=None):
310
+ protocol = 'https' if args.cert else 'http'
311
+ url_params = ""
312
+ token = os.environ.get("PYWEBEXEC_TOKEN")
313
+ if token:
314
+ url_params = f"?token={token}"
315
+ if command_id:
316
+ print(f"{protocol}://{hostname}:{args.port}/popup/{command_id}{url_params}")
317
+ print(f"{protocol}://{ip}:{args.port}/popup/{command_id}{url_params}")
318
+ else:
319
+ print(f"{protocol}://{hostname}:{args.port}{url_params}")
320
+ print(f"{protocol}://{ip}:{args.port}{url_params}")
321
+
322
+
323
+ def is_port_in_use(address, port):
324
+ with socket(AF_INET, SOCK_STREAM) as s:
325
+ return s.connect_ex((address, port)) == 0
326
+
327
+
301
328
  def parseargs():
302
- global app, args, COMMAND_STATUS_DIR
329
+ global app, args, COMMAND_STATUS_DIR, hostname, ip
303
330
 
304
331
  parser = argparse.ArgumentParser(description='Run the command execution server.')
305
332
  parser.add_argument('-u', '--user', help='Username for basic auth')
@@ -344,15 +371,14 @@ def parseargs():
344
371
  os.mkdir(COMMAND_STATUS_DIR, mode=0o700)
345
372
  if args.action == "term":
346
373
  COMMAND_STATUS_DIR = f"{os.getcwd()}/{COMMAND_STATUS_DIR}"
347
- sys.exit(start_term())
374
+ sys.exit(start_term(str(uuid.uuid4())))
375
+
348
376
  (hostname, ip) = resolve(gethostname()) if args.listen == '0.0.0.0' else resolve(args.listen)
349
- url_params = ""
350
377
 
351
378
  if args.tokenurl:
352
379
  token = os.environ.get("PYWEBEXEC_TOKEN", token_urlsafe())
353
380
  os.environ["PYWEBEXEC_TOKEN"] = token
354
381
  app.config["TOKEN_URL"] = token
355
- url_params = f"?token={token}"
356
382
 
357
383
  if args.gencert:
358
384
  args.cert = args.cert or f"{CONFDIR}/pywebexec.crt"
@@ -375,12 +401,6 @@ def parseargs():
375
401
  app.config['USER'] = None
376
402
  app.config['PASSWORD'] = None
377
403
 
378
- if args.action != 'stop':
379
- print("Starting server:")
380
- protocol = 'https' if args.cert else 'http'
381
- print(f"{protocol}://{hostname}:{args.port}{url_params}")
382
- print(f"{protocol}://{ip}:{args.port}{url_params}")
383
-
384
404
  return args
385
405
 
386
406
  def get_status_file_path(command_id):
@@ -700,18 +720,28 @@ def popup(command_id):
700
720
  def main():
701
721
  global COMMAND_STATUS_DIR
702
722
  basef = f"{CONFDIR}/pywebexec_{args.listen}:{args.port}"
723
+ if args.action == "restart":
724
+ daemon_d('stop', pidfilepath=basef)
725
+ args.action = "start"
726
+ port_used = is_port_in_use(args.listen, args.port)
727
+ if args.action != "stop":
728
+ print("Starting server:")
729
+ print_urls()
730
+ if args.action != "stop" and port_used:
731
+ print(f"Error: port {args.port} already in use", file=sys.stderr)
732
+ return 1
703
733
  if args.action == "shareterm":
704
734
  COMMAND_STATUS_DIR = f"{os.getcwd()}/{COMMAND_STATUS_DIR}"
705
735
  with open(basef + ".log", "ab+") as log:
706
736
  pywebexec = subprocess.Popen([sys.executable] + sys.argv[:-1], stdout=log, stderr=log)
707
- start_term()
737
+ command_id = str(uuid.uuid4())
738
+ print_urls(command_id)
739
+ res = start_term(command_id)
740
+ print("Stopping server")
708
741
  time.sleep(1)
709
742
  pywebexec.terminate()
710
- sys.exit()
743
+ sys.exit(res)
711
744
 
712
- if args.action == "restart":
713
- daemon_d('stop', pidfilepath=basef)
714
- args.action = "start"
715
745
  if args.action == "start":
716
746
  return start_gunicorn(daemonized=True, baselog=basef)
717
747
  if args.action:
@@ -720,5 +750,5 @@ def main():
720
750
 
721
751
 
722
752
  if __name__ == '__main__':
723
- main()
753
+ sys.exit(main())
724
754
  # app.run(host='0.0.0.0', port=5000)
pywebexec/version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.4.13'
16
- __version_tuple__ = version_tuple = (1, 4, 13)
15
+ __version__ = version = '1.4.15'
16
+ __version_tuple__ = version_tuple = (1, 4, 15)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pywebexec
3
- Version: 1.4.13
3
+ Version: 1.4.15
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -1,6 +1,6 @@
1
1
  pywebexec/__init__.py,sha256=4spIsVaF8RJt8S58AG_wWoORRNkws9Iwqprj27C3ljM,99
2
- pywebexec/pywebexec.py,sha256=KNRO31L0ArCxkS9Ph98YKzMumn0j41-ocr9TkQgKMmQ,26977
3
- pywebexec/version.py,sha256=bhORB-auReBqhWH8Z8Dx1LQ8cW3mTgChFk4qt6yE3rs,413
2
+ pywebexec/pywebexec.py,sha256=KDvV9_Gbp016p_3clO_-b59j0fSyk4nbPNJK1ehfKsc,28102
3
+ pywebexec/version.py,sha256=GV6XwJnZtaCHeM6MpSSHX9ZtGIZAtVvtA-5uewZQic0,413
4
4
  pywebexec/static/css/Consolas NF.ttf,sha256=DJEOzF0eqZ-kxu3Gs_VE8X0NJqiobBzmxWDGpdgGRxI,1313900
5
5
  pywebexec/static/css/style.css,sha256=cGJHPFj23SQ_bFpesfUaFA3VFxhXtpRUOL_zzx3x_X8,5726
6
6
  pywebexec/static/css/xterm.css,sha256=gy8_LGA7Q61DUf8ElwFQzHqHMBQnbbEmpgZcbdgeSHI,5383
@@ -23,9 +23,9 @@ pywebexec/static/js/xterm/xterm.js,sha256=Bzka76jZwEhVt_LlS0e0qMw7ryGa1p5qfxFyeo
23
23
  pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  pywebexec/templates/index.html,sha256=DYtT555wSNhnFtzzHhPMWJireynCJNnAuTytpoORQeE,2321
25
25
  pywebexec/templates/popup.html,sha256=T6_tAOUoA58sA1oxB5pb8i42RenoMdCsH8T86Gccb6Q,945
26
- pywebexec-1.4.13.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
27
- pywebexec-1.4.13.dist-info/METADATA,sha256=vbf7BnbahIuCrkt8wGfyAo25vU5PqIGHgaor4L8uV2Y,7801
28
- pywebexec-1.4.13.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
29
- pywebexec-1.4.13.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
30
- pywebexec-1.4.13.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
31
- pywebexec-1.4.13.dist-info/RECORD,,
26
+ pywebexec-1.4.15.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
27
+ pywebexec-1.4.15.dist-info/METADATA,sha256=kak3uf5US-34yqqjx7GsyY_tW1AiUF9yJMDSs5n6TLY,7801
28
+ pywebexec-1.4.15.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
29
+ pywebexec-1.4.15.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
30
+ pywebexec-1.4.15.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
31
+ pywebexec-1.4.15.dist-info/RECORD,,