global_config.py revision 88434b12bf2c38f1099c0307b0313fe3f379364b
1ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mbligh"""A singleton class for accessing global config values 2ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mbligh 3ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mblighprovides access to global configuration file 4ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mbligh""" 5ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mbligh 6ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mbligh__author__ = 'raphtee@google.com (Travis Miller)' 7ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mbligh 8da8fb97be0353f54eb7e62e132482d728684f200lmrimport os, sys, ConfigParser, logging 911788296e58691a3149355a4fc4a3fa1084c689dmblighfrom autotest_lib.client.common_lib import error 10ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mbligh 11104e9ce7a74041fd673ceac5c8b0bc67c74edcd5mbligh 12ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mblighclass ConfigError(error.AutotestError): 130afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski pass 14ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mbligh 15ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mbligh 16104e9ce7a74041fd673ceac5c8b0bc67c74edcd5mblighclass ConfigValueError(ConfigError): 170afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski pass 18104e9ce7a74041fd673ceac5c8b0bc67c74edcd5mbligh 19104e9ce7a74041fd673ceac5c8b0bc67c74edcd5mbligh 206d08b3c3fc2858ccd60a323008703179f93ae38blmr 216d08b3c3fc2858ccd60a323008703179f93ae38blmrcommon_lib_dir = os.path.dirname(sys.modules[__name__].__file__) 226d08b3c3fc2858ccd60a323008703179f93ae38blmrclient_dir = os.path.dirname(common_lib_dir) 236d08b3c3fc2858ccd60a323008703179f93ae38blmrroot_dir = os.path.dirname(client_dir) 246d08b3c3fc2858ccd60a323008703179f93ae38blmr 256d08b3c3fc2858ccd60a323008703179f93ae38blmr# Check if the config files are at autotest's root dir 266d08b3c3fc2858ccd60a323008703179f93ae38blmr# This will happen if client is executing inside a full autotest tree, or if 276d08b3c3fc2858ccd60a323008703179f93ae38blmr# other entry points are being executed 286d08b3c3fc2858ccd60a323008703179f93ae38blmrglobal_config_path_root = os.path.join(root_dir, 'global_config.ini') 296d08b3c3fc2858ccd60a323008703179f93ae38blmrshadow_config_path_root = os.path.join(root_dir, 'shadow_config.ini') 3088434b12bf2c38f1099c0307b0313fe3f379364bChris Masoneconfig_in_root = os.path.exists(global_config_path_root) 316d08b3c3fc2858ccd60a323008703179f93ae38blmr 326d08b3c3fc2858ccd60a323008703179f93ae38blmr# Check if the config files are at autotest's client dir 336d08b3c3fc2858ccd60a323008703179f93ae38blmr# This will happen if a client stand alone execution is happening 346d08b3c3fc2858ccd60a323008703179f93ae38blmrglobal_config_path_client = os.path.join(client_dir, 'global_config.ini') 356d08b3c3fc2858ccd60a323008703179f93ae38blmrconfig_in_client = os.path.exists(global_config_path_client) 366d08b3c3fc2858ccd60a323008703179f93ae38blmr 376d08b3c3fc2858ccd60a323008703179f93ae38blmrif config_in_root: 386d08b3c3fc2858ccd60a323008703179f93ae38blmr DEFAULT_CONFIG_FILE = global_config_path_root 3988434b12bf2c38f1099c0307b0313fe3f379364bChris Masone if os.path.exists(shadow_config_path_root): 4088434b12bf2c38f1099c0307b0313fe3f379364bChris Masone DEFAULT_SHADOW_FILE = shadow_config_path_root 4188434b12bf2c38f1099c0307b0313fe3f379364bChris Masone else: 4288434b12bf2c38f1099c0307b0313fe3f379364bChris Masone DEFAULT_SHADOW_FILE = None 436d08b3c3fc2858ccd60a323008703179f93ae38blmr RUNNING_STAND_ALONE_CLIENT = False 446d08b3c3fc2858ccd60a323008703179f93ae38blmrelif config_in_client: 456d08b3c3fc2858ccd60a323008703179f93ae38blmr DEFAULT_CONFIG_FILE = global_config_path_client 466d08b3c3fc2858ccd60a323008703179f93ae38blmr DEFAULT_SHADOW_FILE = None 476d08b3c3fc2858ccd60a323008703179f93ae38blmr RUNNING_STAND_ALONE_CLIENT = True 486d08b3c3fc2858ccd60a323008703179f93ae38blmrelse: 49da8fb97be0353f54eb7e62e132482d728684f200lmr DEFAULT_CONFIG_FILE = None 50da8fb97be0353f54eb7e62e132482d728684f200lmr DEFAULT_SHADOW_FILE = None 51da8fb97be0353f54eb7e62e132482d728684f200lmr RUNNING_STAND_ALONE_CLIENT = True 526d08b3c3fc2858ccd60a323008703179f93ae38blmr 53ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mblighclass global_config(object): 54893db3d528e4c7d10ef5b7073dbf63670dffbccashoward _NO_DEFAULT_SPECIFIED = object() 55893db3d528e4c7d10ef5b7073dbf63670dffbccashoward 560afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski config = None 570afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski config_file = DEFAULT_CONFIG_FILE 580afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski shadow_file = DEFAULT_SHADOW_FILE 596d08b3c3fc2858ccd60a323008703179f93ae38blmr running_stand_alone_client = RUNNING_STAND_ALONE_CLIENT 606d08b3c3fc2858ccd60a323008703179f93ae38blmr 616d08b3c3fc2858ccd60a323008703179f93ae38blmr 626d08b3c3fc2858ccd60a323008703179f93ae38blmr def check_stand_alone_client_run(self): 636d08b3c3fc2858ccd60a323008703179f93ae38blmr return self.running_stand_alone_client 640afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 650afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 660afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski def set_config_files(self, config_file=DEFAULT_CONFIG_FILE, 670afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski shadow_file=DEFAULT_SHADOW_FILE): 680afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski self.config_file = config_file 690afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski self.shadow_file = shadow_file 700afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski self.config = None 710afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 720afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 73d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward def _handle_no_value(self, section, key, default): 74893db3d528e4c7d10ef5b7073dbf63670dffbccashoward if default is self._NO_DEFAULT_SPECIFIED: 75d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward msg = ("Value '%s' not found in section '%s'" % 76d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward (key, section)) 77d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward raise ConfigError(msg) 78d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward else: 79d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward return default 80d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward 81d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward 826d08b3c3fc2858ccd60a323008703179f93ae38blmr def get_section_values(self, section): 836d08b3c3fc2858ccd60a323008703179f93ae38blmr """ 846d08b3c3fc2858ccd60a323008703179f93ae38blmr Return a config parser object containing a single section of the 856d08b3c3fc2858ccd60a323008703179f93ae38blmr global configuration, that can be later written to a file object. 866d08b3c3fc2858ccd60a323008703179f93ae38blmr 876d08b3c3fc2858ccd60a323008703179f93ae38blmr @param section: Section we want to turn into a config parser object. 886d08b3c3fc2858ccd60a323008703179f93ae38blmr @return: ConfigParser() object containing all the contents of section. 896d08b3c3fc2858ccd60a323008703179f93ae38blmr """ 906d08b3c3fc2858ccd60a323008703179f93ae38blmr cfgparser = ConfigParser.ConfigParser() 916d08b3c3fc2858ccd60a323008703179f93ae38blmr cfgparser.add_section(section) 926d08b3c3fc2858ccd60a323008703179f93ae38blmr for option, value in self.config.items(section): 936d08b3c3fc2858ccd60a323008703179f93ae38blmr cfgparser.set(section, option, value) 946d08b3c3fc2858ccd60a323008703179f93ae38blmr return cfgparser 956d08b3c3fc2858ccd60a323008703179f93ae38blmr 966d08b3c3fc2858ccd60a323008703179f93ae38blmr 97893db3d528e4c7d10ef5b7073dbf63670dffbccashoward def get_config_value(self, section, key, type=str, 98893db3d528e4c7d10ef5b7073dbf63670dffbccashoward default=_NO_DEFAULT_SPECIFIED, allow_blank=False): 9950c0e71efd37c04c5f441c7e4dd095632b54c35fshoward self._ensure_config_parsed() 1000afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 1010afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski try: 1020afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski val = self.config.get(section, key) 103d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward except ConfigParser.Error: 104d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward return self._handle_no_value(section, key, default) 105d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward 106d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward if not val.strip() and not allow_blank: 107d1ee1dd3f3e5ac44f00d7a96deb815dbe1beedadshoward return self._handle_no_value(section, key, default) 1080afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 109893db3d528e4c7d10ef5b7073dbf63670dffbccashoward return self._convert_value(key, section, val, type) 1100afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 1110afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 11250c0e71efd37c04c5f441c7e4dd095632b54c35fshoward def override_config_value(self, section, key, new_value): 11350c0e71efd37c04c5f441c7e4dd095632b54c35fshoward """ 11450c0e71efd37c04c5f441c7e4dd095632b54c35fshoward Override a value from the config file with a new value. 11550c0e71efd37c04c5f441c7e4dd095632b54c35fshoward """ 11650c0e71efd37c04c5f441c7e4dd095632b54c35fshoward self._ensure_config_parsed() 11750c0e71efd37c04c5f441c7e4dd095632b54c35fshoward self.config.set(section, key, new_value) 11850c0e71efd37c04c5f441c7e4dd095632b54c35fshoward 11950c0e71efd37c04c5f441c7e4dd095632b54c35fshoward 12050c0e71efd37c04c5f441c7e4dd095632b54c35fshoward def reset_config_values(self): 12150c0e71efd37c04c5f441c7e4dd095632b54c35fshoward """ 12250c0e71efd37c04c5f441c7e4dd095632b54c35fshoward Reset all values to those found in the config files (undoes all 12350c0e71efd37c04c5f441c7e4dd095632b54c35fshoward overrides). 12450c0e71efd37c04c5f441c7e4dd095632b54c35fshoward """ 12550c0e71efd37c04c5f441c7e4dd095632b54c35fshoward self.parse_config_file() 12650c0e71efd37c04c5f441c7e4dd095632b54c35fshoward 12750c0e71efd37c04c5f441c7e4dd095632b54c35fshoward 12850c0e71efd37c04c5f441c7e4dd095632b54c35fshoward def _ensure_config_parsed(self): 129d876f459fff6cc4994cab329b1f80c99a86edcbdmbligh if self.config is None: 13050c0e71efd37c04c5f441c7e4dd095632b54c35fshoward self.parse_config_file() 13150c0e71efd37c04c5f441c7e4dd095632b54c35fshoward 13250c0e71efd37c04c5f441c7e4dd095632b54c35fshoward 1330afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski def merge_configs(self, shadow_config): 1340afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski # overwrite whats in config with whats in shadow_config 1350afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski sections = shadow_config.sections() 1360afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski for section in sections: 1370afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski # add the section if need be 1380afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski if not self.config.has_section(section): 1390afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski self.config.add_section(section) 1400afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski # now run through all options and set them 1410afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski options = shadow_config.options(section) 1420afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski for option in options: 1430afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski val = shadow_config.get(section, option) 1440afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski self.config.set(section, option, val) 1450afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 1460afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 1470afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski def parse_config_file(self): 1480afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski self.config = ConfigParser.ConfigParser() 149da8fb97be0353f54eb7e62e132482d728684f200lmr if self.config_file and os.path.exists(self.config_file): 150da8fb97be0353f54eb7e62e132482d728684f200lmr self.config.read(self.config_file) 151da8fb97be0353f54eb7e62e132482d728684f200lmr else: 152da8fb97be0353f54eb7e62e132482d728684f200lmr raise ConfigError('%s not found' % (self.config_file)) 1530afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 1540afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski # now also read the shadow file if there is one 1550afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski # this will overwrite anything that is found in the 1560afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski # other config 1576d08b3c3fc2858ccd60a323008703179f93ae38blmr if self.shadow_file and os.path.exists(self.shadow_file): 1580afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski shadow_config = ConfigParser.ConfigParser() 1590afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski shadow_config.read(self.shadow_file) 1600afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski # now we merge shadow into global 1610afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski self.merge_configs(shadow_config) 1620afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 1630afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 1640afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski # the values that are pulled from ini 1650afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski # are strings. But we should attempt to 1660afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski # convert them to other types if needed. 167893db3d528e4c7d10ef5b7073dbf63670dffbccashoward def _convert_value(self, key, section, value, value_type): 1680afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski # strip off leading and trailing white space 1690afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski sval = value.strip() 1700afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 1710afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski # if length of string is zero then return None 1720afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski if len(sval) == 0: 173a5f30c207b211e2bf57c6d4297734da54055af90showard if value_type == str: 1740afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski return "" 175a5f30c207b211e2bf57c6d4297734da54055af90showard elif value_type == bool: 1760afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski return False 177a5f30c207b211e2bf57c6d4297734da54055af90showard elif value_type == int: 1780afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski return 0 179a5f30c207b211e2bf57c6d4297734da54055af90showard elif value_type == float: 1800afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski return 0.0 181a5f30c207b211e2bf57c6d4297734da54055af90showard elif value_type == list: 182c5ddfd1f71caef9ec0c84c53ef7db42fcdc33e1cmbligh return [] 1830afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski else: 1840afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski return None 1850afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 186a5f30c207b211e2bf57c6d4297734da54055af90showard if value_type == bool: 1870afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski if sval.lower() == "false": 1880afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski return False 1890afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski else: 1900afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski return True 1910afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 192a5f30c207b211e2bf57c6d4297734da54055af90showard if value_type == list: 193c5ddfd1f71caef9ec0c84c53ef7db42fcdc33e1cmbligh # Split the string using ',' and return a list 194c5ddfd1f71caef9ec0c84c53ef7db42fcdc33e1cmbligh return [val.strip() for val in sval.split(',')] 195c5ddfd1f71caef9ec0c84c53ef7db42fcdc33e1cmbligh 1960afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski try: 197a5f30c207b211e2bf57c6d4297734da54055af90showard conv_val = value_type(sval) 1980afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski return conv_val 1990afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski except: 200a5f30c207b211e2bf57c6d4297734da54055af90showard msg = ("Could not convert %s value %r in section %s to type %s" % 201a5f30c207b211e2bf57c6d4297734da54055af90showard (key, sval, section, value_type)) 2020afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski raise ConfigValueError(msg) 2030afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 2040afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski 2050afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski# insure the class is a singleton. Now the symbol global_config 206ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mbligh# will point to the one and only one instace of the class 207ed4d6ddc79993492b22aeeb36574b3cb7c8bad44mblighglobal_config = global_config() 208