Revision 37dc17e3 lib/cmdlib/__init__.py

b/lib/cmdlib/__init__.py
66 66
from ganeti.cmdlib.base import ResultWithJobs, LogicalUnit, NoHooksLU, \
67 67
  Tasklet, _QueryBase
68 68
from ganeti.cmdlib.common import _ExpandInstanceName, _ExpandItemName, \
69
  _ExpandNodeName, _ShareAll
69
  _ExpandNodeName, _ShareAll, _CheckNodeGroupInstances
70 70
from ganeti.cmdlib.tags import LUTagsGet, LUTagsSearch, LUTagsSet, LUTagsDel
71
from ganeti.cmdlib.network import LUNetworkAdd, LUNetworkRemove, \
72
  LUNetworkSetParams, _NetworkQuery, LUNetworkQuery, LUNetworkConnect, \
73
  LUNetworkDisconnect
71 74

  
72 75
import ganeti.masterd.instance # pylint: disable=W0611
73 76

  
......
153 156
  return inst_groups
154 157

  
155 158

  
156
def _CheckNodeGroupInstances(cfg, group_uuid, owned_instances):
157
  """Checks if the instances in a node group are still correct.
158

  
159
  @type cfg: L{config.ConfigWriter}
160
  @param cfg: The cluster configuration
161
  @type group_uuid: string
162
  @param group_uuid: Node group UUID
163
  @type owned_instances: set or frozenset
164
  @param owned_instances: List of currently owned instances
165

  
166
  """
167
  wanted_instances = cfg.GetNodeGroupInstances(group_uuid)
168
  if owned_instances != wanted_instances:
169
    raise errors.OpPrereqError("Instances in node group '%s' changed since"
170
                               " locks were acquired, wanted '%s', have '%s';"
171
                               " retry the operation" %
172
                               (group_uuid,
173
                                utils.CommaJoin(wanted_instances),
174
                                utils.CommaJoin(owned_instances)),
175
                               errors.ECODE_STATE)
176

  
177
  return wanted_instances
178

  
179

  
180 159
def _SupportsOob(cfg, node):
181 160
  """Tells if node supports OOB.
182 161

  
......
898 877
          _ComputeViolatingInstances(old_ipolicy, instances, cfg))
899 878

  
900 879

  
901
def _BuildNetworkHookEnv(name, subnet, gateway, network6, gateway6,
902
                         mac_prefix, tags):
903
  """Builds network related env variables for hooks
904

  
905
  This builds the hook environment from individual variables.
906

  
907
  @type name: string
908
  @param name: the name of the network
909
  @type subnet: string
910
  @param subnet: the ipv4 subnet
911
  @type gateway: string
912
  @param gateway: the ipv4 gateway
913
  @type network6: string
914
  @param network6: the ipv6 subnet
915
  @type gateway6: string
916
  @param gateway6: the ipv6 gateway
917
  @type mac_prefix: string
918
  @param mac_prefix: the mac_prefix
919
  @type tags: list
920
  @param tags: the tags of the network
921

  
922
  """
923
  env = {}
924
  if name:
925
    env["NETWORK_NAME"] = name
926
  if subnet:
927
    env["NETWORK_SUBNET"] = subnet
928
  if gateway:
929
    env["NETWORK_GATEWAY"] = gateway
930
  if network6:
931
    env["NETWORK_SUBNET6"] = network6
932
  if gateway6:
933
    env["NETWORK_GATEWAY6"] = gateway6
934
  if mac_prefix:
935
    env["NETWORK_MAC_PREFIX"] = mac_prefix
936
  if tags:
937
    env["NETWORK_TAGS"] = " ".join(tags)
938

  
939
  return env
940

  
941

  
942 880
def _BuildInstanceHookEnv(name, primary_node, secondary_nodes, os_type, status,
943 881
                          minmem, maxmem, vcpus, nics, disk_template, disks,
944 882
                          bep, hvp, hypervisor_name, tags):
......
15715 15653
    return result
15716 15654

  
15717 15655

  
15718
class LUNetworkAdd(LogicalUnit):
15719
  """Logical unit for creating networks.
15720

  
15721
  """
15722
  HPATH = "network-add"
15723
  HTYPE = constants.HTYPE_NETWORK
15724
  REQ_BGL = False
15725

  
15726
  def BuildHooksNodes(self):
15727
    """Build hooks nodes.
