Revision f380d53c lib/cmdlib/common.py
b/lib/cmdlib/common.py | ||
---|---|---|
20 | 20 |
|
21 | 21 |
|
22 | 22 |
"""Common functions used by multiple logical units.""" |
23 |
|
|
23 | 24 |
import copy |
24 | 25 |
import os |
25 | 26 |
|
27 |
from ganeti import compat |
|
26 | 28 |
from ganeti import constants |
27 | 29 |
from ganeti import errors |
28 | 30 |
from ganeti import hypervisor |
29 | 31 |
from ganeti import locking |
30 | 32 |
from ganeti import objects |
33 |
from ganeti import opcodes |
|
31 | 34 |
from ganeti import pathutils |
32 | 35 |
from ganeti import rpc |
33 | 36 |
from ganeti import ssconf |
... | ... | |
722 | 725 |
""" |
723 | 726 |
vm_nodes = frozenset(lu.cfg.GetNonVmCapableNodeList()) |
724 | 727 |
return [name for name in nodenames if name not in vm_nodes] |
728 |
|
|
729 |
|
|
730 |
def _GetDefaultIAllocator(cfg, ialloc): |
|
731 |
"""Decides on which iallocator to use. |
|
732 |
|
|
733 |
@type cfg: L{config.ConfigWriter} |
|
734 |
@param cfg: Cluster configuration object |
|
735 |
@type ialloc: string or None |
|
736 |
@param ialloc: Iallocator specified in opcode |
|
737 |
@rtype: string |
|
738 |
@return: Iallocator name |
|
739 |
|
|
740 |
""" |
|
741 |
if not ialloc: |
|
742 |
# Use default iallocator |
|
743 |
ialloc = cfg.GetDefaultIAllocator() |
|
744 |
|
|
745 |
if not ialloc: |
|
746 |
raise errors.OpPrereqError("No iallocator was specified, neither in the" |
|
747 |
" opcode nor as a cluster-wide default", |
|
748 |
errors.ECODE_INVAL) |
|
749 |
|
|
750 |
return ialloc |
|
751 |
|
|
752 |
|
|
753 |
def _CheckInstancesNodeGroups(cfg, instances, owned_groups, owned_nodes, |
|
754 |
cur_group_uuid): |
|
755 |
"""Checks if node groups for locked instances are still correct. |
|
756 |
|
|
757 |
@type cfg: L{config.ConfigWriter} |
|
758 |
@param cfg: Cluster configuration |
|
759 |
@type instances: dict; string as key, L{objects.Instance} as value |
|
760 |
@param instances: Dictionary, instance name as key, instance object as value |
|
761 |
@type owned_groups: iterable of string |
|
762 |
@param owned_groups: List of owned groups |
|
763 |
@type owned_nodes: iterable of string |
|
764 |
@param owned_nodes: List of owned nodes |
|
765 |
@type cur_group_uuid: string or None |
|
766 |
@param cur_group_uuid: Optional group UUID to check against instance's groups |
|
767 |
|
|
768 |
""" |
|
769 |
for (name, inst) in instances.items(): |
|
770 |
assert owned_nodes.issuperset(inst.all_nodes), \ |
|
771 |
"Instance %s's nodes changed while we kept the lock" % name |
|
772 |
|
|
773 |
inst_groups = _CheckInstanceNodeGroups(cfg, name, owned_groups) |
|
774 |
|
|
775 |
assert cur_group_uuid is None or cur_group_uuid in inst_groups, \ |
|
776 |
"Instance %s has no node in group %s" % (name, cur_group_uuid) |
|
777 |
|
|
778 |
|
|
779 |
def _CheckInstanceNodeGroups(cfg, instance_name, owned_groups, |
|
780 |
primary_only=False): |
|
781 |
"""Checks if the owned node groups are still correct for an instance. |
|
782 |
|
|
783 |
@type cfg: L{config.ConfigWriter} |
|
784 |
@param cfg: The cluster configuration |
|
785 |
@type instance_name: string |
|
786 |
@param instance_name: Instance name |
|
787 |
@type owned_groups: set or frozenset |
|
788 |
@param owned_groups: List of currently owned node groups |
|
789 |
@type primary_only: boolean |
|
790 |
@param primary_only: Whether to check node groups for only the primary node |
|
791 |
|
|
792 |
""" |
|
793 |
inst_groups = cfg.GetInstanceNodeGroups(instance_name, primary_only) |
|
794 |
|
|
795 |
if not owned_groups.issuperset(inst_groups): |
|
796 |
raise errors.OpPrereqError("Instance %s's node groups changed since" |
|
797 |
" locks were acquired, current groups are" |
|
798 |
" are '%s', owning groups '%s'; retry the" |
|
799 |
" operation" % |
|
800 |
(instance_name, |
|
801 |
utils.CommaJoin(inst_groups), |
|
802 |
utils.CommaJoin(owned_groups)), |
|
803 |
errors.ECODE_STATE) |
|
804 |
|
|
805 |
return inst_groups |
|
806 |
|
|
807 |
|
|
808 |
def _LoadNodeEvacResult(lu, alloc_result, early_release, use_nodes): |
|
809 |
"""Unpacks the result of change-group and node-evacuate iallocator requests. |
|
810 |
|
|
811 |
Iallocator modes L{constants.IALLOCATOR_MODE_NODE_EVAC} and |
|
812 |
L{constants.IALLOCATOR_MODE_CHG_GROUP}. |
|
813 |
|
|
814 |
@type lu: L{LogicalUnit} |
|
815 |
@param lu: Logical unit instance |
|
816 |
@type alloc_result: tuple/list |
|
817 |
@param alloc_result: Result from iallocator |
|
818 |
@type early_release: bool |
|
819 |
@param early_release: Whether to release locks early if possible |
|
820 |
@type use_nodes: bool |
|
821 |
@param use_nodes: Whether to display node names instead of groups |
|
822 |
|
|
823 |
""" |
|
824 |
(moved, failed, jobs) = alloc_result |
|
825 |
|
|
826 |
if failed: |
|
827 |
failreason = utils.CommaJoin("%s (%s)" % (name, reason) |
|
828 |
for (name, reason) in failed) |
|
829 |
lu.LogWarning("Unable to evacuate instances %s", failreason) |
|
830 |
raise errors.OpExecError("Unable to evacuate instances %s" % failreason) |
|
831 |
|
|
832 |
if moved: |
|
833 |
lu.LogInfo("Instances to be moved: %s", |
|
834 |
utils.CommaJoin("%s (to %s)" % |
|
835 |
(name, _NodeEvacDest(use_nodes, group, nodes)) |
|
836 |
for (name, group, nodes) in moved)) |
|
837 |
|
|
838 |
return [map(compat.partial(_SetOpEarlyRelease, early_release), |
|
839 |
map(opcodes.OpCode.LoadOpCode, ops)) |
|
840 |
for ops in jobs] |
|
841 |
|
|
842 |
|
|
843 |
def _NodeEvacDest(use_nodes, group, nodes): |
|
844 |
"""Returns group or nodes depending on caller's choice. |
|
845 |
|
|
846 |
""" |
|
847 |
if use_nodes: |
|
848 |
return utils.CommaJoin(nodes) |
|
849 |
else: |
|
850 |
return group |
|
851 |
|
|
852 |
|
|
853 |
def _SetOpEarlyRelease(early_release, op): |
|
854 |
"""Sets C{early_release} flag on opcodes if available. |
|
855 |
|
|
856 |
""" |
|
857 |
try: |
|
858 |
op.early_release = early_release |
|
859 |
except AttributeError: |
|
860 |
assert not isinstance(op, opcodes.OpInstanceReplaceDisks) |
|
861 |
|
|
862 |
return op |
|
863 |
|
|
864 |
|
|
865 |
def _MapInstanceDisksToNodes(instances): |
|
866 |
"""Creates a map from (node, volume) to instance name. |
|
867 |
|
|
868 |
@type instances: list of L{objects.Instance} |
|
869 |
@rtype: dict; tuple of (node name, volume name) as key, instance name as value |
|
870 |
|
|
871 |
""" |
|
872 |
return dict(((node, vol), inst.name) |
|
873 |
for inst in instances |
|
874 |
for (node, vols) in inst.MapLVsByNode().items() |
|
875 |
for vol in vols) |
Also available in: Unified diff