Revision 37dc17e3

b/Makefile.am
311 311
	lib/cmdlib/__init__.py \
312 312
	lib/cmdlib/common.py \
313 313
	lib/cmdlib/base.py \
314
	lib/cmdlib/tags.py
314
	lib/cmdlib/tags.py \
315
	lib/cmdlib/network.py
315 316

  
316 317
hypervisor_PYTHON = \
317 318
	lib/hypervisor/__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,
b/lib/cmdlib/common.py
23 23

  
24 24
from ganeti import errors
25 25
from ganeti import locking
26
from ganeti import utils
26 27

  
27 28

  
28 29
def _ExpandItemName(fn, name, kind):
......
57 58

  
58 59
  """
59 60
  return dict.fromkeys(locking.LEVELS, 1)
61

  
62

  
63
def _CheckNodeGroupInstances(cfg, group_uuid, owned_instances):
64
  """Checks if the instances in a node group are still correct.
65

  
66
  @type cfg: L{config.ConfigWriter}
67
  @param cfg: The cluster configuration
68
  @type group_uuid: string
69
  @param group_uuid: Node group UUID
70
  @type owned_instances: set or frozenset
71
  @param owned_instances: List of currently owned instances
72

  
73
  """
74
  wanted_instances = cfg.GetNodeGroupInstances(group_uuid)
75
  if owned_instances != wanted_instances:
76
    raise errors.OpPrereqError("Instances in node group '%s' changed since"
77
                               " locks were acquired, wanted '%s', have '%s';"
78
                               " retry the operation" %
79
                               (group_uuid,
80
                                utils.CommaJoin(wanted_instances),
81
                                utils.CommaJoin(owned_instances)),
82
                               errors.ECODE_STATE)
83

  
84
  return wanted_instances
b/lib/cmdlib/network.py
1
#
2
#
3

  
4
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

  
21

  
22
"""Logical units dealing with networks."""
23

  
24
from ganeti import constants
25
from ganeti import errors
26
from ganeti import locking
27
from ganeti import network
28
from ganeti import objects
29
from ganeti import qlang
30
from ganeti import query
31
from ganeti import utils
32
from ganeti.cmdlib.base import LogicalUnit, NoHooksLU, _QueryBase
33
from ganeti.cmdlib.common import _ShareAll, _CheckNodeGroupInstances
34

  
35

  
36
def _BuildNetworkHookEnv(name, subnet, gateway, network6, gateway6,
37
                         mac_prefix, tags):
38
  """Builds network related env variables for hooks
39

  
40
  This builds the hook environment from individual variables.
41

  
42
  @type name: string
43
  @param name: the name of the network
44
  @type subnet: string
45
  @param subnet: the ipv4 subnet
46
  @type gateway: string
47
  @param gateway: the ipv4 gateway
48
  @type network6: string
49
  @param network6: the ipv6 subnet
50
  @type gateway6: string
51
  @param gateway6: the ipv6 gateway
52
  @type mac_prefix: string
53
  @param mac_prefix: the mac_prefix
54
  @type tags: list
55
  @param tags: the tags of the network
56

  
57
  """
58
  env = {}
59
  if name:
60
    env["NETWORK_NAME"] = name
61
  if subnet:
62
    env["NETWORK_SUBNET"] = subnet
63
  if gateway:
64
    env["NETWORK_GATEWAY"] = gateway
65
  if network6:
66
    env["NETWORK_SUBNET6"] = network6
67
  if gateway6:
68
    env["NETWORK_GATEWAY6"] = gateway6
69
  if mac_prefix:
70
    env["NETWORK_MAC_PREFIX"] = mac_prefix
71
  if tags:
72
    env["NETWORK_TAGS"] = " ".join(tags)
73

  
74
  return env
75

  
76

  
77
class LUNetworkAdd(LogicalUnit):
78
  """Logical unit for creating networks.
