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