"""Implement __repr__ for ConfigObjects."""
return repr(self.ToDict())
+ def __eq__(self, other):
+ """Implement __eq__ for ConfigObjects."""
+ return isinstance(other, self.__class__) and self.ToDict() == other.ToDict()
+
def UpgradeConfig(self):
"""Fill defaults for missing configuration values.
"""
__slots__ = ["tags"]
- VALID_TAG_RE = re.compile("^[\w.+*/:@-]+$")
+ VALID_TAG_RE = re.compile(r"^[\w.+*/:@-]+$")
@classmethod
def ValidateTag(cls, tag):
def HasAnyDiskOfType(self, dev_type):
"""Check if in there is at disk of the given type in the configuration.
- @type dev_type: L{constants.LDS_BLOCK}
+ @type dev_type: L{constants.DTS_BLOCK}
@param dev_type: the type to look for
@rtype: boolean
@return: boolean indicating if a disk of the given type was found or not
node.UpgradeConfig()
for instance in self.instances.values():
instance.UpgradeConfig()
+ self._UpgradeEnabledDiskTemplates()
if self.nodegroups is None:
self.nodegroups = {}
for nodegroup in self.nodegroups.values():
nodegroup.UpgradeConfig()
+ InstancePolicy.UpgradeDiskTemplates(
+ nodegroup.ipolicy, self.cluster.enabled_disk_templates)
if self.cluster.drbd_usermode_helper is None:
- # To decide if we set an helper let's check if at least one instance has
- # a DRBD disk. This does not cover all the possible scenarios but it
- # gives a good approximation.
- if self.HasAnyDiskOfType(constants.LD_DRBD8):
+ if self.cluster.IsDiskTemplateEnabled(constants.DT_DRBD8):
self.cluster.drbd_usermode_helper = constants.DEFAULT_DRBD_HELPER
if self.networks is None:
self.networks = {}
for network in self.networks.values():
network.UpgradeConfig()
- self._UpgradeEnabledDiskTemplates()
def _UpgradeEnabledDiskTemplates(self):
"""Upgrade the cluster's enabled disk templates by inspecting the currently
enabled and/or used disk templates.
"""
- # enabled_disk_templates in the cluster config were introduced in 2.8.
- # Remove this code once upgrading from earlier versions is deprecated.
if not self.cluster.enabled_disk_templates:
template_set = \
set([inst.disk_template for inst in self.instances.values()])
if self.cluster.volume_group_name:
template_set.add(constants.DT_DRBD8)
template_set.add(constants.DT_PLAIN)
- # FIXME: Adapt this when dis/enabling at configure time is removed.
- # Enable 'sharedfile', if they are enabled, even though they might
- # currently not be used.
- if constants.ENABLE_SHARED_FILE_STORAGE:
- template_set.add(constants.DT_SHARED_FILE)
# Set enabled_disk_templates to the inferred disk templates. Order them
# according to a preference list that is based on Ganeti's history of
# supported disk templates.
self.cluster.enabled_disk_templates.append(preferred_template)
template_set.remove(preferred_template)
self.cluster.enabled_disk_templates.extend(list(template_set))
+ InstancePolicy.UpgradeDiskTemplates(
+ self.cluster.ipolicy, self.cluster.enabled_disk_templates)
class NIC(ConfigObject):
"""Config object representing a network card."""
- __slots__ = ["name", "mac", "ip", "network", "nicparams", "netinfo"] + _UUID
+ __slots__ = ["name", "mac", "ip", "network",
+ "nicparams", "netinfo", "pci"] + _UUID
@classmethod
def CheckParameterSyntax(cls, nicparams):
class Disk(ConfigObject):
"""Config object representing a block device."""
- __slots__ = (["name", "dev_type", "logical_id", "physical_id",
- "children", "iv_name", "size", "mode", "params", "spindles"] +
- _UUID)
+ __slots__ = (["name", "dev_type", "logical_id", "children", "iv_name",
+ "size", "mode", "params", "spindles", "pci"] + _UUID +
+ # dynamic_params is special. It depends on the node this instance
+ # is sent to, and should not be persisted.
+ ["dynamic_params"])
def CreateOnSecondary(self):
"""Test if this device needs to be created on a secondary node."""
- return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
+ return self.dev_type in (constants.DT_DRBD8, constants.DT_PLAIN)
def AssembleOnSecondary(self):
"""Test if this device needs to be assembled on a secondary node."""
- return self.dev_type in (constants.LD_DRBD8, constants.LD_LV)
+ return self.dev_type in (constants.DT_DRBD8, constants.DT_PLAIN)
def OpenOnSecondary(self):
"""Test if this device needs to be opened on a secondary node."""
- return self.dev_type in (constants.LD_LV,)
+ return self.dev_type in (constants.DT_PLAIN,)
def StaticDevPath(self):
"""Return the device path if this device type has a static one.
should check that it is a valid path.
"""
- if self.dev_type == constants.LD_LV:
+ if self.dev_type == constants.DT_PLAIN:
return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
- elif self.dev_type == constants.LD_BLOCKDEV:
+ elif self.dev_type == constants.DT_BLOCK:
return self.logical_id[1]
- elif self.dev_type == constants.LD_RBD:
+ elif self.dev_type == constants.DT_RBD:
return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
return None
-1.
"""
- if self.dev_type == constants.LD_DRBD8:
+ if self.dev_type == constants.DT_DRBD8:
return 0
return -1
def IsBasedOnDiskType(self, dev_type):
"""Check if the disk or its children are based on the given type.
- @type dev_type: L{constants.LDS_BLOCK}
+ @type dev_type: L{constants.DTS_BLOCK}
@param dev_type: the type to look for
@rtype: boolean
@return: boolean indicating if a device of the given type was found or not
devices needs to (or can) be assembled.
"""
- if self.dev_type in [constants.LD_LV, constants.LD_FILE,
- constants.LD_BLOCKDEV, constants.LD_RBD,
- constants.LD_EXT]:
+ if self.dev_type in [constants.DT_PLAIN, constants.DT_FILE,
+ constants.DT_BLOCK, constants.DT_RBD,
+ constants.DT_EXT, constants.DT_SHARED_FILE]:
result = [node_uuid]
- elif self.dev_type in constants.LDS_DRBD:
+ elif self.dev_type in constants.DTS_DRBD:
result = [self.logical_id[0], self.logical_id[1]]
if node_uuid not in result:
raise errors.ConfigurationError("DRBD device passed unknown node")
@return: a dictionary of volume-groups and the required size
"""
- if self.dev_type == constants.LD_LV:
+ if self.dev_type == constants.DT_PLAIN:
return {self.logical_id[0]: amount}
- elif self.dev_type == constants.LD_DRBD8:
+ elif self.dev_type == constants.DT_DRBD8:
if self.children:
return self.children[0].ComputeGrowth(amount)
else:
actual algorithms from bdev.
"""
- if self.dev_type in (constants.LD_LV, constants.LD_FILE,
- constants.LD_RBD, constants.LD_EXT):
+ if self.dev_type in (constants.DT_PLAIN, constants.DT_FILE,
+ constants.DT_RBD, constants.DT_EXT,
+ constants.DT_SHARED_FILE):
self.size += amount
- elif self.dev_type == constants.LD_DRBD8:
+ elif self.dev_type == constants.DT_DRBD8:
if self.children:
self.children[0].RecordGrow(amount)
self.size += amount
"""Apply changes to size, spindles and mode.
"""
- if self.dev_type == constants.LD_DRBD8:
+ if self.dev_type == constants.DT_DRBD8:
if self.children:
self.children[0].Update(size=size, mode=mode)
else:
child.UnsetSize()
self.size = 0
- def SetPhysicalID(self, target_node_uuid, nodes_ip):
- """Convert the logical ID to the physical ID.
-
- This is used only for drbd, which needs ip/port configuration.
+ def UpdateDynamicDiskParams(self, target_node_uuid, nodes_ip):
+ """Updates the dynamic disk params for the given node.
- The routine descends down and updates its children also, because
- this helps when the only the top device is passed to the remote
- node.
+ This is mainly used for drbd, which needs ip/port configuration.
Arguments:
- target_node_uuid: the node UUID we wish to configure for
- nodes_ip: a mapping of node name to ip
- The target_node must exist in in nodes_ip, and must be one of the
- nodes in the logical ID for each of the DRBD devices encountered
- in the disk tree.
+ The target_node must exist in nodes_ip, and should be one of the
+ nodes in the logical ID if this device is a DRBD device.
"""
if self.children:
for child in self.children:
- child.SetPhysicalID(target_node_uuid, nodes_ip)
+ child.UpdateDynamicDiskParams(target_node_uuid, nodes_ip)
- if self.logical_id is None and self.physical_id is not None:
- return
- if self.dev_type in constants.LDS_DRBD:
- pnode_uuid, snode_uuid, port, pminor, sminor, secret = self.logical_id
+ dyn_disk_params = {}
+ if self.logical_id is not None and self.dev_type in constants.DTS_DRBD:
+ pnode_uuid, snode_uuid, _, pminor, sminor, _ = self.logical_id
if target_node_uuid not in (pnode_uuid, snode_uuid):
- raise errors.ConfigurationError("DRBD device not knowing node %s" %
- target_node_uuid)
+ # disk object is being sent to neither the primary nor the secondary
+ # node. reset the dynamic parameters, the target node is not
+ # supposed to use them.
+ self.dynamic_params = dyn_disk_params
+ return
+
pnode_ip = nodes_ip.get(pnode_uuid, None)
snode_ip = nodes_ip.get(snode_uuid, None)
if pnode_ip is None or snode_ip is None:
raise errors.ConfigurationError("Can't find primary or secondary node"
" for %s" % str(self))
- p_data = (pnode_ip, port)
- s_data = (snode_ip, port)
if pnode_uuid == target_node_uuid:
- self.physical_id = p_data + s_data + (pminor, secret)
+ dyn_disk_params[constants.DDP_LOCAL_IP] = pnode_ip
+ dyn_disk_params[constants.DDP_REMOTE_IP] = snode_ip
+ dyn_disk_params[constants.DDP_LOCAL_MINOR] = pminor
+ dyn_disk_params[constants.DDP_REMOTE_MINOR] = sminor
else: # it must be secondary, we tested above
- self.physical_id = s_data + p_data + (sminor, secret)
- else:
- self.physical_id = self.logical_id
- return
+ dyn_disk_params[constants.DDP_LOCAL_IP] = snode_ip
+ dyn_disk_params[constants.DDP_REMOTE_IP] = pnode_ip
+ dyn_disk_params[constants.DDP_LOCAL_MINOR] = sminor
+ dyn_disk_params[constants.DDP_REMOTE_MINOR] = pminor
- def ToDict(self):
+ self.dynamic_params = dyn_disk_params
+
+ # pylint: disable=W0221
+ def ToDict(self, include_dynamic_params=False):
"""Disk-specific conversion to standard python types.
This replaces the children lists of objects with lists of
"""
bo = super(Disk, self).ToDict()
+ if not include_dynamic_params and "dynamic_params" in bo:
+ del bo["dynamic_params"]
for attr in ("children",):
alist = bo.get(attr, None)
obj.children = outils.ContainerFromDicts(obj.children, list, Disk)
if obj.logical_id and isinstance(obj.logical_id, list):
obj.logical_id = tuple(obj.logical_id)
- if obj.physical_id and isinstance(obj.physical_id, list):
- obj.physical_id = tuple(obj.physical_id)
- if obj.dev_type in constants.LDS_DRBD:
+ if obj.dev_type in constants.DTS_DRBD:
# we need a tuple of length six here
if len(obj.logical_id) < 6:
obj.logical_id += (None,) * (6 - len(obj.logical_id))
"""Custom str() formatter for disks.
"""
- if self.dev_type == constants.LD_LV:
+ if self.dev_type == constants.DT_PLAIN:
val = "<LogicalVolume(/dev/%s/%s" % self.logical_id
- elif self.dev_type in constants.LDS_DRBD:
+ elif self.dev_type in constants.DTS_DRBD:
node_a, node_b, port, minor_a, minor_b = self.logical_id[:5]
val = "<DRBD8("
- if self.physical_id is None:
- phy = "unconfigured"
- else:
- phy = ("configured as %s:%s %s:%s" %
- (self.physical_id[0], self.physical_id[1],
- self.physical_id[2], self.physical_id[3]))
- val += ("hosts=%s/%d-%s/%d, port=%s, %s, " %
- (node_a, minor_a, node_b, minor_b, port, phy))
+ val += ("hosts=%s/%d-%s/%d, port=%s, " %
+ (node_a, minor_a, node_b, minor_b, port))
if self.children and self.children.count(None) == 0:
val += "backend=%s, metadev=%s" % (self.children[0], self.children[1])
else:
val += "no local storage"
else:
- val = ("<Disk(type=%s, logical_id=%s, physical_id=%s, children=%s" %
- (self.dev_type, self.logical_id, self.physical_id, self.children))
+ val = ("<Disk(type=%s, logical_id=%s, children=%s" %
+ (self.dev_type, self.logical_id, self.children))
if self.iv_name is None:
val += ", not visible"
else:
self.params = {}
# add here config upgrade for this disk
+ # map of legacy device types (mapping differing LD constants to new
+ # DT constants)
+ LEG_DEV_TYPE_MAP = {"lvm": constants.DT_PLAIN, "drbd8": constants.DT_DRBD8}
+ if self.dev_type in LEG_DEV_TYPE_MAP:
+ self.dev_type = LEG_DEV_TYPE_MAP[self.dev_type]
+
@staticmethod
def ComputeLDParams(disk_template, disk_params):
"""Computes Logical Disk parameters from Disk Template parameters.
result = list()
dt_params = disk_params[disk_template]
if disk_template == constants.DT_DRBD8:
- result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_DRBD8], {
+ result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.DT_DRBD8], {
constants.LDP_RESYNC_RATE: dt_params[constants.DRBD_RESYNC_RATE],
constants.LDP_BARRIERS: dt_params[constants.DRBD_DISK_BARRIERS],
constants.LDP_NO_META_FLUSH: dt_params[constants.DRBD_META_BARRIERS],
}))
# data LV
- result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], {
+ result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.DT_PLAIN], {
constants.LDP_STRIPES: dt_params[constants.DRBD_DATA_STRIPES],
}))
# metadata LV
- result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], {
+ result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.DT_PLAIN], {
constants.LDP_STRIPES: dt_params[constants.DRBD_META_STRIPES],
}))
elif disk_template in (constants.DT_FILE, constants.DT_SHARED_FILE):
- result.append(constants.DISK_LD_DEFAULTS[constants.LD_FILE])
+ result.append(constants.DISK_LD_DEFAULTS[disk_template])
elif disk_template == constants.DT_PLAIN:
- result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], {
+ result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.DT_PLAIN], {
constants.LDP_STRIPES: dt_params[constants.LV_STRIPES],
}))
elif disk_template == constants.DT_BLOCK:
- result.append(constants.DISK_LD_DEFAULTS[constants.LD_BLOCKDEV])
+ result.append(constants.DISK_LD_DEFAULTS[constants.DT_BLOCK])
elif disk_template == constants.DT_RBD:
- result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_RBD], {
+ result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.DT_RBD], {
constants.LDP_POOL: dt_params[constants.RBD_POOL],
+ constants.LDP_ACCESS: dt_params[constants.RBD_ACCESS],
}))
elif disk_template == constants.DT_EXT:
- result.append(constants.DISK_LD_DEFAULTS[constants.LD_EXT])
+ result.append(constants.DISK_LD_DEFAULTS[constants.DT_EXT])
return result
"""
@classmethod
+ def UpgradeDiskTemplates(cls, ipolicy, enabled_disk_templates):
+ """Upgrades the ipolicy configuration."""
+ if constants.IPOLICY_DTS in ipolicy:
+ if not set(ipolicy[constants.IPOLICY_DTS]).issubset(
+ set(enabled_disk_templates)):
+ ipolicy[constants.IPOLICY_DTS] = list(
+ set(ipolicy[constants.IPOLICY_DTS]) & set(enabled_disk_templates))
+
+ @classmethod
def CheckParameterSyntax(cls, ipolicy, check_std):
""" Check the instance policy for validity.
"""
def _Helper(nodes, device):
"""Recursively computes nodes given a top device."""
- if device.dev_type in constants.LDS_DRBD:
+ if device.dev_type in constants.DTS_DRBD:
nodea, nodeb = device.logical_id[:2]
nodes.add(nodea)
nodes.add(nodeb)
devs = self.disks
for dev in devs:
- if dev.dev_type == constants.LD_LV:
+ if dev.dev_type == constants.DT_PLAIN:
lvmap[node_uuid].append(dev.logical_id[0] + "/" + dev.logical_id[1])
- elif dev.dev_type in constants.LDS_DRBD:
+ elif dev.dev_type in constants.DTS_DRBD:
if dev.children:
self.MapLVsByNode(lvmap, dev.children, dev.logical_id[0])
self.MapLVsByNode(lvmap, dev.children, dev.logical_id[1])
__slots__ = [
"serial_no",
"rsahostkeypub",
+ "dsahostkeypub",
"highest_used_port",
"tcpudp_port_pool",
"mac_prefix",