예제 #1
0
    def destroy(self, path):
        """
        Destroy: send EXIT to bootstrap, XFER files to the successor of this node and destroy the FUSE mount
        """

        # notify bootstrap that we left
        try:
            req_pkt = protocol.construct_packet(protocol.Verbs.EXIT,
                                                protocol.Status.OK, {})
            protocol.sock_send_recv(self.bootstrap_ip, req_pkt,
                                    protocol.BOOTSTRAP_PORT)
        except ProtocolError:
            pass
        except IOError as ex:
            logging.exception(ex)
            pass

        # remove our self so relocate_files will not calculate our self as the succ for any files
        try:
            hashing.HASHING_OBJ.remove_node(hashing.HASHING_OBJ.id_hash)
        except ZeroDivisionError:  # thrown if last node is exiting
            pass
        relocate_files(True)

        # destroy
        return super(Difuse, self).destroy(path)
예제 #2
0
 def write(self, path, data, offset, fh):
     """
     Write
     """
     path = path[1:]
     if path in os.listdir(LOCAL_ROOT):
         path = join(LOCAL_ROOT, path)
         fd = os.open(path, os.O_WRONLY)
         os.lseek(fd, offset, os.SEEK_SET)
         writen = os.write(fd, data)
         os.close(fd)
         return writen
     try:
         host_ip = protocol.lookup(self.bootstrap_ip, path)
         req_payload = {
             'filename': path,
             'offset': offset,
             'bytes': list(data)
         }
         req_pkt = protocol.construct_packet(protocol.Verbs.WRITE_REQ,
                                             protocol.Status.OK,
                                             req_payload)
         header, payload = protocol.sock_send_recv(host_ip, req_pkt)
         logging.debug(header)
         if header.status != protocol.Status.OK.name:
             if header.status == protocol.Status.EACCES.name:
                 raise FuseOSError(errno.EACCES)
             elif header.status == protocol.Status.ENOENT.name:
                 raise FuseOSError(errno.ENOENT)
             else:
                 raise FuseOSError(errno.EIO)
         return payload['cnt']
     except (ProtocolError, KeyError):
         raise FuseOSError(errno.EIO)
예제 #3
0
    def unlink(self, path):
        """
        unlink: lookup the location of the file and send request to host. if local, remove.
        """
        path = path[1:]

        # check if local, if local send unlink req and return
        if path in os.listdir(LOCAL_ROOT):
            os.remove(join(LOCAL_ROOT, path))
            return

        req_payload = {'filename': path}
        req_pkt = protocol.construct_packet(protocol.Verbs.UNLINK_REQ,
                                            protocol.Status.OK, req_payload)
        # not local, lookup
        host_ip = protocol.lookup(self.bootstrap_ip, path)
        try:
            header, _ = protocol.sock_send_recv(host_ip, req_pkt)
            if header.status != protocol.Status.OK.name:
                if header.status == protocol.Status.ENOENT.name:
                    raise FuseOSError(errno.ENOENT)
                elif header.status == protocol.Status.EACCES.name:
                    raise FuseOSError(errno.EACCES)
                else:
                    raise FuseOSError(errno.EIO)
        except IOError:
            raise FuseOSError(errno.EIO)
예제 #4
0
 def truncate(self, path, length, fh=None):
     """
     Truncate
     """
     path = path[1:]
     if path in os.listdir(LOCAL_ROOT):
         os.truncate(join(LOCAL_ROOT, path), length)
     try:
         host_ip = protocol.lookup(self.bootstrap_ip, path)
     except FileNotFoundError:
         raise FuseOSError(errno.ENOENT)
     try:
         req_payload = {'filename': path, 'len': length}
         req_pkt = protocol.construct_packet(protocol.Verbs.TRUNC_REQ,
                                             protocol.Status.OK,
                                             req_payload)
         header, payload = protocol.sock_send_recv(host_ip, req_pkt)
         if header.status != protocol.Status.OK.name:
             if header.status == protocol.Status.EACCES.name:
                 raise FuseOSError(errno.EACCES)
             elif header.status == protocol.Status.ENOENT.name:
                 raise FuseOSError(errno.ENOENT)
             else:
                 raise FuseOSError(errno.EIO)
     except ProtocolError:
         raise FuseOSError(errno.EIO)