15728

  
15729
    """
15730
    mn = self.cfg.GetMasterNode()
15731
    return ([mn], [mn])
15732

  
15733
  def CheckArguments(self):
15734
    if self.op.mac_prefix:
15735
      self.op.mac_prefix = \
15736
        utils.NormalizeAndValidateThreeOctetMacPrefix(self.op.mac_prefix)
15737

  
15738
  def ExpandNames(self):
15739
    self.network_uuid = self.cfg.GenerateUniqueID(self.proc.GetECId())
15740

  
15741
    if self.op.conflicts_check:
15742
      self.share_locks[locking.LEVEL_NODE] = 1
15743
      self.share_locks[locking.LEVEL_NODE_ALLOC] = 1
15744
      self.needed_locks = {
15745
        locking.LEVEL_NODE: locking.ALL_SET,
15746
        locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
15747
        }
15748
    else:
15749
      self.needed_locks = {}
15750

  
15751
    self.add_locks[locking.LEVEL_NETWORK] = self.network_uuid
15752

  
15753
  def CheckPrereq(self):
15754
    if self.op.network is None:
15755
      raise errors.OpPrereqError("Network must be given",
15756
                                 errors.ECODE_INVAL)
15757

  
15758
    try:
15759
      existing_uuid = self.cfg.LookupNetwork(self.op.network_name)
15760
    except errors.OpPrereqError:
15761
      pass
15762
    else:
15763
      raise errors.OpPrereqError("Desired network name '%s' already exists as a"
15764
                                 " network (UUID: %s)" %
15765
                                 (self.op.network_name, existing_uuid),
15766
                                 errors.ECODE_EXISTS)
15767

  
15768
    # Check tag validity
15769
    for tag in self.op.tags:
15770
      objects.TaggableObject.ValidateTag(tag)
15771

  
15772
  def BuildHooksEnv(self):
15773
    """Build hooks env.
15774

  
15775
    """
15776
    args = {
15777
      "name": self.op.network_name,
15778
      "subnet": self.op.network,
15779
      "gateway": self.op.gateway,
15780
      "network6": self.op.network6,
15781
      "gateway6": self.op.gateway6,
15782
      "mac_prefix": self.op.mac_prefix,
15783
      "tags": self.op.tags,
15784
      }
15785
    return _BuildNetworkHookEnv(**args) # pylint: disable=W0142
15786

  
15787
  def Exec(self, feedback_fn):
15788
    """Add the ip pool to the cluster.
15789

  
15790
    """
15791
    nobj = objects.Network(name=self.op.network_name,
15792
                           network=self.op.network,
15793
                           gateway=self.op.gateway,
15794
                           network6=self.op.network6,
15795
                           gateway6=self.op.gateway6,
15796
                           mac_prefix=self.op.mac_prefix,
15797
                           uuid=self.network_uuid)
15798
    # Initialize the associated address pool
15799
    try:
15800
      pool = network.AddressPool.InitializeNetwork(nobj)
15801
    except errors.AddressPoolError, err:
15802
      raise errors.OpExecError("Cannot create IP address pool for network"
15803
                               " '%s': %s" % (self.op.network_name, err))
15804

  
15805
    # Check if we need to reserve the nodes and the cluster master IP
15806
    # These may not be allocated to any instances in routed mode, as
15807
    # they wouldn't function anyway.
15808
    if self.op.conflicts_check:
15809
      for node in self.cfg.GetAllNodesInfo().values():
15810
        for ip in [node.primary_ip, node.secondary_ip]:
15811
          try:
15812
            if pool.Contains(ip):
15813
              pool.Reserve(ip)
15814
              self.LogInfo("Reserved IP address of node '%s' (%s)",
15815
                           node.name, ip)
15816
          except errors.AddressPoolError, err:
15817
            self.LogWarning("Cannot reserve IP address '%s' of node '%s': %s",
15818
                            ip, node.name, err)
15819

  
15820
      master_ip = self.cfg.GetClusterInfo().master_ip
15821
      try:
15822
        if pool.Contains(master_ip):
15823
          pool.Reserve(master_ip)
15824
          self.LogInfo("Reserved cluster master IP address (%s)", master_ip)
15825
      except errors.AddressPoolError, err:
15826
        self.LogWarning("Cannot reserve cluster master IP address (%s): %s",
15827
                        master_ip, err)
15828

  
15829
    if self.op.add_reserved_ips:
15830
      for ip in self.op.add_reserved_ips:
15831
        try:
15832
          pool.Reserve(ip, external=True)
15833
        except errors.AddressPoolError, err:
15834
          raise errors.OpExecError("Cannot reserve IP address '%s': %s" %
15835
                                   (ip, err))
15836

  
15837
    if self.op.tags:
15838
      for tag in self.op.tags:
15839
        nobj.AddTag(tag)
15840

  
15841
    self.cfg.AddNetwork(nobj, self.proc.GetECId(), check_uuid=False)
15842
    del self.remove_locks[locking.LEVEL_NETWORK]
15843

  
15844

  
15845
class LUNetworkRemove(LogicalUnit):
15846
  HPATH = "network-remove"
15847
  HTYPE = constants.HTYPE_NETWORK
15848
  REQ_BGL = False
15849

  
15850
  def ExpandNames(self):
15851
    self.network_uuid = self.cfg.LookupNetwork(self.op.network_name)
15852

  
15853
    self.share_locks[locking.LEVEL_NODEGROUP] = 1
15854
    self.needed_locks = {
15855
      locking.LEVEL_NETWORK: [self.network_uuid],
15856
      locking.LEVEL_NODEGROUP: locking.ALL_SET,
15857
      }
15858

  
15859
  def CheckPrereq(self):
15860
    """Check prerequisites.