79

  
80
  """
81
  HPATH = "network-add"
82
  HTYPE = constants.HTYPE_NETWORK
83
  REQ_BGL = False
84

  
85
  def BuildHooksNodes(self):
86
    """Build hooks nodes.
87

  
88
    """
89
    mn = self.cfg.GetMasterNode()
90
    return ([mn], [mn])
91

  
92
  def CheckArguments(self):
93
    if self.op.mac_prefix:
94
      self.op.mac_prefix = \
95
        utils.NormalizeAndValidateThreeOctetMacPrefix(self.op.mac_prefix)
96

  
97
  def ExpandNames(self):
98
    self.network_uuid = self.cfg.GenerateUniqueID(self.proc.GetECId())
99

  
100
    if self.op.conflicts_check:
101
      self.share_locks[locking.LEVEL_NODE] = 1
102
      self.share_locks[locking.LEVEL_NODE_ALLOC] = 1
103
      self.needed_locks = {
104
        locking.LEVEL_NODE: locking.ALL_SET,
105
        locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
106
        }
107
    else:
108
      self.needed_locks = {}
109

  
110
    self.add_locks[locking.LEVEL_NETWORK] = self.network_uuid
111

  
112
  def CheckPrereq(self):
113
    if self.op.network is None:
114
      raise errors.OpPrereqError("Network must be given",
115
                                 errors.ECODE_INVAL)
116

  
117
    try:
118
      existing_uuid = self.cfg.LookupNetwork(self.op.network_name)
119
    except errors.OpPrereqError:
120
      pass
121
    else:
122
      raise errors.OpPrereqError("Desired network name '%s' already exists as a"
123
                                 " network (UUID: %s)" %
124
                                 (self.op.network_name, existing_uuid),
125
                                 errors.ECODE_EXISTS)
126

  
127
    # Check tag validity
128
    for tag in self.op.tags:
129
      objects.TaggableObject.ValidateTag(tag)
130

  
131
  def BuildHooksEnv(self):
132
    """Build hooks env.
133

  
134
    """
135
    args = {
136
      "name": self.op.network_name,
137
      "subnet": self.op.network,
138
      "gateway": self.op.gateway,
139
      "network6": self.op.network6,
140
      "gateway6": self.op.gateway6,
141
      "mac_prefix": self.op.mac_prefix,
142
      "tags": self.op.tags,
143
      }
144
    return _BuildNetworkHookEnv(**args) # pylint: disable=W0142
145

  
146
  def Exec(self, feedback_fn):
147
    """Add the ip pool to the cluster.
