#
#
-# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc.
+# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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
"""
return self._config_data.cluster.SimpleFillDP(group.diskparams)
- def _UnlockedGetNetworkMACPrefix(self, net):
+ def _UnlockedGetNetworkMACPrefix(self, net_uuid):
"""Return the network mac prefix if it exists or the cluster level default.
"""
prefix = None
- if net:
- net_uuid = self._UnlockedLookupNetwork(net)
- if net_uuid:
- nobj = self._UnlockedGetNetwork(net_uuid)
- if nobj.mac_prefix:
- prefix = nobj.mac_prefix
+ if net_uuid:
+ nobj = self._UnlockedGetNetwork(net_uuid)
+ if nobj.mac_prefix:
+ prefix = nobj.mac_prefix
return prefix
return GenMac
@locking.ssynchronized(_config_lock, shared=1)
- def GenerateMAC(self, net, ec_id):
+ def GenerateMAC(self, net_uuid, ec_id):
"""Generate a MAC for an instance.
This should check the current instances for duplicates.
"""
existing = self._AllMACs()
- prefix = self._UnlockedGetNetworkMACPrefix(net)
+ prefix = self._UnlockedGetNetworkMACPrefix(net_uuid)
gen_mac = self._GenerateOneMAC(prefix)
return self._temporary_ids.Generate(existing, gen_mac, ec_id)
(constants.RELEASE_ACTION, address, net_uuid))
@locking.ssynchronized(_config_lock, shared=1)
- def ReleaseIp(self, net, address, ec_id):
+ def ReleaseIp(self, net_uuid, address, ec_id):
"""Give a specified IP address back to an IP pool.
This is just a wrapper around _UnlockedReleaseIp.
"""
- net_uuid = self._UnlockedLookupNetwork(net)
if net_uuid:
self._UnlockedReleaseIp(net_uuid, address, ec_id)
@locking.ssynchronized(_config_lock, shared=1)
- def GenerateIp(self, net, ec_id):
+ def GenerateIp(self, net_uuid, ec_id):
"""Find a free IPv4 address for an instance.
"""
- net_uuid = self._UnlockedLookupNetwork(net)
nobj = self._UnlockedGetNetwork(net_uuid)
pool = network.AddressPool(nobj)
_, address, _ = self._temporary_ips.Generate([], gen_one, ec_id)
return address
- def _UnlockedReserveIp(self, net_uuid, address, ec_id):
+ def _UnlockedReserveIp(self, net_uuid, address, ec_id, check=True):
"""Reserve a given IPv4 address for use by an instance.
"""
pool = network.AddressPool(nobj)
try:
isreserved = pool.IsReserved(address)
+ isextreserved = pool.IsReserved(address, external=True)
except errors.AddressPoolError:
raise errors.ReservationError("IP address not in network")
if isreserved:
raise errors.ReservationError("IP address already in use")
+ if check and isextreserved:
+ raise errors.ReservationError("IP is externally reserved")
return self._temporary_ips.Reserve(ec_id,
(constants.RESERVE_ACTION,
address, net_uuid))
@locking.ssynchronized(_config_lock, shared=1)
- def ReserveIp(self, net, address, ec_id):
+ def ReserveIp(self, net_uuid, address, ec_id, check=True):
"""Reserve a given IPv4 address for use by an instance.
"""
- net_uuid = self._UnlockedLookupNetwork(net)
if net_uuid:
- return self._UnlockedReserveIp(net_uuid, address, ec_id)
+ return self._UnlockedReserveIp(net_uuid, address, ec_id, check)
@locking.ssynchronized(_config_lock, shared=1)
def ReserveLV(self, lv_name, ec_id):
lvnames.update(lv_list)
return lvnames
+ def _AllDisks(self):
+ """Compute the list of all Disks (recursively, including children).
+
+ """
+ def DiskAndAllChildren(disk):
+ """Returns a list containing the given disk and all of his children.
+
+ """
+ disks = [disk]
+ if disk.children:
+ for child_disk in disk.children:
+ disks.extend(DiskAndAllChildren(child_disk))
+ return disks
+
+ disks = []
+ for instance in self._config_data.instances.values():
+ for disk in instance.disks:
+ disks.extend(DiskAndAllChildren(disk))
+ return disks
+
+ def _AllNICs(self):
+ """Compute the list of all NICs.
+
+ """
+ nics = []
+ for instance in self._config_data.instances.values():
+ nics.extend(instance.nics)
+ return nics
+
def _AllIDs(self, include_temporary):
"""Compute the list of all UUIDs and names we have.
invalid_hvs = set(cluster.enabled_hypervisors) - constants.HYPER_TYPES
if invalid_hvs:
result.append("enabled hypervisors contains invalid entries: %s" %
- invalid_hvs)
+ utils.CommaJoin(invalid_hvs))
missing_hvp = (set(cluster.enabled_hypervisors) -
set(cluster.hvparams.keys()))
if missing_hvp:
result.append("hypervisor parameters missing for the enabled"
" hypervisor(s) %s" % utils.CommaJoin(missing_hvp))
+ if not cluster.enabled_disk_templates:
+ result.append("enabled disk templates list doesn't have any entries")
+ invalid_disk_templates = set(cluster.enabled_disk_templates) \
+ - constants.DISK_TEMPLATES
+ if invalid_disk_templates:
+ result.append("enabled disk templates list contains invalid entries:"
+ " %s" % utils.CommaJoin(invalid_disk_templates))
+
if cluster.master_node not in data.nodes:
result.append("cluster has invalid primary node '%s'" %
cluster.master_node)
except errors.ConfigurationError, err:
result.append("%s has invalid nicparams: %s" % (owner, err))
- def _helper_ipolicy(owner, params, check_std):
+ def _helper_ipolicy(owner, ipolicy, iscluster):
try:
- objects.InstancePolicy.CheckParameterSyntax(params, check_std)
+ objects.InstancePolicy.CheckParameterSyntax(ipolicy, iscluster)
except errors.ConfigurationError, err:
result.append("%s has invalid instance policy: %s" % (owner, err))
-
- def _helper_ispecs(owner, params):
- for key, value in params.items():
- if key in constants.IPOLICY_ISPECS:
- fullkey = "ipolicy/" + key
- _helper(owner, fullkey, value, constants.ISPECS_PARAMETER_TYPES)
+ for key, value in ipolicy.items():
+ if key == constants.ISPECS_MINMAX:
+ for k in range(len(value)):
+ _helper_ispecs(owner, "ipolicy/%s[%s]" % (key, k), value[k])
+ elif key == constants.ISPECS_STD:
+ _helper(owner, "ipolicy/" + key, value,
+ constants.ISPECS_PARAMETER_TYPES)
else:
# FIXME: assuming list type
if key in constants.IPOLICY_PARAMETERS:
" expecting %s, got %s" %
(owner, key, exp_type.__name__, type(value)))
+ def _helper_ispecs(owner, parentkey, params):
+ for (key, value) in params.items():
+ fullkey = "/".join([parentkey, key])
+ _helper(owner, fullkey, value, constants.ISPECS_PARAMETER_TYPES)
+
# check cluster parameters
_helper("cluster", "beparams", cluster.SimpleFillBE({}),
constants.BES_PARAMETER_TYPES)
_helper_nic("cluster", cluster.SimpleFillNIC({}))
_helper("cluster", "ndparams", cluster.SimpleFillND({}),
constants.NDS_PARAMETER_TYPES)
- _helper_ipolicy("cluster", cluster.SimpleFillIPolicy({}), True)
- _helper_ispecs("cluster", cluster.SimpleFillIPolicy({}))
+ _helper_ipolicy("cluster", cluster.ipolicy, True)
# per-instance checks
for instance_name in data.instances:
filled, constants.NICS_PARAMETER_TYPES)
_helper_nic(owner, filled)
+ # disk template checks
+ if not instance.disk_template in data.cluster.enabled_disk_templates:
+ result.append("instance '%s' uses the disabled disk template '%s'." %
+ (instance_name, instance.disk_template))
+
# parameter checks
if instance.beparams:
_helper("instance %s" % instance.name, "beparams",
_helper("node %s" % node.name, "ndparams",
cluster.FillND(node, data.nodegroups[node.group]),
constants.NDS_PARAMETER_TYPES)
+ used_globals = constants.NDC_GLOBALS.intersection(node.ndparams)
+ if used_globals:
+ result.append("Node '%s' has some global parameters set: %s" %
+ (node.name, utils.CommaJoin(used_globals)))
# nodegroups checks
nodegroups_names = set()
group_name = "group %s" % nodegroup.name
_helper_ipolicy(group_name, cluster.SimpleFillIPolicy(nodegroup.ipolicy),
False)
- _helper_ispecs(group_name, cluster.SimpleFillIPolicy(nodegroup.ipolicy))
if nodegroup.ndparams:
_helper(group_name, "ndparams",
cluster.SimpleFillND(nodegroup.ndparams),
return self._config_data.cluster.enabled_hypervisors[0]
@locking.ssynchronized(_config_lock, shared=1)
- def GetHostKey(self):
+ def GetRsaHostKey(self):
"""Return the rsa hostkey from the config.
@rtype: string
return self._config_data.cluster.rsahostkeypub
@locking.ssynchronized(_config_lock, shared=1)
+ def GetDsaHostKey(self):
+ """Return the dsa hostkey from the config.
+
+ @rtype: string
+ @return: the dsa hostkey
+
+ """
+ return self._config_data.cluster.dsahostkeypub
+
+ @locking.ssynchronized(_config_lock, shared=1)
def GetDefaultIAllocator(self):
"""Get the default instance allocator for this cluster.
raise errors.ConfigurationError("Cannot add '%s': UUID %s already"
" in use" % (item.name, item.uuid))
- def _SetInstanceStatus(self, instance_name, status):
+ def _SetInstanceStatus(self, instance_name, status, disks_active):
"""Set the instance's status to a given value.
"""
- assert status in constants.ADMINST_ALL, \
- "Invalid status '%s' passed to SetInstanceStatus" % (status,)
-
if instance_name not in self._config_data.instances:
raise errors.ConfigurationError("Unknown instance '%s'" %
instance_name)
instance = self._config_data.instances[instance_name]
- if instance.admin_state != status:
+
+ if status is None:
+ status = instance.admin_state
+ if disks_active is None:
+ disks_active = instance.disks_active
+
+ assert status in constants.ADMINST_ALL, \
+ "Invalid status '%s' passed to SetInstanceStatus" % (status,)
+
+ if instance.admin_state != status or \
+ instance.disks_active != disks_active:
instance.admin_state = status
+ instance.disks_active = disks_active
instance.serial_no += 1
instance.mtime = time.time()
self._WriteConfig()
def MarkInstanceUp(self, instance_name):
"""Mark the instance status to up in the config.
+ This also sets the instance disks active flag.
+
"""
- self._SetInstanceStatus(instance_name, constants.ADMINST_UP)
+ self._SetInstanceStatus(instance_name, constants.ADMINST_UP, True)
@locking.ssynchronized(_config_lock)
def MarkInstanceOffline(self, instance_name):
"""Mark the instance status to down in the config.
+ This also clears the instance disks active flag.
+
"""
- self._SetInstanceStatus(instance_name, constants.ADMINST_OFFLINE)
+ self._SetInstanceStatus(instance_name, constants.ADMINST_OFFLINE, False)
@locking.ssynchronized(_config_lock)
def RemoveInstance(self, instance_name):
instance = self._UnlockedGetInstanceInfo(instance_name)
for nic in instance.nics:
- if nic.network is not None and nic.ip is not None:
- net_uuid = self._UnlockedLookupNetwork(nic.network)
- if net_uuid:
- # Return all IP addresses to the respective address pools
- self._UnlockedCommitIp(constants.RELEASE_ACTION, net_uuid, nic.ip)
+ if nic.network and nic.ip:
+ # Return all IP addresses to the respective address pools
+ self._UnlockedCommitIp(constants.RELEASE_ACTION, nic.network, nic.ip)
del self._config_data.instances[instance_name]
self._config_data.cluster.serial_no += 1
inst = self._config_data.instances[old_name].Copy()
inst.name = new_name
- for (idx, disk) in enumerate(inst.disks):
- if disk.dev_type == constants.LD_FILE:
+ for (_, disk) in enumerate(inst.disks):
+ if disk.dev_type in [constants.DT_FILE, constants.DT_SHARED_FILE]:
# rename the file paths in logical and physical id
file_storage_dir = os.path.dirname(os.path.dirname(disk.logical_id[1]))
disk.logical_id = (disk.logical_id[0],
utils.PathJoin(file_storage_dir, inst.name,
- "disk%s" % idx))
+ os.path.basename(disk.logical_id[1])))
disk.physical_id = disk.logical_id
# Actually replace instance object
def MarkInstanceDown(self, instance_name):
"""Mark the status of an instance to down in the configuration.
+ This does not touch the instance disks active flag, as shut down instances
+ can still have active disks.
+
+ """
+ self._SetInstanceStatus(instance_name, constants.ADMINST_DOWN, None)
+
+ @locking.ssynchronized(_config_lock)
+ def MarkInstanceDisksActive(self, instance_name):
+ """Mark the status of instance disks active.
+
"""
- self._SetInstanceStatus(instance_name, constants.ADMINST_DOWN)
+ self._SetInstanceStatus(instance_name, None, True)
+
+ @locking.ssynchronized(_config_lock)
+ def MarkInstanceDisksInactive(self, instance_name):
+ """Mark the status of instance disks inactive.
+
+ """
+ self._SetInstanceStatus(instance_name, None, False)
def _UnlockedGetInstanceList(self):
"""Get the list of instances.
for node_name in nodes)
@locking.ssynchronized(_config_lock, shared=1)
+ def GetInstanceNetworks(self, instance_name):
+ """Returns set of network UUIDs for instance's nics.
+
+ @rtype: frozenset
+
+ """
+ instance = self._UnlockedGetInstanceInfo(instance_name)
+ if not instance:
+ raise errors.ConfigurationError("Unknown instance '%s'" % instance_name)
+
+ networks = set()
+ for nic in instance.nics:
+ if nic.network:
+ networks.add(nic.network)
+
+ return frozenset(networks)
+
+ @locking.ssynchronized(_config_lock, shared=1)
def GetMultiInstanceInfo(self, instances):
"""Get the configuration of multiple instances.
return (self._config_data.instances.values() +
self._config_data.nodes.values() +
self._config_data.nodegroups.values() +
+ self._config_data.networks.values() +
+ self._AllDisks() +
+ self._AllNICs() +
[self._config_data.cluster])
def _OpenConfig(self, accept_foreign):
# This is ok even if it acquires the internal lock, as _UpgradeConfig is
# only called at config init time, without the lock held
self.DropECReservations(_UPGRADE_CONFIG_JID)
+ else:
+ config_errors = self._UnlockedVerifyConfig()
+ if config_errors:
+ errmsg = ("Loaded configuration data is not consistent: %s" %
+ (utils.CommaJoin(config_errors)))
+ logging.critical(errmsg)
def _DistributeConfig(self, feedback_fn):
"""Distribute the configuration to the other nodes.
if check_uuid:
self._EnsureUUID(net, ec_id)
- existing_uuid = self._UnlockedLookupNetwork(net.name)
- if existing_uuid:
- raise errors.OpPrereqError("Desired network name '%s' already"
- " exists as a network (UUID: %s)" %
- (net.name, existing_uuid),
- errors.ECODE_EXISTS)
net.serial_no = 1
+ net.ctime = net.mtime = time.time()
self._config_data.networks[net.uuid] = net
self._config_data.cluster.serial_no += 1
@raises errors.OpPrereqError: when the target network cannot be found
"""
+ if target is None:
+ return None
if target in self._config_data.networks:
return target
for net in self._config_data.networks.values():
if net.name == target:
return net.uuid
- return None
+ raise errors.OpPrereqError("Network '%s' not found" % target,
+ errors.ECODE_NOENT)
@locking.ssynchronized(_config_lock, shared=1)
def LookupNetwork(self, target):
self._config_data.cluster.serial_no += 1
self._WriteConfig()
- def _UnlockedGetGroupNetParams(self, net, node):
+ def _UnlockedGetGroupNetParams(self, net_uuid, node):
"""Get the netparams (mode, link) of a network.
Get a network's netparams for a given node.
- @type net: string
- @param net: network name
+ @type net_uuid: string
+ @param net_uuid: network uuid
@type node: string
@param node: node name
@rtype: dict or None
@return: netparams
"""
- net_uuid = self._UnlockedLookupNetwork(net)
- if net_uuid is None:
- return None
-
node_info = self._UnlockedGetNodeInfo(node)
nodegroup_info = self._UnlockedGetNodeGroup(node_info.group)
netparams = nodegroup_info.networks.get(net_uuid, None)
return netparams
@locking.ssynchronized(_config_lock, shared=1)
- def GetGroupNetParams(self, net, node):
+ def GetGroupNetParams(self, net_uuid, node):
"""Locking wrapper of _UnlockedGetGroupNetParams()
"""
- return self._UnlockedGetGroupNetParams(net, node)
+ return self._UnlockedGetGroupNetParams(net_uuid, node)
@locking.ssynchronized(_config_lock, shared=1)
def CheckIPInNodeGroup(self, ip, node):