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