148

  
149
    """
150
    nobj = objects.Network(name=self.op.network_name,
151
                           network=self.op.network,
152
                           gateway=self.op.gateway,
153
                           network6=self.op.network6,
154
                           gateway6=self.op.gateway6,
155
                           mac_prefix=self.op.mac_prefix,
156
                           uuid=self.network_uuid)
157
    # Initialize the associated address pool
158
    try:
159
      pool = network.AddressPool.InitializeNetwork(nobj)
160
    except errors.AddressPoolError, err:
161
      raise errors.OpExecError("Cannot create IP address pool for network"
162
                               " '%s': %s" % (self.op.network_name, err))
163

  
164
    # Check if we need to reserve the nodes and the cluster master IP
165
    # These may not be allocated to any instances in routed mode, as
166
    # they wouldn't function anyway.
167
    if self.op.conflicts_check:
168
      for node in self.cfg.GetAllNodesInfo().values():
169
        for ip in [node.primary_ip, node.secondary_ip]:
170
          try:
171
            if pool.Contains(ip):
172
              pool.Reserve(ip)
173
              self.LogInfo("Reserved IP address of node '%s' (%s)",
174
                           node.name, ip)
175
          except errors.AddressPoolError, err:
176
            self.LogWarning("Cannot reserve IP address '%s' of node '%s': %s",
177
                            ip, node.name, err)
178

  
179
      master_ip = self.cfg.GetClusterInfo().master_ip
180
      try:
181
        if pool.Contains(master_ip):
182
          pool.Reserve(master_ip)
183
          self.LogInfo("Reserved cluster master IP address (%s)", master_ip)
184
      except errors.AddressPoolError, err:
185
        self.LogWarning("Cannot reserve cluster master IP address (%s): %s",
186
                        master_ip, err)
187

  
188
    if self.op.add_reserved_ips:
189
      for ip in self.op.add_reserved_ips:
190
        try:
191
          pool.Reserve(ip, external=True)
192
        except errors.AddressPoolError, err:
193
          raise errors.OpExecError("Cannot reserve IP address '%s': %s" %
194
                                   (ip, err))
195

  
196
    if self.op.tags:
197
      for tag in self.op.tags:
198
        nobj.AddTag(tag)
199

  
200
    self.cfg.AddNetwork(nobj, self.proc.GetECId(), check_uuid=False)
201
    del self.remove_locks[locking.LEVEL_NETWORK]
202

  
203

  
204
class LUNetworkRemove(LogicalUnit):
205
  HPATH = "network-remove"
206
  HTYPE = constants.HTYPE_NETWORK
207
  REQ_BGL = False
208

  
209
  def ExpandNames(self):
210
    self.network_uuid = self.cfg.LookupNetwork(self.op.network_name)
211

  
212
    self.share_locks[locking.LEVEL_NODEGROUP] = 1
213
    self.needed_locks = {
214
      locking.LEVEL_NETWORK: [self.network_uuid],
215
      locking.LEVEL_NODEGROUP: locking.ALL_SET,
216
      }
217

  
218
  def CheckPrereq(self):
219
    """Check prerequisites.
220

  
221
    This checks that the given network name exists as a network, that is
222
    empty (i.e., contains no nodes), and that is not the last group of the
223
    cluster.
224

  
225
    """
226
    # Verify that the network is not conncted.
227
    node_groups = [group.name
228
                   for group in self.cfg.GetAllNodeGroupsInfo().values()
229
                   if self.network_uuid in group.networks]
230

  
231
    if node_groups:
232
      self.LogWarning("Network '%s' is connected to the following"
233
                      " node groups: %s" %
234
                      (self.op.network_name,
235
                       utils.CommaJoin(utils.NiceSort(node_groups))))
236
      raise errors.OpPrereqError("Network still connected", errors.ECODE_STATE)
237

  
238
  def BuildHooksEnv(self):
239
    """Build hooks env.
240

  
241
    """
242
    return {
243
      "NETWORK_NAME": self.op.network_name,
244
      }
245

  
246
  def BuildHooksNodes(self):
247
    """Build hooks nodes.
248

  
249
    """
250
    mn = self.cfg.GetMasterNode()
251
    return ([mn], [mn])
252

  
253
  def Exec(self, feedback_fn):
254
    """Remove the network.
255

  
256
    """
257
    try:
258
      self.cfg.RemoveNetwork(self.network_uuid)
259
    except errors.ConfigurationError:
260
      raise errors.OpExecError("Network '%s' with UUID %s disappeared" %
261
                               (self.op.network_name, self.network_uuid))
262

  
263

  
264
class LUNetworkSetParams(LogicalUnit):
265
  """Modifies the parameters of a network.
266

  
267
  """
268
  HPATH = "network-modify"
269
  HTYPE = constants.HTYPE_NETWORK
270
  REQ_BGL = False
271

  
272
  def CheckArguments(self):
273
    if (self.op.gateway and
274
        (self.op.add_reserved_ips or self.op.remove_reserved_ips)):
275
      raise errors.OpPrereqError("Cannot modify gateway and reserved ips"
276
                                 " at once", errors.ECODE_INVAL)
277

  
278
  def ExpandNames(self):
279
    self.network_uuid = self.cfg.LookupNetwork(self.op.network_name)
280

  
281
    self.needed_locks = {
282
      locking.LEVEL_NETWORK: [self.network_uuid],
283
      }
284

  
285
  def CheckPrereq(self):
286
    """Check prerequisites.
