import tempfile
import random
import logging
+import time
from ganeti import errors
from ganeti import locking
data = self._config_data
seen_lids = []
seen_pids = []
+
+ # global cluster checks
+ if not data.cluster.enabled_hypervisors:
+ result.append("enabled hypervisors list doesn't have any entries")
+ invalid_hvs = set(data.cluster.enabled_hypervisors) - constants.HYPER_TYPES
+ if invalid_hvs:
+ result.append("enabled hypervisors contains invalid entries: %s" %
+ invalid_hvs)
+
+ if data.cluster.master_node not in data.nodes:
+ result.append("cluster has invalid primary node '%s'" %
+ data.cluster.master_node)
+
+ # per-instance checks
for instance_name in data.instances:
instance = data.instances[instance_name]
if instance.primary_node not in data.nodes:
"""Get the hypervisor type for this cluster.
"""
- return self._config_data.cluster.default_hypervisor
+ return self._config_data.cluster.enabled_hypervisors[0]
@locking.ssynchronized(_config_lock, shared=1)
def GetHostKey(self):
" MAC address '%s' already in use." % (instance.name, nic.mac))
instance.serial_no = 1
+ instance.ctime = instance.mtime = time.time()
self._config_data.instances[instance.name] = instance
self._config_data.cluster.serial_no += 1
self._UnlockedReleaseDRBDMinors(instance.name)
if instance.admin_up != status:
instance.admin_up = status
instance.serial_no += 1
+ instance.mtime = time.time()
self._WriteConfig()
@locking.ssynchronized(_config_lock)
logging.info("Adding node %s to configuration" % node.name)
node.serial_no = 1
+ node.ctime = node.mtime = time.time()
self._config_data.nodes[node.name] = node
self._config_data.cluster.serial_no += 1
self._WriteConfig()
"""
self._config_data.serial_no += 1
+ self._config_data.mtime = time.time()
def _OpenConfig(self):
"""Read the config data from disk.
"""
- f = open(self._cfg_file, 'r')
+ raw_data = utils.ReadFile(self._cfg_file)
+
try:
- try:
- data = objects.ConfigData.FromDict(serializer.Load(f.read()))
- except Exception, err:
- raise errors.ConfigurationError(err)
- finally:
- f.close()
+ data = objects.ConfigData.FromDict(serializer.Load(raw_data))
+ except Exception, err:
+ raise errors.ConfigurationError(err)
# Make sure the configuration has the right version
_ValidateConfig(data)
result = rpc.RpcRunner.call_upload_file(node_list, self._cfg_file,
address_list=addr_list)
- for node in node_list:
- if not result[node]:
- logging.error("copy of file %s to node %s failed",
- self._cfg_file, node)
+ for to_node, to_result in result.items():
+ msg = to_result.fail_msg
+ if msg:
+ msg = ("Copy of file %s to node %s failed: %s" %
+ (self._cfg_file, to_node, msg))
+ logging.error(msg)
bad = True
return not bad
destination = self._cfg_file
self._BumpSerialNo()
txt = serializer.Dump(self._config_data.ToDict())
- dir_name, file_name = os.path.split(destination)
- fd, name = tempfile.mkstemp('.newconfig', file_name, dir_name)
- f = os.fdopen(fd, 'w')
- try:
- f.write(txt)
- os.fsync(f.fileno())
- finally:
- f.close()
- # we don't need to do os.close(fd) as f.close() did it
- os.rename(name, destination)
+
+ utils.WriteFile(destination, data=txt)
+
self.write_count += 1
# and redistribute the config file to master candidates
# Write ssconf files on all nodes (including locally)
if self._last_cluster_serial < self._config_data.cluster.serial_no:
if not self._offline:
- rpc.RpcRunner.call_write_ssconf_files(self._UnlockedGetNodeList(),
- self._UnlockedGetSsconfValues())
+ result = rpc.RpcRunner.call_write_ssconf_files(\
+ self._UnlockedGetNodeList(),
+ self._UnlockedGetSsconfValues())
+ for nname, nresu in result.items():
+ msg = nresu.fail_msg
+ if msg:
+ logging.warning("Error while uploading ssconf files to"
+ " node %s: %s", nname, msg)
self._last_cluster_serial = self._config_data.cluster.serial_no
def _UnlockedGetSsconfValues(self):
instance_names = utils.NiceSort(self._UnlockedGetInstanceList())
node_names = utils.NiceSort(self._UnlockedGetNodeList())
node_info = [self._UnlockedGetNodeInfo(name) for name in node_names]
+ node_pri_ips = ["%s %s" % (ninfo.name, ninfo.primary_ip)
+ for ninfo in node_info]
+ node_snd_ips = ["%s %s" % (ninfo.name, ninfo.secondary_ip)
+ for ninfo in node_info]
instance_data = fn(instance_names)
off_data = fn(node.name for node in node_info if node.offline)
on_data = fn(node.name for node in node_info if not node.offline)
mc_data = fn(node.name for node in node_info if node.master_candidate)
+ mc_ips_data = fn(node.primary_ip for node in node_info
+ if node.master_candidate)
node_data = fn(node_names)
+ node_pri_ips_data = fn(node_pri_ips)
+ node_snd_ips_data = fn(node_snd_ips)
cluster = self._config_data.cluster
cluster_tags = fn(cluster.GetTags())
constants.SS_CLUSTER_TAGS: cluster_tags,
constants.SS_FILE_STORAGE_DIR: cluster.file_storage_dir,
constants.SS_MASTER_CANDIDATES: mc_data,
+ constants.SS_MASTER_CANDIDATES_IPS: mc_ips_data,
constants.SS_MASTER_IP: cluster.master_ip,
constants.SS_MASTER_NETDEV: cluster.master_netdev,
constants.SS_MASTER_NODE: cluster.master_node,
constants.SS_NODE_LIST: node_data,
+ constants.SS_NODE_PRIMARY_IPS: node_pri_ips_data,
+ constants.SS_NODE_SECONDARY_IPS: node_snd_ips_data,
constants.SS_OFFLINE_NODES: off_data,
constants.SS_ONLINE_NODES: on_data,
constants.SS_INSTANCE_LIST: instance_data,
self._WriteConfig()
@locking.ssynchronized(_config_lock, shared=1)
- def GetDefBridge(self):
- """Return the default bridge.
-
- """
- return self._config_data.cluster.default_bridge
-
- @locking.ssynchronized(_config_lock, shared=1)
def GetMACPrefix(self):
"""Return the mac prefix.
raise errors.ConfigurationError("Configuration updated since object"
" has been read or unknown object")
target.serial_no += 1
+ target.mtime = now = time.time()
if update_serial:
# for node updates, we need to increase the cluster serial too
self._config_data.cluster.serial_no += 1
+ self._config_data.cluster.mtime = now
if isinstance(target, objects.Instance):
self._UnlockedReleaseDRBDMinors(target.name)