def __handle_client_connection(self, client_sock): """ Read message from a specific client socket and closes the socket If a problem arises in the communication with the client, the client socket will also be closed """ socket_transferer = BlockingSocketTransferer(client_sock) try: msg = socket_transferer.receive_plain_text() except Exception: ClientListener.logger.exception("Error while reading socket {}".format(client_sock)) socket_transferer.abort() return try: parsed_msg = json.loads(msg) except json.decoder.JSONDecodeError as e: ClientListener.logger.exception("Error parsing json") socket_transferer.send_plain_text(json.dumps({"message": "ERROR", "data": str(e)})) socket_transferer.close() return self.backup_scheduler_write.send((parsed_msg['command'], parsed_msg['args'])) try: message, data = self.backup_scheduler_read.recv() except EOFError as e: ClientListener.logger.exception("Backup scheduler death") socket_transferer.abort() raise e try: socket_transferer.send_plain_text(json.dumps({"message": message, "data": data})) except Exception: ClientListener.logger.exception("Error writing through socket") socket_transferer.abort() return socket_transferer.close()
def test_send_text(self): self.p = Process(target=message_sender, args=(self.barrier, TestBlockingSocketTransferer.TEST_PORT)) self.p.start() self.barrier.wait() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', TestBlockingSocketTransferer.TEST_PORT)) socket_transferer = BlockingSocketTransferer(sock) self.assertEqual(socket_transferer.receive_plain_text(), "Hola uacho") socket_transferer.close()
def test_error_json_and_then_working(self): self.barrier.wait() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', TestClientListener.PORT)) socket_transferer = BlockingSocketTransferer(sock) socket_transferer.send_plain_text("asd") msg = socket_transferer.receive_plain_text() self.assertEqual(json.loads(msg)["message"], "ERROR") sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', TestClientListener.PORT)) socket_transferer = BlockingSocketTransferer(sock) socket_transferer.send_plain_text( '{"command": "dummy", "args": {"one": "one"}}') command, args = self.backup_scheduler_recv.recv() self.assertEqual(command, 'dummy') self.assertEqual(args, {"one": "one"}) self.backup_scheduler_send.send(("OK", {})) msg = socket_transferer.receive_plain_text() self.assertEqual(json.loads(msg), {"message": "OK", "data": {}}) socket_transferer.close()
def test_detect_backup_scheduler_dead(self): self.barrier.wait() self.backup_scheduler_send.close() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', TestClientListener.PORT)) socket_transferer = BlockingSocketTransferer(sock) socket_transferer.send_plain_text( '{"command": "dummy", "args": {"one": "one"}}') msg = socket_transferer.receive_plain_text() self.assertEqual("ABORT", msg) sleep(1) self.assertTrue(not self.p.is_alive())
def test_fail_to_receive_file(self): sleep(5) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', TestSidecar.PORT)) socket_transferer = BlockingSocketTransferer(sock) socket_transferer.send_plain_text( json.dumps({ "checksum": "", "path": '/tmp/example' })) _ = socket_transferer.receive_plain_text() socket_transferer.close() sleep(5)
def __handle_client_connection(client_sock, backup_no: int): """ Read message from a specific client socket and closes the socket If a problem arises in the communication with the client, the client socket will also be closed """ socket_transferer = BlockingSocketTransferer(client_sock) try: msg = socket_transferer.receive_plain_text() msg = json.loads(msg) path, previous_checksum = msg['path'], msg['checksum'] SidecarProcess.logger.debug("Previous checksum for path %s is '%s'" % (path, previous_checksum)) except (OSError, TimeoutError) as e: SidecarProcess.logger.exception("Error while reading socket %s: %s" % (client_sock, e)) socket_transferer.abort() return try: backup_file = BackupFile.create_from_path(path, TMP_BACKUP_PATH % backup_no) except Exception: SidecarProcess.logger.exception("Error while making backup file") socket_transferer.abort() return file_checksum = backup_file.get_hash() if file_checksum == previous_checksum: SidecarProcess.logger.info("Previous checksum equals to actual data, skipping backup") socket_transferer.send_plain_text("SAME") socket_transferer.abort() return else: socket_transferer.send_plain_text("DIFF") try: socket_transferer.send_file(TMP_BACKUP_PATH % backup_no) SidecarProcess.logger.debug("Backup file sent") socket_transferer.send_plain_text(file_checksum) except Exception as e: SidecarProcess.logger.exception("Error while writing socket %s: %s" % (client_sock, e)) socket_transferer.abort() return finally: socket_transferer.close() return
def __call__(self) -> NoReturn: """ Code for running the handler in a new process The process works this way: 1. Connects to node sidecar asking for node_path compressed 2. If the backup is the same as previous checksum, writes a .SAME file 3. Downloads the file saving it in write file path 3.1. At start it writes an empty file named self.write_file_path but ending with .WIP 3.2. Starts saving the backup in a file located in self.write_file_path 3.3. When the backup is saved saves an empty file named self.write_file_path but ending with .CORRECT 3.4. Deletes the .WIP file 4. Seppuku """ NodeHandlerProcess.logger.debug( "Starting node handler for node %s:%d and path %s" % (self.node_address, self.node_port, self.node_path)) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.connect((self.node_address, self.node_port)) socket_transferer = BlockingSocketTransferer(sock) socket_transferer.send_plain_text( json.dumps({ "checksum": self.previous_checksum, "path": self.node_path })) except Exception as e: NodeHandlerProcess.logger.exception( "Error while writing socket %s: %s" % (sock, e)) NodeHandlerProcess.logger.info( "Terminating handler for node %s:%d and path %s" % (self.node_address, self.node_port, self.node_path)) return msg = socket_transferer.receive_plain_text() if msg == "SAME": NodeHandlerProcess.logger.debug("The backup was the same") NodeHandlerProcess.logger.info( "Terminating handler for node %s:%d and path %s" % (self.node_address, self.node_port, self.node_path)) open(SAME_FILE_FORMAT % self.write_file_path, 'w').close() return if msg == "ABORT": NodeHandlerProcess.logger.error("Abort order sent from sidecar") NodeHandlerProcess.logger.info( "Terminating handler for node %s:%d and path %s" % (self.node_address, self.node_port, self.node_path)) return open(WIP_FILE_FORMAT % self.write_file_path, 'w').close() data_file = open(self.write_file_path, 'ab') try: socket_transferer.receive_file_data(data_file) NodeHandlerProcess.logger.debug("File data received") checksum = socket_transferer.receive_plain_text() except Exception as e: NodeHandlerProcess.logger.exception( "Error while reading socket %s: %s" % (sock, e)) NodeHandlerProcess.logger.info( "Terminating handler for node %s:%d and path %s" % (self.node_address, self.node_port, self.node_path)) return data_file.close() backup_file = BackupFile(self.write_file_path) if backup_file.get_hash() == checksum: NodeHandlerProcess.logger.debug("Backup checksum: %s" % checksum) else: NodeHandlerProcess.logger.error( "Error verifying checksum. Local: %s vs Server: %s" % (backup_file.get_hash(), checksum)) return open(CORRECT_FILE_FORMAT % self.write_file_path, 'w').close() os.remove(WIP_FILE_FORMAT % self.write_file_path) NodeHandlerProcess.logger.info( "Terminating handler for node %s:%d and path %s" % (self.node_address, self.node_port, self.node_path))
parser = argparse.ArgumentParser( description='Sends a command to backup server') parser.add_argument('--port', required=True, type=int, help='the port of the the server') parser.add_argument('--address', required=True, help='the address of the server') parser.add_argument('--command', required=True, help='the command to run') parser.add_argument('--args', required=True, help='the args dict') args = parser.parse_args() port = args.port address = args.address command = args.command dict_arguments = json.loads(args.args) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((address, port)) socket_transferer = BlockingSocketTransferer(sock) socket_transferer.send_plain_text( json.dumps({ "command": command, "args": dict_arguments })) msg = socket_transferer.receive_plain_text() print(msg) socket_transferer.close()