287

  
288
    """
289
    self.network = self.cfg.GetNetwork(self.network_uuid)
290
    self.gateway = self.network.gateway
291
    self.mac_prefix = self.network.mac_prefix
292
    self.network6 = self.network.network6
293
    self.gateway6 = self.network.gateway6
294
    self.tags = self.network.tags
295

  
296
    self.pool = network.AddressPool(self.network)
297

  
298
    if self.op.gateway:
299
      if self.op.gateway == constants.VALUE_NONE:
300
        self.gateway = None
301
      else:
302
        self.gateway = self.op.gateway
303
        if self.pool.IsReserved(self.gateway):
304
          raise errors.OpPrereqError("Gateway IP address '%s' is already"
305
                                     " reserved" % self.gateway,
306
                                     errors.ECODE_STATE)
307

  
308
    if self.op.mac_prefix:
309
      if self.op.mac_prefix == constants.VALUE_NONE:
310
        self.mac_prefix = None
311
      else:
312
        self.mac_prefix = \
313
          utils.NormalizeAndValidateThreeOctetMacPrefix(self.op.mac_prefix)
314

  
315
    if self.op.gateway6:
316
      if self.op.gateway6 == constants.VALUE_NONE:
317
        self.gateway6 = None
318
      else:
319
        self.gateway6 = self.op.gateway6
320

  
321
    if self.op.network6:
322
      if self.op.network6 == constants.VALUE_NONE:
323
        self.network6 = None
324
      else:
325
        self.network6 = self.op.network6
326

  
327
  def BuildHooksEnv(self):
328
    """Build hooks env.
329

  
330
    """
331
    args = {
332
      "name": self.op.network_name,
333
      "subnet": self.network.network,
334
      "gateway": self.gateway,
335
      "network6": self.network6,
336
      "gateway6": self.gateway6,
337
      "mac_prefix": self.mac_prefix,
338
      "tags": self.tags,
339
      }
340
    return _BuildNetworkHookEnv(**args) # pylint: disable=W0142
341

  
342
  def BuildHooksNodes(self):
343
    """Build hooks nodes.
344

  
345
    """
346
    mn = self.cfg.GetMasterNode()
347
    return ([mn], [mn])
348

  
349
  def Exec(self, feedback_fn):
350
    """Modifies the network.
