self._cfg_file = cfg_file
self._temporary_ids = set()
self._temporary_drbds = {}
+ self._temporary_macs = set()
# Note: in order to prevent errors when resolving our name in
# _DistributeConfig, we compute it here once and reuse it; it's
# better to raise an error before starting to modify the config
byte2 = random.randrange(0, 256)
byte3 = random.randrange(0, 256)
mac = "%s:%02x:%02x:%02x" % (prefix, byte1, byte2, byte3)
- if mac not in all_macs:
+ if mac not in all_macs and mac not in self._temporary_macs:
break
retries -= 1
else:
raise errors.ConfigurationError("Can't generate unique MAC")
+ self._temporary_macs.add(mac)
return mac
@locking.ssynchronized(_config_lock, shared=1)
"""
all_macs = self._AllMACs()
- return mac in all_macs
+ return mac in all_macs or mac in self._temporary_macs
@locking.ssynchronized(_config_lock, shared=1)
def GenerateDRBDSecret(self):
return result
+ def _CheckDiskIDs(self, disk, l_ids, p_ids):
+ """Compute duplicate disk IDs
+
+ @type disk: L{objects.Disk}
+ @param disk: the disk at which to start searching
+ @type l_ids: list
+ @param l_ids: list of current logical ids
+ @type p_ids: list
+ @param p_ids: list of current physical ids
+ @rtype: list
+ @return: a list of error messages
+
+ """
+ result = []
+ if disk.logical_id is not None:
+ if disk.logical_id in l_ids:
+ result.append("duplicate logical id %s" % str(disk.logical_id))
+ else:
+ l_ids.append(disk.logical_id)
+ if disk.physical_id is not None:
+ if disk.physical_id in p_ids:
+ result.append("duplicate physical id %s" % str(disk.physical_id))
+ else:
+ p_ids.append(disk.physical_id)
+
+ if disk.children:
+ for child in disk.children:
+ result.extend(self._CheckDiskIDs(child, l_ids, p_ids))
+ return result
+
def _UnlockedVerifyConfig(self):
"""Verify function.
seen_macs = []
ports = {}
data = self._config_data
+ seen_lids = []
+ seen_pids = []
for instance_name in data.instances:
instance = data.instances[instance_name]
if instance.primary_node not in data.nodes:
for idx, disk in enumerate(instance.disks):
result.extend(["instance '%s' disk %d error: %s" %
(instance.name, idx, msg) for msg in disk.Verify()])
+ result.extend(self._CheckDiskIDs(disk, seen_lids, seen_pids))
# cluster-wide pool of free ports
for free_port in data.cluster.tcpudp_port_pool:
result.append("Not enough master candidates: actual %d, target %d" %
(mc_now, mc_max))
+ # node checks
+ for node in data.nodes.values():
+ if [node.master_candidate, node.drained, node.offline].count(True) > 1:
+ result.append("Node %s state is invalid: master_candidate=%s,"
+ " drain=%s, offline=%s" %
+ (node.name, node.master_candidate, node.drain,
+ node.offline))
+
# drbd minors check
d_map, duplicates = self._UnlockedComputeDRBDMap()
for node, minor, instance_a, instance_b in duplicates:
all_lvs = instance.MapLVsByNode()
logging.info("Instance '%s' DISK_LAYOUT: %s", instance.name, all_lvs)
+ all_macs = self._AllMACs()
+ for nic in instance.nics:
+ if nic.mac in all_macs:
+ raise errors.ConfigurationError("Cannot add instance %s:"
+ " MAC address '%s' already in use." % (instance.name, nic.mac))
+
instance.serial_no = 1
self._config_data.instances[instance.name] = instance
+ self._config_data.cluster.serial_no += 1
self._UnlockedReleaseDRBDMinors(instance.name)
+ for nic in instance.nics:
+ self._temporary_macs.discard(nic.mac)
self._WriteConfig()
def _SetInstanceStatus(self, instance_name, status):
if instance_name not in self._config_data.instances:
raise errors.ConfigurationError("Unknown instance '%s'" % instance_name)
del self._config_data.instances[instance_name]
+ self._config_data.cluster.serial_no += 1
self._WriteConfig()
@locking.ssynchronized(_config_lock)
"""Get the configuration of all instances.
@rtype: dict
- @returns: dict of (instance, instance_info), where instance_info is what
+ @return: dict of (instance, instance_info), where instance_info is what
would GetInstanceInfo return for the node
"""
"""
mc_now = mc_max = 0
for node in self._config_data.nodes.itervalues():
- if not node.offline:
+ if not (node.offline or node.drained):
mc_max += 1
if node.master_candidate:
mc_now += 1
if mc_now >= mc_max:
break
node = self._config_data.nodes[name]
- if node.master_candidate or node.offline:
+ if node.master_candidate or node.offline or node.drained:
continue
mod_list.append(node)
node.master_candidate = True
"""
fn = "\n".join
+ instance_names = utils.NiceSort(self._UnlockedGetInstanceList())
node_names = utils.NiceSort(self._UnlockedGetNodeList())
node_info = [self._UnlockedGetNodeInfo(name) for name in node_names]
+ 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)
node_data = fn(node_names)
cluster = self._config_data.cluster
+ cluster_tags = fn(cluster.GetTags())
return {
constants.SS_CLUSTER_NAME: cluster.cluster_name,
+ constants.SS_CLUSTER_TAGS: cluster_tags,
constants.SS_FILE_STORAGE_DIR: cluster.file_storage_dir,
constants.SS_MASTER_CANDIDATES: mc_data,
constants.SS_MASTER_IP: cluster.master_ip,
constants.SS_MASTER_NODE: cluster.master_node,
constants.SS_NODE_LIST: node_data,
constants.SS_OFFLINE_NODES: off_data,
+ constants.SS_ONLINE_NODES: on_data,
+ constants.SS_INSTANCE_LIST: instance_data,
constants.SS_RELEASE_VERSION: constants.RELEASE_VERSION,
}
if isinstance(target, objects.Instance):
self._UnlockedReleaseDRBDMinors(target.name)
+ for nic in target.nics:
+ self._temporary_macs.discard(nic.mac)
self._WriteConfig()