15861

  
15862
    This checks that the given network name exists as a network, that is
15863
    empty (i.e., contains no nodes), and that is not the last group of the
15864
    cluster.
15865

  
15866
    """
15867
    # Verify that the network is not conncted.
15868
    node_groups = [group.name
15869
                   for group in self.cfg.GetAllNodeGroupsInfo().values()
15870
                   if self.network_uuid in group.networks]
15871

  
15872
    if node_groups:
15873
      self.LogWarning("Network '%s' is connected to the following"
15874
                      " node groups: %s" %
15875
                      (self.op.network_name,
15876
                       utils.CommaJoin(utils.NiceSort(node_groups))))
15877
      raise errors.OpPrereqError("Network still connected", errors.ECODE_STATE)
15878

  
15879
  def BuildHooksEnv(self):
15880
    """Build hooks env.
15881

  
15882
    """
15883
    return {
15884
      "NETWORK_NAME": self.op.network_name,
15885
      }
15886

  
15887
  def BuildHooksNodes(self):
15888
    """Build hooks nodes.
15889

  
15890
    """
15891
    mn = self.cfg.GetMasterNode()
15892
    return ([mn], [mn])
15893

  
15894
  def Exec(self, feedback_fn):
15895
    """Remove the network.
15896

  
15897
    """
15898
    try:
15899
      self.cfg.RemoveNetwork(self.network_uuid)
15900
    except errors.ConfigurationError:
15901
      raise errors.OpExecError("Network '%s' with UUID %s disappeared" %
15902
                               (self.op.network_name, self.network_uuid))
15903

  
15904

  
15905
class LUNetworkSetParams(LogicalUnit):
15906
  """Modifies the parameters of a network.
15907

  
15908
  """
15909
  HPATH = "network-modify"
15910
  HTYPE = constants.HTYPE_NETWORK
15911
  REQ_BGL = False
15912

  
15913
  def CheckArguments(self):
15914
    if (self.op.gateway and
15915
        (self.op.add_reserved_ips or self.op.remove_reserved_ips)):
15916
      raise errors.OpPrereqError("Cannot modify gateway and reserved ips"
15917
                                 " at once", errors.ECODE_INVAL)
15918

  
15919
  def ExpandNames(self):
15920
    self.network_uuid = self.cfg.LookupNetwork(self.op.network_name)
15921

  
15922
    self.needed_locks = {
15923
      locking.LEVEL_NETWORK: [self.network_uuid],
15924
      }
15925

  
15926
  def CheckPrereq(self):
15927
    """Check prerequisites.
