Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / network.py @ 5cbf7832

History | View | Annotate | Download (22.6 kB)

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.uuid)
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
  @param instances: the instances to check
540
  @type instances: list of instance objects
541
  @raise errors.OpPrereqError: If conflicting IP addresses are found.
542

543
  """
544
  conflicts = []
545

    
546
  for instance in instances:
547
    instconflicts = [(idx, nic.ip)
548
                     for (idx, nic) in enumerate(instance.nics)
549
                     if check_fn(nic)]
550

    
551
    if instconflicts:
552
      conflicts.append((instance.name, instconflicts))
553

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

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

    
566

    
567
class LUNetworkConnect(LogicalUnit):
568
  """Connect a network to a nodegroup
569

570
  """
571
  HPATH = "network-connect"
572
  HTYPE = constants.HTYPE_NETWORK
573
  REQ_BGL = False
574

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

    
581
    self.network_uuid = self.cfg.LookupNetwork(self.network_name)
582
    self.group_uuid = self.cfg.LookupNodeGroup(self.group_name)
583

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

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

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

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

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

    
613
  def BuildHooksNodes(self):
614
    node_uuids = self.cfg.GetNodeGroup(self.group_uuid).members
615
    return (node_uuids, node_uuids)
616

    
617
  def CheckPrereq(self):
618
    owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
619

    
620
    assert self.group_uuid in owned_groups
621

    
622
    # Check if locked instances are still correct
623
    owned_instance_names = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
624
    if self.op.conflicts_check:
625
      CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instance_names)
626

    
627
    self.netparams = {
628
      constants.NIC_MODE: self.network_mode,
629
      constants.NIC_LINK: self.network_link,
630
      }
631
    objects.NIC.CheckParameterSyntax(self.netparams)
632

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

    
642
    # check only if not already connected
643
    elif self.op.conflicts_check:
644
      pool = network.AddressPool(self.cfg.GetNetwork(self.network_uuid))
645

    
646
      _NetworkConflictCheck(
647
        self, lambda nic: pool.Contains(nic.ip), "connect to",
648
        [instance_info for (_, instance_info) in
649
         self.cfg.GetMultiInstanceInfoByName(owned_instance_names)])
650

    
651
  def Exec(self, feedback_fn):
652
    # Connect the network and update the group only if not already connected
653
    if not self.connected:
654
      self.group.networks[self.network_uuid] = self.netparams
655
      self.cfg.Update(self.group, feedback_fn)
656

    
657

    
658
class LUNetworkDisconnect(LogicalUnit):
659
  """Disconnect a network to a nodegroup
660

661
  """
662
  HPATH = "network-disconnect"
663
  HTYPE = constants.HTYPE_NETWORK
664
  REQ_BGL = False
665

    
666
  def ExpandNames(self):
667
    self.network_name = self.op.network_name
668
    self.group_name = self.op.group_name
669

    
670
    self.network_uuid = self.cfg.LookupNetwork(self.network_name)
671
    self.group_uuid = self.cfg.LookupNodeGroup(self.group_name)
672

    
673
    self.needed_locks = {
674
      locking.LEVEL_INSTANCE: [],
675
      locking.LEVEL_NODEGROUP: [self.group_uuid],
676
      }
677
    self.share_locks[locking.LEVEL_INSTANCE] = 1
678

    
679
  def DeclareLocks(self, level):
680
    if level == locking.LEVEL_INSTANCE:
681
      assert not self.needed_locks[locking.LEVEL_INSTANCE]
682

    
683
      # Lock instances optimistically, needs verification once group lock has
684
      # been acquired
685
      self.needed_locks[locking.LEVEL_INSTANCE] = \
686
        self.cfg.GetInstanceNames(
687
          self.cfg.GetNodeGroupInstances(self.group_uuid))
688

    
689
  def BuildHooksEnv(self):
690
    ret = {
691
      "GROUP_NAME": self.group_name,
692
      }
693
    return ret
694

    
695
  def BuildHooksNodes(self):
696
    nodes = self.cfg.GetNodeGroup(self.group_uuid).members
697
    return (nodes, nodes)
698

    
699
  def CheckPrereq(self):
700
    owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
701

    
702
    assert self.group_uuid in owned_groups
703

    
704
    # Check if locked instances are still correct
705
    owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
706
    CheckNodeGroupInstances(self.cfg, self.group_uuid, owned_instances)
707

    
708
    self.group = self.cfg.GetNodeGroup(self.group_uuid)
709
    self.connected = True
710
    if self.network_uuid not in self.group.networks:
711
      self.LogWarning("Network '%s' is not mapped to group '%s'",
712
                      self.network_name, self.group.name)
713
      self.connected = False
714

    
715
    # We need this check only if network is not already connected
716
    else:
717
      _NetworkConflictCheck(
718
        self, lambda nic: nic.network == self.network_uuid, "disconnect from",
719
        [instance_info for (_, instance_info) in
720
        self.cfg.GetMultiInstanceInfoByName(owned_instances)])
721

    
722
  def Exec(self, feedback_fn):
723
    # Disconnect the network and update the group only if network is connected
724
    if self.connected:
725
      del self.group.networks[self.network_uuid]
726
      self.cfg.Update(self.group, feedback_fn)