Revision 909064a1

b/lib/cmdlib.py
15518 15518

  
15519 15519

  
15520 15520
class _NetworkQuery(_QueryBase):
15521
  FIELDS = query.NETWORK_FIELDS
15522

  
15521 15523
  def ExpandNames(self, lu):
15522
    pass
15524
    lu.needed_locks = {}
15525

  
15526
    self._all_networks = lu.cfg.GetAllNetworksInfo()
15527
    name_to_uuid = dict((n.name, n.uuid) for n in self._all_networks.values())
15528

  
15529
    if not self.names:
15530
      self.wanted = [name_to_uuid[name]
15531
                     for name in utils.NiceSort(name_to_uuid.keys())]
15532
    else:
15533
      # Accept names to be either names or UUIDs.
15534
      missing = []
15535
      self.wanted = []
15536
      all_uuid = frozenset(self._all_networks.keys())
15537

  
15538
      for name in self.names:
15539
        if name in all_uuid:
15540
          self.wanted.append(name)
15541
        elif name in name_to_uuid:
15542
          self.wanted.append(name_to_uuid[name])
15543
        else:
15544
          missing.append(name)
15545

  
15546
      if missing:
15547
        raise errors.OpPrereqError("Some networks do not exist: %s" % missing,
15548
                                   errors.ECODE_NOENT)
15523 15549

  
15524 15550
  def DeclareLocks(self, lu, level):
15525 15551
    pass
15526 15552

  
15527 15553
  def _GetQueryData(self, lu):
15528
    pass
15554
    """Computes the list of networks and their attributes.
15555

  
15556
    """
15557
    do_instances = query.NETQ_INST in self.requested_data
15558
    do_groups = do_instances or (query.NETQ_GROUP in self.requested_data)
15559
    do_stats = query.NETQ_STATS in self.requested_data
15560
    cluster = lu.cfg.GetClusterInfo()
15561

  
15562
    network_to_groups = None
15563
    network_to_instances = None
15564
    stats = None
15565

  
15566
    # For NETQ_GROUP, we need to map network->[groups]
15567
    if do_groups:
15568
      all_groups = lu.cfg.GetAllNodeGroupsInfo()
15569
      network_to_groups = dict((uuid, []) for uuid in self.wanted)
15570
      default_nicpp = cluster.nicparams[constants.PP_DEFAULT]
15571

  
15572
      if do_instances:
15573
        all_instances = lu.cfg.GetAllInstancesInfo()
15574
        all_nodes = lu.cfg.GetAllNodesInfo()
15575
        network_to_instances = dict((uuid, []) for uuid in self.wanted)
15576

  
15577

  
15578
      for group in all_groups.values():
15579
        if do_instances:
15580
          group_nodes = [node.name for node in all_nodes.values() if
15581
                         node.group == group.uuid]
15582
          group_instances = [instance for instance in all_instances.values()
15583
                             if instance.primary_node in group_nodes]
15584

  
15585
        for net_uuid in group.networks.keys():
15586
          if net_uuid in network_to_groups:
15587
            netparams = group.networks[net_uuid]
15588
            mode = netparams[constants.NIC_MODE]
15589
            link = netparams[constants.NIC_LINK]
15590
            info = group.name + '(' + mode + ', ' + link + ')'
15591
            network_to_groups[net_uuid].append(info)
15592

  
15593
            if do_instances:
15594
              for instance in group_instances:
15595
                for nic in instance.nics:
15596
                  if nic.network == self._all_networks[net_uuid].name:
15597
                    network_to_instances[net_uuid].append(instance.name)
15598
                    break
15599

  
15600
    if do_stats:
15601
      stats = {}
15602
      for uuid, net in self._all_networks.items():
15603
        if uuid in self.wanted:
15604
          pool = network.AddressPool(net)
15605
          stats[uuid] = {
15606
            "free_count": pool.GetFreeCount(),
15607
            "reserved_count": pool.GetReservedCount(),
15608
            "map": pool.GetMap(),
15609
            "external_reservations": ", ".join(pool.GetExternalReservations()),
15610
            }
15611

  
15612
    return query.NetworkQueryData([self._all_networks[uuid]
15613
                                   for uuid in self.wanted],
15614
                                   network_to_groups,
15615
                                   network_to_instances,
15616
                                   stats)
15529 15617

  
15530 15618

  
15531 15619
class LUNetworkQuery(NoHooksLU):
15532
  pass
15620
  """Logical unit for querying networks.
15621

  
15622
  """