15928

  
15929
    """
15930
    self.network = self.cfg.GetNetwork(self.network_uuid)
15931
    self.gateway = self.network.gateway
15932
    self.mac_prefix = self.network.mac_prefix
15933
    self.network6 = self.network.network6
15934
    self.gateway6 = self.network.gateway6
15935
    self.tags = self.network.tags
15936

  
15937
    self.pool = network.AddressPool(self.network)
15938

  
15939
    if self.op.gateway:
15940
      if self.op.gateway == constants.VALUE_NONE:
15941
        self.gateway = None
15942
      else:
15943
        self.gateway = self.op.gateway
15944
        if self.pool.IsReserved(self.gateway):
15945
          raise errors.OpPrereqError("Gateway IP address '%s' is already"
15946
                                     " reserved" % self.gateway,
15947
                                     errors.ECODE_STATE)
15948

  
15949
    if self.op.mac_prefix:
15950
      if self.op.mac_prefix == constants.VALUE_NONE:
15951
        self.mac_prefix = None
15952
      else:
15953
        self.mac_prefix = \
15954
          utils.NormalizeAndValidateThreeOctetMacPrefix(self.op.mac_prefix)
15955

  
15956
    if self.op.gateway6:
15957
      if self.op.gateway6 == constants.VALUE_NONE:
15958
        self.gateway6 = None
15959
      else:
15960
        self.gateway6 = self.op.gateway6
15961

  
15962
    if self.op.network6:
15963
      if self.op.network6 == constants.VALUE_NONE:
15964
        self.network6 = None
15965
      else:
15966
        self.network6 = self.op.network6
15967

  
15968
  def BuildHooksEnv(self):
15969
    """Build hooks env.
15970

  
15971
    """
15972
    args = {
15973
      "name": self.op.network_name,
15974
      "subnet": self.network.network,
15975
      "gateway": self.gateway,
15976
      "network6": self.network6,
15977
      "gateway6": self.gateway6,
15978
      "mac_prefix": self.mac_prefix,
15979
      "tags": self.tags,
15980
      }
15981
    return _BuildNetworkHookEnv(**args) # pylint: disable=W0142
15982

  
15983
  def BuildHooksNodes(self):
15984
    """Build hooks nodes.
15985

  
15986
    """
15987
    mn = self.cfg.GetMasterNode()
15988
    return ([mn], [mn])
15989

  
15990
  def Exec(self, feedback_fn):
15991
    """Modifies the network.
15992

  
15993
    """
15994
    #TODO: reserve/release via temporary reservation manager
15995
    #      extend cfg.ReserveIp/ReleaseIp with the external flag
15996
    if self.op.gateway:
15997
      if self.gateway == self.network.gateway:
15998
        self.LogWarning("Gateway is already %s", self.gateway)
15999
      else:
16000
        if self.gateway:
16001
          self.pool.Reserve(self.gateway, external=True)
16002
        if self.network.gateway:
16003
          self.pool.Release(self.network.gateway, external=True)
16004
        self.network.gateway = self.gateway
16005

  
16006
    if self.op.add_reserved_ips:
16007
      for ip in self.op.add_reserved_ips:
16008
        try:
16009
          if self.pool.IsReserved(ip):
16010
            self.LogWarning("IP address %s is already reserved", ip)
16011
          else:
16012
            self.pool.Reserve(ip, external=True)
16013
        except errors.AddressPoolError, err:
16014
          self.LogWarning("Cannot reserve IP address %s: %s", ip, err)
16015

  
16016
    if self.op.remove_reserved_ips:
16017
      for ip in self.op.remove_reserved_ips:
16018
        if ip == self.network.gateway:
16019
          self.LogWarning("Cannot unreserve Gateway's IP")
16020
          continue
16021
        try:
16022
          if not self.pool.IsReserved(ip):
16023
            self.LogWarning("IP address %s is already unreserved", ip)
16024
          else:
16025
            self.pool.Release(ip, external=True)
16026
        except errors.AddressPoolError, err:
16027
          self.LogWarning("Cannot release IP address %s: %s", ip, err)
16028

  
16029
    if self.op.mac_prefix:
16030
      self.network.mac_prefix = self.mac_prefix
16031

  
16032
    if self.op.network6:
16033
      self.network.network6 = self.network6
16034

  
16035
    if self.op.gateway6:
16036
      self.network.gateway6 = self.gateway6
16037

  
16038
    self.pool.Validate()
16039

  
16040
    self.cfg.Update(self.network, feedback_fn)
16041

  
16042

  
16043
class _NetworkQuery(_QueryBase):
16044
  FIELDS = query.NETWORK_FIELDS
16045

  
16046
  def ExpandNames(self, lu):
16047
    lu.needed_locks = {}
16048
    lu.share_locks = _ShareAll()
16049

  
16050
    self.do_locking = self.use_locking
16051

  
16052
    all_networks = lu.cfg.GetAllNetworksInfo()
16053
    name_to_uuid = dict((n.name, n.uuid) for n in all_networks.values())
16054

  
16055
    if self.names:
16056
      missing = []
16057
      self.wanted = []
16058

  
16059
      for name in self.names:
16060
        if name in name_to_uuid:
16061
          self.wanted.append(name_to_uuid[name])
16062
        else:
16063
          missing.append(name)
16064

  
16065
      if missing:
16066
        raise errors.OpPrereqError("Some networks do not exist: %s" % missing,
16067
                                   errors.ECODE_NOENT)
16068
    else:
16069
      self.wanted = locking.ALL_SET
16070

  
16071
    if self.do_locking:
16072
      lu.needed_locks[locking.LEVEL_NETWORK] = self.wanted
16073
      if query.NETQ_INST in self.requested_data:
16074
        lu.needed_locks[locking.LEVEL_INSTANCE] = locking.ALL_SET
16075
      if query.NETQ_GROUP in self.requested_data:
16076
        lu.needed_locks[locking.LEVEL_NODEGROUP] = locking.ALL_SET
16077

  
16078
  def DeclareLocks(self, lu, level):
16079
    pass
16080

  
16081
  def _GetQueryData(self, lu):
16082
    """Computes the list of networks and their attributes.
