def __init__(self, root, mountpoint, hypervisor='Docker', module_root='middleboxes'): """Instantiates a Nfio object. Args: root: The root directory of nfio file system. The root directory stores persistent state about the system. mountpoint: The mountpoint of nfio file system. The mountpoint is required to intercept the file system calls via fuse. All the file system calls for fuse mounted files/directories are intercepted by libfuse and our provided implementation is executed. hypervisor: The type of hypervisor to use for deploying VNFs. The default is to use Docker containers. However, we also plan to add support for Libvirt. module_root: Root directory of the middlebox modules. Each middlebox provides it's own implementation of certain system calls in a separate module. module_root points to the root of that module. If nothing is provided a default of 'middleboxes' will be assumed. Returns: Nothing. Mounts nf.io file system at the specified mountpoint and creates a loop to act upon different file system calls. """ self.root = root self.mountpoint = mountpoint self.hypervisor = hypervisor self.vnfs_ops = VNFSOperations(root) self.module_root = module_root
def _write(root, path, buf, offset, fh): f_path = full_path(root, path) vnfs_ops = VNFSOperations(root) file_name = vnfs_ops.vnfs_get_file_name(f_path) #if file_name == "action": if file_name in special_files and special_files[file_name]+'_write' in globals(): try: nf_config = get_nf_config(vnfs_ops, f_path) # call the custom write function logger.info('Writing to ' + file_name + ' in ' + nf_config['nf_instance_name'] + '@' + nf_config['host']) ret_str = globals()[special_files[file_name]+'_write'](vnfs_ops._hypervisor, nf_config, buf.rstrip("\n")) except errors.HypervisorError, ex: logger.debug('raised OSErro ' + str(ex.errno)) raise OSError(ex.errno, os.strerror(ex.errno)) logger.info('Successfully wrote ' + file_name + ' in ' + nf_config['nf_instance_name'] + '@' + nf_config['host']) #if buf.rstrip("\n") == "activate": # try: # vnfs_ops.vnfs_deploy_nf(nf_path) # except errors.VNFCreateError: # #raise OSError(errno.EBUSY, os.strerror(errno.EBUSY)) # raise OSError(747, 'Cannot create VNF') #elif buf.rstrip("\n") == "stop": # vnfs_ops.vnfs_stop_vnf(nf_path) #elif buf.rstrip("\n") == "start": # vnfs_ops.vnfs_start_vnf(nf_path) #elif buf.rstrip("\n") == "destroy": # vnfs_ops.vnfs_destroy_vnf(nf_path) os.lseek(fh, offset, os.SEEK_SET) os.write(fh, buf.rstrip("\n")) return len(buf)
def __init__( self, root, mountpoint, hypervisor='Docker', module_root='middleboxes'): """Instantiates a Nfio object. Args: root: The root directory of nfio file system. The root directory stores persistent state about the system. mountpoint: The mountpoint of nfio file system. The mountpoint is required to intercept the file system calls via fuse. All the file system calls for fuse mounted files/directories are intercepted by libfuse and our provided implementation is executed. hypervisor: The type of hypervisor to use for deploying VNFs. The default is to use Docker containers. However, we also plan to add support for Libvirt. module_root: Root directory of the middlebox modules. Each middlebox provides it's own implementation of certain system calls in a separate module. module_root points to the root of that module. If nothing is provided a default of 'middleboxes' will be assumed. Returns: Nothing. Mounts nf.io file system at the specified mountpoint and creates a loop to act upon different file system calls. """ self.root = root self.mountpoint = mountpoint self.hypervisor = hypervisor self.vnfs_ops = VNFSOperations(root) self.module_root = module_root
def _getattr(root, path, fh=None): vnfs_ops = VNFSOperations(root) f_path = full_path(root, path) st = os.lstat(f_path) file_name = vnfs_ops.vnfs_get_file_name(f_path) return_dictionary = dict() return_dictionary['st_atime'] = st.st_atime return_dictionary['st_ctime'] = st.st_ctime return_dictionary['st_gid'] = st.st_gid return_dictionary['st_mode'] = st.st_mode return_dictionary['st_mtime'] = st.st_mtime return_dictionary['st_nlink'] = st.st_nlink return_dictionary['st_size'] = st.st_size return_dictionary['st_uid'] = st.st_uid if file_name in special_files: return_dictionary['st_size'] = 1000 return return_dictionary
def _read(root, path, length, offset, fh): f_path = full_path(root, path) vnfs_ops = VNFSOperations(root) file_name = vnfs_ops.vnfs_get_file_name(f_path) nf_path = '' if file_name in special_files: tokens = f_path.encode('ascii').split('/') last_index_to_keep = tokens.index('nf-types') + 3 nf_path = "/".join(tokens[0:last_index_to_keep]) if file_name == "rx_bytes": ret_str = vnfs_ops.vnfs_get_rx_bytes(nf_path) if offset >= len(ret_str): ret_str = '' elif file_name == 'tx_bytes': ret_str = vnfs_ops.vnfs_get_tx_bytes(nf_path) if offset >= len(ret_str): ret_str = '' elif file_name == 'pkt_drops': ret_str = vnfs_ops.vnfs_get_pkt_drops(nf_path) if offset >= len(ret_str): ret_str = '' elif file_name == 'status': ret_str = vnfs_ops.vnfs_get_status(nf_path) if offset >= len(ret_str): ret_str = '' else: os.lseek(fh, offset, os.SEEK_SET) ret_str = os.read(fh, length) return ret_str
def _write(root, path, buf, offset, fh): f_path = full_path(root, path) vnfs_ops = VNFSOperations(root) file_name = vnfs_ops.vnfs_get_file_name(f_path) if file_name == "action": path_tokens = f_path.split("/") nf_path = "/".join(path_tokens[0 : path_tokens.index("nf-types") + 3]) if buf.rstrip("\n") == "activate": vnfs_ops.vnfs_deploy_nf(nf_path) elif buf.rstrip("\n") == "stop": vnfs_ops.vnfs_stop_vnf(nf_path) elif buf.rstrip("\n") == "start": vnfs_ops.vnfs_start_vnf(nf_path) elif buf.rstrip("\n") == "destroy": vnfs_ops.vnfs_destroy_vnf(nf_path) os.lseek(fh, offset, os.SEEK_SET) os.write(fh, buf.rstrip("\n")) return len(buf) else: os.lseek(fh, offset, os.SEEK_SET) return os.write(fh, buf)
def _read(root, path, length, offset, fh): f_path = full_path(root, path) vnfs_ops = VNFSOperations(root) file_name = vnfs_ops.vnfs_get_file_name(f_path) nf_path = "" if file_name in special_files: tokens = f_path.encode("ascii").split("/") last_index_to_keep = tokens.index("nf-types") + 3 nf_path = "/".join(tokens[0:last_index_to_keep]) if file_name == "rx_bytes": ret_str = vnfs_ops.vnfs_get_rx_bytes(nf_path) if offset >= len(ret_str): ret_str = "" elif file_name == "tx_bytes": ret_str = vnfs_ops.vnfs_get_tx_bytes(nf_path) if offset >= len(ret_str): ret_str = "" elif file_name == "pkt_drops": ret_str = vnfs_ops.vnfs_get_pkt_drops(nf_path) if offset >= len(ret_str): ret_str = "" elif file_name == "status": ret_str = vnfs_ops.vnfs_get_status(nf_path) if offset >= len(ret_str): ret_str = "" else: os.lseek(fh, offset, os.SEEK_SET) ret_str = os.read(fh, length) return ret_str
def _read(root, path, length, offset, fh): f_path = full_path(root, path) vnfs_ops = VNFSOperations(root) file_name = vnfs_ops.vnfs_get_file_name(f_path) nf_path = '' ret_str = '' if file_name in special_files and special_files[file_name]+'_read' in globals(): try: nf_config = get_nf_config(vnfs_ops, f_path) # call the custom read function logger.info('Reading ' + file_name + ' from ' + nf_config['nf_instance_name'] + '@' + nf_config['host']) ret_str = globals()[special_files[file_name]+'_read'](vnfs_ops._hypervisor, nf_config) except errors.HypervisorError, ex: logger.debug('raised OSErro ' + str(ex.errno)) raise OSError(ex.errno, os.strerror(ex.errno)) logger.info('Successfully read ' + file_name + ' from ' + nf_config['nf_instance_name'] + '@' + nf_config['host']) if offset >= len(ret_str): ret_str = ''
def _write(root, path, buf, offset, fh): f_path = full_path(root, path) vnfs_ops = VNFSOperations(root) file_name = vnfs_ops.vnfs_get_file_name(f_path) #if file_name == "action": if file_name in special_files and special_files[file_name]+'_write' in globals(): try: nf_config = get_nf_config(vnfs_ops, f_path) # call the custom write function logger.info('Writing to ' + file_name + ' in ' + nf_config['nf_instance_name'] + '@' + nf_config['host']) ret_str = globals()[special_files[file_name]+'_write'](vnfs_ops._hypervisor, nf_config, buf.rstrip("\n")) logger.info('Successfully wrote ' + file_name + ' in ' + nf_config['nf_instance_name'] + '@' + nf_config['host']) except errors.nfioError, ex: logger.error('Failed to write ' + file_name + ' in ' + nf_config['nf_instance_name'] + '@' + nf_config['host'] + ' : ' + ex.__class__.__name__) #raise OSError(ex.errno, os.strerror(ex.errno)) os.lseek(fh, offset, os.SEEK_SET) os.write(fh, buf.rstrip("\n")) return len(buf)
def _write(root, path, buf, offset, fh): f_path = full_path(root, path) vnfs_ops = VNFSOperations(root) file_name = vnfs_ops.vnfs_get_file_name(f_path) #if file_name == "action": if file_name in special_files and special_files[ file_name] + '_write' in globals(): try: nf_config = get_nf_config(vnfs_ops, f_path) # call the custom write function logger.info('Writing to ' + file_name + ' in ' + nf_config['nf_instance_name'] + '@' + nf_config['host']) ret_str = globals()[special_files[file_name] + '_write']( vnfs_ops._hypervisor, nf_config, buf.rstrip("\n")) except errors.HypervisorError, ex: logger.debug('raised OSErro ' + str(ex.errno)) raise OSError(ex.errno, os.strerror(ex.errno)) logger.info('Successfully wrote ' + file_name + ' in ' + nf_config['nf_instance_name'] + '@' + nf_config['host']) #if buf.rstrip("\n") == "activate": # try: # vnfs_ops.vnfs_deploy_nf(nf_path) # except errors.VNFCreateError: # #raise OSError(errno.EBUSY, os.strerror(errno.EBUSY)) # raise OSError(747, 'Cannot create VNF') #elif buf.rstrip("\n") == "stop": # vnfs_ops.vnfs_stop_vnf(nf_path) #elif buf.rstrip("\n") == "start": # vnfs_ops.vnfs_start_vnf(nf_path) #elif buf.rstrip("\n") == "destroy": # vnfs_ops.vnfs_destroy_vnf(nf_path) os.lseek(fh, offset, os.SEEK_SET) os.write(fh, buf.rstrip("\n")) return len(buf)
def _read(root, path, length, offset, fh): f_path = full_path(root, path) vnfs_ops = VNFSOperations(root) file_name = vnfs_ops.vnfs_get_file_name(f_path) nf_path = '' ret_str = '' if file_name in special_files and special_files[file_name]+'_read' in globals(): try: nf_config = get_nf_config(vnfs_ops, f_path) # call the custom read function logger.info('Reading ' + file_name + ' from ' + nf_config['nf_instance_name'] + '@' + nf_config['host']) ret_str = globals()[special_files[file_name]+'_read'](vnfs_ops._hypervisor, nf_config) logger.info('Successfully read ' + file_name + ' from ' + nf_config['nf_instance_name'] + '@' + nf_config['host']) except errors.nfioError, ex: logger.error('Failed to read ' + file_name + ' from ' + nf_config['nf_instance_name'] + '@' + nf_config['host'] + ' : ' + ex.__class__.__name__) #raise OSError(ex.errno, os.strerror(ex.errno)) if offset >= len(ret_str): ret_str = ''
class Nfio(Operations): def __init__( self, root, mountpoint, hypervisor='Docker', module_root='middleboxes'): """Instantiates a Nfio object. Args: root: The root directory of nfio file system. The root directory stores persistent state about the system. mountpoint: The mountpoint of nfio file system. The mountpoint is required to intercept the file system calls via fuse. All the file system calls for fuse mounted files/directories are intercepted by libfuse and our provided implementation is executed. hypervisor: The type of hypervisor to use for deploying VNFs. The default is to use Docker containers. However, we also plan to add support for Libvirt. module_root: Root directory of the middlebox modules. Each middlebox provides it's own implementation of certain system calls in a separate module. module_root points to the root of that module. If nothing is provided a default of 'middleboxes' will be assumed. Returns: Nothing. Mounts nf.io file system at the specified mountpoint and creates a loop to act upon different file system calls. """ self.root = root self.mountpoint = mountpoint self.hypervisor = hypervisor self.vnfs_ops = VNFSOperations(root) self.module_root = module_root # Helpers # ======= def _full_path(self, partial): """Returns the absolute path of a partially specified path. Args: partial: The partially specified path. e.g., nf-types/firewall This partially specified path should be a relative path under the mounted directory of nfio" Returns: The absolute path for the partially specified path. The absolute path is in respect to nfio root directory. e.g., if partial is nf-types/firewall and nfio root is /vnfsroot, then the return value will be /vnfsroot/nf-types/firewall """ if partial.startswith("/"): partial = partial[1:] path = os.path.join(self.root, partial) return path # Filesystem methods # ================== def access(self, path, mode): full_path = self._full_path(path) if not os.access(full_path, mode): raise FuseOSError(errno.EACCES) def chmod(self, path, mode): full_path = self._full_path(path) return os.chmod(full_path, mode) def chown(self, path, uid, gid): full_path = self._full_path(path) return os.chown(full_path, uid, gid) def getattr(self, path, fh=None): """ Returns the file attributes of the file specified by path Args: path: Path of the file fh: Open file handle to the file Returns: A dictionary containing file attributes. The dictionary contains the following keys: st_atime: Last access time st_ctime: File creation time st_gid: Group id of the owner group st_mode: File access mode st_mtime: Last modification time st_nlink: Number of symbolic links to the file st_size: Size of the file in bytes st_uid: User id of the file owner Note: For special placeholder files for VNFs, st_size is set to a constant 1000. This is to make sure read utilities such as cat work for these special placeholder files. """ opcode = self.vnfs_ops.vnfs_get_opcode(path) if opcode == VNFSOperations.OP_NF: nf_type = self.vnfs_ops.vnfs_get_nf_type(path) if len(nf_type) > 0: try: mbox_module = importlib.import_module( self.module_root + "." + nf_type) except ImportError: logger.error('VNF module file missing. Add "' + nf_type + '.py" under the directory ' + self.module_root) ## TODO: raise an custom exception and handle it in a OS ## specific way raise OSError(errno.ENOSYS) return mbox_module._getattr(self.root, path, fh) full_path = self._full_path(path) st = os.lstat(full_path) file_name = self.vnfs_ops.vnfs_get_file_name(full_path) return dict( (key, getattr( st, key)) for key in ( 'st_atime', 'st_ctime', 'st_gid', 'st_mode', 'st_mtime', 'st_nlink', 'st_size', 'st_uid')) def readdir(self, path, fh): full_path = self._full_path(path) dirents = ['.', '..'] if os.path.isdir(full_path): dirents.extend(os.listdir(full_path)) for entry in dirents: yield entry def readlink(self, path): pathname = os.readlink(self._full_path(path)) if pathname.startswith(self.root): pathname = self.mountpoint + pathname[len(self.root):] return pathname def mknod(self, path, mode, dev): return os.mknod(self._full_path(path), mode, dev) def rmdir(self, path): full_path = self._full_path(path) return os.rmdir(full_path) def mkdir(self, path, mode): """ The semantics have been redefined to create a new VNF instance when a directory is created under a specific type of VNF directory. Args: path: path of the directory to create. The path also represents the name of the new VNF instance to be created. mode: File access mode for the new directory. Returns: If path does not correspond to a directory under a specific VNF type directory then errno.EPERM is returned. Otherwise the return code is same as os.mkdir()'s return code. """ opcode = self.vnfs_ops.vnfs_get_opcode(path) if opcode == VNFSOperations.OP_NF: nf_type = self.vnfs_ops.vnfs_get_nf_type(path) # Check if this directory is an instance directory or a type # directory path_tokens = path.split("/") if path_tokens.index("nf-types") == len(path_tokens) - 2: return os.mkdir(self._full_path(path), mode) mbox_module = importlib.import_module( self.module_root + "." + nf_type) result = mbox_module._mkdir(self.root, path, mode) elif opcode == VNFSOperations.OP_UNDEFINED: result = errno.EPERM return result def statfs(self, path): full_path = self._full_path(path) stv = os.statvfs(full_path) return dict( (key, getattr( stv, key)) for key in ( 'f_bavail', 'f_bfree', 'f_blocks', 'f_bsize', 'f_favail', 'f_ffree', 'f_files', 'f_flag', 'f_frsize', 'f_namemax')) def unlink(self, path): return os.unlink(self._full_path(path)) def symlink(self, name, target): return os.symlink(self._full_path(target), name) def rename(self, old, new): return os.rename(self._full_path(old), self._full_path(new)) def link(self, target, name): return os.link(self._full_path(target), self._full_path(name)) def utimens(self, path, times=None): return os.utime(self._full_path(path), times) # File methods # ============ def open(self, path, flags): full_path = self._full_path(path) return os.open(full_path, flags) def create(self, path, mode, fi=None): full_path = self._full_path(path) return os.open(full_path, os.O_WRONLY | os.O_CREAT, mode) def read(self, path, length, offset, fh): """ Reads an open file. This nfio specific implementation parses path to see if the read is from any VNF or not. In case the read is from a VNF, the corresponding VNF module is loaded and the module's _read function is invoked to complete the read system call. Args: path: path represents the path of the file to read from length: number of bytes to read from the file offset: byte offset indicating the starting byte to read from fh: file descriptor of the open file represented by path Returns: length bytes from offset byte of the file represented by fh and path Notes: VNFs can have special files which are placeholders for statistics such as number of received/sent bytes etc. VNFs provide their own implementation of read and handle reading of these special placeholder files. """ full_path = self._full_path(path) opcode = self.vnfs_ops.vnfs_get_opcode(full_path) file_name = self.vnfs_ops.vnfs_get_file_name(full_path) if opcode == self.vnfs_ops.OP_NF: nf_type = self.vnfs_ops.vnfs_get_nf_type(path) mbox_module = importlib.import_module( self.module_root + "." + nf_type) return mbox_module._read(self.root, path, length, offset, fh) os.lseek(fh, offset, os.SEEK_SET) return os.read(fh, length) def write(self, path, buf, offset, fh): """ Write to an open file. In this nfio specific implementation the path is parsed to see if the write is for any specific VNF or not. If the write is for any file under a VNF directory then the corresponding VNF module is loaded and the module's _write function is invoked. Args: path: path to the file to write buf: the data to write offset: the byte offset at which the write should begin fh: file descriptor of the open file represented by path Returns: Returns the number of bytes written to the file starting at offset Note: VNFs can have special files where writing specific strings trigger a specific function. For example, writing 'activate' to the 'action' file of a VNF will start the VNF. VNF specific modules handle such special cases of writing. """ opcode = self.vnfs_ops.vnfs_get_opcode(path) full_path = self._full_path(path) file_name = self.vnfs_ops.vnfs_get_file_name(path) if opcode == VNFSOperations.OP_NF: nf_type = self.vnfs_ops.vnfs_get_nf_type(full_path) mbox_module = importlib.import_module( self.module_root + "." + nf_type) return mbox_module._write(self.root, path, buf, offset, fh) os.lseek(fh, offset, os.SEEK_SET) return os.write(fh, buf) def truncate(self, path, length, fh=None): full_path = self._full_path(path) with open(full_path, 'r+') as f: f.truncate(length) def flush(self, path, fh): return os.fsync(fh) def release(self, path, fh): return os.close(fh) def fsync(self, path, fdatasync, fh): return self.flush(path, fh)
def _mkdir(root, path, mode): vnfs_ops = VNFSOperations(root) result = vnfs_ops.vnfs_create_vnf_instance(path, mode) return result
class Nfio(Operations): def __init__(self, root, mountpoint, hypervisor='Docker', module_root='middleboxes'): """Instantiates a Nfio object. Args: root: The root directory of nfio file system. The root directory stores persistent state about the system. mountpoint: The mountpoint of nfio file system. The mountpoint is required to intercept the file system calls via fuse. All the file system calls for fuse mounted files/directories are intercepted by libfuse and our provided implementation is executed. hypervisor: The type of hypervisor to use for deploying VNFs. The default is to use Docker containers. However, we also plan to add support for Libvirt. module_root: Root directory of the middlebox modules. Each middlebox provides it's own implementation of certain system calls in a separate module. module_root points to the root of that module. If nothing is provided a default of 'middleboxes' will be assumed. Returns: Nothing. Mounts nf.io file system at the specified mountpoint and creates a loop to act upon different file system calls. """ self.root = root self.mountpoint = mountpoint self.hypervisor = hypervisor self.vnfs_ops = VNFSOperations(root) self.module_root = module_root # Helpers # ======= def _full_path(self, partial): """Returns the absolute path of a partially specified path. Args: partial: The partially specified path. e.g., nf-types/firewall This partially specified path should be a relative path under the mounted directory of nfio" Returns: The absolute path for the partially specified path. The absolute path is in respect to nfio root directory. e.g., if partial is nf-types/firewall and nfio root is /vnfsroot, then the return value will be /vnfsroot/nf-types/firewall """ if partial.startswith("/"): partial = partial[1:] path = os.path.join(self.root, partial) return path # Filesystem methods # ================== def access(self, path, mode): full_path = self._full_path(path) if not os.access(full_path, mode): raise FuseOSError(errno.EACCES) def chmod(self, path, mode): full_path = self._full_path(path) return os.chmod(full_path, mode) def chown(self, path, uid, gid): full_path = self._full_path(path) return os.chown(full_path, uid, gid) def getattr(self, path, fh=None): """ Returns the file attributes of the file specified by path Args: path: Path of the file fh: Open file handle to the file Returns: A dictionary containing file attributes. The dictionary contains the following keys: st_atime: Last access time st_ctime: File creation time st_gid: Group id of the owner group st_mode: File access mode st_mtime: Last modification time st_nlink: Number of symbolic links to the file st_size: Size of the file in bytes st_uid: User id of the file owner Note: For special placeholder files for VNFs, st_size is set to a constant 1000. This is to make sure read utilities such as cat work for these special placeholder files. """ opcode = self.vnfs_ops.vnfs_get_opcode(path) if opcode == VNFSOperations.OP_NF: nf_type = self.vnfs_ops.vnfs_get_nf_type(path) if len(nf_type) > 0: try: mbox_module = importlib.import_module(self.module_root + "." + nf_type) except ImportError: logger.error('VNF module file missing. Add "' + nf_type + '.py" under the directory ' + self.module_root) ## TODO: raise an custom exception and handle it in a OS ## specific way raise OSError(errno.ENOSYS) return mbox_module._getattr(self.root, path, fh) full_path = self._full_path(path) st = os.lstat(full_path) file_name = self.vnfs_ops.vnfs_get_file_name(full_path) return dict((key, getattr(st, key)) for key in ('st_atime', 'st_ctime', 'st_gid', 'st_mode', 'st_mtime', 'st_nlink', 'st_size', 'st_uid')) def readdir(self, path, fh): full_path = self._full_path(path) dirents = ['.', '..'] if os.path.isdir(full_path): dirents.extend(os.listdir(full_path)) for entry in dirents: yield entry def readlink(self, path): pathname = os.readlink(self._full_path(path)) if pathname.startswith(self.root): pathname = self.mountpoint + pathname[len(self.root):] return pathname def mknod(self, path, mode, dev): return os.mknod(self._full_path(path), mode, dev) def rmdir(self, path): full_path = self._full_path(path) return os.rmdir(full_path) def mkdir(self, path, mode): """ The semantics have been redefined to create a new VNF instance when a directory is created under a specific type of VNF directory. Args: path: path of the directory to create. The path also represents the name of the new VNF instance to be created. mode: File access mode for the new directory. Returns: If path does not correspond to a directory under a specific VNF type directory then errno.EPERM is returned. Otherwise the return code is same as os.mkdir()'s return code. """ opcode = self.vnfs_ops.vnfs_get_opcode(path) if opcode == VNFSOperations.OP_NF: nf_type = self.vnfs_ops.vnfs_get_nf_type(path) # Check if this directory is an instance directory or a type # directory path_tokens = path.split("/") if path_tokens.index("nf-types") == len(path_tokens) - 2: return os.mkdir(self._full_path(path), mode) mbox_module = importlib.import_module(self.module_root + "." + nf_type) result = mbox_module._mkdir(self.root, path, mode) elif opcode == VNFSOperations.OP_UNDEFINED: result = errno.EPERM return result def statfs(self, path): full_path = self._full_path(path) stv = os.statvfs(full_path) return dict((key, getattr(stv, key)) for key in ('f_bavail', 'f_bfree', 'f_blocks', 'f_bsize', 'f_favail', 'f_ffree', 'f_files', 'f_flag', 'f_frsize', 'f_namemax')) def unlink(self, path): return os.unlink(self._full_path(path)) def symlink(self, name, target): return os.symlink(self._full_path(target), name) def rename(self, old, new): return os.rename(self._full_path(old), self._full_path(new)) def link(self, target, name): return os.link(self._full_path(target), self._full_path(name)) def utimens(self, path, times=None): return os.utime(self._full_path(path), times) # File methods # ============ def open(self, path, flags): full_path = self._full_path(path) return os.open(full_path, flags) def create(self, path, mode, fi=None): full_path = self._full_path(path) return os.open(full_path, os.O_WRONLY | os.O_CREAT, mode) def read(self, path, length, offset, fh): """ Reads an open file. This nfio specific implementation parses path to see if the read is from any VNF or not. In case the read is from a VNF, the corresponding VNF module is loaded and the module's _read function is invoked to complete the read system call. Args: path: path represents the path of the file to read from length: number of bytes to read from the file offset: byte offset indicating the starting byte to read from fh: file descriptor of the open file represented by path Returns: length bytes from offset byte of the file represented by fh and path Notes: VNFs can have special files which are placeholders for statistics such as number of received/sent bytes etc. VNFs provide their own implementation of read and handle reading of these special placeholder files. """ full_path = self._full_path(path) opcode = self.vnfs_ops.vnfs_get_opcode(full_path) file_name = self.vnfs_ops.vnfs_get_file_name(full_path) if opcode == self.vnfs_ops.OP_NF: nf_type = self.vnfs_ops.vnfs_get_nf_type(path) mbox_module = importlib.import_module(self.module_root + "." + nf_type) return mbox_module._read(self.root, path, length, offset, fh) os.lseek(fh, offset, os.SEEK_SET) return os.read(fh, length) def write(self, path, buf, offset, fh): """ Write to an open file. In this nfio specific implementation the path is parsed to see if the write is for any specific VNF or not. If the write is for any file under a VNF directory then the corresponding VNF module is loaded and the module's _write function is invoked. Args: path: path to the file to write buf: the data to write offset: the byte offset at which the write should begin fh: file descriptor of the open file represented by path Returns: Returns the number of bytes written to the file starting at offset Note: VNFs can have special files where writing specific strings trigger a specific function. For example, writing 'activate' to the 'action' file of a VNF will start the VNF. VNF specific modules handle such special cases of writing. """ opcode = self.vnfs_ops.vnfs_get_opcode(path) full_path = self._full_path(path) file_name = self.vnfs_ops.vnfs_get_file_name(path) if opcode == VNFSOperations.OP_NF: nf_type = self.vnfs_ops.vnfs_get_nf_type(full_path) mbox_module = importlib.import_module(self.module_root + "." + nf_type) return mbox_module._write(self.root, path, buf, offset, fh) os.lseek(fh, offset, os.SEEK_SET) return os.write(fh, buf) def truncate(self, path, length, fh=None): full_path = self._full_path(path) with open(full_path, 'r+') as f: f.truncate(length) def flush(self, path, fh): return os.fsync(fh) def release(self, path, fh): return os.close(fh) def fsync(self, path, fdatasync, fh): return self.flush(path, fh)
def _write(root, path, buf, offset, fh): f_path = full_path(root, path) vnfs_ops = VNFSOperations(root) file_name = vnfs_ops.vnfs_get_file_name(f_path) if file_name == "action": path_tokens = f_path.split("/") nf_path = "/".join(path_tokens[0:path_tokens.index("nf-types") + 3]) if buf.rstrip("\n") == "activate": vnfs_ops.vnfs_deploy_nf(nf_path) elif buf.rstrip("\n") == "stop": vnfs_ops.vnfs_stop_vnf(nf_path) elif buf.rstrip("\n") == "start": vnfs_ops.vnfs_start_vnf(nf_path) elif buf.rstrip("\n") == "destroy": vnfs_ops.vnfs_destroy_vnf(nf_path) os.lseek(fh, offset, os.SEEK_SET) os.write(fh, buf.rstrip("\n")) return len(buf) else: os.lseek(fh, offset, os.SEEK_SET) return os.write(fh, buf)