15623
  REQ_BGL = False
15624

  
15625
  def CheckArguments(self):
15626
    self.nq = _NetworkQuery(qlang.MakeSimpleFilter("name", self.op.names),
15627
                            self.op.output_fields, False)
15628

  
15629
  def ExpandNames(self):
15630
    self.nq.ExpandNames(self)
15631

  
15632
  def Exec(self, feedback_fn):
15633
    return self.nq.OldStyleQuery(self)
15634

  
15533 15635

  
15534 15636

  
15535 15637
class LUNetworkConnect(LogicalUnit):
b/lib/luxi.py
60 60
REQ_QUERY_INSTANCES = "QueryInstances"
61 61
REQ_QUERY_NODES = "QueryNodes"
62 62
REQ_QUERY_GROUPS = "QueryGroups"
63
REQ_QUERY_NETWORKS = "QueryNetworks"
63 64
REQ_QUERY_EXPORTS = "QueryExports"
64 65
REQ_QUERY_CONFIG_VALUES = "QueryConfigValues"
65 66
REQ_QUERY_CLUSTER_INFO = "QueryClusterInfo"
......
560 561
  def QueryGroups(self, names, fields, use_locking):
561 562
    return self.CallMethod(REQ_QUERY_GROUPS, (names, fields, use_locking))
562 563

  
564
  def QueryNetworks(self, names, fields, use_locking):
565
    return self.CallMethod(REQ_QUERY_NETWORKS, (names, fields, use_locking))
566

  
563 567
  def QueryExports(self, nodes, use_locking):
564 568
    return self.CallMethod(REQ_QUERY_EXPORTS, (nodes, use_locking))
565 569

  
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
......
2434 2438
    ])
2435 2439

  
2436 2440

  
2441
class NetworkQueryData:
2442
  """Data container for network data queries.
2443

  
2444
  """
2445
  def __init__(self, networks, network_to_groups,
2446
               network_to_instances, stats):
2447
    """Initializes this class.
2448

  
2449
    @param networks: List of network objects
2450
    @type network_to_groups: dict; network UUID as key
2451
    @param network_to_groups: Per-network list of groups
2452
    @type network_to_instances: dict; network UUID as key
2453
    @param network_to_instances: Per-network list of instances
2454
    @type stats: dict; network UUID as key
2455
    @param stats: Per-network usage statistics
2456

  
2457
    """
2458
    self.networks = networks
2459
    self.network_to_groups = network_to_groups
2460
    self.network_to_instances = network_to_instances
2461
    self.stats = stats
2462

  
2463
  def __iter__(self):
2464
    """Iterate over all networks.
2465

  
2466
    """
2467
    for net in self.networks:
2468
      if self.stats:
2469
        self.curstats = self.stats.get(net.uuid, None)
2470
      else:
2471
        self.curstats = None
2472
      yield net
2473

  
2474

  
2475
_NETWORK_SIMPLE_FIELDS = {
2476
  "name": ("Network", QFT_TEXT, 0, "The network"),
2477
  "network": ("Subnet", QFT_TEXT, 0, "The subnet"),
2478
  "gateway": ("Gateway", QFT_OTHER, 0, "The gateway"),
2479
  "network6": ("IPv6Subnet", QFT_OTHER, 0, "The ipv6 subnet"),
2480
  "gateway6": ("IPv6Gateway", QFT_OTHER, 0, "The ipv6 gateway"),
2481
  "mac_prefix": ("MacPrefix", QFT_OTHER, 0, "The mac prefix"),
2482
  "network_type": ("NetworkType", QFT_OTHER, 0, "The network type"),
2483
  }
2484

  
2485

  
2486
_NETWORK_STATS_FIELDS = {
2487
  "free_count": ("FreeCount", QFT_NUMBER, 0, "How many addresses are free"),
2488
  "reserved_count": ("ReservedCount", QFT_NUMBER, 0, "How many addresses are reserved"),
2489
  "map": ("Map", QFT_TEXT, 0, "The actual mapping"),
2490
  "external_reservations": ("ExternalReservations", QFT_TEXT, 0, "The external reservations"),
2491
  }
2492

  
2493

  
2494
def _GetNetworkStatsField(field, kind, ctx, net):
2495
  """Gets the value of a "stats" field from L{NetworkQueryData}.
2496

  
2497
  @param field: Field name
2498
  @param kind: Data kind, one of L{constants.QFT_ALL}
2499
  @type ctx: L{NetworkQueryData}
2500

  
2501
  """
2502

  
2503
  try:
