X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/03d1dba21dc2ebd55c4a7b7e3d8eeff15ac5597a..5420ffc91f71c548233fc346b535df97f8606697:/lib/ssconf.py diff --git a/lib/ssconf.py b/lib/ssconf.py index 9165f12..cce1141 100644 --- a/lib/ssconf.py +++ b/lib/ssconf.py @@ -112,31 +112,143 @@ class SimpleConfigWriter(SimpleConfigReader): mode=0600) -def _SsconfPath(name): - if not RE_VALID_SSCONF_NAME.match(name): - raise errors.ParameterError("Invalid ssconf name: %s" % name) - return "%s/ssconf_%s" % (constants.DATA_DIR, name) +class SimpleStore(object): + """Interface to static cluster data. + This is different that the config.ConfigWriter and + SimpleConfigReader classes in that it holds data that will always be + present, even on nodes which don't have all the cluster data. -def WriteSsconfFiles(values): - """Writes legacy ssconf files to be used by external scripts. - - @type values: dict - @param values: Dictionary of (name, value) + Other particularities of the datastore: + - keys are restricted to predefined values """ - ssconf_lock = utils.FileLock(constants.SSCONF_LOCK_FILE) + _SS_FILEPREFIX = "ssconf_" + _VALID_KEYS = ( + constants.SS_CLUSTER_NAME, + constants.SS_CLUSTER_TAGS, + constants.SS_FILE_STORAGE_DIR, + constants.SS_MASTER_CANDIDATES, + constants.SS_MASTER_IP, + constants.SS_MASTER_NETDEV, + constants.SS_MASTER_NODE, + constants.SS_NODE_LIST, + constants.SS_OFFLINE_NODES, + constants.SS_ONLINE_NODES, + constants.SS_INSTANCE_LIST, + constants.SS_RELEASE_VERSION, + ) + _MAX_SIZE = 131072 + + def __init__(self, cfg_location=None): + if cfg_location is None: + self._cfg_dir = constants.DATA_DIR + else: + self._cfg_dir = cfg_location + + def KeyToFilename(self, key): + """Convert a given key into filename. - # Get lock while writing files - ssconf_lock.Exclusive(blocking=True, timeout=SSCONF_LOCK_TIMEOUT) - try: - for name, value in values.iteritems(): - if not value.endswith("\n"): - value += "\n" - utils.WriteFile(_SsconfPath(name), - data=value) - finally: - ssconf_lock.Unlock() + """ + if key not in self._VALID_KEYS: + raise errors.ProgrammerError("Invalid key requested from SSConf: '%s'" + % str(key)) + + filename = self._cfg_dir + '/' + self._SS_FILEPREFIX + key + return filename + + def _ReadFile(self, key): + """Generic routine to read keys. + + This will read the file which holds the value requested. Errors + will be changed into ConfigurationErrors. + + """ + filename = self.KeyToFilename(key) + try: + fh = file(filename, 'r') + try: + data = fh.read(self._MAX_SIZE) + data = data.rstrip('\n') + finally: + fh.close() + except EnvironmentError, err: + raise errors.ConfigurationError("Can't read from the ssconf file:" + " '%s'" % str(err)) + return data + + def WriteFiles(self, values): + """Writes ssconf files used by external scripts. + + @type values: dict + @param values: Dictionary of (name, value) + + """ + ssconf_lock = utils.FileLock(constants.SSCONF_LOCK_FILE) + + # Get lock while writing files + ssconf_lock.Exclusive(blocking=True, timeout=SSCONF_LOCK_TIMEOUT) + try: + for name, value in values.iteritems(): + if value and not value.endswith("\n"): + value += "\n" + utils.WriteFile(self.KeyToFilename(name), data=value, mode=0444) + finally: + ssconf_lock.Unlock() + + def GetFileList(self): + """Return the list of all config files. + + This is used for computing node replication data. + + """ + return [self.KeyToFilename(key) for key in self._VALID_KEYS] + + def GetClusterName(self): + """Get the cluster name. + + """ + return self._ReadFile(constants.SS_CLUSTER_NAME) + + def GetFileStorageDir(self): + """Get the file storage dir. + + """ + return self._ReadFile(constants.SS_FILE_STORAGE_DIR) + + def GetMasterCandidates(self): + """Return the list of master candidates. + + """ + data = self._ReadFile(constants.SS_MASTER_CANDIDATES) + nl = data.splitlines(False) + return nl + + def GetMasterIP(self): + """Get the IP of the master node for this cluster. + + """ + return self._ReadFile(constants.SS_MASTER_IP) + + def GetMasterNetdev(self): + """Get the netdev to which we'll add the master ip. + + """ + return self._ReadFile(constants.SS_MASTER_NETDEV) + + def GetMasterNode(self): + """Get the hostname of the master node for this cluster. + + """ + return self._ReadFile(constants.SS_MASTER_NODE) + + def GetNodeList(self): + """Return the list of cluster nodes. + + """ + data = self._ReadFile(constants.SS_NODE_LIST) + nl = data.splitlines(False) + return nl def GetMasterAndMyself(ss=None): @@ -148,9 +260,14 @@ def GetMasterAndMyself(ss=None): The function does not handle any errors, these should be handled in the caller (errors.ConfigurationError, errors.ResolverError). + @param ss: either a sstore.SimpleConfigReader or a + sstore.SimpleStore instance + @rtype: tuple + @return: a tuple (master node name, my own name) + """ if ss is None: - ss = SimpleConfigReader() + ss = SimpleStore() return ss.GetMasterNode(), utils.HostInfo().name