Revision 1c3231aa lib/config.py
b/lib/config.py | ||
---|---|---|
760 | 760 |
(mc_now, mc_max)) |
761 | 761 |
|
762 | 762 |
# node checks |
763 |
for node_name, node in data.nodes.items():
|
|
764 |
if node.name != node_name:
|
|
765 |
result.append("Node '%s' is indexed by wrong name '%s'" %
|
|
766 |
(node.name, node_name))
|
|
763 |
for node_uuid, node in data.nodes.items():
|
|
764 |
if node.uuid != node_uuid:
|
|
765 |
result.append("Node '%s' is indexed by wrong UUID '%s'" %
|
|
766 |
(node.name, node_uuid))
|
|
767 | 767 |
if [node.master_candidate, node.drained, node.offline].count(True) > 1: |
768 | 768 |
result.append("Node %s state is invalid: master_candidate=%s," |
769 | 769 |
" drain=%s, offline=%s" % |
... | ... | |
862 | 862 |
""" |
863 | 863 |
return self._UnlockedVerifyConfig() |
864 | 864 |
|
865 |
def _UnlockedSetDiskID(self, disk, node_name):
|
|
865 |
def _UnlockedSetDiskID(self, disk, node_uuid):
|
|
866 | 866 |
"""Convert the unique ID to the ID needed on the target nodes. |
867 | 867 |
|
868 | 868 |
This is used only for drbd, which needs ip/port configuration. |
... | ... | |
876 | 876 |
""" |
877 | 877 |
if disk.children: |
878 | 878 |
for child in disk.children: |
879 |
self._UnlockedSetDiskID(child, node_name)
|
|
879 |
self._UnlockedSetDiskID(child, node_uuid)
|
|
880 | 880 |
|
881 | 881 |
if disk.logical_id is None and disk.physical_id is not None: |
882 | 882 |
return |
883 | 883 |
if disk.dev_type == constants.LD_DRBD8: |
884 | 884 |
pnode, snode, port, pminor, sminor, secret = disk.logical_id |
885 |
if node_name not in (pnode, snode):
|
|
885 |
if node_uuid not in (pnode, snode):
|
|
886 | 886 |
raise errors.ConfigurationError("DRBD device not knowing node %s" % |
887 |
node_name)
|
|
887 |
node_uuid)
|
|
888 | 888 |
pnode_info = self._UnlockedGetNodeInfo(pnode) |
889 | 889 |
snode_info = self._UnlockedGetNodeInfo(snode) |
890 | 890 |
if pnode_info is None or snode_info is None: |
... | ... | |
892 | 892 |
" for %s" % str(disk)) |
893 | 893 |
p_data = (pnode_info.secondary_ip, port) |
894 | 894 |
s_data = (snode_info.secondary_ip, port) |
895 |
if pnode == node_name:
|
|
895 |
if pnode == node_uuid:
|
|
896 | 896 |
disk.physical_id = p_data + s_data + (pminor, secret) |
897 | 897 |
else: # it must be secondary, we tested above |
898 | 898 |
disk.physical_id = s_data + p_data + (sminor, secret) |
... | ... | |
901 | 901 |
return |
902 | 902 |
|
903 | 903 |
@locking.ssynchronized(_config_lock) |
904 |
def SetDiskID(self, disk, node_name):
|
|
904 |
def SetDiskID(self, disk, node_uuid):
|
|
905 | 905 |
"""Convert the unique ID to the ID needed on the target nodes. |
906 | 906 |
|
907 | 907 |
This is used only for drbd, which needs ip/port configuration. |
... | ... | |
911 | 911 |
node. |
912 | 912 |
|
913 | 913 |
""" |
914 |
return self._UnlockedSetDiskID(disk, node_name)
|
|
914 |
return self._UnlockedSetDiskID(disk, node_uuid)
|
|
915 | 915 |
|
916 | 916 |
@locking.ssynchronized(_config_lock) |
917 | 917 |
def AddTcpUdpPort(self, port): |
... | ... | |
961 | 961 |
"""Compute the used DRBD minor/nodes. |
962 | 962 |
|
963 | 963 |
@rtype: (dict, list) |
964 |
@return: dictionary of node_name: dict of minor: instance_name;
|
|
964 |
@return: dictionary of node_uuid: dict of minor: instance_name;
|
|
965 | 965 |
the returned dict will have all the nodes in it (even if with |
966 | 966 |
an empty list), and a list of duplicates; if the duplicates |
967 | 967 |
list is not empty, the configuration is corrupted and its caller |
... | ... | |
1002 | 1002 |
|
1003 | 1003 |
This is just a wrapper over L{_UnlockedComputeDRBDMap}. |
1004 | 1004 |
|
1005 |
@return: dictionary of node_name: dict of minor: instance_name;
|
|
1005 |
@return: dictionary of node_uuid: dict of minor: instance_name;
|
|
1006 | 1006 |
the returned dict will have all the nodes in it (even if with |
1007 | 1007 |
an empty list). |
1008 | 1008 |
|
... | ... | |
1014 | 1014 |
return d_map |
1015 | 1015 |
|
1016 | 1016 |
@locking.ssynchronized(_config_lock) |
1017 |
def AllocateDRBDMinor(self, nodes, instance): |
|
1017 |
def AllocateDRBDMinor(self, node_uuids, instance):
|
|
1018 | 1018 |
"""Allocate a drbd minor. |
1019 | 1019 |
|
1020 | 1020 |
The free minor will be automatically computed from the existing |
... | ... | |
1034 | 1034 |
raise errors.ConfigurationError("Duplicate DRBD ports detected: %s" % |
1035 | 1035 |
str(duplicates)) |
1036 | 1036 |
result = [] |
1037 |
for nname in nodes:
|
|
1038 |
ndata = d_map[nname]
|
|
1037 |
for nuuid in node_uuids:
|
|
1038 |
ndata = d_map[nuuid]
|
|
1039 | 1039 |
if not ndata: |
1040 | 1040 |
# no minors used, we can start at 0 |
1041 | 1041 |
result.append(0) |
1042 | 1042 |
ndata[0] = instance |
1043 |
self._temporary_drbds[(nname, 0)] = instance
|
|
1043 |
self._temporary_drbds[(nuuid, 0)] = instance
|
|
1044 | 1044 |
continue |
1045 | 1045 |
keys = ndata.keys() |
1046 | 1046 |
keys.sort() |
... | ... | |
1052 | 1052 |
else: |
1053 | 1053 |
minor = ffree |
1054 | 1054 |
# double-check minor against current instances |
1055 |
assert minor not in d_map[nname], \
|
|
1055 |
assert minor not in d_map[nuuid], \
|
|
1056 | 1056 |
("Attempt to reuse allocated DRBD minor %d on node %s," |
1057 | 1057 |
" already allocated to instance %s" % |
1058 |
(minor, nname, d_map[nname][minor]))
|
|
1058 |
(minor, nuuid, d_map[nuuid][minor]))
|
|
1059 | 1059 |
ndata[minor] = instance |
1060 | 1060 |
# double-check minor against reservation |
1061 |
r_key = (nname, minor)
|
|
1061 |
r_key = (nuuid, minor)
|
|
1062 | 1062 |
assert r_key not in self._temporary_drbds, \ |
1063 | 1063 |
("Attempt to reuse reserved DRBD minor %d on node %s," |
1064 | 1064 |
" reserved for instance %s" % |
1065 |
(minor, nname, self._temporary_drbds[r_key]))
|
|
1065 |
(minor, nuuid, self._temporary_drbds[r_key]))
|
|
1066 | 1066 |
self._temporary_drbds[r_key] = instance |
1067 | 1067 |
result.append(minor) |
1068 | 1068 |
logging.debug("Request to allocate drbd minors, input: %s, returning %s", |
1069 |
nodes, result) |
|
1069 |
node_uuids, result)
|
|
1070 | 1070 |
return result |
1071 | 1071 |
|
1072 | 1072 |
def _UnlockedReleaseDRBDMinors(self, instance): |
... | ... | |
1120 | 1120 |
|
1121 | 1121 |
@locking.ssynchronized(_config_lock, shared=1) |
1122 | 1122 |
def GetMasterNode(self): |
1123 |
"""Get the hostname of the master node for this cluster.
|
|
1123 |
"""Get the UUID of the master node for this cluster.
|
|
1124 | 1124 |
|
1125 |
@return: Master hostname
|
|
1125 |
@return: Master node UUID
|
|
1126 | 1126 |
|
1127 | 1127 |
""" |
1128 | 1128 |
return self._config_data.cluster.master_node |
1129 | 1129 |
|
1130 | 1130 |
@locking.ssynchronized(_config_lock, shared=1) |
1131 |
def GetMasterNodeName(self): |
|
1132 |
"""Get the hostname of the master node for this cluster. |
|
1133 |
|
|
1134 |
@return: Master node hostname |
|
1135 |
|
|
1136 |
""" |
|
1137 |
return self._UnlockedGetNodeName(self._config_data.cluster.master_node) |
|
1138 |
|
|
1139 |
@locking.ssynchronized(_config_lock, shared=1) |
|
1131 | 1140 |
def GetMasterIP(self): |
1132 | 1141 |
"""Get the IP of the master node for this cluster. |
1133 | 1142 |
|
... | ... | |
1214 | 1223 |
""" |
1215 | 1224 |
cluster = self._config_data.cluster |
1216 | 1225 |
result = objects.MasterNetworkParameters( |
1217 |
name=cluster.master_node, ip=cluster.master_ip,
|
|
1226 |
uuid=cluster.master_node, ip=cluster.master_ip,
|
|
1218 | 1227 |
netmask=cluster.master_netmask, netdev=cluster.master_netdev, |
1219 | 1228 |
ip_family=cluster.primary_ip_family) |
1220 | 1229 |
|
... | ... | |
1372 | 1381 |
"""Get nodes which are member in the same nodegroups as the given nodes. |
1373 | 1382 |
|
1374 | 1383 |
""" |
1375 |
ngfn = lambda node_name: self._UnlockedGetNodeInfo(node_name).group
|
|
1376 |
return frozenset(member_name
|
|
1377 |
for node_name in nodes
|
|
1378 |
for member_name in
|
|
1379 |
self._UnlockedGetNodeGroup(ngfn(node_name)).members)
|
|
1384 |
ngfn = lambda node_uuid: self._UnlockedGetNodeInfo(node_uuid).group
|
|
1385 |
return frozenset(member_uuid
|
|
1386 |
for node_uuid in nodes
|
|
1387 |
for member_uuid in
|
|
1388 |
self._UnlockedGetNodeGroup(ngfn(node_uuid)).members)
|
|
1380 | 1389 |
|
1381 | 1390 |
@locking.ssynchronized(_config_lock, shared=1) |
1382 | 1391 |
def GetMultiNodeGroupInfo(self, group_uuids): |
... | ... | |
1631 | 1640 |
else: |
1632 | 1641 |
nodes = instance.all_nodes |
1633 | 1642 |
|
1634 |
return frozenset(self._UnlockedGetNodeInfo(node_name).group
|
|
1635 |
for node_name in nodes)
|
|
1643 |
return frozenset(self._UnlockedGetNodeInfo(node_uuid).group
|
|
1644 |
for node_uuid in nodes)
|
|
1636 | 1645 |
|
1637 | 1646 |
@locking.ssynchronized(_config_lock, shared=1) |
1638 | 1647 |
def GetInstanceNetworks(self, instance_name): |
... | ... | |
1708 | 1717 |
|
1709 | 1718 |
node.serial_no = 1 |
1710 | 1719 |
node.ctime = node.mtime = time.time() |
1711 |
self._UnlockedAddNodeToGroup(node.name, node.group)
|
|
1712 |
self._config_data.nodes[node.name] = node
|
|
1720 |
self._UnlockedAddNodeToGroup(node.uuid, node.group)
|
|
1721 |
self._config_data.nodes[node.uuid] = node
|
|
1713 | 1722 |
self._config_data.cluster.serial_no += 1 |
1714 | 1723 |
self._WriteConfig() |
1715 | 1724 |
|
1716 | 1725 |
@locking.ssynchronized(_config_lock) |
1717 |
def RemoveNode(self, node_name):
|
|
1726 |
def RemoveNode(self, node_uuid):
|
|
1718 | 1727 |
"""Remove a node from the configuration. |
1719 | 1728 |
|
1720 | 1729 |
""" |
1721 |
logging.info("Removing node %s from configuration", node_name)
|
|
1730 |
logging.info("Removing node %s from configuration", node_uuid)
|
|
1722 | 1731 |
|
1723 |
if node_name not in self._config_data.nodes:
|
|
1724 |
raise errors.ConfigurationError("Unknown node '%s'" % node_name)
|
|
1732 |
if node_uuid not in self._config_data.nodes:
|
|
1733 |
raise errors.ConfigurationError("Unknown node '%s'" % node_uuid)
|
|
1725 | 1734 |
|
1726 |
self._UnlockedRemoveNodeFromGroup(self._config_data.nodes[node_name])
|
|
1727 |
del self._config_data.nodes[node_name]
|
|
1735 |
self._UnlockedRemoveNodeFromGroup(self._config_data.nodes[node_uuid])
|
|
1736 |
del self._config_data.nodes[node_uuid]
|
|
1728 | 1737 |
self._config_data.cluster.serial_no += 1 |
1729 | 1738 |
self._WriteConfig() |
1730 | 1739 |
|
1731 | 1740 |
def ExpandNodeName(self, short_name): |
1732 |
"""Attempt to expand an incomplete node name. |
|
1741 |
"""Attempt to expand an incomplete node name into a node UUID.
|
|
1733 | 1742 |
|
1734 | 1743 |
""" |
1735 |
# Locking is done in L{ConfigWriter.GetNodeList} |
|
1736 |
return _MatchNameComponentIgnoreCase(short_name, self.GetNodeList()) |
|
1744 |
# Locking is done in L{ConfigWriter.GetAllNodesInfo} |
|
1745 |
all_nodes = self.GetAllNodesInfo().values() |
|
1746 |
expanded_name = _MatchNameComponentIgnoreCase( |
|
1747 |
short_name, [node.name for node in all_nodes]) |
|
1737 | 1748 |
|
1738 |
def _UnlockedGetNodeInfo(self, node_name): |
|
1749 |
if expanded_name is not None: |
|
1750 |
# there has to be exactly one node whith that name |
|
1751 |
node = (filter(lambda n: n.name == expanded_name, all_nodes)[0]) |
|
1752 |
return (node.uuid, node.name) |
|
1753 |
else: |
|
1754 |
return None |
|
1755 |
|
|
1756 |
def _UnlockedGetNodeInfo(self, node_uuid): |
|
1739 | 1757 |
"""Get the configuration of a node, as stored in the config. |
1740 | 1758 |
|
1741 | 1759 |
This function is for internal use, when the config lock is already |
1742 | 1760 |
held. |
1743 | 1761 |
|
1744 |
@param node_name: the node name, e.g. I{node1.example.com}
|
|
1762 |
@param node_uuid: the node UUID
|
|
1745 | 1763 |
|
1746 | 1764 |
@rtype: L{objects.Node} |
1747 | 1765 |
@return: the node object |
1748 | 1766 |
|
1749 | 1767 |
""" |
1750 |
if node_name not in self._config_data.nodes:
|
|
1768 |
if node_uuid not in self._config_data.nodes:
|
|
1751 | 1769 |
return None |
1752 | 1770 |
|
1753 |
return self._config_data.nodes[node_name]
|
|
1771 |
return self._config_data.nodes[node_uuid]
|
|
1754 | 1772 |
|
1755 | 1773 |
@locking.ssynchronized(_config_lock, shared=1) |
1756 |
def GetNodeInfo(self, node_name):
|
|
1774 |
def GetNodeInfo(self, node_uuid):
|
|
1757 | 1775 |
"""Get the configuration of a node, as stored in the config. |
1758 | 1776 |
|
1759 | 1777 |
This is just a locked wrapper over L{_UnlockedGetNodeInfo}. |
1760 | 1778 |
|
1761 |
@param node_name: the node name, e.g. I{node1.example.com}
|
|
1779 |
@param node_uuid: the node UUID
|
|
1762 | 1780 |
|
1763 | 1781 |
@rtype: L{objects.Node} |
1764 | 1782 |
@return: the node object |
1765 | 1783 |
|
1766 | 1784 |
""" |
1767 |
return self._UnlockedGetNodeInfo(node_name)
|
|
1785 |
return self._UnlockedGetNodeInfo(node_uuid)
|
|
1768 | 1786 |
|
1769 | 1787 |
@locking.ssynchronized(_config_lock, shared=1) |
1770 |
def GetNodeInstances(self, node_name):
|
|
1788 |
def GetNodeInstances(self, node_uuid):
|
|
1771 | 1789 |
"""Get the instances of a node, as stored in the config. |
1772 | 1790 |
|
1773 |
@param node_name: the node name, e.g. I{node1.example.com}
|
|
1791 |
@param node_uuid: the node UUID
|
|
1774 | 1792 |
|
1775 | 1793 |
@rtype: (list, list) |
1776 | 1794 |
@return: a tuple with two lists: the primary and the secondary instances |
... | ... | |
1779 | 1797 |
pri = [] |
1780 | 1798 |
sec = [] |
1781 | 1799 |
for inst in self._config_data.instances.values(): |
1782 |
if inst.primary_node == node_name:
|
|
1800 |
if inst.primary_node == node_uuid:
|
|
1783 | 1801 |
pri.append(inst.name) |
1784 |
if node_name in inst.secondary_nodes:
|
|
1802 |
if node_uuid in inst.secondary_nodes:
|
|
1785 | 1803 |
sec.append(inst.name) |
1786 | 1804 |
return (pri, sec) |
1787 | 1805 |
|
... | ... | |
1802 | 1820 |
|
1803 | 1821 |
return frozenset(inst.name |
1804 | 1822 |
for inst in self._config_data.instances.values() |
1805 |
for node_name in nodes_fn(inst)
|
|
1806 |
if self._UnlockedGetNodeInfo(node_name).group == uuid)
|
|
1823 |
for node_uuid in nodes_fn(inst)
|
|
1824 |
if self._UnlockedGetNodeInfo(node_uuid).group == uuid)
|
|
1807 | 1825 |
|
1808 | 1826 |
def _UnlockedGetHvparamsString(self, hvname): |
1809 | 1827 |
"""Return the string representation of the list of hyervisor parameters of |
... | ... | |
1855 | 1873 |
""" |
1856 | 1874 |
all_nodes = [self._UnlockedGetNodeInfo(node) |
1857 | 1875 |
for node in self._UnlockedGetNodeList()] |
1858 |
return [node.name for node in all_nodes if not node.offline]
|
|
1876 |
return [node.uuid for node in all_nodes if not node.offline]
|
|
1859 | 1877 |
|
1860 | 1878 |
@locking.ssynchronized(_config_lock, shared=1) |
1861 | 1879 |
def GetOnlineNodeList(self): |
... | ... | |
1871 | 1889 |
""" |
1872 | 1890 |
all_nodes = [self._UnlockedGetNodeInfo(node) |
1873 | 1891 |
for node in self._UnlockedGetNodeList()] |
1874 |
return [node.name for node in all_nodes if node.vm_capable]
|
|
1892 |
return [node.uuid for node in all_nodes if node.vm_capable]
|
|
1875 | 1893 |
|
1876 | 1894 |
@locking.ssynchronized(_config_lock, shared=1) |
1877 | 1895 |
def GetNonVmCapableNodeList(self): |
... | ... | |
1880 | 1898 |
""" |
1881 | 1899 |
all_nodes = [self._UnlockedGetNodeInfo(node) |
1882 | 1900 |
for node in self._UnlockedGetNodeList()] |
1883 |
return [node.name for node in all_nodes if not node.vm_capable]
|
|
1901 |
return [node.uuid for node in all_nodes if not node.vm_capable]
|
|
1884 | 1902 |
|
1885 | 1903 |
@locking.ssynchronized(_config_lock, shared=1) |
1886 |
def GetMultiNodeInfo(self, nodes): |
|
1904 |
def GetMultiNodeInfo(self, node_uuids):
|
|
1887 | 1905 |
"""Get the configuration of multiple nodes. |
1888 | 1906 |
|
1889 |
@param nodes: list of node names
|
|
1907 |
@param node_uuids: list of node UUIDs
|
|
1890 | 1908 |
@rtype: list |
1891 | 1909 |
@return: list of tuples of (node, node_info), where node_info is |
1892 | 1910 |
what would GetNodeInfo return for the node, in the original |
1893 | 1911 |
order |
1894 | 1912 |
|
1895 | 1913 |
""" |
1896 |
return [(name, self._UnlockedGetNodeInfo(name)) for name in nodes] |
|
1914 |
return [(uuid, self._UnlockedGetNodeInfo(uuid)) for uuid in node_uuids] |
|
1915 |
|
|
1916 |
def _UnlockedGetAllNodesInfo(self): |
|
1917 |
"""Gets configuration of all nodes. |
|
1918 |
|
|
1919 |
@note: See L{GetAllNodesInfo} |
|
1920 |
|
|
1921 |
""" |
|
1922 |
return dict([(node_uuid, self._UnlockedGetNodeInfo(node_uuid)) |
|
1923 |
for node_uuid in self._UnlockedGetNodeList()]) |
|
1897 | 1924 |
|
1898 | 1925 |
@locking.ssynchronized(_config_lock, shared=1) |
1899 | 1926 |
def GetAllNodesInfo(self): |
... | ... | |
1906 | 1933 |
""" |
1907 | 1934 |
return self._UnlockedGetAllNodesInfo() |
1908 | 1935 |
|
1909 |
def _UnlockedGetAllNodesInfo(self): |
|
1910 |
"""Gets configuration of all nodes. |
|
1936 |
def _UnlockedGetNodeInfoByName(self, node_name): |
|
1937 |
for node in self._UnlockedGetAllNodesInfo().values(): |
|
1938 |
if node.name == node_name: |
|
1939 |
return node |
|
1940 |
return None |
|
1911 | 1941 |
|
1912 |
@note: See L{GetAllNodesInfo} |
|
1942 |
@locking.ssynchronized(_config_lock, shared=1) |
|
1943 |
def GetNodeInfoByName(self, node_name): |
|
1944 |
"""Get the L{objects.Node} object for a named node. |
|
1945 |
|
|
1946 |
@param node_name: name of the node to get information for |
|
1947 |
@type node_name: string |
|
1948 |
@return: the corresponding L{objects.Node} instance or None if no |
|
1949 |
information is available |
|
1950 |
|
|
1951 |
""" |
|
1952 |
return self._UnlockedGetNodeInfoByName(node_name) |
|
1953 |
|
|
1954 |
def _UnlockedGetNodeName(self, node_spec): |
|
1955 |
if isinstance(node_spec, objects.Node): |
|
1956 |
return node_spec.name |
|
1957 |
elif isinstance(node_spec, basestring): |
|
1958 |
node_info = self._UnlockedGetNodeInfo(node_spec) |
|
1959 |
if node_info is None: |
|
1960 |
raise errors.OpExecError("Unknown node: %s" % node_spec) |
|
1961 |
return node_info.name |
|
1962 |
else: |
|
1963 |
raise errors.ProgrammerError("Can't handle node spec '%s'" % node_spec) |
|
1964 |
|
|
1965 |
@locking.ssynchronized(_config_lock, shared=1) |
|
1966 |
def GetNodeName(self, node_spec): |
|
1967 |
"""Gets the node name for the passed node. |
|
1968 |
|
|
1969 |
@param node_spec: node to get names for |
|
1970 |
@type node_spec: either node UUID or a L{objects.Node} object |
|
1971 |
@rtype: string |
|
1972 |
@return: node name |
|
1973 |
|
|
1974 |
""" |
|
1975 |
return self._UnlockedGetNodeName(node_spec) |
|
1976 |
|
|
1977 |
def _UnlockedGetNodeNames(self, node_specs): |
|
1978 |
return [self._UnlockedGetNodeName(node_spec) for node_spec in node_specs] |
|
1979 |
|
|
1980 |
@locking.ssynchronized(_config_lock, shared=1) |
|
1981 |
def GetNodeNames(self, node_specs): |
|
1982 |
"""Gets the node names for the passed list of nodes. |
|
1983 |
|
|
1984 |
@param node_specs: list of nodes to get names for |
|
1985 |
@type node_specs: list of either node UUIDs or L{objects.Node} objects |
|
1986 |
@rtype: list of strings |
|
1987 |
@return: list of node names |
|
1913 | 1988 |
|
1914 | 1989 |
""" |
1915 |
return dict([(node, self._UnlockedGetNodeInfo(node)) |
|
1916 |
for node in self._UnlockedGetNodeList()]) |
|
1990 |
return self._UnlockedGetNodeNames(node_specs) |
|
1917 | 1991 |
|
1918 | 1992 |
@locking.ssynchronized(_config_lock, shared=1) |
1919 |
def GetNodeGroupsFromNodes(self, nodes): |
|
1993 |
def GetNodeGroupsFromNodes(self, node_uuids):
|
|
1920 | 1994 |
"""Returns groups for a list of nodes. |
1921 | 1995 |
|
1922 |
@type nodes: list of string |
|
1923 |
@param nodes: List of node names
|
|
1996 |
@type node_uuids: list of string
|
|
1997 |
@param node_uuids: List of node UUIDs
|
|
1924 | 1998 |
@rtype: frozenset |
1925 | 1999 |
|
1926 | 2000 |
""" |
1927 |
return frozenset(self._UnlockedGetNodeInfo(name).group for name in nodes) |
|
2001 |
return frozenset(self._UnlockedGetNodeInfo(uuid).group |
|
2002 |
for uuid in node_uuids) |
|
1928 | 2003 |
|
1929 | 2004 |
def _UnlockedGetMasterCandidateStats(self, exceptions=None): |
1930 | 2005 |
"""Get the number of current and maximum desired and possible candidates. |
... | ... | |
1937 | 2012 |
""" |
1938 | 2013 |
mc_now = mc_should = mc_max = 0 |
1939 | 2014 |
for node in self._config_data.nodes.values(): |
1940 |
if exceptions and node.name in exceptions:
|
|
2015 |
if exceptions and node.uuid in exceptions:
|
|
1941 | 2016 |
continue |
1942 | 2017 |
if not (node.offline or node.drained) and node.master_capable: |
1943 | 2018 |
mc_max += 1 |
... | ... | |
1961 | 2036 |
return self._UnlockedGetMasterCandidateStats(exceptions) |
1962 | 2037 |
|
1963 | 2038 |
@locking.ssynchronized(_config_lock) |
1964 |
def MaintainCandidatePool(self, exceptions): |
|
2039 |
def MaintainCandidatePool(self, exception_node_uuids):
|
|
1965 | 2040 |
"""Try to grow the candidate pool to the desired size. |
1966 | 2041 |
|
1967 |
@type exceptions: list |
|
1968 |
@param exceptions: if passed, list of nodes that should be ignored |
|
2042 |
@type exception_node_uuids: list
|
|
2043 |
@param exception_node_uuids: if passed, list of nodes that should be ignored
|
|
1969 | 2044 |
@rtype: list |
1970 | 2045 |
@return: list with the adjusted nodes (L{objects.Node} instances) |
1971 | 2046 |
|
1972 | 2047 |
""" |
1973 |
mc_now, mc_max, _ = self._UnlockedGetMasterCandidateStats(exceptions) |
|
2048 |
mc_now, mc_max, _ = self._UnlockedGetMasterCandidateStats( |
|
2049 |
exception_node_uuids) |
|
1974 | 2050 |
mod_list = [] |
1975 | 2051 |
if mc_now < mc_max: |
1976 | 2052 |
node_list = self._config_data.nodes.keys() |
1977 | 2053 |
random.shuffle(node_list) |
1978 |
for name in node_list:
|
|
2054 |
for uuid in node_list:
|
|
1979 | 2055 |
if mc_now >= mc_max: |
1980 | 2056 |
break |
1981 |
node = self._config_data.nodes[name]
|
|
2057 |
node = self._config_data.nodes[uuid]
|
|
1982 | 2058 |
if (node.master_candidate or node.offline or node.drained or |
1983 |
node.name in exceptions or not node.master_capable):
|
|
2059 |
node.uuid in exception_node_uuids or not node.master_capable):
|
|
1984 | 2060 |
continue |
1985 | 2061 |
mod_list.append(node) |
1986 | 2062 |
node.master_candidate = True |
... | ... | |
1996 | 2072 |
|
1997 | 2073 |
return mod_list |
1998 | 2074 |
|
1999 |
def _UnlockedAddNodeToGroup(self, node_name, nodegroup_uuid):
|
|
2075 |
def _UnlockedAddNodeToGroup(self, node_uuid, nodegroup_uuid):
|
|
2000 | 2076 |
"""Add a given node to the specified group. |
2001 | 2077 |
|
2002 | 2078 |
""" |
... | ... | |
2006 | 2082 |
# the meantime. It's ok though, as we'll fail cleanly if the node group |
2007 | 2083 |
# is not found anymore. |
2008 | 2084 |
raise errors.OpExecError("Unknown node group: %s" % nodegroup_uuid) |
2009 |
if node_name not in self._config_data.nodegroups[nodegroup_uuid].members:
|
|
2010 |
self._config_data.nodegroups[nodegroup_uuid].members.append(node_name)
|
|
2085 |
if node_uuid not in self._config_data.nodegroups[nodegroup_uuid].members:
|
|
2086 |
self._config_data.nodegroups[nodegroup_uuid].members.append(node_uuid)
|
|
2011 | 2087 |
|
2012 | 2088 |
def _UnlockedRemoveNodeFromGroup(self, node): |
2013 | 2089 |
"""Remove a given node from its group. |
... | ... | |
2016 | 2092 |
nodegroup = node.group |
2017 | 2093 |
if nodegroup not in self._config_data.nodegroups: |
2018 | 2094 |
logging.warning("Warning: node '%s' has unknown node group '%s'" |
2019 |
" (while being removed from it)", node.name, nodegroup)
|
|
2095 |
" (while being removed from it)", node.uuid, nodegroup)
|
|
2020 | 2096 |
nodegroup_obj = self._config_data.nodegroups[nodegroup] |
2021 |
if node.name not in nodegroup_obj.members:
|
|
2097 |
if node.uuid not in nodegroup_obj.members:
|
|
2022 | 2098 |
logging.warning("Warning: node '%s' not a member of its node group '%s'" |
2023 |
" (while being removed from it)", node.name, nodegroup)
|
|
2099 |
" (while being removed from it)", node.uuid, nodegroup)
|
|
2024 | 2100 |
else: |
2025 |
nodegroup_obj.members.remove(node.name)
|
|
2101 |
nodegroup_obj.members.remove(node.uuid)
|
|
2026 | 2102 |
|
2027 | 2103 |
@locking.ssynchronized(_config_lock) |
2028 | 2104 |
def AssignGroupNodes(self, mods): |
... | ... | |
2037 | 2113 |
|
2038 | 2114 |
resmod = [] |
2039 | 2115 |
|
2040 |
# Try to resolve names/UUIDs first
|
|
2041 |
for (node_name, new_group_uuid) in mods:
|
|
2116 |
# Try to resolve UUIDs first |
|
2117 |
for (node_uuid, new_group_uuid) in mods:
|
|
2042 | 2118 |
try: |
2043 |
node = nodes[node_name]
|
|
2119 |
node = nodes[node_uuid]
|
|
2044 | 2120 |
except KeyError: |
2045 |
raise errors.ConfigurationError("Unable to find node '%s'" % node_name)
|
|
2121 |
raise errors.ConfigurationError("Unable to find node '%s'" % node_uuid)
|
|
2046 | 2122 |
|
2047 | 2123 |
if node.group == new_group_uuid: |
2048 | 2124 |
# Node is being assigned to its current group |
2049 | 2125 |
logging.debug("Node '%s' was assigned to its current group (%s)", |
2050 |
node_name, node.group)
|
|
2126 |
node_uuid, node.group)
|
|
2051 | 2127 |
continue |
2052 | 2128 |
|
2053 | 2129 |
# Try to find current group of node |
... | ... | |
2064 | 2140 |
raise errors.ConfigurationError("Unable to find new group '%s'" % |
2065 | 2141 |
new_group_uuid) |
2066 | 2142 |
|
2067 |
assert node.name in old_group.members, \
|
|
2143 |
assert node.uuid in old_group.members, \
|
|
2068 | 2144 |
("Inconsistent configuration: node '%s' not listed in members for its" |
2069 |
" old group '%s'" % (node.name, old_group.uuid))
|
|
2070 |
assert node.name not in new_group.members, \
|
|
2145 |
" old group '%s'" % (node.uuid, old_group.uuid))
|
|
2146 |
assert node.uuid not in new_group.members, \
|
|
2071 | 2147 |
("Inconsistent configuration: node '%s' already listed in members for" |
2072 |
" its new group '%s'" % (node.name, new_group.uuid))
|
|
2148 |
" its new group '%s'" % (node.uuid, new_group.uuid))
|
|
2073 | 2149 |
|
2074 | 2150 |
resmod.append((node, old_group, new_group)) |
2075 | 2151 |
|
... | ... | |
2081 | 2157 |
node.group = new_group.uuid |
2082 | 2158 |
|
2083 | 2159 |
# Update members of involved groups |
2084 |
if node.name in old_group.members:
|
|
2085 |
old_group.members.remove(node.name)
|
|
2086 |
if node.name not in new_group.members:
|
|
2087 |
new_group.members.append(node.name)
|
|
2160 |
if node.uuid in old_group.members:
|
|
2161 |
old_group.members.remove(node.uuid)
|
|
2162 |
if node.uuid not in new_group.members:
|
|
2163 |
new_group.members.append(node.uuid)
|
|
2088 | 2164 |
|
2089 | 2165 |
# Update timestamps and serials (only once per node/group object) |
2090 | 2166 |
now = time.time() |
... | ... | |
2135 | 2211 |
raise errors.ConfigurationError("Incomplete configuration" |
2136 | 2212 |
" (missing cluster.rsahostkeypub)") |
2137 | 2213 |
|
2138 |
if data.cluster.master_node != self._my_hostname and not accept_foreign: |
|
2214 |
if not data.cluster.master_node in data.nodes: |
|
2215 |
msg = ("The configuration denotes node %s as master, but does not" |
|
2216 |
" contain information about this node" % |
|
2217 |
data.cluster.master_node) |
|
2218 |
raise errors.ConfigurationError(msg) |
|
2219 |
|
|
2220 |
master_info = data.nodes[data.cluster.master_node] |
|
2221 |
if master_info.name != self._my_hostname and not accept_foreign: |
|
2139 | 2222 |
msg = ("The configuration denotes node %s as master, while my" |
2140 | 2223 |
" hostname is %s; opening a foreign configuration is only" |
2141 | 2224 |
" possible in accept_foreign mode" % |
2142 |
(data.cluster.master_node, self._my_hostname))
|
|
2225 |
(master_info.name, self._my_hostname))
|
|
2143 | 2226 |
raise errors.ConfigurationError(msg) |
2144 | 2227 |
|
2145 | 2228 |
self._config_data = data |
... | ... | |
2188 | 2271 |
# nodegroups are being added, and upon normally loading the config, |
2189 | 2272 |
# because the members list of a node group is discarded upon |
2190 | 2273 |
# serializing/deserializing the object. |
2191 |
self._UnlockedAddNodeToGroup(node.name, node.group)
|
|
2274 |
self._UnlockedAddNodeToGroup(node.uuid, node.group)
|
|
2192 | 2275 |
|
2193 | 2276 |
modified = (oldconf != self._config_data.ToDict()) |
2194 | 2277 |
if modified: |
... | ... | |
2222 | 2305 |
# since the node list comes from _UnlocketGetNodeList, and we are |
2223 | 2306 |
# called with the lock held, so no modifications should take place |
2224 | 2307 |
# in between |
2225 |
for node_name in self._UnlockedGetNodeList(): |
|
2226 |
if node_name == myhostname: |
|
2227 |
continue |
|
2228 |
node_info = self._UnlockedGetNodeInfo(node_name) |
|
2229 |
if not node_info.master_candidate: |
|
2308 |
for node_uuid in self._UnlockedGetNodeList(): |
|
2309 |
node_info = self._UnlockedGetNodeInfo(node_uuid) |
|
2310 |
if node_info.name == myhostname or not node_info.master_candidate: |
|
2230 | 2311 |
continue |
2231 | 2312 |
node_list.append(node_info.name) |
2232 | 2313 |
addr_list.append(node_info.primary_ip) |
... | ... | |
2293 | 2374 |
if self._last_cluster_serial < self._config_data.cluster.serial_no: |
2294 | 2375 |
if not self._offline: |
2295 | 2376 |
result = self._GetRpc(None).call_write_ssconf_files( |
2296 |
self._UnlockedGetOnlineNodeList(),
|
|
2377 |
self._UnlockedGetNodeNames(self._UnlockedGetOnlineNodeList()),
|
|
2297 | 2378 |
self._UnlockedGetSsconfValues()) |
2298 | 2379 |
|
2299 | 2380 |
for nname, nresu in result.items(): |
... | ... | |
2352 | 2433 |
""" |
2353 | 2434 |
fn = "\n".join |
2354 | 2435 |
instance_names = utils.NiceSort(self._UnlockedGetInstanceList()) |
2355 |
node_names = utils.NiceSort(self._UnlockedGetNodeList())
|
|
2356 |
node_info = [self._UnlockedGetNodeInfo(name) for name in node_names]
|
|
2436 |
node_infos = self._UnlockedGetAllNodesInfo().values()
|
|
2437 |
node_names = [node.name for node in node_infos]
|
|
2357 | 2438 |
node_pri_ips = ["%s %s" % (ninfo.name, ninfo.primary_ip) |
2358 |
for ninfo in node_info] |
|
2439 |
for ninfo in node_infos]
|
|
2359 | 2440 |
node_snd_ips = ["%s %s" % (ninfo.name, ninfo.secondary_ip) |
2360 |
for ninfo in node_info] |
|
2441 |
for ninfo in node_infos]
|
|
2361 | 2442 |
|
2362 | 2443 |
instance_data = fn(instance_names) |
2363 |
off_data = fn(node.name for node in node_info if node.offline) |
|
2364 |
on_data = fn(node.name for node in node_info if not node.offline) |
|
2365 |
mc_data = fn(node.name for node in node_info if node.master_candidate) |
|
2366 |
mc_ips_data = fn(node.primary_ip for node in node_info |
|
2444 |
off_data = fn(node.name for node in node_infos if node.offline)
|
|
2445 |
on_data = fn(node.name for node in node_infos if not node.offline)
|
|
2446 |
mc_data = fn(node.name for node in node_infos if node.master_candidate)
|
|
2447 |
mc_ips_data = fn(node.primary_ip for node in node_infos
|
|
2367 | 2448 |
if node.master_candidate) |
2368 | 2449 |
node_data = fn(node_names) |
2369 | 2450 |
node_pri_ips_data = fn(node_pri_ips) |
... | ... | |
2394 | 2475 |
constants.SS_MASTER_IP: cluster.master_ip, |
2395 | 2476 |
constants.SS_MASTER_NETDEV: cluster.master_netdev, |
2396 | 2477 |
constants.SS_MASTER_NETMASK: str(cluster.master_netmask), |
2397 |
constants.SS_MASTER_NODE: cluster.master_node,
|
|
2478 |
constants.SS_MASTER_NODE: self._UnlockedGetNodeName(cluster.master_node),
|
|
2398 | 2479 |
constants.SS_NODE_LIST: node_data, |
2399 | 2480 |
constants.SS_NODE_PRIMARY_IPS: node_pri_ips_data, |
2400 | 2481 |
constants.SS_NODE_SECONDARY_IPS: node_snd_ips_data, |
... | ... | |
2679 | 2760 |
self._config_data.cluster.serial_no += 1 |
2680 | 2761 |
self._WriteConfig() |
2681 | 2762 |
|
2682 |
def _UnlockedGetGroupNetParams(self, net_uuid, node): |
|
2763 |
def _UnlockedGetGroupNetParams(self, net_uuid, node_uuid):
|
|
2683 | 2764 |
"""Get the netparams (mode, link) of a network. |
2684 | 2765 |
|
2685 | 2766 |
Get a network's netparams for a given node. |
2686 | 2767 |
|
2687 | 2768 |
@type net_uuid: string |
2688 | 2769 |
@param net_uuid: network uuid |
2689 |
@type node: string |
|
2690 |
@param node: node name
|
|
2770 |
@type node_uuid: string
|
|
2771 |
@param node_uuid: node UUID
|
|
2691 | 2772 |
@rtype: dict or None |
2692 | 2773 |
@return: netparams |
2693 | 2774 |
|
2694 | 2775 |
""" |
2695 |
node_info = self._UnlockedGetNodeInfo(node) |
|
2776 |
node_info = self._UnlockedGetNodeInfo(node_uuid)
|
|
2696 | 2777 |
nodegroup_info = self._UnlockedGetNodeGroup(node_info.group) |
2697 | 2778 |
netparams = nodegroup_info.networks.get(net_uuid, None) |
2698 | 2779 |
|
2699 | 2780 |
return netparams |
2700 | 2781 |
|
2701 | 2782 |
@locking.ssynchronized(_config_lock, shared=1) |
2702 |
def GetGroupNetParams(self, net_uuid, node): |
|
2783 |
def GetGroupNetParams(self, net_uuid, node_uuid):
|
|
2703 | 2784 |
"""Locking wrapper of _UnlockedGetGroupNetParams() |
2704 | 2785 |
|
2705 | 2786 |
""" |
2706 |
return self._UnlockedGetGroupNetParams(net_uuid, node) |
|
2787 |
return self._UnlockedGetGroupNetParams(net_uuid, node_uuid)
|
|
2707 | 2788 |
|
2708 | 2789 |
@locking.ssynchronized(_config_lock, shared=1) |
2709 |
def CheckIPInNodeGroup(self, ip, node): |
|
2790 |
def CheckIPInNodeGroup(self, ip, node_uuid):
|
|
2710 | 2791 |
"""Check IP uniqueness in nodegroup. |
2711 | 2792 |
|
2712 | 2793 |
Check networks that are connected in the node's node group |
... | ... | |
2715 | 2796 |
|
2716 | 2797 |
@type ip: string |
2717 | 2798 |
@param ip: ip address |
2718 |
@type node: string |
|
2719 |
@param node: node name
|
|
2799 |
@type node_uuid: string
|
|
2800 |
@param node_uuid: node UUID
|
|
2720 | 2801 |
@rtype: (string, dict) or (None, None) |
2721 | 2802 |
@return: (network name, netparams) |
2722 | 2803 |
|
2723 | 2804 |
""" |
2724 | 2805 |
if ip is None: |
2725 | 2806 |
return (None, None) |
2726 |
node_info = self._UnlockedGetNodeInfo(node) |
|
2807 |
node_info = self._UnlockedGetNodeInfo(node_uuid)
|
|
2727 | 2808 |
nodegroup_info = self._UnlockedGetNodeGroup(node_info.group) |
2728 | 2809 |
for net_uuid in nodegroup_info.networks.keys(): |
2729 | 2810 |
net_info = self._UnlockedGetNetwork(net_uuid) |
Also available in: Unified diff