#
#
-# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Google Inc.
+# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 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
from ganeti import errors
from ganeti import constants
from ganeti import netutils
+from ganeti import utils
from socket import AF_INET
_TIMESTAMPS = ["ctime", "mtime"]
_UUID = ["uuid"]
+# constants used to create InstancePolicy dictionary
+TISPECS_GROUP_TYPES = {
+ constants.ISPECS_MIN: constants.VTYPE_INT,
+ constants.ISPECS_MAX: constants.VTYPE_INT,
+ }
+
+TISPECS_CLUSTER_TYPES = {
+ constants.ISPECS_MIN: constants.VTYPE_INT,
+ constants.ISPECS_MAX: constants.VTYPE_INT,
+ constants.ISPECS_STD: constants.VTYPE_INT,
+ }
+
def FillDict(defaults_dict, custom_dict, skip_keys=None):
"""Basic function to apply settings on top a default dict.
return ret_dict
+def FillIPolicy(default_ipolicy, custom_ipolicy, skip_keys=None):
+ """Fills an instance policy with defaults.
+
+ """
+ assert frozenset(default_ipolicy.keys()) == constants.IPOLICY_ALL_KEYS
+ ret_dict = {}
+ for key in constants.IPOLICY_ISPECS:
+ ret_dict[key] = FillDict(default_ipolicy[key],
+ custom_ipolicy.get(key, {}),
+ skip_keys=skip_keys)
+ # list items
+ for key in [constants.IPOLICY_DTS]:
+ ret_dict[key] = list(custom_ipolicy.get(key, default_ipolicy[key]))
+
+ return ret_dict
+
+
def UpgradeGroupedParams(target, defaults):
"""Update all groups for the target parameter.
return result
+def MakeEmptyIPolicy():
+ """Create empty IPolicy dictionary.
+
+ """
+ return dict([
+ (constants.ISPECS_MIN, {}),
+ (constants.ISPECS_MAX, {}),
+ (constants.ISPECS_STD, {}),
+ ])
+
+
+def CreateIPolicyFromOpts(ispecs_mem_size=None,
+ ispecs_cpu_count=None,
+ ispecs_disk_count=None,
+ ispecs_disk_size=None,
+ ispecs_nic_count=None,
+ ipolicy_disk_templates=None,
+ group_ipolicy=False,
+ allowed_values=None,
+ fill_all=False):
+ """Creation of instance policy based on command line options.
+
+ @param fill_all: whether for cluster policies we should ensure that
+ all values are filled
+
+
+ """
+ # prepare ipolicy dict
+ ipolicy_transposed = {
+ constants.ISPEC_MEM_SIZE: ispecs_mem_size,
+ constants.ISPEC_CPU_COUNT: ispecs_cpu_count,
+ constants.ISPEC_DISK_COUNT: ispecs_disk_count,
+ constants.ISPEC_DISK_SIZE: ispecs_disk_size,
+ constants.ISPEC_NIC_COUNT: ispecs_nic_count,
+ }
+
+ # first, check that the values given are correct
+ if group_ipolicy:
+ forced_type = TISPECS_GROUP_TYPES
+ else:
+ forced_type = TISPECS_CLUSTER_TYPES
+
+ for specs in ipolicy_transposed.values():
+ utils.ForceDictType(specs, forced_type, allowed_values=allowed_values)
+
+ # then transpose
+ ipolicy_out = MakeEmptyIPolicy()
+ for name, specs in ipolicy_transposed.iteritems():
+ assert name in constants.ISPECS_PARAMETERS
+ for key, val in specs.items(): # {min: .. ,max: .., std: ..}
+ ipolicy_out[key][name] = val
+
+ # no filldict for lists
+ if not group_ipolicy and fill_all and ipolicy_disk_templates is None:
+ ipolicy_disk_templates = constants.DISK_TEMPLATES
+ if ipolicy_disk_templates is not None:
+ ipolicy_out[constants.IPOLICY_DTS] = list(ipolicy_disk_templates)
+
+ assert not (frozenset(ipolicy_out.keys()) - constants.IPOLICY_ALL_KEYS)
+
+ return ipolicy_out
+
+
class ConfigObject(object):
"""A generic config object.
return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
elif self.dev_type == constants.LD_BLOCKDEV:
return self.logical_id[1]
+ elif self.dev_type == constants.LD_RBD:
+ return "/dev/%s/%s" % (self.logical_id[0], self.logical_id[1])
return None
def ChildrenNeeded(self):
"""
if self.dev_type in [constants.LD_LV, constants.LD_FILE,
- constants.LD_BLOCKDEV]:
+ constants.LD_BLOCKDEV, constants.LD_RBD]:
result = [node]
elif self.dev_type in constants.LDS_DRBD:
result = [self.logical_id[0], self.logical_id[1]]
actual algorithms from bdev.
"""
- if self.dev_type in (constants.LD_LV, constants.LD_FILE):
+ if self.dev_type in (constants.LD_LV, constants.LD_FILE,
+ constants.LD_RBD):
self.size += amount
elif self.dev_type == constants.LD_DRBD8:
if self.children:
raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
" disk type %s" % self.dev_type)
+ def Update(self, size=None, mode=None):
+ """Apply changes to size and mode.
+
+ """
+ if self.dev_type == constants.LD_DRBD8:
+ if self.children:
+ self.children[0].Update(size=size, mode=mode)
+ else:
+ assert not self.children
+
+ if size is not None:
+ self.size = size
+ if mode is not None:
+ self.mode = mode
+
def UnsetSize(self):
"""Sets recursively the size to zero for the disk and its children.
# add here config upgrade for this disk
+class InstancePolicy(ConfigObject):
+ """Config object representing instance policy limits dictionary."""
+ __slots__ = ["min", "max", "std", "disk_templates"]
+
+ @classmethod
+ def CheckParameterSyntax(cls, ipolicy):
+ """ Check the instance policy for validity.
+
+ """
+ for param in constants.ISPECS_PARAMETERS:
+ InstancePolicy.CheckISpecSyntax(ipolicy, param)
+ if constants.IPOLICY_DTS in ipolicy:
+ InstancePolicy.CheckDiskTemplates(ipolicy[constants.IPOLICY_DTS])
+ wrong_keys = frozenset(ipolicy.keys()) - constants.IPOLICY_ALL_KEYS
+ if wrong_keys:
+ raise errors.ConfigurationError("Invalid keys in ipolicy: %s" %
+ utils.CommaJoin(wrong_keys))
+
+ @classmethod
+ def CheckISpecSyntax(cls, ipolicy, name):
+ """Check the instance policy for validity on a given key.
+
+ We check if the instance policy makes sense for a given key, that is
+ if ipolicy[min][name] <= ipolicy[std][name] <= ipolicy[max][name].
+
+ @type ipolicy: dict
+ @param ipolicy: dictionary with min, max, std specs
+ @type name: string
+ @param name: what are the limits for
+ @raise errors.ConfigureError: when specs for given name are not valid
+
+ """
+ min_v = ipolicy[constants.ISPECS_MIN].get(name, 0)
+ std_v = ipolicy[constants.ISPECS_STD].get(name, min_v)
+ max_v = ipolicy[constants.ISPECS_MAX].get(name, std_v)
+ err = ("Invalid specification of min/max/std values for %s: %s/%s/%s" %
+ (name,
+ ipolicy[constants.ISPECS_MIN].get(name, "-"),
+ ipolicy[constants.ISPECS_MAX].get(name, "-"),
+ ipolicy[constants.ISPECS_STD].get(name, "-")))
+ if min_v > std_v or std_v > max_v:
+ raise errors.ConfigurationError(err)
+
+ @classmethod
+ def CheckDiskTemplates(cls, disk_templates):
+ """Checks the disk templates for validity.
+
+ """
+ wrong = frozenset(disk_templates).difference(constants.DISK_TEMPLATES)
+ if wrong:
+ raise errors.ConfigurationError("Invalid disk template(s) %s" %
+ utils.CommaJoin(wrong))
+
+
class Instance(TaggableObject):
"""Config object representing an instance."""
__slots__ = [
"members",
"ndparams",
"diskparams",
+ "ipolicy",
"serial_no",
"hv_state_static",
"disk_state_static",
if self.alloc_policy is None:
self.alloc_policy = constants.ALLOC_POLICY_PREFERRED
- # We only update mtime, and not ctime, since we would not be able to provide
- # a correct value for creation time.
+ # We only update mtime, and not ctime, since we would not be able
+ # to provide a correct value for creation time.
if self.mtime is None:
self.mtime = time.time()
self.diskparams = UpgradeDiskParams(self.diskparams)
+ if self.ipolicy is None:
+ self.ipolicy = MakeEmptyIPolicy()
def FillND(self, node):
"""Return filled out ndparams for L{objects.Node}
"shared_file_storage_dir",
"enabled_hypervisors",
"hvparams",
+ "ipolicy",
"os_hvp",
"beparams",
"osparams",
self.diskparams = UpgradeDiskParams(self.diskparams)
+ # instance policy added before 2.6
+ if self.ipolicy is None:
+ self.ipolicy = FillIPolicy(constants.IPOLICY_DEFAULTS, {})
+ else:
+ # we can either make sure to upgrade the ipolicy always, or only
+ # do it in some corner cases (e.g. missing keys); note that this
+ # will break any removal of keys from the ipolicy dict
+ self.ipolicy = FillIPolicy(constants.IPOLICY_DEFAULTS, self.ipolicy)
+
@property
def primary_hypervisor(self):
"""The first hypervisor is the primary.
"""
return FillDict(self.ndparams, ndparams)
+ def SimpleFillIPolicy(self, ipolicy):
+ """ Fill instance policy dict with defaults.
+
+ @type ipolicy: dict
+ @param ipolicy: the dict to fill
+ @rtype: dict
+ @return: a copy of passed ipolicy with missing keys filled from
+ the cluster defaults
+
+ """
+ return FillIPolicy(self.ipolicy, ipolicy)
+
class BlockDevStatus(ConfigObject):
"""Config object representing the status of a block device."""