1*9c5db199SXin Li# Lint as: python2, python3 2*9c5db199SXin Li""" 3*9c5db199SXin LiWrapper around ConfigParser to manage testcases configuration. 4*9c5db199SXin Li 5*9c5db199SXin Li@author [email protected] (Ricardo Salveti de Araujo) 6*9c5db199SXin Li""" 7*9c5db199SXin Li 8*9c5db199SXin Lifrom __future__ import absolute_import 9*9c5db199SXin Lifrom __future__ import division 10*9c5db199SXin Lifrom __future__ import print_function 11*9c5db199SXin Lifrom six.moves.configparser import ConfigParser 12*9c5db199SXin Lifrom six.moves import range 13*9c5db199SXin Lifrom six import StringIO 14*9c5db199SXin Lifrom os import path 15*9c5db199SXin Liimport re, six, string 16*9c5db199SXin Lifrom autotest_lib.client.common_lib import utils 17*9c5db199SXin Li 18*9c5db199SXin Li__all__ = ['config_loader'] 19*9c5db199SXin Li 20*9c5db199SXin Liclass config_loader: 21*9c5db199SXin Li """ 22*9c5db199SXin Li Base class of the configuration parser 23*9c5db199SXin Li """ 24*9c5db199SXin Li def __init__(self, cfg, tmpdir='/tmp', raise_errors=False): 25*9c5db199SXin Li """ 26*9c5db199SXin Li Instantiate ConfigParser and provide the file like object that we'll 27*9c5db199SXin Li use to read configuration data from. 28*9c5db199SXin Li @param cfg: Where we'll get configuration data. It can be either: 29*9c5db199SXin Li * A URL containing the file 30*9c5db199SXin Li * A valid file path inside the filesystem 31*9c5db199SXin Li * A string containing configuration data 32*9c5db199SXin Li @param tmpdir: Where we'll dump the temporary conf files. 33*9c5db199SXin Li @param raise_errors: Whether config value absences will raise 34*9c5db199SXin Li ValueError exceptions. 35*9c5db199SXin Li """ 36*9c5db199SXin Li # Base Parser 37*9c5db199SXin Li self.parser = ConfigParser() 38*9c5db199SXin Li # Raise errors when lacking values 39*9c5db199SXin Li self.raise_errors = raise_errors 40*9c5db199SXin Li # File is already a file like object 41*9c5db199SXin Li if hasattr(cfg, 'read'): 42*9c5db199SXin Li self.cfg = cfg 43*9c5db199SXin Li self.parser.readfp(self.cfg) 44*9c5db199SXin Li elif isinstance(cfg, six.string_types): 45*9c5db199SXin Li # Config file is a URL. Download it to a temp dir 46*9c5db199SXin Li if cfg.startswith('http') or cfg.startswith('ftp'): 47*9c5db199SXin Li self.cfg = path.join(tmpdir, path.basename(cfg)) 48*9c5db199SXin Li utils.urlretrieve(cfg, self.cfg) 49*9c5db199SXin Li self.parser.read(self.cfg) 50*9c5db199SXin Li # Config is a valid filesystem path to a file. 51*9c5db199SXin Li elif path.exists(path.abspath(cfg)): 52*9c5db199SXin Li if path.isfile(cfg): 53*9c5db199SXin Li self.cfg = path.abspath(cfg) 54*9c5db199SXin Li self.parser.read(self.cfg) 55*9c5db199SXin Li else: 56*9c5db199SXin Li e_msg = 'Invalid config file path: %s' % cfg 57*9c5db199SXin Li raise IOError(e_msg) 58*9c5db199SXin Li # Config file is just a string, convert it to a python file like 59*9c5db199SXin Li # object using StringIO 60*9c5db199SXin Li else: 61*9c5db199SXin Li self.cfg = StringIO(cfg) 62*9c5db199SXin Li self.parser.readfp(self.cfg) 63*9c5db199SXin Li 64*9c5db199SXin Li 65*9c5db199SXin Li def get(self, section, option, default=None): 66*9c5db199SXin Li """ 67*9c5db199SXin Li Get the value of a option. 68*9c5db199SXin Li 69*9c5db199SXin Li Section of the config file and the option name. 70*9c5db199SXin Li You can pass a default value if the option doesn't exist. 71*9c5db199SXin Li 72*9c5db199SXin Li @param section: Configuration file section. 73*9c5db199SXin Li @param option: Option we're looking after. 74*9c5db199SXin Li @default: In case the option is not available and raise_errors is set 75*9c5db199SXin Li to False, return the default. 76*9c5db199SXin Li """ 77*9c5db199SXin Li if not self.parser.has_option(section, option): 78*9c5db199SXin Li if self.raise_errors: 79*9c5db199SXin Li raise ValueError('No value for option %s. Please check your ' 80*9c5db199SXin Li 'config file "%s".' % (option, self.cfg)) 81*9c5db199SXin Li else: 82*9c5db199SXin Li return default 83*9c5db199SXin Li 84*9c5db199SXin Li return self.parser.get(section, option) 85*9c5db199SXin Li 86*9c5db199SXin Li 87*9c5db199SXin Li def set(self, section, option, value): 88*9c5db199SXin Li """ 89*9c5db199SXin Li Set an option. 90*9c5db199SXin Li 91*9c5db199SXin Li This change is not persistent unless saved with 'save()'. 92*9c5db199SXin Li """ 93*9c5db199SXin Li if not self.parser.has_section(section): 94*9c5db199SXin Li self.parser.add_section(section) 95*9c5db199SXin Li return self.parser.set(section, option, value) 96*9c5db199SXin Li 97*9c5db199SXin Li 98*9c5db199SXin Li def remove(self, section, option): 99*9c5db199SXin Li """ 100*9c5db199SXin Li Remove an option. 101*9c5db199SXin Li """ 102*9c5db199SXin Li if self.parser.has_section(section): 103*9c5db199SXin Li self.parser.remove_option(section, option) 104*9c5db199SXin Li 105*9c5db199SXin Li 106*9c5db199SXin Li def save(self): 107*9c5db199SXin Li """ 108*9c5db199SXin Li Save the configuration file with all modifications 109*9c5db199SXin Li """ 110*9c5db199SXin Li if not self.cfg: 111*9c5db199SXin Li return 112*9c5db199SXin Li fileobj = open(self.cfg, 'w') 113*9c5db199SXin Li try: 114*9c5db199SXin Li self.parser.write(fileobj) 115*9c5db199SXin Li finally: 116*9c5db199SXin Li fileobj.close() 117*9c5db199SXin Li 118*9c5db199SXin Li 119*9c5db199SXin Li def check(self, section): 120*9c5db199SXin Li """ 121*9c5db199SXin Li Check if the config file has valid values 122*9c5db199SXin Li """ 123*9c5db199SXin Li if not self.parser.has_section(section): 124*9c5db199SXin Li return False, "Section not found: %s"%(section) 125*9c5db199SXin Li 126*9c5db199SXin Li options = self.parser.items(section) 127*9c5db199SXin Li for i in range(options.__len__()): 128*9c5db199SXin Li param = options[i][0] 129*9c5db199SXin Li aux = string.split(param, '.') 130*9c5db199SXin Li 131*9c5db199SXin Li if aux.__len__ < 2: 132*9c5db199SXin Li return False, "Invalid parameter syntax at %s"%(param) 133*9c5db199SXin Li 134*9c5db199SXin Li if not self.check_parameter(aux[0], options[i][1]): 135*9c5db199SXin Li return False, "Invalid value at %s"%(param) 136*9c5db199SXin Li 137*9c5db199SXin Li return True, None 138*9c5db199SXin Li 139*9c5db199SXin Li 140*9c5db199SXin Li def check_parameter(self, param_type, parameter): 141*9c5db199SXin Li """ 142*9c5db199SXin Li Check if a option has a valid value 143*9c5db199SXin Li """ 144*9c5db199SXin Li if parameter == '' or parameter == None: 145*9c5db199SXin Li return False 146*9c5db199SXin Li elif param_type == "ip" and self.__isipaddress(parameter): 147*9c5db199SXin Li return True 148*9c5db199SXin Li elif param_type == "int" and self.__isint(parameter): 149*9c5db199SXin Li return True 150*9c5db199SXin Li elif param_type == "float" and self.__isfloat(parameter): 151*9c5db199SXin Li return True 152*9c5db199SXin Li elif param_type == "str" and self.__isstr(parameter): 153*9c5db199SXin Li return True 154*9c5db199SXin Li 155*9c5db199SXin Li return False 156*9c5db199SXin Li 157*9c5db199SXin Li 158*9c5db199SXin Li def __isipaddress(self, parameter): 159*9c5db199SXin Li """ 160*9c5db199SXin Li Verify if the ip address is valid 161*9c5db199SXin Li 162*9c5db199SXin Li @param ip String: IP Address 163*9c5db199SXin Li @return True if a valid IP Address or False 164*9c5db199SXin Li """ 165*9c5db199SXin Li octet1 = "([1-9][0-9]{,1}|1[0-9]{2}|2[0-4][0-9]|25[0-5])" 166*9c5db199SXin Li octet = "([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])" 167*9c5db199SXin Li pattern = "^" + octet1 + "\.(" + octet + "\.){2}" + octet + "$" 168*9c5db199SXin Li if re.match(pattern, parameter) == None: 169*9c5db199SXin Li return False 170*9c5db199SXin Li else: 171*9c5db199SXin Li return True 172*9c5db199SXin Li 173*9c5db199SXin Li 174*9c5db199SXin Li def __isint(self, parameter): 175*9c5db199SXin Li try: 176*9c5db199SXin Li int(parameter) 177*9c5db199SXin Li except Exception as e_stack: 178*9c5db199SXin Li return False 179*9c5db199SXin Li return True 180*9c5db199SXin Li 181*9c5db199SXin Li 182*9c5db199SXin Li def __isfloat(self, parameter): 183*9c5db199SXin Li try: 184*9c5db199SXin Li float(parameter) 185*9c5db199SXin Li except Exception as e_stack: 186*9c5db199SXin Li return False 187*9c5db199SXin Li return True 188*9c5db199SXin Li 189*9c5db199SXin Li 190*9c5db199SXin Li def __isstr(self, parameter): 191*9c5db199SXin Li try: 192*9c5db199SXin Li str(parameter) 193*9c5db199SXin Li except Exception as e_stack: 194*9c5db199SXin Li return False 195*9c5db199SXin Li return True 196