""" Wrapper around ConfigParser to manage testcases configuration. @author rsalveti@linux.vnet.ibm.com (Ricardo Salveti de Araujo) """ from ConfigParser import ConfigParser from StringIO import StringIO from os import path import types, re, string from autotest_lib.client.common_lib import utils __all__ = ['config_loader'] class config_loader: """ Base class of the configuration parser """ def __init__(self, cfg, tmpdir='/tmp', raise_errors=False): """ Instantiate ConfigParser and provide the file like object that we'll use to read configuration data from. @param cfg: Where we'll get configuration data. It can be either: * A URL containing the file * A valid file path inside the filesystem * A string containing configuration data @param tmpdir: Where we'll dump the temporary conf files. @param raise_errors: Whether config value absences will raise ValueError exceptions. """ # Base Parser self.parser = ConfigParser() # Raise errors when lacking values self.raise_errors = raise_errors # File is already a file like object if hasattr(cfg, 'read'): self.cfg = cfg self.parser.readfp(self.cfg) elif isinstance(cfg, types.StringTypes): # Config file is a URL. Download it to a temp dir if cfg.startswith('http') or cfg.startswith('ftp'): self.cfg = path.join(tmpdir, path.basename(cfg)) utils.urlretrieve(cfg, self.cfg) self.parser.read(self.cfg) # Config is a valid filesystem path to a file. elif path.exists(path.abspath(cfg)): if path.isfile(cfg): self.cfg = path.abspath(cfg) self.parser.read(self.cfg) else: e_msg = 'Invalid config file path: %s' % cfg raise IOError(e_msg) # Config file is just a string, convert it to a python file like # object using StringIO else: self.cfg = StringIO(cfg) self.parser.readfp(self.cfg) def get(self, section, option, default=None): """ Get the value of a option. Section of the config file and the option name. You can pass a default value if the option doesn't exist. @param section: Configuration file section. @param option: Option we're looking after. @default: In case the option is not available and raise_errors is set to False, return the default. """ if not self.parser.has_option(section, option): if self.raise_errors: raise ValueError('No value for option %s. Please check your ' 'config file "%s".' % (option, self.cfg)) else: return default return self.parser.get(section, option) def set(self, section, option, value): """ Set an option. This change is not persistent unless saved with 'save()'. """ if not self.parser.has_section(section): self.parser.add_section(section) return self.parser.set(section, option, value) def remove(self, section, option): """ Remove an option. """ if self.parser.has_section(section): self.parser.remove_option(section, option) def save(self): """ Save the configuration file with all modifications """ if not self.cfg: return fileobj = file(self.cfg, 'w') try: self.parser.write(fileobj) finally: fileobj.close() def check(self, section): """ Check if the config file has valid values """ if not self.parser.has_section(section): return False, "Section not found: %s"%(section) options = self.parser.items(section) for i in range(options.__len__()): param = options[i][0] aux = string.split(param, '.') if aux.__len__ < 2: return False, "Invalid parameter syntax at %s"%(param) if not self.check_parameter(aux[0], options[i][1]): return False, "Invalid value at %s"%(param) return True, None def check_parameter(self, param_type, parameter): """ Check if a option has a valid value """ if parameter == '' or parameter == None: return False elif param_type == "ip" and self.__isipaddress(parameter): return True elif param_type == "int" and self.__isint(parameter): return True elif param_type == "float" and self.__isfloat(parameter): return True elif param_type == "str" and self.__isstr(parameter): return True return False def __isipaddress(self, parameter): """ Verify if the ip address is valid @param ip String: IP Address @return True if a valid IP Address or False """ octet1 = "([1-9][0-9]{,1}|1[0-9]{2}|2[0-4][0-9]|25[0-5])" octet = "([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])" pattern = "^" + octet1 + "\.(" + octet + "\.){2}" + octet + "$" if re.match(pattern, parameter) == None: return False else: return True def __isint(self, parameter): try: int(parameter) except Exception, e_stack: return False return True def __isfloat(self, parameter): try: float(parameter) except Exception, e_stack: return False return True def __isstr(self, parameter): try: str(parameter) except Exception, e_stack: return False return True