X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/ad8b2f9b43ab684af680cd93b1f64061d49bc051..95075fba4aa1e1cb404f44b1027f86e8b03a0a88:/lib/ssconf.py diff --git a/lib/ssconf.py b/lib/ssconf.py index 94cab4d..582564a 100644 --- a/lib/ssconf.py +++ b/lib/ssconf.py @@ -28,11 +28,13 @@ configuration data, which is mostly static and available to all nodes. import sys import re +import os from ganeti import errors from ganeti import constants from ganeti import utils from ganeti import serializer +from ganeti import objects SSCONF_LOCK_TIMEOUT = 10 @@ -52,21 +54,77 @@ class SimpleConfigReader(object): """ self._file_name = file_name - self._Load() + self._last_inode = None + self._last_mtime = None + self._last_size = None + # we need a forced reload at class init time, to initialize _last_* + self._Load(force=True) - def _Load(self): + def _Load(self, force=False): """Loads (or reloads) the config file. + @type force: boolean + @param force: whether to force the reload without checking the mtime + @rtype: boolean + @return: boolean value that says whether we reloaded the configuration or + not (because we decided it was already up-to-date) + """ try: + cfg_stat = os.stat(self._file_name) + except EnvironmentError, err: + raise errors.ConfigurationError("Cannot stat config file %s: %s" % + (self._file_name, err)) + inode = cfg_stat.st_ino + mtime = cfg_stat.st_mtime + size = cfg_stat.st_size + + reload = False + if force or inode != self._last_inode or \ + mtime > self._last_mtime or \ + size != self._last_size: + self._last_inode = inode + self._last_mtime = mtime + self._last_size = size + reload = True + + if not reload: + return False + + try: self._config_data = serializer.Load(utils.ReadFile(self._file_name)) - except IOError, err: + except EnvironmentError, err: raise errors.ConfigurationError("Cannot read config file %s: %s" % (self._file_name, err)) except ValueError, err: raise errors.ConfigurationError("Cannot load config file %s: %s" % (self._file_name, err)) + self._ip_to_instance = {} + self._instances_ips = [] + self._inst_ips_by_link = {} + c_nparams = self._config_data['cluster']['nicparams'][constants.PP_DEFAULT] + for iname in self._config_data['instances']: + instance = self._config_data['instances'][iname] + for nic in instance['nics']: + if 'ip' in nic and nic['ip']: + self._instances_ips.append(nic['ip']) + self._ip_to_instance[nic['ip']] = iname + params = objects.FillDict(c_nparams, nic['nicparams']) + if not params['link'] in self._inst_ips_by_link: + self._inst_ips_by_link[params['link']] = [] + self._inst_ips_by_link[params['link']].append(nic['ip']) + + self._nodes_primary_ips = [] + self._mc_primary_ips = [] + for node_name in self._config_data["nodes"]: + node = self._config_data["nodes"][node_name] + self._nodes_primary_ips.append(node["primary_ip"]) + if node["master_candidate"]: + self._mc_primary_ips.append(node["primary_ip"]) + + return True + # Clients can request a reload of the config file, so we export our internal # _Load function as Reload. Reload = _Load @@ -89,9 +147,6 @@ class SimpleConfigReader(object): def GetFileStorageDir(self): return self._config_data["cluster"]["file_storage_dir"] - def GetHypervisorType(self): - return self._config_data["cluster"]["hypervisor"] - def GetNodeList(self): return self._config_data["nodes"].keys() @@ -101,6 +156,68 @@ class SimpleConfigReader(object): def GetClusterSerialNo(self): return self._config_data["cluster"]["serial_no"] + def GetNodeStatusFlags(self, node): + """Get a node's status flags + + @type node: string + @param node: node name + @rtype: (bool, bool, bool) + @return: (master_candidate, drained, offline) (or None if no such node) + + """ + if node not in self._config_data["nodes"]: + return None + + master_candidate = self._config_data["nodes"][node]["master_candidate"] + drained = self._config_data["nodes"][node]["drained"] + offline = self._config_data["nodes"][node]["offline"] + return master_candidate, drained, offline + + def GetInstanceByIp(self, ip): + if ip not in self._ip_to_instance: + return None + return self._ip_to_instance[ip] + + def GetNodePrimaryIp(self, node): + """Get a node's primary ip + + @type node: string + @param node: node name + @rtype: string, or None + @return: node's primary ip, or None if no such node + + """ + if node not in self._config_data["nodes"]: + return None + return self._config_data["nodes"][node]["primary_ip"] + + def GetInstancePrimaryNode(self, instance): + """Get an instance's primary node + + @type instance: string + @param instance: instance name + @rtype: string, or None + @return: primary node, or None if no such instance + + """ + if instance not in self._config_data["instances"]: + return None + return self._config_data["instances"][instance]["primary_node"] + + def GetNodesPrimaryIps(self): + return self._nodes_primary_ips + + def GetMasterCandidatesPrimaryIps(self): + return self._mc_primary_ips + + def GetInstancesIps(self, link): + if link is None: + return self._instances_ips + if link in self._inst_ips_by_link: + return self._inst_ips_by_link[link] + else: + return [] + class SimpleStore(object): """Interface to static cluster data.