from ganeti import constants
from ganeti import rpc
from ganeti import objects
+from ganeti import serializer
class ConfigWriter:
raise errors.ConfigurationError("Can't generate unique MAC")
return mac
+ def IsMacInUse(self, mac):
+ """Predicate: check if the specified MAC is in use in the Ganeti cluster.
+
+ This only checks instances managed by this cluster, it does not
+ check for potential collisions elsewhere.
+
+ """
+ self._OpenConfig()
+ self._ReleaseLock()
+ all_macs = self._AllMACs()
+ return mac in all_macs
+
def _ComputeAllLVs(self):
"""Compute the list of all LVs.
existing.update(exceptions)
retries = 64
while retries > 0:
- unique_id = utils.GetUUID()
+ unique_id = utils.NewUUID()
if unique_id not in existing and unique_id is not None:
break
else:
result = []
seen_macs = []
+ ports = {}
data = self._config_data
for instance_name in data.instances:
instance = data.instances[instance_name]
if instance.primary_node not in data.nodes:
- result.append("Instance '%s' has invalid primary node '%s'" %
+ result.append("instance '%s' has invalid primary node '%s'" %
(instance_name, instance.primary_node))
for snode in instance.secondary_nodes:
if snode not in data.nodes:
- result.append("Instance '%s' has invalid secondary node '%s'" %
+ result.append("instance '%s' has invalid secondary node '%s'" %
(instance_name, snode))
for idx, nic in enumerate(instance.nics):
if nic.mac in seen_macs:
- result.append("Instance '%s' has NIC %d mac %s duplicate" %
+ result.append("instance '%s' has NIC %d mac %s duplicate" %
(instance_name, idx, nic.mac))
else:
seen_macs.append(nic.mac)
+
+ # gather the drbd ports for duplicate checks
+ for dsk in instance.disks:
+ if dsk.dev_type in constants.LDS_DRBD:
+ tcp_port = dsk.logical_id[2]
+ if tcp_port not in ports:
+ ports[tcp_port] = []
+ ports[tcp_port].append((instance.name, "drbd disk %s" % dsk.iv_name))
+ # gather network port reservation
+ net_port = getattr(instance, "network_port", None)
+ if net_port is not None:
+ if net_port not in ports:
+ ports[net_port] = []
+ ports[net_port].append((instance.name, "network port"))
+
+ # cluster-wide pool of free ports
+ for free_port in self._config_data.cluster.tcpudp_port_pool:
+ if free_port not in ports:
+ ports[free_port] = []
+ ports[free_port].append(("cluster", "port marked as free"))
+
+ # compute tcp/udp duplicate ports
+ keys = ports.keys()
+ keys.sort()
+ for pnum in keys:
+ pdata = ports[pnum]
+ if len(pdata) > 1:
+ txt = ", ".join(["%s/%s" % val for val in pdata])
+ result.append("tcp/udp port %s has duplicates: %s" % (pnum, txt))
+
+ # highest used tcp port check
+ if keys:
+ if keys[-1] > self._config_data.cluster.highest_used_port:
+ result.append("Highest used port mismatch, saved %s, computed %s" %
+ (self._config_data.cluster.highest_used_port,
+ keys[-1]))
+
return result
def SetDiskID(self, disk, node_name):
self._config_data.instances[instance.name] = instance
self._WriteConfig()
- def MarkInstanceUp(self, instance_name):
- """Mark the instance status to up in the config.
+ def _SetInstanceStatus(self, instance_name, status):
+ """Set the instance's status to a given value.
"""
+ if status not in ("up", "down"):
+ raise errors.ProgrammerError("Invalid status '%s' passed to"
+ " ConfigWriter._SetInstanceStatus()" %
+ status)
self._OpenConfig()
if instance_name not in self._config_data.instances:
raise errors.ConfigurationError("Unknown instance '%s'" %
instance_name)
instance = self._config_data.instances[instance_name]
- instance.status = "up"
- self._WriteConfig()
+ if instance.status != status:
+ instance.status = status
+ self._WriteConfig()
+
+ def MarkInstanceUp(self, instance_name):
+ """Mark the instance status to up in the config.
+
+ """
+ self._SetInstanceStatus(instance_name, "up")
def RemoveInstance(self, instance_name):
"""Remove the instance from the configuration.
"""Mark the status of an instance to down in the configuration.
"""
- self._OpenConfig()
-
- if instance_name not in self._config_data.instances:
- raise errors.ConfigurationError("Unknown instance '%s'" % instance_name)
- instance = self._config_data.instances[instance_name]
- instance.status = "down"
- self._WriteConfig()
+ self._SetInstanceStatus(instance_name, "down")
def GetInstanceList(self):
"""Get the list of instances.
f = open(self._cfg_file, 'r')
try:
try:
- data = objects.ConfigData.Load(f)
+ data = objects.ConfigData.FromDict(serializer.Load(f.read()))
except Exception, err:
raise errors.ConfigurationError(err)
finally:
nodelist = self.GetNodeList()
myhostname = self._my_hostname
- tgt_list = []
- for node in nodelist:
- nodeinfo = self.GetNodeInfo(node)
- if nodeinfo.name == myhostname:
- continue
- tgt_list.append(node)
+ try:
+ nodelist.remove(myhostname)
+ except ValueError:
+ pass
- result = rpc.call_upload_file(tgt_list, self._cfg_file)
- for node in tgt_list:
+ result = rpc.call_upload_file(nodelist, self._cfg_file)
+ for node in nodelist:
if not result[node]:
logger.Error("copy of file %s to node %s failed" %
(self._cfg_file, node))
if destination is None:
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:
- self._config_data.Dump(f)
+ f.write(txt)
os.fsync(f.fileno())
finally:
f.close()