pmanager.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #!/usr/bin/env python3
  2. import json
  3. import os
  4. import signal
  5. import socket
  6. import subprocess
  7. import sys
  8. import time
  9. import websocket
  10. DEBUG = True
  11. DEBUG = False
  12. def log(s):
  13. if not DEBUG:
  14. return
  15. print(s)
  16. def sendmsg(msg):
  17. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  18. ret = None
  19. try:
  20. s.connect(('localhost', 9999))
  21. tosend = msg + "\r\n"
  22. encoded_msg = tosend.encode("ascii")
  23. s.sendall(encoded_msg)
  24. ret = s.recv(4096)
  25. s.close()
  26. except Exception as e:
  27. log(e)
  28. return None
  29. log("[nc output] %s " % ret)
  30. return ret
  31. class PManager:
  32. ws = websocket.WebSocket()
  33. ip = "ws://192.168.1.208:9001"
  34. p_list = {}
  35. ptable = {}
  36. log_list = {}
  37. name = ""
  38. def __init__(self, name, ptable):
  39. self.ptable = ptable
  40. self.conn(self.ip)
  41. self.name = name
  42. signal.signal(signal.SIGINT, self.sighandler)
  43. signal.signal(signal.SIGCHLD, signal.SIG_IGN) #To kill zombies
  44. while True:
  45. try:
  46. data = self.ws.recv()
  47. except Exception as e:
  48. log(e)
  49. self.conn(self.ip)
  50. continue
  51. try:
  52. j = json.loads(data)
  53. except Exception as e:
  54. log(e)
  55. log("Invalid json?")
  56. continue
  57. if ("type" not in j or "command" not in j or
  58. "key" not in j or j["type"] != "snowmix"):
  59. log("Dropping: %s" % j)
  60. continue
  61. #log(j)
  62. if j["command"] == "oneshot":
  63. self.oneshot(j["key"])
  64. if j["command"] == "launch":
  65. opts = None
  66. if "options" in j:
  67. opts = j["options"]
  68. self.launch(j["key"],opts)
  69. if j["command"] == "kill":
  70. self.stop(j["key"])
  71. if j["command"] == "netcat":
  72. sendmsg(j["key"])
  73. if j["command"] == "status": #and j["key"] == self.name:
  74. self.sendstatus()
  75. def sendstatus(self):
  76. self.send({"type": "snowmix", "subtype": "statusreport", "name": self.name, "data":self.p_list})
  77. def send(self, data):
  78. try:
  79. if type(data) is dict:
  80. data = json.dumps(data)
  81. print(data)
  82. self.ws.send(data)
  83. except Exception as e:
  84. print(e)
  85. def conn(self, target):
  86. if self.ws is None:
  87. self.ws = websocket.WebSocket()
  88. try:
  89. self.ws.connect(target)
  90. except Exception as e:
  91. log(e)
  92. time.sleep(2)
  93. self.conn(target) #keep trying you basterd
  94. def close(self):
  95. if self.ws is None:
  96. return
  97. self.ws.close()
  98. def sighandler(self, sig, frame):
  99. log("\rExiting!")
  100. self.close()
  101. log("Bye!")
  102. sys.exit(0)
  103. def stop(self, key):
  104. if key not in self.p_list:
  105. log("key %s doesn't exist! not killing!" % (key))
  106. return
  107. try:
  108. os.killpg(os.getpgid(self.p_list[key]), signal.SIGTERM)
  109. except Exception as e:
  110. log("This process (%d) can't be killed! Why?" % self.p_list[key])
  111. log(e)
  112. try:
  113. self.log_list[key].close()
  114. except Exception as e:
  115. log("ex file: %s" % e)
  116. if key in self.log_list:
  117. del self.log_list[key]
  118. del self.p_list[key]
  119. self.sendstatus()
  120. def oneshot(self, key):
  121. if key not in self.ptable:
  122. log("This process (%s) is not on my table!" % key)
  123. return
  124. log("Oneshotting! key: %s" % key)
  125. try:
  126. proc = subprocess.Popen(self.ptable[key], preexec_fn=os.setsid)
  127. except Exception as e:
  128. log(e)
  129. def launch(self, key, options=None):
  130. if key in self.p_list:
  131. log("key %s exist! not running!" % (key))
  132. return
  133. if key not in self.ptable:
  134. log("This process (%s) is not on my table!" % key)
  135. return
  136. log("Launching! key: %s, opts: %s" % (key, options))
  137. tolaunch = self.ptable[key]
  138. if options is not None:
  139. options = [ o for o in options if type(o) is str ]
  140. tolaunch = tolaunch + options
  141. log(tolaunch)
  142. self.log_list[key] = open("/tmp/%s" % key, "w")
  143. try:
  144. proc = subprocess.Popen(tolaunch, preexec_fn=os.setsid, stdout=self.log_list[key])
  145. #Le doy su propio grupo al subproceso
  146. except Exception as e:
  147. log(e)
  148. sys.exit(1)
  149. self.p_list[key] = proc.pid
  150. self.sendstatus()
  151. return proc.pid
  152. if __name__ == "__main__":
  153. if len(sys.argv) != 2:
  154. print("Usage: ./%s <file.json>" % (sys.argv[0]))
  155. sys.exit(1)
  156. try:
  157. data = json.loads(open(sys.argv[1]).read())
  158. except Exception as e:
  159. print(e)
  160. sys.exit(2)
  161. ptable = data["data"]
  162. name = data["name"]
  163. m = PManager(name, ptable)