예제 #5
0
 def read(self, path, size, offset, fh):
     """
     Read
     """
     path = path[1:]
     if path in os.listdir(LOCAL_ROOT):
         with open(join(LOCAL_ROOT, path), 'rb') as f:
             f.seek(offset)
             return f.read(size)
     try:
         host_ip = protocol.lookup(self.bootstrap_ip, path)
         req_payload = {'filename': path, 'cnt': size, 'offset': offset}
         req_pkt = protocol.construct_packet(protocol.Verbs.READ_REQ,
                                             protocol.Status.OK,
                                             req_payload)
         header, payload = protocol.sock_send_recv(host_ip, req_pkt)
         if header.status != protocol.Status.OK.name:
             if header.status == protocol.Status.ENOENT.name:
                 raise FileNotFoundError
             elif header.status == protocol.Status.EACCES.name:
                 raise PermissionError
         return bytes(payload['bytes'])
     except ProtocolError as ex:
         logging.exception(ex)
         raise FuseOSError(errno.EIO)
     except FileNotFoundError:
         raise FuseOSError(errno.ENOENT)
     except PermissionError:
         raise FuseOSError(errno.EACCES)
예제 #6
0
    def __init__(self, bootstrap_ip, fuse_mount):
        """
        init the node server, join the cluster, construct the listening socket
        """
        self.fuse_mount = fuse_mount
        self.bootstrap_ip = bootstrap_ip

        # establish server socket
        self.sock = socket.socket()
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind((HOST, protocol.PORT))
        self.sock.listen(5)

        # Send JOIN to the bootstrap and initialize the Hashing data structures
        req_pkt = protocol.construct_packet(protocol.Verbs.JOIN,
                                            protocol.Status.OK, {})
        try:
            # send JOIN and receive IP_TABLE
            header, payload = protocol.sock_send_recv(bootstrap_ip, req_pkt,
                                                      protocol.BOOTSTRAP_PORT)
            logging.debug(f'received {header}')
            if header.status != protocol.Status.OK.name:
                raise IOError('Did not received status: ok')

            # init the hashing object using the Bootstrap's data
            ip_table = Hashing.deserializable_ip_table(payload['ip_table'])
            hash_unit = sorted(ip_table.keys())
            id_hash = Hashing.difuse_hash(payload['ip'])
            hashing.HASHING_OBJ = Hashing(hash_unit, ip_table, id_hash)
            logging.info(f'ID: {id_hash}')
            # if files need to be relocated, relocate them
            relocate_files()
        except IOError as ex:
            logging.exception(ex)
예제 #7
0
def relocate_files(relocate_all=False):
    """
    Scans the LOCAL_ROOT directory for files that need to be relocated and sends XFER_RES to each node where files
    should be transferred.
    :relocate_all: Default false. If true, all files on local root will be transferred to the successor
    :return: None
    """
    # table that maps an ID hash to a list of dictionary to send
    xfer_res_table = {id_hash: [] for id_hash in hashing.HASHING_OBJ.hash_unit}

    # build xfer res table for each file in the local root
    for filename in os.listdir(LOCAL_ROOT):
        file_hash = Hashing.difuse_hash(filename)
        try:
            file_succ = Hashing.succ(file_hash)
        except ZeroDivisionError: # thrown if last node exiting
            return
        logging.debug(f'filename: {filename} | file_hash: {file_hash}')
        if relocate_all or file_succ != hashing.HASHING_OBJ.id_hash:
            try:
                with open(join(LOCAL_ROOT, filename), 'rb') as f:
                    file_bytes = f.read()
                    xfer_res_table[file_succ].append({
                        'filename': filename,
                        'bytes': list(file_bytes)
                    })
            except Exception as ex:
                logging.exception(ex)
                pass
    # send the XFER_RES
    for id_hash, xfer_list in xfer_res_table.items():
        # no files to transfer, do not send anything
        if not xfer_list:
            continue

        conn_ip = hashing.HASHING_OBJ.ip_table[id_hash]
        logging.info(f'relocating {xfer_list} to {conn_ip}')
        xfer_res_pkt = protocol.construct_packet(protocol.Verbs.XFER, protocol.Status.OK, {'files': xfer_list})
        try:
            protocol.sock_send_recv(conn_ip, xfer_res_pkt)
        except Exception as ex:
            logging.exception(ex)
        else:
            for xfer_file in xfer_list:
                os.remove(join(LOCAL_ROOT, xfer_file['filename']))
