pmanager.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. opts = None
  64. if "options" in j:
  65. opts = j["options"]
  66. self.oneshot(j["key"], opts)
  67. if j["command"] == "launch":
  68. opts = None
  69. if "options" in j:
  70. opts = j["options"]
  71. self.launch(j["key"], opts)
  72. if j["command"] == "kill":
  73. self.stop(j["key"])
  74. if j["command"] == "netcat":
  75. sendmsg(j["key"])
  76. if j["command"] == "status": #and j["key"] == self.name:
  77. self.sendstatus()
  78. def sendstatus(self):
  79. self.send({"type": "snowmix", "subtype": "statusreport", "name": self.name, "data":self.p_list})
  80. def send(self, data):
  81. try:
  82. if type(data) is dict:
  83. data = json.dumps(data)
  84. print(data)
  85. self.ws.send(data)
  86. except Exception as e:
  87. print(e)
  88. def conn(self, target):
  89. if self.ws is None:
  90. self.ws = websocket.WebSocket()
  91. try:
  92. self.ws.connect(target)
  93. except Exception as e:
  94. log(e)
  95. time.sleep(2)
  96. self.conn(target) #keep trying you basterd
  97. def close(self):
  98. if self.ws is None:
  99. return
  100. self.ws.close()
  101. def sighandler(self, sig, frame):
  102. log("\rExiting!")
  103. self.close()
  104. log("Bye!")
  105. sys.exit(0)
  106. def stop(self, key):
  107. if key not in self.p_list:
  108. log("key %s doesn't exist! not killing!" % (key))
  109. return
  110. try:
  111. os.killpg(os.getpgid(self.p_list[key]), signal.SIGTERM)
  112. except Exception as e:
  113. log("This process (%d) can't be killed! Why?" % self.p_list[key])
  114. log(e)
  115. try:
  116. self.log_list[key].close()
  117. except Exception as e:
  118. log("ex file: %s" % e)
  119. if key in self.log_list:
  120. del self.log_list[key]
  121. del self.p_list[key]
  122. self.sendstatus()
  123. def oneshot(self, key, options=None):
  124. if key not in self.ptable:
  125. log("This process (%s) is not on my table!" % key)
  126. return
  127. log("Oneshotting! key: %s" % key)
  128. tolaunch = self.ptable[key]
  129. if options is not None:
  130. options = [ o for o in options if type(o) is str ]
  131. tolaunch = tolaunch + options
  132. log(tolaunch)
  133. try:
  134. proc = subprocess.Popen(tolaunch, preexec_fn=os.setsid)
  135. except Exception as e:
  136. log(e)
  137. def launch(self, key, options=None):
  138. if key in self.p_list:
  139. log("key %s exist! not running!" % (key))
  140. return
  141. if key not in self.ptable:
  142. log("This process (%s) is not on my table!" % key)
  143. return
  144. log("Launching! key: %s, opts: %s" % (key, options))
  145. tolaunch = self.ptable[key]
  146. if options is not None:
  147. options = [ o for o in options if type(o) is str ]
  148. tolaunch = tolaunch + options
  149. log(tolaunch)
  150. self.log_list[key] = open("/tmp/%s" % key, "w")
  151. try:
  152. proc = subprocess.Popen(tolaunch, preexec_fn=os.setsid, stdout=self.log_list[key])
  153. #Le doy su propio grupo al subproceso
  154. except Exception as e:
  155. log(e)
  156. sys.exit(1)
  157. self.p_list[key] = proc.pid
  158. self.sendstatus()
  159. return proc.pid
  160. if __name__ == "__main__":
  161. if len(sys.argv) != 2:
  162. print("Usage: ./%s <file.json>" % (sys.argv[0]))
  163. sys.exit(1)
  164. try:
  165. data = json.loads(open(sys.argv[1]).read())
  166. except Exception as e:
  167. print(e)
  168. sys.exit(2)
  169. ptable = data["data"]
  170. name = data["name"]
  171. m = PManager(name, ptable)