Revision 306bed0e

b/lib/cmdlib.py
15479 15479

  
15480 15480

  
15481 15481
class _NetworkQuery(_QueryBase):
15482
  FIELDS = query.NETWORK_FIELDS
15483

  
15482 15484
  def ExpandNames(self, lu):
15483
    pass
15485
    lu.needed_locks = {}
15486

  
15487
    self._all_networks = lu.cfg.GetAllNetworksInfo()
15488
    name_to_uuid = dict((n.name, n.uuid) for n in self._all_networks.values())
15489

  
15490
    if not self.names:
15491
      self.wanted = [name_to_uuid[name]
15492
                     for name in utils.NiceSort(name_to_uuid.keys())]
15493
    else:
15494
      # Accept names to be either names or UUIDs.
15495
      missing = []
15496
      self.wanted = []
15497
      all_uuid = frozenset(self._all_networks.keys())
15498

  
15499
      for name in self.names:
15500
        if name in all_uuid:
15501
          self.wanted.append(name)
15502
        elif name in name_to_uuid:
15503
          self.wanted.append(name_to_uuid[name])
15504
        else:
15505
          missing.append(name)
15506

  
15507
      if missing:
15508
        raise errors.OpPrereqError("Some networks do not exist: %s" % missing,
15509
                                   errors.ECODE_NOENT)
15484 15510

  
15485 15511
  def DeclareLocks(self, lu, level):
15486 15512
    pass
15487 15513

  
15488 15514
  def _GetQueryData(self, lu):
15489
    pass
15515
    """Computes the list of networks and their attributes.
15516

  
15517
    """
15518
    do_instances = query.NETQ_INST in self.requested_data
15519
    do_groups = do_instances or (query.NETQ_GROUP in self.requested_data)
15520
    do_stats = query.NETQ_STATS in self.requested_data
15521
    cluster = lu.cfg.GetClusterInfo()
15522

  
15523
    network_to_groups = None
15524
    network_to_instances = None
15525
    stats = None
15526

  
15527
    # For NETQ_GROUP, we need to map network->[groups]
15528
    if do_groups:
15529
      all_groups = lu.cfg.GetAllNodeGroupsInfo()
15530
      network_to_groups = dict((uuid, []) for uuid in self.wanted)
15531
      default_nicpp = cluster.nicparams[constants.PP_DEFAULT]
15532

  
15533
      if do_instances:
15534
        all_instances = lu.cfg.GetAllInstancesInfo()
15535
        all_nodes = lu.cfg.GetAllNodesInfo()
15536
        network_to_instances = dict((uuid, []) for uuid in self.wanted)
15537

  
15538

  
15539
      for group in all_groups.values():
15540
        if do_instances:
15541
          group_nodes = [node.name for node in all_nodes.values() if
15542
                         node.group == group.uuid]
15543
          group_instances = [instance for instance in all_instances.values()
15544
                             if instance.primary_node in group_nodes]
15545

  
15546
        for net_uuid in group.networks.keys():
15547
          if net_uuid in network_to_groups:
15548
            netparams = group.networks[net_uuid]
15549
            mode = netparams[constants.NIC_MODE]
15550
            link = netparams[constants.NIC_LINK]
15551
            info = group.name + '(' + mode + ', ' + link + ')'
15552
            network_to_groups[net_uuid].append(info)
15553

  
15554
            if do_instances:
15555
              for instance in group_instances:
15556
                for nic in instance.nics:
15557
                  if nic.network == self._all_networks[net_uuid].name:
15558
                    network_to_instances[net_uuid].append(instance.name)
15559
                    break
15560

  
15561
    if do_stats:
15562
      stats = {}
15563
      for uuid, net in self._all_networks.items():
15564
        if uuid in self.wanted:
15565
          pool = network.AddressPool(net)
15566
          stats[uuid] = {
15567
            "free_count": pool.GetFreeCount(),
15568
            "reserved_count": pool.GetReservedCount(),
15569
            "map": pool.GetMap(),
15570
            "external_reservations": ", ".join(pool.GetExternalReservations()),
15571
            }
15572

  
15573
    return query.NetworkQueryData([self._all_networks[uuid]
15574
                                   for uuid in self.wanted],
15575
                                   network_to_groups,
15576
                                   network_to_instances,
15577
                                   stats)
15490 15578

  
15491 15579

  
15492 15580
class LUNetworkQuery(NoHooksLU):
15493
  pass
15581
  """Logical unit for querying networks.
15582

  
15583
  """
15584
  REQ_BGL = False
15585

  
15586
  def CheckArguments(self):
15587
    self.nq = _NetworkQuery(qlang.MakeSimpleFilter("name", self.op.names),
15588
                            self.op.output_fields, False)