16083

  
16084
    """
16085
    all_networks = lu.cfg.GetAllNetworksInfo()
16086

  
16087
    network_uuids = self._GetNames(lu, all_networks.keys(),
16088
                                   locking.LEVEL_NETWORK)
16089

  
16090
    do_instances = query.NETQ_INST in self.requested_data
16091
    do_groups = query.NETQ_GROUP in self.requested_data
16092

  
16093
    network_to_instances = None
16094
    network_to_groups = None
16095

  
16096
    # For NETQ_GROUP, we need to map network->[groups]
16097
    if do_groups:
16098
      all_groups = lu.cfg.GetAllNodeGroupsInfo()
16099
      network_to_groups = dict((uuid, []) for uuid in network_uuids)
16100
      for _, group in all_groups.iteritems():
16101
        for net_uuid in network_uuids:
16102
          netparams = group.networks.get(net_uuid, None)
16103
          if netparams:
16104
            info = (group.name, netparams[constants.NIC_MODE],
16105
                    netparams[constants.NIC_LINK])
16106

  
16107
            network_to_groups[net_uuid].append(info)
16108

  
16109
    if do_instances:
16110
      all_instances = lu.cfg.GetAllInstancesInfo()
16111
      network_to_instances = dict((uuid, []) for uuid in network_uuids)
16112
      for instance in all_instances.values():
16113
        for nic in instance.nics:
16114
          if nic.network in network_uuids:
16115
            network_to_instances[nic.network].append(instance.name)
16116
            break
16117

  
16118
    if query.NETQ_STATS in self.requested_data:
16119
      stats = \
16120
        dict((uuid,
16121
              self._GetStats(network.AddressPool(all_networks[uuid])))
16122
             for uuid in network_uuids)
16123
    else:
16124
      stats = None
16125

  
16126
    return query.NetworkQueryData([all_networks[uuid]
16127
                                   for uuid in network_uuids],
16128
                                   network_to_groups,
16129
                                   network_to_instances,
16130
                                   stats)
16131

  
16132
  @staticmethod
16133
  def _GetStats(pool):
16134
    """Returns statistics for a network address pool.
16135

  
16136
    """
16137
    return {
16138
      "free_count": pool.GetFreeCount(),
16139
      "reserved_count": pool.GetReservedCount(),
16140
      "map": pool.GetMap(),
16141
      "external_reservations":
16142
        utils.CommaJoin(pool.GetExternalReservations()),
16143
      }
16144

  
16145

  
16146
class LUNetworkQuery(NoHooksLU):
16147
  """Logical unit for querying networks.
16148

  
16149
  """
16150
  REQ_BGL = False
16151

  
16152
  def CheckArguments(self):
16153
    self.nq = _NetworkQuery(qlang.MakeSimpleFilter("name", self.op.names),
16154
                            self.op.output_fields, self.op.use_locking)
16155

  
16156
  def ExpandNames(self):
16157
    self.nq.ExpandNames(self)
16158

  
16159
  def Exec(self, feedback_fn):
16160
    return self.nq.OldStyleQuery(self)
16161

  
16162

  
16163
class LUNetworkConnect(LogicalUnit):
16164
  """Connect a network to a nodegroup
