X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/12378fe30a39ae0f99680bce84963dea59e4665e..091232220479c4b35c69d19d53a729c9874d8fda:/lib/config.py diff --git a/lib/config.py b/lib/config.py index a4f864d..c98caff 100644 --- a/lib/config.py +++ b/lib/config.py @@ -133,6 +133,26 @@ def _MatchNameComponentIgnoreCase(short_name, names): return utils.MatchNameComponent(short_name, names, case_sensitive=False) +def _CheckInstanceDiskIvNames(disks): + """Checks if instance's disks' C{iv_name} attributes are in order. + + @type disks: list of L{objects.Disk} + @param disks: List of disks + @rtype: list of tuples; (int, string, string) + @return: List of wrongly named disks, each tuple contains disk index, + expected and actual name + + """ + result = [] + + for (idx, disk) in enumerate(disks): + exp_iv_name = "disk/%s" % idx + if disk.iv_name != exp_iv_name: + result.append((idx, exp_iv_name, disk.iv_name)) + + return result + + class ConfigWriter: """The interface to the cluster configuration. @@ -212,6 +232,40 @@ class ConfigWriter: return self._config_data.cluster.FillND(node, nodegroup) @locking.ssynchronized(_config_lock, shared=1) + def GetInstanceDiskParams(self, instance): + """Get the disk params populated with inherit chain. + + @type instance: L{objects.Instance} + @param instance: The instance we want to know the params for + @return: A dict with the filled in disk params + + """ + node = self._UnlockedGetNodeInfo(instance.primary_node) + nodegroup = self._UnlockedGetNodeGroup(node.group) + return self._UnlockedGetGroupDiskParams(nodegroup) + + @locking.ssynchronized(_config_lock, shared=1) + def GetGroupDiskParams(self, group): + """Get the disk params populated with inherit chain. + + @type group: L{objects.NodeGroup} + @param group: The group we want to know the params for + @return: A dict with the filled in disk params + + """ + return self._UnlockedGetGroupDiskParams(group) + + def _UnlockedGetGroupDiskParams(self, group): + """Get the disk params populated with inherit chain down to node-group. + + @type group: L{objects.NodeGroup} + @param group: The group we want to know the params for + @return: A dict with the filled in disk params + + """ + return self._config_data.cluster.SimpleFillDP(group.diskparams) + + @locking.ssynchronized(_config_lock, shared=1) def GenerateMAC(self, ec_id): """Generate a MAC for an instance. @@ -426,9 +480,9 @@ class ConfigWriter: except errors.ConfigurationError, err: result.append("%s has invalid nicparams: %s" % (owner, err)) - def _helper_ipolicy(owner, params): + def _helper_ipolicy(owner, params, check_std): try: - objects.InstancePolicy.CheckParameterSyntax(params) + objects.InstancePolicy.CheckParameterSyntax(params, check_std) except errors.ConfigurationError, err: result.append("%s has invalid instance policy: %s" % (owner, err)) @@ -439,10 +493,14 @@ class ConfigWriter: _helper(owner, fullkey, value, constants.ISPECS_PARAMETER_TYPES) else: # FIXME: assuming list type - if not isinstance(value, list): + if key in constants.IPOLICY_PARAMETERS: + exp_type = float + else: + exp_type = list + if not isinstance(value, exp_type): result.append("%s has invalid instance policy: for %s," - " expecting list, got %s" % - (owner, key, type(value))) + " expecting %s, got %s" % + (owner, key, exp_type.__name__, type(value))) # check cluster parameters _helper("cluster", "beparams", cluster.SimpleFillBE({}), @@ -452,7 +510,7 @@ class ConfigWriter: _helper_nic("cluster", cluster.SimpleFillNIC({})) _helper("cluster", "ndparams", cluster.SimpleFillND({}), constants.NDS_PARAMETER_TYPES) - _helper_ipolicy("cluster", cluster.SimpleFillIPolicy({})) + _helper_ipolicy("cluster", cluster.SimpleFillIPolicy({}), True) _helper_ispecs("cluster", cluster.SimpleFillIPolicy({})) # per-instance checks @@ -487,12 +545,12 @@ class ConfigWriter: cluster.FillBE(instance), constants.BES_PARAMETER_TYPES) # gather the drbd ports for duplicate checks - for dsk in instance.disks: + for (idx, dsk) in enumerate(instance.disks): if dsk.dev_type in constants.LDS_DRBD: tcp_port = dsk.logical_id[2] if tcp_port not in ports: ports[tcp_port] = [] - ports[tcp_port].append((instance.name, "drbd disk %s" % dsk.iv_name)) + ports[tcp_port].append((instance.name, "drbd disk %s" % idx)) # gather network port reservation net_port = getattr(instance, "network_port", None) if net_port is not None: @@ -506,6 +564,15 @@ class ConfigWriter: (instance.name, idx, msg) for msg in disk.Verify()]) result.extend(self._CheckDiskIDs(disk, seen_lids, seen_pids)) + wrong_names = _CheckInstanceDiskIvNames(instance.disks) + if wrong_names: + tmp = "; ".join(("name of disk %s should be '%s', but is '%s'" % + (idx, exp_name, actual_name)) + for (idx, exp_name, actual_name) in wrong_names) + + result.append("Instance '%s' has wrongly named disks: %s" % + (instance.name, tmp)) + # cluster-wide pool of free ports for free_port in cluster.tcpudp_port_pool: if free_port not in ports: @@ -569,7 +636,8 @@ class ConfigWriter: else: nodegroups_names.add(nodegroup.name) group_name = "group %s" % nodegroup.name - _helper_ipolicy(group_name, cluster.SimpleFillIPolicy(nodegroup.ipolicy)) + _helper_ipolicy(group_name, cluster.SimpleFillIPolicy(nodegroup.ipolicy), + False) _helper_ispecs(group_name, cluster.SimpleFillIPolicy(nodegroup.ipolicy)) if nodegroup.ndparams: _helper(group_name, "ndparams", @@ -690,12 +758,15 @@ class ConfigWriter: def AddTcpUdpPort(self, port): """Adds a new port to the available port pool. + @warning: this method does not "flush" the configuration (via + L{_WriteConfig}); callers should do that themselves once the + configuration is stable + """ if not isinstance(port, int): raise errors.ProgrammerError("Invalid type passed for port") self._config_data.cluster.tcpudp_port_pool.add(port) - self._WriteConfig() @locking.ssynchronized(_config_lock, shared=1) def GetPortList(self): @@ -1073,7 +1144,7 @@ class ConfigWriter: if target is None: if len(self._config_data.nodegroups) != 1: raise errors.OpPrereqError("More than one node group exists. Target" - " group must be specified explicitely.") + " group must be specified explicitly.") else: return self._config_data.nodegroups.keys()[0] if target in self._config_data.nodegroups: @@ -1149,6 +1220,17 @@ class ConfigWriter: for member_name in self._UnlockedGetNodeGroup(ngfn(node_name)).members) + @locking.ssynchronized(_config_lock, shared=1) + def GetMultiNodeGroupInfo(self, group_uuids): + """Get the configuration of multiple node groups. + + @param group_uuids: List of node group UUIDs + @rtype: list + @return: List of tuples of (group_uuid, group_info) + + """ + return [(uuid, self._UnlockedGetNodeGroup(uuid)) for uuid in group_uuids] + @locking.ssynchronized(_config_lock) def AddInstance(self, instance, ec_id): """Add an instance to the config. @@ -1256,24 +1338,27 @@ class ConfigWriter: """ if old_name not in self._config_data.instances: raise errors.ConfigurationError("Unknown instance '%s'" % old_name) - inst = self._config_data.instances[old_name] - del self._config_data.instances[old_name] + + # Operate on a copy to not loose instance object in case of a failure + inst = self._config_data.instances[old_name].Copy() inst.name = new_name - for disk in inst.disks: + for (idx, disk) in enumerate(inst.disks): if disk.dev_type == constants.LD_FILE: # rename the file paths in logical and physical id file_storage_dir = os.path.dirname(os.path.dirname(disk.logical_id[1])) - disk_fname = "disk%s" % disk.iv_name.split("/")[1] - disk.physical_id = disk.logical_id = (disk.logical_id[0], - utils.PathJoin(file_storage_dir, - inst.name, - disk_fname)) + disk.logical_id = (disk.logical_id[0], + utils.PathJoin(file_storage_dir, inst.name, + "disk%s" % idx)) + disk.physical_id = disk.logical_id + + # Actually replace instance object + del self._config_data.instances[old_name] + self._config_data.instances[inst.name] = inst # Force update of ssconf files self._config_data.cluster.serial_no += 1 - self._config_data.instances[inst.name] = inst self._WriteConfig() @locking.ssynchronized(_config_lock) @@ -1803,8 +1888,8 @@ class ConfigWriter: # Make sure the configuration has the right version _ValidateConfig(data) - if (not hasattr(data, 'cluster') or - not hasattr(data.cluster, 'rsahostkeypub')): + if (not hasattr(data, "cluster") or + not hasattr(data.cluster, "rsahostkeypub")): raise errors.ConfigurationError("Incomplete configuration" " (missing cluster.rsahostkeypub)")