15589

  
15590
  def ExpandNames(self):
15591
    self.nq.ExpandNames(self)
15592

  
15593
  def Exec(self, feedback_fn):
15594
    return self.nq.OldStyleQuery(self)
15595

  
15494 15596

  
15495 15597

  
15496 15598
class LUNetworkConnect(LogicalUnit):
b/lib/luxi.py
62 62
REQ_QUERY_INSTANCES = "QueryInstances"
63 63
REQ_QUERY_NODES = "QueryNodes"
64 64
REQ_QUERY_GROUPS = "QueryGroups"
65
REQ_QUERY_NETWORKS = "QueryNetworks"
65 66
REQ_QUERY_EXPORTS = "QueryExports"
66 67
REQ_QUERY_CONFIG_VALUES = "QueryConfigValues"
67 68
REQ_QUERY_CLUSTER_INFO = "QueryClusterInfo"
......
566 567
  def QueryGroups(self, names, fields, use_locking):
567 568
    return self.CallMethod(REQ_QUERY_GROUPS, (names, fields, use_locking))
568 569

  
570
  def QueryNetworks(self, names, fields, use_locking):
571
    return self.CallMethod(REQ_QUERY_NETWORKS, (names, fields, use_locking))
572

  
569 573
  def QueryExports(self, nodes, use_locking):
570 574
    return self.CallMethod(REQ_QUERY_EXPORTS, (nodes, use_locking))
571 575

  
b/lib/query.py
71 71
                              RS_NORMAL, RS_UNKNOWN, RS_NODATA,
72 72
                              RS_UNAVAIL, RS_OFFLINE)
73 73

  
74
(NETQ_CONFIG,
75
 NETQ_GROUP,
76
 NETQ_STATS,
77
 NETQ_INST) = range(300, 304)
74 78

  
75 79
# Constants for requesting data from the caller/data provider. Each property
76 80
# collected/computed separately by the data provider should have its own to
......
2422 2426
    ])
2423 2427

  
2424 2428

  
2429
class NetworkQueryData:
2430
  """Data container for network data queries.
2431

  
2432
  """
2433
  def __init__(self, networks, network_to_groups,
2434
               network_to_instances, stats):
2435
    """Initializes this class.
2436

  
2437
    @param networks: List of network objects
2438
    @type network_to_groups: dict; network UUID as key
2439
    @param network_to_groups: Per-network list of groups
2440
    @type network_to_instances: dict; network UUID as key
2441
    @param network_to_instances: Per-network list of instances
2442
    @type stats: dict; network UUID as key
2443
    @param stats: Per-network usage statistics
2444

  
2445
    """
2446
    self.networks = networks
2447
    self.network_to_groups = network_to_groups
2448
    self.network_to_instances = network_to_instances
2449
    self.stats = stats
2450

  
2451
  def __iter__(self):
2452
    """Iterate over all networks.
2453

  
2454
    """
2455
    for net in self.networks:
2456
      if self.stats:
2457
        self.curstats = self.stats.get(net.uuid, None)
2458
      else:
2459
        self.curstats = None
2460
      yield net
2461

  
2462

  
2463
_NETWORK_SIMPLE_FIELDS = {
2464
  "name": ("Network", QFT_TEXT, 0, "The network"),
2465
  "network": ("Subnet", QFT_TEXT, 0, "The subnet"),
2466
  "gateway": ("Gateway", QFT_OTHER, 0, "The gateway"),
2467
  "network6": ("IPv6Subnet", QFT_OTHER, 0, "The ipv6 subnet"),
2468
  "gateway6": ("IPv6Gateway", QFT_OTHER, 0, "The ipv6 gateway"),
2469
  "mac_prefix": ("MacPrefix", QFT_OTHER, 0, "The mac prefix"),
2470
  "network_type": ("NetworkType", QFT_OTHER, 0, "The network type"),
2471
  }
2472

  
2473

  
2474
_NETWORK_STATS_FIELDS = {
2475
  "free_count": ("FreeCount", QFT_NUMBER, 0, "How many addresses are free"),
2476
  "reserved_count": ("ReservedCount", QFT_NUMBER, 0, "How many addresses are reserved"),
2477
  "map": ("Map", QFT_TEXT, 0, "The actual mapping"),
2478
  "external_reservations": ("ExternalReservations", QFT_TEXT, 0, "The external reservations"),
2479
  }
2480

  
2481

  
2482
def _GetNetworkStatsField(field, kind, ctx, net):
2483
  """Gets the value of a "stats" field from L{NetworkQueryData}.
2484

  
2485
  @param field: Field name
2486
  @param kind: Data kind, one of L{constants.QFT_ALL}
2487
  @type ctx: L{NetworkQueryData}
2488

  
2489
  """