351

  
352
    """
353
    #TODO: reserve/release via temporary reservation manager
354
    #      extend cfg.ReserveIp/ReleaseIp with the external flag
355
    if self.op.gateway:
356
      if self.gateway == self.network.gateway:
357
        self.LogWarning("Gateway is already %s", self.gateway)
358
      else:
359
        if self.gateway:
360
          self.pool.Reserve(self.gateway, external=True)
361
        if self.network.gateway:
362
          self.pool.Release(self.network.gateway, external=True)
363
        self.network.gateway = self.gateway
364

  
365
    if self.op.add_reserved_ips:
366
      for ip in self.op.add_reserved_ips:
367
        try:
368
          if self.pool.IsReserved(ip):
369
            self.LogWarning("IP address %s is already reserved", ip)
370
          else:
371
            self.pool.Reserve(ip, external=True)
372
        except errors.AddressPoolError, err:
373
          self.LogWarning("Cannot reserve IP address %s: %s", ip, err)
374

  
375
    if self.op.remove_reserved_ips:
376
      for ip in self.op.remove_reserved_ips:
377
        if ip == self.network.gateway:
378
          self.LogWarning("Cannot unreserve Gateway's IP")
379
          continue
380
        try:
381
          if not self.pool.IsReserved(ip):
382
            self.LogWarning("IP address %s is already unreserved", ip)
383
          else:
384
            self.pool.Release(ip, external=True)
385
        except errors.AddressPoolError, err:
386
          self.LogWarning("Cannot release IP address %s: %s", ip, err)
387

  
388
    if self.op.mac_prefix:
389
      self.network.mac_prefix = self.mac_prefix
390

  
391
    if self.op.network6:
392
      self.network.network6 = self.network6
393

  
394
    if self.op.gateway6:
395
      self.network.gateway6 = self.gateway6
396

  
397
    self.pool.Validate()
398

  
399
    self.cfg.Update(self.network, feedback_fn)
400

  
401

  
402
class _NetworkQuery(_QueryBase):
403
  FIELDS = query.NETWORK_FIELDS
404

  
405
  def ExpandNames(self, lu):
406
    lu.needed_locks = {}
407
    lu.share_locks = _ShareAll()
408

  
409
    self.do_locking = self.use_locking
410

  
411
    all_networks = lu.cfg.GetAllNetworksInfo()
412
    name_to_uuid = dict((n.name, n.uuid) for n in all_networks.values())
413

  
414
    if self.names:
415
      missing = []
416
      self.wanted = []
417

  
418
      for name in self.names:
419
        if name in name_to_uuid:
420
          self.wanted.append(name_to_uuid[name])
421
        else:
422
          missing.append(name)
423

  
424
      if missing:
425
        raise errors.OpPrereqError("Some networks do not exist: %s" % missing,
426
                                   errors.ECODE_NOENT)
427
    else:
428
      self.wanted = locking.ALL_SET
429

  
430
    if self.do_locking:
431
      lu.needed_locks[locking.LEVEL_NETWORK] = self.wanted
432
      if query.NETQ_INST in self.requested_data:
433
        lu.needed_locks[locking.LEVEL_INSTANCE] = locking.ALL_SET
434
      if query.NETQ_GROUP in self.requested_data:
435
        lu.needed_locks[locking.LEVEL_NODEGROUP] = locking.ALL_SET
436

  
437
  def DeclareLocks(self, lu, level):
438
    pass
439

  
440
  def _GetQueryData(self, lu):
441
    """Computes the list of networks and their attributes.
442

  
443
    """
444
    all_networks = lu.cfg.GetAllNetworksInfo()
445

  
446
    network_uuids = self._GetNames(lu, all_networks.keys(),
447
                                   locking.LEVEL_NETWORK)
448

  
449
    do_instances = query.NETQ_INST in self.requested_data
450
    do_groups = query.NETQ_GROUP in self.requested_data
451

  
452
    network_to_instances = None
453
    network_to_groups = None
454

  
455
    # For NETQ_GROUP, we need to map network->[groups]
456
    if do_groups:
457
      all_groups = lu.cfg.GetAllNodeGroupsInfo()
458
      network_to_groups = dict((uuid, []) for uuid in network_uuids)
459
      for _, group in all_groups.iteritems():
460
        for net_uuid in network_uuids:
461
          netparams = group.networks.get(net_uuid, None)
462
          if netparams:
463
            info = (group.name, netparams[constants.NIC_MODE],
464
                    netparams[constants.NIC_LINK])
465

  
466
            network_to_groups[net_uuid].append(info)
467

  
468
    if do_instances:
469
      all_instances = lu.cfg.GetAllInstancesInfo()
470
      network_to_instances = dict((uuid, []) for uuid in network_uuids)
471
      for instance in all_instances.values():
472
        for nic in instance.nics:
473
          if nic.network in network_uuids:
474
            network_to_instances[nic.network].append(instance.name)
475
            break
476

  
477
    if query.NETQ_STATS in self.requested_data:
478
      stats = \
479
        dict((uuid,
480
              self._GetStats(network.AddressPool(all_networks[uuid])))
481
             for uuid in network_uuids)
482
    else:
483
      stats = None
484

  
485
    return query.NetworkQueryData([all_networks[uuid]
486
                                   for uuid in network_uuids],
487
                                   network_to_groups,
488
                                   network_to_instances,
489
                                   stats)
490

  
491
  @staticmethod
492
  def _GetStats(pool):
493
    """Returns statistics for a network address pool.
