cmd-ctrld.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import http.server
  2. import urllib.parse
  3. import json
  4. import re
  5. import ssl, socket
  6. import ISC
  7. import pprint
  8. import select
  9. import csv
  10. import random
  11. from hashlib import sha1
  12. try:
  13. import threading
  14. except ImportError:
  15. import dummy_threading as threading
  16. URL_PATTERN = re.compile('/([\w]+)(?:/([\w]+))?/?')
  17. class SecureHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
  18. '''
  19. Process GET and POST
  20. '''
  21. def parse_path(self, path):
  22. groups = URL_PATTERN.match(path)
  23. if not groups:
  24. return (NULL, NULL)
  25. return (groups.group(1), groups.group(2))
  26. def check_username(self,name):
  27. reader = csv.reader(open("passwd.csv"), delimiter="\t", quoting=csv.QUOTE_MINIMAL)
  28. for row in reader:
  29. if name==row[0]:
  30. self.user=[row[0],row[1],row[2]]
  31. return 1
  32. return 0
  33. def check(self):
  34. length = self.headers.get('content-length')
  35. nbytes = int(length)
  36. user_info = json.loads((self.rfile.read(nbytes)).decode())
  37. if not user_info:
  38. return ["error: invalid username or password"], http.client.UNAUTHORIZED
  39. if not self.check_username(user_info['username']):
  40. return ["error:the username doesn't exists"], http.client.UNAUTHORIZED
  41. if sha1((user_info['password'] + self.user[2]).encode()).hexdigest() != self.user[1] :
  42. return ["error:the username and passwd did not match!"], http.client.UNAUTHORIZED
  43. else :
  44. id = self.headers.get('cookie')
  45. self.server.session[id]['username'] = user_info['username']
  46. return ["login sucess !"], http.client.OK
  47. def do_GET(self):
  48. id = self.headers.get('cookie')
  49. if id not in self.server.session:
  50. self.server.session[id]={}
  51. reply_value = []
  52. if "username" not in self.server.session[id]:
  53. reply_value = ["please post username and passwd"]
  54. else:
  55. identifier, module = self.parse_path(self.path)
  56. if identifier != None:
  57. data = self.server.get_reply_data_for_GET(identifier, module)
  58. if data:
  59. reply_value = data
  60. self.send_response(200)
  61. self.end_headers()
  62. self.wfile.write(json.dumps(reply_value).encode())
  63. def do_POST(self):
  64. id = self.headers.get('cookie')
  65. if id not in self.server.session:
  66. self.server.session[id] = {}
  67. reply_msg = []
  68. rcode = 200
  69. if self.path == '/':
  70. reply_msg, rcode = self.check()
  71. elif "username" not in self.server.session[id]:
  72. reply_msg, rcode = ["please login!"], http.client.UNAUTHORIZED
  73. else:
  74. mod, cmd = self.parse_path(self.path)
  75. param = None
  76. len = self.headers.get('Content-Length')
  77. if len:
  78. post_str = str(self.rfile.read(int(len)).decode())
  79. print("command parameter:%s" % post_str)
  80. param = json.loads(post_str)
  81. reply_msg = self.server.send_command_to_module(mod, cmd, param)
  82. print('cmd-ctrld finish send message \'%s\' to module %s' % (cmd, mod))
  83. #TODO, set proper rcode
  84. self.send_response(rcode)
  85. self.end_headers()
  86. self.wfile.write(json.dumps(reply_msg).encode())
  87. class CommandControl():
  88. def __init__(self):
  89. self.cc = ISC.CC.Session()
  90. self.cc.group_subscribe('Cmd-Ctrld')
  91. self.cc.group_subscribe('Boss', 'Cmd-Ctrld')
  92. self.command_spec = self.get_cmd_specification()
  93. self.config_spec = self.get_data_specification()
  94. self.config_data = self.get_config_data()
  95. def get_cmd_specification(self):
  96. return self.send_command('ConfigManager', 'get_commands')
  97. def get_config_data(self):
  98. return self.send_command('ConfigManager', 'get_config')
  99. def update_config_data(self, module_name, command_name):
  100. if module_name == 'ConfigManager' and command_name == 'set_config':
  101. self.config_data = self.get_config_data()
  102. def get_data_specification(self):
  103. return self.send_command('ConfigManager', 'get_data_spec')
  104. def handle_recv_msg(self):
  105. # Handle received message, if 'shutdown' is received, return False
  106. (message, env) = self.cc.group_recvmsg(True)
  107. while message:
  108. if 'commands_update' in message:
  109. self.command_spec[message['commands_update'][0]] = message['commands_update'][1]
  110. elif 'specification_update' in message:
  111. msgvalue = message['specification_update']
  112. self.config_spec[msgvalue[0]] = msgvalue[1]
  113. elif 'command' in message and message['command'][0] == 'shutdown':
  114. return False;
  115. (message, env) = self.cc.group_recvmsg(True)
  116. return True
  117. def send_command(self, module_name, command_name, params = None):
  118. content = [command_name]
  119. if params:
  120. content.append(params)
  121. msg = {'command' : content}
  122. print('cmd-ctrld send command \'%s\' to %s' %(command_name, module_name))
  123. try:
  124. # Do special for Boss shutdown. TODO, avoid specicialism
  125. if module_name == 'Boss' and command_name == 'shutdown':
  126. self.cc.group_sendmsg(msg, module_name, 'boss')
  127. return {}
  128. self.cc.group_sendmsg(msg, module_name)
  129. answer, env = self.cc.group_recvmsg(False)
  130. if answer and 'result' in answer.keys() and type(answer['result']) == list:
  131. # TODO: with the new cc implementation, replace "1" by 1
  132. if answer['result'][0] == "1":
  133. # todo: exception
  134. print("Error: " + str(answer['result'][1]))
  135. return {}
  136. else:
  137. self.update_config_data(module_name, command_name)
  138. if len(answer['result']) > 1:
  139. return answer['result'][1]
  140. return {}
  141. else:
  142. print("Error: unexpected answer from %s" % module_name)
  143. except Exception as e:
  144. print(e)
  145. print('cmd-ctrld fail send command \'%s\' to %s' % (command_name, module_name))
  146. return {}
  147. class SecureHTTPServer(http.server.HTTPServer):
  148. def __init__(self, server_address, RequestHandlerClass):
  149. http.server.HTTPServer.__init__(self, server_address, RequestHandlerClass)
  150. self.session = {}
  151. self.cmdctrl = CommandControl()
  152. self.__is_shut_down = threading.Event()
  153. self.__serving = False
  154. def get_request(self):
  155. newsocket, fromaddr = self.socket.accept()
  156. try:
  157. connstream = ssl.wrap_socket(newsocket,
  158. server_side = True,
  159. certfile = 'create_your_cert.pem',
  160. keyfile = 'create_your_cert.pem',
  161. ssl_version = ssl.PROTOCOL_SSLv23)
  162. return (connstream, fromaddr)
  163. except ssl.SSLError as e :
  164. print("error happen***********")
  165. print(e)
  166. def get_reply_data_for_GET(self, id, module_name):
  167. if module_name is None:
  168. if id == 'command_spec':
  169. return self.cmdctrl.command_spec
  170. elif id == 'config_data':
  171. return self.cmdctrl.config_data
  172. elif id == 'config_spec':
  173. return self.cmdctrl.config_spec
  174. else:
  175. return None
  176. def serve_forever(self, poll_interval = 0.5):
  177. self.__serving = True
  178. self.__is_shut_down.clear()
  179. while self.__serving:
  180. if not self.cmdctrl.handle_recv_msg():
  181. break
  182. r, w, e = select.select([self], [], [], poll_interval)
  183. if r:
  184. self._handle_request_noblock()
  185. self.__is_shut_down.set()
  186. def shutdown(self):
  187. self.__serving = False
  188. self.__is_shut_down.wait()
  189. def send_command_to_module(self, module_name, command_name, params):
  190. return self.cmdctrl.send_command(module_name, command_name, params)
  191. def run(server_class = SecureHTTPServer, addr = 'localhost', port = 8080):
  192. print("cmd-ctrld module is starting on :%s port:%d" %(addr, port))
  193. httpd = server_class((addr, port), SecureHTTPRequestHandler)
  194. httpd.serve_forever()
  195. if __name__ == '__main__':
  196. try:
  197. run()
  198. except ISC.CC.SessionError as se:
  199. print("[cmd-ctrld] Error creating cmd-ctrld, "
  200. "is the command channel daemon running?")
  201. except KeyboardInterrupt:
  202. print("exit http server")