X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/73e0328b245b54bd599ccde5fe2b48b735add196..6a1434d7cdb5df75a98cc0a364e78f1a4c86bba6:/lib/objects.py diff --git a/lib/objects.py b/lib/objects.py index 17a8190..29f03e0 100644 --- a/lib/objects.py +++ b/lib/objects.py @@ -1,7 +1,7 @@ # # -# Copyright (C) 2006, 2007 Google Inc. +# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,7 +26,7 @@ pass to and from external parties. """ -# pylint: disable-msg=E0203,W0201 +# pylint: disable=E0203,W0201 # E0203: Access to member %r before its definition, since we use # objects.py which doesn't explicitely initialise its members @@ -36,14 +36,17 @@ pass to and from external parties. import ConfigParser import re import copy +import time from cStringIO import StringIO from ganeti import errors from ganeti import constants +from socket import AF_INET + __all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance", - "OS", "Node", "Cluster", "FillDict"] + "OS", "Node", "NodeGroup", "Cluster", "FillDict"] _TIMESTAMPS = ["ctime", "mtime"] _UUID = ["uuid"] @@ -167,7 +170,7 @@ class ConfigObject(object): raise errors.ConfigurationError("Invalid object passed to FromDict:" " expected dict, got %s" % type(val)) val_str = dict([(str(k), v) for k, v in val.iteritems()]) - obj = cls(**val_str) # pylint: disable-msg=W0142 + obj = cls(**val_str) # pylint: disable=W0142 return obj @staticmethod @@ -200,6 +203,8 @@ class ConfigObject(object): if not isinstance(c_type, type): raise TypeError("Container type %s passed to _ContainerFromDicts is" " not a type" % type(c_type)) + if source is None: + source = c_type() if c_type is dict: ret = dict([(k, e_type.FromDict(v)) for k, v in source.iteritems()]) elif c_type in (list, tuple, set, frozenset): @@ -312,8 +317,14 @@ class TaggableObject(ConfigObject): class ConfigData(ConfigObject): """Top-level config object.""" - __slots__ = (["version", "cluster", "nodes", "instances", "serial_no"] + - _TIMESTAMPS) + __slots__ = [ + "version", + "cluster", + "nodes", + "nodegroups", + "instances", + "serial_no", + ] + _TIMESTAMPS def ToDict(self): """Custom function for top-level config data. @@ -324,7 +335,7 @@ class ConfigData(ConfigObject): """ mydict = super(ConfigData, self).ToDict() mydict["cluster"] = mydict["cluster"].ToDict() - for key in "nodes", "instances": + for key in "nodes", "instances", "nodegroups": mydict[key] = self._ContainerToDicts(mydict[key]) return mydict @@ -338,8 +349,24 @@ class ConfigData(ConfigObject): obj.cluster = Cluster.FromDict(obj.cluster) obj.nodes = cls._ContainerFromDicts(obj.nodes, dict, Node) obj.instances = cls._ContainerFromDicts(obj.instances, dict, Instance) + obj.nodegroups = cls._ContainerFromDicts(obj.nodegroups, dict, NodeGroup) return obj + 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} + @param dev_type: the type to look for + @rtype: boolean + @return: boolean indicating if a disk of the given type was found or not + + """ + for instance in self.instances.values(): + for disk in instance.disks: + if disk.IsBasedOnDiskType(dev_type): + return True + return False + def UpgradeConfig(self): """Fill defaults for missing configuration values. @@ -349,11 +376,21 @@ class ConfigData(ConfigObject): node.UpgradeConfig() for instance in self.instances.values(): instance.UpgradeConfig() + if self.nodegroups is None: + self.nodegroups = {} + for nodegroup in self.nodegroups.values(): + nodegroup.UpgradeConfig() + 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): + self.cluster.drbd_usermode_helper = constants.DEFAULT_DRBD_HELPER class NIC(ConfigObject): """Config object representing a network card.""" - __slots__ = ["mac", "ip", "bridge", "nicparams"] + __slots__ = ["mac", "ip", "nicparams"] @classmethod def CheckParameterSyntax(cls, nicparams): @@ -364,7 +401,8 @@ class NIC(ConfigObject): @raise errors.ConfigurationError: when a parameter is not valid """ - if nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES: + if (nicparams[constants.NIC_MODE] not in constants.NIC_VALID_MODES and + nicparams[constants.NIC_MODE] != constants.VALUE_AUTO): err = "Invalid nic mode: %s" % nicparams[constants.NIC_MODE] raise errors.ConfigurationError(err) @@ -373,20 +411,6 @@ class NIC(ConfigObject): err = "Missing bridged nic link" raise errors.ConfigurationError(err) - def UpgradeConfig(self): - """Fill defaults for missing configuration values. - - """ - if self.nicparams is None: - self.nicparams = {} - if self.bridge is not None: - self.nicparams[constants.NIC_MODE] = constants.NIC_MODE_BRIDGED - self.nicparams[constants.NIC_LINK] = self.bridge - # bridge is no longer used it 2.1. The slot is left there to support - # upgrading, but will be removed in 2.2 - if self.bridge is not None: - self.bridge = None - class Disk(ConfigObject): """Config object representing a block device.""" @@ -418,6 +442,8 @@ class Disk(ConfigObject): """ if self.dev_type == constants.LD_LV: return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1]) + elif self.dev_type == constants.LD_BLOCKDEV: + return self.logical_id[1] return None def ChildrenNeeded(self): @@ -436,6 +462,21 @@ class Disk(ConfigObject): 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} + @param dev_type: the type to look for + @rtype: boolean + @return: boolean indicating if a device of the given type was found or not + + """ + if self.children: + for child in self.children: + if child.IsBasedOnDiskType(dev_type): + return True + return self.dev_type == dev_type + def GetNodes(self, node): """This function returns the nodes this device lives on. @@ -445,7 +486,8 @@ class Disk(ConfigObject): devices needs to (or can) be assembled. """ - if self.dev_type in [constants.LD_LV, constants.LD_FILE]: + if self.dev_type in [constants.LD_LV, constants.LD_FILE, + constants.LD_BLOCKDEV]: result = [node] elif self.dev_type in constants.LDS_DRBD: result = [self.logical_id[0], self.logical_id[1]] @@ -490,6 +532,28 @@ class Disk(ConfigObject): # be different) return result + def ComputeGrowth(self, amount): + """Compute the per-VG growth requirements. + + This only works for VG-based disks. + + @type amount: integer + @param amount: the desired increase in (user-visible) disk space + @rtype: dict + @return: a dictionary of volume-groups and the required size + + """ + if self.dev_type == constants.LD_LV: + return {self.logical_id[0]: amount} + elif self.dev_type == constants.LD_DRBD8: + if self.children: + return self.children[0].ComputeGrowth(amount) + else: + return {} + else: + # Other disk types do not require VG space + return {} + def RecordGrow(self, amount): """Update the size of this disk after growth. @@ -498,7 +562,7 @@ class Disk(ConfigObject): actual algorithms from bdev. """ - if self.dev_type == constants.LD_LV or self.dev_type == constants.LD_FILE: + if self.dev_type in (constants.LD_LV, constants.LD_FILE): self.size += amount elif self.dev_type == constants.LD_DRBD8: if self.children: @@ -599,7 +663,7 @@ class Disk(ConfigObject): """ if self.dev_type == constants.LD_LV: - val = "