from tools import tasks
-_LOGGER = logging.getLogger(__name__)
class ModuleManager(object):
"""Simple module manager which acts as system wrapper for Kernel Modules.
"""
"""
self._modules = []
- def insert_modules(self, modules):
- """Method inserts list of modules. In case that module name ends
- with .ko suffix then insmod will be used for its insertion. Otherwise
- modprobe will be called.
+ def insert_module(self, module):
+ """Method inserts given module.
+
+ In case that module name ends with .ko suffix then insmod will
+ be used for its insertion. Otherwise modprobe will be called.
- :returns: None
+ :param module: a name of kernel module
"""
+ module_base_name = os.path.basename(os.path.splitext(module)[0])
- for module in modules:
- if self.is_module_inserted(module):
- continue
+ if self.is_module_inserted(module):
+ self._logger.info('Module already loaded \'%s\'.', module_base_name)
+ # add it to internal list, so we can try to remove it at the end
+ self._modules.append(module)
+ return
+
+ try:
+ if module.endswith('.ko'):
+ tasks.run_task(['sudo', 'insmod', module], self._logger,
+ 'Insmod module \'%s\'...' % module_base_name, True)
+ else:
+ tasks.run_task(['sudo', 'modprobe', module], self._logger,
+ 'Modprobe module \'%s\'...' % module_base_name, True)
+ self._modules.append(module)
+ except subprocess.CalledProcessError:
+ # in case of error, show full module name
+ self._logger.error('Unable to insert module \'%s\'.', module)
+ raise # fail catastrophically
- try:
- if module.endswith('.ko'):
- tasks.run_task(['sudo', 'insmod', module], self._logger,
- 'Insmod module \'%s\'...' % module, True)
- else:
- tasks.run_task(['sudo', 'modprobe', module], self._logger,
- 'Modprobe module \'%s\'...' % module, True)
- _LOGGER.info("Inserted Module %s", module)
- self._modules.append(module)
- except subprocess.CalledProcessError:
- self._logger.error('Unable to insert module \'%s\'.', module)
- raise # fail catastrophically
+ def insert_modules(self, modules):
+ """Method inserts list of modules.
- def insert_module_group(self, module_group, group_path_prefix):
+ :param modules: a list of modules to be inserted
+ """
+ for module in modules:
+ self.insert_module(module)
+
+ def insert_module_group(self, module_group, path_prefix):
"""Ensure all modules in a group are inserted into the system.
:param module_group: A name of configuration item containing a list
- of module names
+ of module names
+ :param path_prefix: A name of directory which contains given
+ group of modules
+ """
+ for (path_suffix, module) in module_group:
+ self.insert_module(os.path.join(path_prefix, path_suffix, '%s.ko' % module))
+
+ def remove_module(self, module):
+ """Removes a single module.
+
+ :param module: a name of kernel module
"""
- for module in module_group:
- # first check if module is loaded
- if self.is_module_inserted(module[1]):
- continue
+ if self.is_module_inserted(module):
+ # get module base name, i.e strip path and .ko suffix if possible
+ module_base_name = os.path.basename(os.path.splitext(module)[0])
try:
- mod_path = os.path.join(group_path_prefix, module[0],
- '%s.ko' % module[1])
- tasks.run_task(['sudo', 'insmod', mod_path], _LOGGER,
- 'Inserting module \'%s\'...' % module[1], True)
- self._modules.append(module)
+ self._logger.info('Removing module \'%s\'...', module_base_name)
+ subprocess.check_call('sudo rmmod {}'.format(module_base_name),
+ shell=True, stderr=subprocess.DEVNULL)
+ # in case that module was loaded automatically by modprobe
+ # to solve dependecies, then it is not in internal list of modules
+ if module in self._modules:
+ self._modules.remove(module)
except subprocess.CalledProcessError:
- _LOGGER.error('Unable to insert module \'%s\'.', module[1])
- raise # fail catastrophically
+ # in case of error, show full module name...
+ self._logger.info('Unable to remove module \'%s\'.', module)
+ # ...and list of dependend modules, if there are any
+ module_details = self.get_module_details(module_base_name)
+ if module_details:
+ mod_dep = module_details.split(' ')[3].rstrip(',')
+ if mod_dep[0] != '-':
+ self._logger.debug('Module \'%s\' is used by module(s) \'%s\'.',
+ module_base_name, mod_dep)
def remove_modules(self):
"""Removes all modules that have been previously inserted.
"""
- for module in self._modules:
- # first check if module is loaded
- if not self.is_module_inserted(module):
- continue
+ # remove modules in reverse order to respect their dependencies
+ for module in reversed(self._modules):
+ self.remove_module(module)
- try:
- # rmmod supports both simple module name and full module path
- # with .ko suffix
- tasks.run_task(['sudo', 'rmmod', module], self._logger,
- 'Removing module \'%s\'...' % module, True)
- self._modules.remove(module)
- except subprocess.CalledProcessError:
- self._logger.error('Unable to remove module \'%s\'.', module)
- continue
- @staticmethod
- def is_module_inserted(module):
+ def is_module_inserted(self, module):
"""Check if a module is inserted on system.
+
+ :param module: a name of kernel module
"""
- if module.endswith('.ko'):
- # get module base name, i.e strip path and .ko suffix if possible
- module_base_name = os.path.basename(os.path.splitext(module)[0])
- else:
- module_base_name = module
+ module_base_name = os.path.basename(os.path.splitext(module)[0])
+
+ return self.get_module_details(module_base_name) != None
+
+ @staticmethod
+ def get_module_details(module):
+ """Return details about given module
+ :param module: a name of kernel module
+ :returns: In case that module is loaded in OS, then corresponding
+ line from /proc/modules will be returned. Otherwise it returns None.
+ """
# get list of modules from kernel
with open('/proc/modules') as mod_file:
loaded_mods = mod_file.readlines()
- # first check if module is loaded
+ # check if module is loaded
for line in loaded_mods:
- if line.startswith(module_base_name):
- return True
- return False
+ # underscores '_' and dashes '-' in module names are interchangeable, so we
+ # have to normalize module names before comparision
+ if line.split(' ')[0].replace('-', '_') == module.replace('-', '_'):
+ return line
- def remove_module(self, module):
- """Removes a single module.
- """
- if self.is_module_inserted(module):
- # get module base name, i.e strip path and .ko suffix if possible
- module_base_name = os.path.basename(os.path.splitext(module)[0])
-
- try:
- # rmmod supports both simple module name and full module path
- # with .ko suffix
- tasks.run_task(['sudo', 'rmmod', module_base_name], self._logger,
- 'Removing module \'%s\'...' % module, True)
- self._modules.remove(module)
- except subprocess.CalledProcessError:
- self._logger.error('Unable to remove module \'%s\'.', module_base_name)
-
- def remove_module_group(self, module_group):
- """Removes all modules in the modules group.
- """
- for module in module_group:
- if not self.is_module_inserted(module[1]):
- continue
- # get module base name, i.e strip path and .ko suffix if possible
- module_base_name = os.path.basename(os.path.splitext(module)[0])
-
- try:
- # rmmod supports both simple module name and full module path
- # with .ko suffix
- tasks.run_task(['sudo', 'rmmod', module_base_name], self._logger,
- 'Removing module \'%s\'...' % module, True)
- self._modules.remove(module)
- except subprocess.CalledProcessError:
- self._logger.error('Unable to remove module \'%s\'.', module_base_name)
+ return None