494

  
495
    """
496
    return {
497
      "free_count": pool.GetFreeCount(),
498
      "reserved_count": pool.GetReservedCount(),
499
      "map": pool.GetMap(),
500
      "external_reservations":
501
        utils.CommaJoin(pool.GetExternalReservations()),
502
      }
503

  
504

  
505
class LUNetworkQuery(NoHooksLU):
506
  """Logical unit for querying networks.
507

  
508
  """
509
  REQ_BGL = False
510

  
511
  def CheckArguments(self):
512
    self.nq = _NetworkQuery(qlang.MakeSimpleFilter("name", self.op.names),
513
                            self.op.output_fields, self.op.use_locking)
514

  
515
  def ExpandNames(self):
516
    self.nq.ExpandNames(self)
517

  
518
  def Exec(self, feedback_fn):
519
    return self.nq.OldStyleQuery(self)
520

  
521

  
522
def _FmtNetworkConflict(details):
523
  """Utility for L{_NetworkConflictCheck}.
524

  
525
  """
526
  return utils.CommaJoin("nic%s/%s" % (idx, ipaddr)
527
                         for (idx, ipaddr) in details)
528

  
529

  
530
def _NetworkConflictCheck(lu, check_fn, action, instances):
531
  """Checks for network interface conflicts with a network.
532

  
533
  @type lu: L{LogicalUnit}
534
  @type check_fn: callable receiving one parameter (L{objects.NIC}) and
535
    returning boolean
536
  @param check_fn: Function checking for conflict
537
  @type action: string
538
  @param action: Part of error message (see code)
539
  @raise errors.OpPrereqError: If conflicting IP addresses are found.
540

  
541
  """
542
  conflicts = []
543

  
544
  for (_, instance) in lu.cfg.GetMultiInstanceInfo(instances):
545
    instconflicts = [(idx, nic.ip)
546
                     for (idx, nic) in enumerate(instance.nics)
547
                     if check_fn(nic)]
548

  
549
    if instconflicts:
550
      conflicts.append((instance.name, instconflicts))
551

  
552
  if conflicts:
553
    lu.LogWarning("IP addresses from network '%s', which is about to %s"
554
                  " node group '%s', are in use: %s" %
555
                  (lu.network_name, action, lu.group.name,
556
                   utils.CommaJoin(("%s: %s" %
557
                                    (name, _FmtNetworkConflict(details)))
558
                                   for (name, details) in conflicts)))
559

  
560
    raise errors.OpPrereqError("Conflicting IP addresses found; "
561
                               " remove/modify the corresponding network"
562
                               " interfaces", errors.ECODE_STATE)
563

  
564

  
565
class LUNetworkConnect(LogicalUnit):
566
  """Connect a network to a nodegroup