예제 #8
0
    def create(self, path, mode, fi=None):
        """

        :param path: filename
        :param mode: mode to creat
        :param fi: no idea
        :return:
        """
        path = path[1:]
        hash_id = hashing.HASHING_OBJ.difuse_hash(path)
        succ = hashing.HASHING_OBJ.succ(hash_id)
        host_ip = hashing.HASHING_OBJ.ip_table[succ]

        # if the successor is local id, create the file here
        if succ == hashing.HASHING_OBJ.id_hash:
            try:
                open(join(LOCAL_ROOT, path), 'xb').close()
            except OSError as ex:
                raise FuseOSError(ex.errno)
            else:
                self.fd += 1
                return self.fd

        # non local creation necessary
        logging.info(f'sending create {path} to {host_ip}')
        payload = {'filename': path}
        pkt = protocol.construct_packet(protocol.Verbs.CREATE,
                                        protocol.Status.OK, payload)
        try:
            header, payload = protocol.sock_send_recv(host_ip, pkt)
            if header.status == protocol.Status.EEXIST.name:
                raise FileExistsError
            if header.status == protocol.Status.EACCES.name:
                raise PermissionError
            if header.status != protocol.Status.OK.name:
                raise FuseOSError(errno.EIO)
        except FileExistsError:
            raise FuseOSError(errno.EEXIST)
        except PermissionError:
            raise FuseOSError(errno.EACCES)
        except ProtocolError:
            raise FuseOSError(errno.EIO)
        else:
            self.fd += 1
            return self.fd
예제 #9
0
    def getattr(self, path, fh=None):
        """
        stat/getattr syscall
        """
        if path == '/':
            return self._stat_dict(os.stat(LOCAL_ROOT))
        path = path[1:]
        if path in os.listdir(LOCAL_ROOT):
            stat = os.stat(join(LOCAL_ROOT, path))
            stat_dict = self._stat_dict(stat)
            stat_dict['st_uid'] = os.getuid()
            stat_dict['st_gid'] = os.getgid()
            return stat_dict

        host_ip = protocol.lookup(self.bootstrap_ip, path)

        try:
            pkt = protocol.construct_packet(protocol.Verbs.STAT_REQ,
                                            protocol.Status.OK,
                                            {'filename': path})
            header, payload = protocol.sock_send_recv(host_ip, pkt)
            logging.debug(f'getattr received {header}')
            if header.verb != protocol.Verbs.STAT_RES.name:
                raise FuseOSError(errno.EIO)
            if header.status == protocol.Status.ENOENT.name:
                raise FuseOSError(errno.ENOENT)
            stat = os.stat_result(payload['stat'])
            stat_dict = self._stat_dict(stat)
            stat_dict['st_uid'] = os.getuid()
            stat_dict['st_gid'] = os.getgid()
            return stat_dict
        except FuseOSError:
            raise
        except (ProtocolError, Exception) as ex:
            logging.exception(ex)
            raise FuseOSError(errno.EIO) from ex