2504
    value = ctx.curstats[field]
2505
  except KeyError:
2506
    return _FS_UNAVAIL
2507

  
2508
  if kind == QFT_TEXT:
2509
    return value
2510

  
2511
  assert kind in (QFT_NUMBER, QFT_UNIT)
2512

  
2513
  # Try to convert into number
2514
  try:
2515
    return int(value)
2516
  except (ValueError, TypeError):
2517
    logging.exception("Failed to convert network field '%s' (value %r) to int",
2518
                      value, field)
2519
    return _FS_UNAVAIL
2520

  
2521

  
2522
def _BuildNetworkFields():
2523
  """Builds list of fields for network queries.
2524

  
2525
  """
2526
  # Add simple fields
2527
  fields = [
2528
    (_MakeField(name, title, kind, doc),
2529
     NETQ_CONFIG, 0, _GetItemAttr(name))
2530
    for (name, (title, kind, flags, doc)) in _NETWORK_SIMPLE_FIELDS.items()]
2531

  
2532
  def _GetLength(getter):
2533
    return lambda ctx, network: len(getter(ctx)[network.uuid])
2534

  
2535
  def _GetSortedList(getter):
2536
    return lambda ctx, network: utils.NiceSort(getter(ctx)[network.uuid])
2537

  
2538
  network_to_groups = operator.attrgetter("network_to_groups")
2539
  network_to_instances = operator.attrgetter("network_to_instances")
2540

  
2541
  # Add fields for node groups
2542
  fields.extend([
2543
    (_MakeField("group_cnt", "NodeGroups", QFT_NUMBER, "Number of nodegroups"),
2544
     NETQ_GROUP, 0, _GetLength(network_to_groups)),
2545
	(_MakeField("group_list", "GroupList", QFT_OTHER, "List of nodegroups"),
2546
     NETQ_GROUP, 0, _GetSortedList(network_to_groups)),
2547
    ])
2548

  
2549
  # Add fields for instances
2550
  fields.extend([
2551
    (_MakeField("inst_cnt", "Instances", QFT_NUMBER, "Number of instances"),
2552
     NETQ_INST, 0, _GetLength(network_to_instances)),
2553
    (_MakeField("inst_list", "InstanceList", QFT_OTHER, "List of instances"),
2554
     NETQ_INST, 0, _GetSortedList(network_to_instances)),
2555
    ])
2556

  
2557
  # Add fields for usage statistics
2558
  fields.extend([
2559
    (_MakeField(name, title, kind, doc), NETQ_STATS, 0,
2560
    compat.partial(_GetNetworkStatsField, name, kind))
2561
    for (name, (title, kind, flags, doc)) in _NETWORK_STATS_FIELDS.items()
2562
    ])
2563

  
2564
  return _PrepareFieldList(fields, [])
2565

  
2437 2566
#: Fields for cluster information
2438 2567
CLUSTER_FIELDS = _BuildClusterFields()
2439 2568

  
......
2458 2587
#: Fields available for exports
2459 2588
EXPORT_FIELDS = _BuildExportFields()
2460 2589

  
2590
#: Fields available for network queries
2591
NETWORK_FIELDS = _BuildNetworkFields()
2592

  
2461 2593
#: All available resources
2462 2594
ALL_FIELDS = {
2463 2595
  constants.QR_CLUSTER: CLUSTER_FIELDS,
......
2468 2600
  constants.QR_OS: OS_FIELDS,
2469 2601
  constants.QR_JOB: JOB_FIELDS,
2470 2602
  constants.QR_EXPORT: EXPORT_FIELDS,
2603
  constants.QR_NETWORK: NETWORK_FIELDS,
2471 2604
  }
2472 2605

  
2473 2606
#: All available field lists
b/lib/server/masterd.py
372 372
      op = opcodes.OpGroupQuery(names=names, output_fields=fields)
373 373
      return self._Query(op)
374 374

  
375
    elif method == luxi.REQ_QUERY_NETWORKS:
376
      (names, fields, use_locking) = args
377
      logging.info("Received network query request for %s", names)
378
      if use_locking:
379
        raise errors.OpPrereqError("Sync queries are not allowed",
380
                                   errors.ECODE_INVAL)
381
      op = opcodes.OpNetworkQuery(names=names, output_fields=fields)
382
      return self._Query(op)
383

  
375 384
    elif method == luxi.REQ_QUERY_EXPORTS:
376 385
      (nodes, use_locking) = args
377 386
      if use_locking:

Also available in: Unified diff