567

  
568
  """
569
  HPATH = "network-connect"
570
  HTYPE = constants.HTYPE_NETWORK
571
  REQ_BGL = False
572

  
573
  def ExpandNames(self):
574
    self.network_name = self.op.network_name
575
    self.group_name = self.op.group_name
576
    self.network_mode = self.op.network_mode
577
    self.network_link = self.op.network_link
578

  
579
    self.network_uuid = self.cfg.LookupNetwork(self.network_name)
580
    self.group_uuid = self.cfg.LookupNodeGroup(self.group_name)
581

  
582
    self.needed_locks = {
583
      locking.LEVEL_INSTANCE: [],
584
      locking.LEVEL_NODEGROUP: [self.group_uuid],
585
      }
586
    self.share_locks[locking.LEVEL_INSTANCE] = 1
587

  
588
    if self.op.conflicts_check:
589
      self.needed_locks[locking.LEVEL_NETWORK] = [self.network_uuid]
590
      self.share_locks[locking.LEVEL_NETWORK] = 1
591

  
592
  def DeclareLocks(self, level):
593
    if level == locking.LEVEL_INSTANCE:
594
      assert not self.needed_locks[locking.LEVEL_INSTANCE]
595

  
596
      # Lock instances optimistically, needs verification once group lock has
597
      # been acquired
598
      if self.op.conflicts_check:
599
        self.needed_locks[locking.LEVEL_INSTANCE] = \
600
            self.cfg.GetNodeGroupInstances(self.group_uuid)
601

  
602
  def BuildHooksEnv(self):
603
    ret = {
604
      "GROUP_NAME": self.group_name,
605
      "GROUP_NETWORK_MODE": self.network_mode,
606
      "GROUP_NETWORK_LINK": self.network_link,
607
      }
608
    return ret
609

  
610
  def BuildHooksNodes(self):
611
    nodes = self.cfg.GetNodeGroup(self.group_uuid).members
612
    return (nodes, nodes)
613

  
614
  def CheckPrereq(self):
615
    owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
616

  
617
    assert self.group_uuid in owned_groups
618

  
619
    # Check if locked instances are still correct
620
    owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
621
    if self.op.conflicts_check:
622
      _CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instances)
623

  
624
    self.netparams = {
625
      constants.NIC_MODE: self.network_mode,
626
      constants.NIC_LINK: self.network_link,
627
      }
628
    objects.NIC.CheckParameterSyntax(self.netparams)
629

  
630
    self.group = self.cfg.GetNodeGroup(self.group_uuid)
631
    #if self.network_mode == constants.NIC_MODE_BRIDGED:
632
    #  _CheckNodeGroupBridgesExist(self, self.network_link, self.group_uuid)
633
    self.connected = False
634
    if self.network_uuid in self.group.networks:
635
      self.LogWarning("Network '%s' is already mapped to group '%s'" %
636
                      (self.network_name, self.group.name))
637
      self.connected = True
638

  
639
    # check only if not already connected
640
    elif self.op.conflicts_check:
641
      pool = network.AddressPool(self.cfg.GetNetwork(self.network_uuid))
642

  
643
      _NetworkConflictCheck(self, lambda nic: pool.Contains(nic.ip),
644
                            "connect to", owned_instances)
645

  
646
  def Exec(self, feedback_fn):
647
    # Connect the network and update the group only if not already connected
648
    if not self.connected:
649
      self.group.networks[self.network_uuid] = self.netparams
650
      self.cfg.Update(self.group, feedback_fn)
651

  
652

  
653
class LUNetworkDisconnect(LogicalUnit):
654
  """Disconnect a network to a nodegroup
655

  
656
  """
657
  HPATH = "network-disconnect"
658
  HTYPE = constants.HTYPE_NETWORK
659
  REQ_BGL = False
660

  
661
  def ExpandNames(self):
662
    self.network_name = self.op.network_name
663
    self.group_name = self.op.group_name
664

  
665
    self.network_uuid = self.cfg.LookupNetwork(self.network_name)
666
    self.group_uuid = self.cfg.LookupNodeGroup(self.group_name)
667

  
668
    self.needed_locks = {
669
      locking.LEVEL_INSTANCE: [],
670
      locking.LEVEL_NODEGROUP: [self.group_uuid],
671
      }
672
    self.share_locks[locking.LEVEL_INSTANCE] = 1
673

  
674
  def DeclareLocks(self, level):
675
    if level == locking.LEVEL_INSTANCE:
676
      assert not self.needed_locks[locking.LEVEL_INSTANCE]
677

  
678
      # Lock instances optimistically, needs verification once group lock has
679
      # been acquired
680
      self.needed_locks[locking.LEVEL_INSTANCE] = \
681
        self.cfg.GetNodeGroupInstances(self.group_uuid)
682

  
683
  def BuildHooksEnv(self):
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff