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