16165

  
16166
  """
16167
  HPATH = "network-connect"
16168
  HTYPE = constants.HTYPE_NETWORK
16169
  REQ_BGL = False
16170

  
16171
  def ExpandNames(self):
16172
    self.network_name = self.op.network_name
16173
    self.group_name = self.op.group_name
16174
    self.network_mode = self.op.network_mode
16175
    self.network_link = self.op.network_link
16176

  
16177
    self.network_uuid = self.cfg.LookupNetwork(self.network_name)
16178
    self.group_uuid = self.cfg.LookupNodeGroup(self.group_name)
16179

  
16180
    self.needed_locks = {
16181
      locking.LEVEL_INSTANCE: [],
16182
      locking.LEVEL_NODEGROUP: [self.group_uuid],
16183
      }
16184
    self.share_locks[locking.LEVEL_INSTANCE] = 1
16185

  
16186
    if self.op.conflicts_check:
16187
      self.needed_locks[locking.LEVEL_NETWORK] = [self.network_uuid]
16188
      self.share_locks[locking.LEVEL_NETWORK] = 1
16189

  
16190
  def DeclareLocks(self, level):
16191
    if level == locking.LEVEL_INSTANCE:
16192
      assert not self.needed_locks[locking.LEVEL_INSTANCE]
16193

  
16194
      # Lock instances optimistically, needs verification once group lock has
16195
      # been acquired
16196
      if self.op.conflicts_check:
16197
        self.needed_locks[locking.LEVEL_INSTANCE] = \
16198
            self.cfg.GetNodeGroupInstances(self.group_uuid)
16199

  
16200
  def BuildHooksEnv(self):
16201
    ret = {
16202
      "GROUP_NAME": self.group_name,
16203
      "GROUP_NETWORK_MODE": self.network_mode,
16204
      "GROUP_NETWORK_LINK": self.network_link,
16205
      }
16206
    return ret
16207

  
16208
  def BuildHooksNodes(self):
16209
    nodes = self.cfg.GetNodeGroup(self.group_uuid).members
16210
    return (nodes, nodes)
16211

  
16212
  def CheckPrereq(self):
16213
    owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
16214

  
16215
    assert self.group_uuid in owned_groups
16216

  
16217
    # Check if locked instances are still correct
16218
    owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
16219
    if self.op.conflicts_check:
16220
      _CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instances)
16221

  
16222
    self.netparams = {
16223
      constants.NIC_MODE: self.network_mode,
16224
      constants.NIC_LINK: self.network_link,
16225
      }
16226
    objects.NIC.CheckParameterSyntax(self.netparams)
16227

  
16228
    self.group = self.cfg.GetNodeGroup(self.group_uuid)
16229
    #if self.network_mode == constants.NIC_MODE_BRIDGED:
16230
    #  _CheckNodeGroupBridgesExist(self, self.network_link, self.group_uuid)
16231
    self.connected = False
16232
    if self.network_uuid in self.group.networks:
16233
      self.LogWarning("Network '%s' is already mapped to group '%s'" %
16234
                      (self.network_name, self.group.name))
16235
      self.connected = True
16236

  
16237
    # check only if not already connected
16238
    elif self.op.conflicts_check:
16239
      pool = network.AddressPool(self.cfg.GetNetwork(self.network_uuid))
16240

  
16241
      _NetworkConflictCheck(self, lambda nic: pool.Contains(nic.ip),
16242
                            "connect to", owned_instances)
16243

  
16244
  def Exec(self, feedback_fn):
16245
    # Connect the network and update the group only if not already connected
16246
    if not self.connected:
16247
      self.group.networks[self.network_uuid] = self.netparams
16248
      self.cfg.Update(self.group, feedback_fn)
16249

  
16250

  
16251
def _NetworkConflictCheck(lu, check_fn, action, instances):
16252
  """Checks for network interface conflicts with a network.
16253

  
16254
  @type lu: L{LogicalUnit}
16255
  @type check_fn: callable receiving one parameter (L{objects.NIC}) and
16256
    returning boolean
16257
  @param check_fn: Function checking for conflict
16258
  @type action: string
16259
  @param action: Part of error message (see code)