2490

  
2491
  try:
2492
    value = ctx.curstats[field]
2493
  except KeyError:
2494
    return _FS_UNAVAIL
2495

  
2496
  if kind == QFT_TEXT:
2497
    return value
2498

  
2499
  assert kind in (QFT_NUMBER, QFT_UNIT)
2500

  
2501
  # Try to convert into number
2502
  try:
2503
    return int(value)
2504
  except (ValueError, TypeError):
2505
    logging.exception("Failed to convert network field '%s' (value %r) to int",
2506
                      value, field)
2507
    return _FS_UNAVAIL
2508

  
2509

  
2510
def _BuildNetworkFields():
2511
  """Builds list of fields for network queries.
2512

  
2513
  """
2514
  # Add simple fields
2515
  fields = [
2516
    (_MakeField(name, title, kind, doc),
2517
     NETQ_CONFIG, 0, _GetItemAttr(name))
2518
    for (name, (title, kind, flags, doc)) in _NETWORK_SIMPLE_FIELDS.items()]
2519

  
2520
  def _GetLength(getter):
2521
    return lambda ctx, network: len(getter(ctx)[network.uuid])
2522

  
2523
  def _GetSortedList(getter):
2524
    return lambda ctx, network: utils.NiceSort(getter(ctx)[network.uuid])
2525

  
2526
  network_to_groups = operator.attrgetter("network_to_groups")
2527
  network_to_instances = operator.attrgetter("network_to_instances")
2528

  
2529
  # Add fields for node groups
2530
  fields.extend([
2531
    (_MakeField("group_cnt", "NodeGroups", QFT_NUMBER, "Number of nodegroups"),
2532
     NETQ_GROUP, 0, _GetLength(network_to_groups)),
2533
	(_MakeField("group_list", "GroupList", QFT_OTHER, "List of nodegroups"),
2534
     NETQ_GROUP, 0, _GetSortedList(network_to_groups)),
2535
    ])
2536

  
2537
  # Add fields for instances
2538
  fields.extend([
2539
    (_MakeField("inst_cnt", "Instances", QFT_NUMBER, "Number of instances"),
2540
     NETQ_INST, 0, _GetLength(network_to_instances)),
2541
    (_MakeField("inst_list", "InstanceList", QFT_OTHER, "List of instances"),
2542
     NETQ_INST, 0, _GetSortedList(network_to_instances)),
2543
    ])
2544

  
2545
  # Add fields for usage statistics
2546
  fields.extend([
2547
    (_MakeField(name, title, kind, doc), NETQ_STATS, 0,
2548
    compat.partial(_GetNetworkStatsField, name, kind))
2549
    for (name, (title, kind, flags, doc)) in _NETWORK_STATS_FIELDS.items()
2550
    ])
2551

  
2552
  return _PrepareFieldList(fields, [])
2553

  
2425 2554
#: Fields for cluster information
2426 2555
CLUSTER_FIELDS = _BuildClusterFields()
2427 2556

  
......
2446 2575
#: Fields available for exports
2447 2576
EXPORT_FIELDS = _BuildExportFields()
2448 2577

  
2578
#: Fields available for network queries
2579
NETWORK_FIELDS = _BuildNetworkFields()
2580

  
2449 2581
#: All available resources
2450 2582
ALL_FIELDS = {
2451 2583
  constants.QR_CLUSTER: CLUSTER_FIELDS,
......
2456 2588
  constants.QR_OS: OS_FIELDS,
2457 2589
  constants.QR_JOB: JOB_FIELDS,
2458 2590
  constants.QR_EXPORT: EXPORT_FIELDS,
2591
  constants.QR_NETWORK: NETWORK_FIELDS,
2459 2592
  }
2460 2593

  
2461 2594
#: All available field lists
b/lib/server/masterd.py
397 397
      op = opcodes.OpGroupQuery(names=names, output_fields=fields)
398 398
      return self._Query(op)
399 399

  
400
    elif method == luxi.REQ_QUERY_NETWORKS:
401
      (names, fields, use_locking) = args
402
      logging.info("Received network query request for %s", names)
403
      if use_locking:
404
        raise errors.OpPrereqError("Sync queries are not allowed",
405
                                   errors.ECODE_INVAL)
406
      op = opcodes.OpNetworkQuery(names=names, output_fields=fields)
407
      return self._Query(op)
408

  
400 409
    elif method == luxi.REQ_QUERY_EXPORTS:
401 410
      (nodes, use_locking) = args
402 411
      if use_locking:

Also available in: Unified diff