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