16260
  @raise errors.OpPrereqError: If conflicting IP addresses are found.
16261

  
16262
  """
16263
  conflicts = []
16264

  
16265
  for (_, instance) in lu.cfg.GetMultiInstanceInfo(instances):
16266
    instconflicts = [(idx, nic.ip)
16267
                     for (idx, nic) in enumerate(instance.nics)
16268
                     if check_fn(nic)]
16269

  
16270
    if instconflicts:
16271
      conflicts.append((instance.name, instconflicts))
16272

  
16273
  if conflicts:
16274
    lu.LogWarning("IP addresses from network '%s', which is about to %s"
16275
                  " node group '%s', are in use: %s" %
16276
                  (lu.network_name, action, lu.group.name,
16277
                   utils.CommaJoin(("%s: %s" %
16278
                                    (name, _FmtNetworkConflict(details)))
16279
                                   for (name, details) in conflicts)))
16280

  
16281
    raise errors.OpPrereqError("Conflicting IP addresses found; "
16282
                               " remove/modify the corresponding network"
16283
                               " interfaces", errors.ECODE_STATE)
16284

  
16285

  
16286
def _FmtNetworkConflict(details):
16287
  """Utility for L{_NetworkConflictCheck}.
16288

  
16289
  """
16290
  return utils.CommaJoin("nic%s/%s" % (idx, ipaddr)
16291
                         for (idx, ipaddr) in details)
16292

  
16293

  
16294
class LUNetworkDisconnect(LogicalUnit):
16295
  """Disconnect a network to a nodegroup
16296

  
16297
  """
16298
  HPATH = "network-disconnect"
16299
  HTYPE = constants.HTYPE_NETWORK
16300
  REQ_BGL = False
16301

  
16302
  def ExpandNames(self):
16303
    self.network_name = self.op.network_name
16304
    self.group_name = self.op.group_name
16305

  
16306
    self.network_uuid = self.cfg.LookupNetwork(self.network_name)
16307
    self.group_uuid = self.cfg.LookupNodeGroup(self.group_name)
16308

  
16309
    self.needed_locks = {
16310
      locking.LEVEL_INSTANCE: [],
16311
      locking.LEVEL_NODEGROUP: [self.group_uuid],
16312
      }
16313
    self.share_locks[locking.LEVEL_INSTANCE] = 1
16314

  
16315
  def DeclareLocks(self, level):
16316
    if level == locking.LEVEL_INSTANCE:
16317
      assert not self.needed_locks[locking.LEVEL_INSTANCE]
16318

  
16319
      # Lock instances optimistically, needs verification once group lock has
16320
      # been acquired
16321
      self.needed_locks[locking.LEVEL_INSTANCE] = \
16322
        self.cfg.GetNodeGroupInstances(self.group_uuid)
16323

  
16324
  def BuildHooksEnv(self):
16325
    ret = {
16326
      "GROUP_NAME": self.group_name,
16327
      }
16328
    return ret
16329

  
16330
  def BuildHooksNodes(self):
16331
    nodes = self.cfg.GetNodeGroup(self.group_uuid).members
16332
    return (nodes, nodes)
16333

  
16334
  def CheckPrereq(self):
16335
    owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
16336

  
16337
    assert self.group_uuid in owned_groups
16338

  
16339
    # Check if locked instances are still correct
16340
    owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
16341
    _CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instances)
16342

  
16343
    self.group = self.cfg.GetNodeGroup(self.group_uuid)
16344
    self.connected = True
16345
    if self.network_uuid not in self.group.networks:
16346
      self.LogWarning("Network '%s' is not mapped to group '%s'",
16347
                      self.network_name, self.group.name)
16348
      self.connected = False
16349

  
16350
    # We need this check only if network is not already connected
16351
    else:
16352
      _NetworkConflictCheck(self, lambda nic: nic.network == self.network_uuid,
16353
                            "disconnect from", owned_instances)
16354

  
16355
  def Exec(self, feedback_fn):
16356
    # Disconnect the network and update the group only if network is connected
16357
    if self.connected:
16358
      del self.group.networks[self.network_uuid]
16359
      self.cfg.Update(self.group, feedback_fn)
16360

  
16361

  
16362 15656
#: Query type implementations
16363 15657
_QUERY_IMPL = {
16364 15658
  constants.QR_CLUSTER: _ClusterQuery,

Also available in: Unified diff