Network name and other info is filled temporarily in netinfo slot.

Export network name during instance queries.

To do so, all the info for the instance's networks must be stored in
InstanceQueryData context. Introduce new cfg method GetInstanceNetworks()
that returns all networks (uuids) of the instance's nics.

LUInstanceQueryData fills NIC data just like as hooks do so we have
all the necessary info in netinfo slot.

Locking is implemented in DeclareLocks easily because networks are locked
at the time when locks for wanted instances have been aquired.

Signed-off-by: Dimitris Aragiorgis <[email protected]>
---
 lib/backend.py             |    5 --
 lib/client/gnt_instance.py |    4 +-
 lib/cmdlib.py              |  166 ++++++++++++++++++++++++++------------------
 lib/config.py              |   51 +++++++++-----
 lib/query.py               |   49 ++++++++++++-
 5 files changed, 179 insertions(+), 96 deletions(-)

diff --git a/lib/backend.py b/lib/backend.py
index cf28d4f..569a616 100644
--- a/lib/backend.py
+++ b/lib/backend.py
@@ -2501,11 +2501,6 @@ def OSEnvironment(instance, inst_os, debug=0):
     if nic.netinfo:
       nobj = objects.Network.FromDict(nic.netinfo)
       result.update(nobj.HooksDict("NIC_%d_" % idx))
-    elif nic.network:
-      # FIXME: broken network reference: the instance NIC specifies a network,
-      # but the relevant network entry was not in the config. This should be
-      # made impossible.
-      result["INSTANCE_NIC%d_NETWORK" % idx] = nic.network
     if constants.HV_NIC_TYPE in instance.hvparams:
       result["NIC_%d_FRONTEND_TYPE" % idx] = \
         instance.hvparams[constants.HV_NIC_TYPE]
diff --git a/lib/client/gnt_instance.py b/lib/client/gnt_instance.py
index ee9bf44..f223566 100644
--- a/lib/client/gnt_instance.py
+++ b/lib/client/gnt_instance.py
@@ -1177,10 +1177,10 @@ def ShowInstanceConfig(opts, args):
     FormatParameterDict(buf, instance["be_instance"], be_actual, level=2)
     # TODO(ganeti 2.7) rework the NICs as well
     buf.write("    - NICs:\n")
-    for idx, (ip, mac, mode, link, network, _) in enumerate(instance["nics"]):
+    for idx, (ip, mac, mode, link, _, netinfo) in enumerate(instance["nics"]):
       buf.write("      - nic/%d: MAC: %s, IP: %s,"
                 " mode: %s, link: %s, network: %s\n" %
-                (idx, mac, ip, mode, link, network))
+                (idx, mac, ip, mode, link, netinfo["name"]))
     buf.write("  Disk template: %s\n" % instance["disk_template"])
     buf.write("  Disks:\n")
 
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 3637644..8ec5946 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -1557,9 +1557,8 @@ def _NICToTuple(lu, nic):
   link = filled_params[constants.NIC_LINK]
   netinfo = None
   if nic.network:
-    net_uuid = lu.cfg.LookupNetwork(nic.network)
-    netinfo = objects.Network.ToDict(lu.cfg.GetNetwork(net_uuid))
-
+    nobj = lu.cfg.GetNetwork(nic.network)
+    netinfo = objects.Network.ToDict(nobj)
   return (nic.ip, nic.mac, mode, link, nic.network, netinfo)
 
 
@@ -5752,6 +5751,7 @@ class _InstanceQuery(_QueryBase):
       lu.needed_locks[locking.LEVEL_INSTANCE] = self.wanted
       lu.needed_locks[locking.LEVEL_NODEGROUP] = []
       lu.needed_locks[locking.LEVEL_NODE] = []
+      lu.needed_locks[locking.LEVEL_NETWORK] = []
       lu.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
 
     self.do_grouplocks = (self.do_locking and
@@ -5771,6 +5771,12 @@ class _InstanceQuery(_QueryBase):
       elif level == locking.LEVEL_NODE:
         lu._LockInstancesNodes() # pylint: disable=W0212
 
+      elif level == locking.LEVEL_NETWORK:
+        lu.needed_locks[locking.LEVEL_NETWORK] = \
+          frozenset(net_uuid
+                    for instance_name in lu.owned_locks(locking.LEVEL_INSTANCE)
+                    for net_uuid in lu.cfg.GetInstanceNetworks(instance_name))
+
   @staticmethod
   def _CheckGroupLocks(lu):
     owned_instances = frozenset(lu.owned_locks(locking.LEVEL_INSTANCE))
@@ -5861,10 +5867,17 @@ class _InstanceQuery(_QueryBase):
       nodes = None
       groups = None
 
+    if query.IQ_NETWORKS in self.requested_data:
+      net_uuids = itertools.chain(*(lu.cfg.GetInstanceNetworks(i.name)
+                                    for i in instance_list))
+      networks = dict((uuid, lu.cfg.GetNetwork(uuid)) for uuid in net_uuids)
+    else:
+      networks = None
+
     return query.InstanceQueryData(instance_list, lu.cfg.GetClusterInfo(),
                                    disk_usage, offline_nodes, bad_nodes,
                                    live_data, wrongnode_inst, consinfo,
-                                   nodes, groups)
+                                   nodes, groups, networks)
 
 
 class LUQuery(NoHooksLU):
@@ -9950,8 +9963,9 @@ def _ComputeNics(op, cluster, default_ip, cfg, ec_id):
 
     check_params = cluster.SimpleFillNIC(nicparams)
     objects.NIC.CheckParameterSyntax(check_params)
+    net_uuid = cfg.LookupNetwork(net)
     nics.append(objects.NIC(mac=mac, ip=nic_ip,
-                            network=net, nicparams=nicparams))
+                            network=net_uuid, nicparams=nicparams))
 
   return nics
 
@@ -10687,14 +10701,15 @@ class LUInstanceCreate(LogicalUnit):
     # Fill in any IPs from IP pools. This must happen here, because we need to
     # know the nic's primary node, as specified by the iallocator
     for idx, nic in enumerate(self.nics):
-      net = nic.network
-      if net is not None:
-        netparams = self.cfg.GetGroupNetParams(net, self.pnode.name)
+      net_uuid = nic.network
+      if net_uuid is not None:
+        nobj = self.cfg.GetNetwork(net_uuid)
+        netparams = self.cfg.GetGroupNetParams(net_uuid, self.pnode.name)
         if netparams is None:
           raise errors.OpPrereqError("No netparams found for network"
                                      " %s. Propably not connected to"
                                      " node's %s nodegroup" %
-                                     (net, self.pnode.name),
+                                     (nobj.name, self.pnode.name),
                                      errors.ECODE_INVAL)
         self.LogInfo("NIC/%d inherits netparams %s" %
                      (idx, netparams.values()))
@@ -10702,19 +10717,19 @@ class LUInstanceCreate(LogicalUnit):
         if nic.ip is not None:
           if nic.ip.lower() == constants.NIC_IP_POOL:
             try:
-              nic.ip = self.cfg.GenerateIp(net, self.proc.GetECId())
+              nic.ip = self.cfg.GenerateIp(net_uuid, self.proc.GetECId())
             except errors.ReservationError:
               raise errors.OpPrereqError("Unable to get a free IP for NIC %d"
                                          " from the address pool" % idx,
                                          errors.ECODE_STATE)
-            self.LogInfo("Chose IP %s from network %s", nic.ip, net)
+            self.LogInfo("Chose IP %s from network %s", nic.ip, nobj.name)
           else:
             try:
-              self.cfg.ReserveIp(net, nic.ip, self.proc.GetECId())
+              self.cfg.ReserveIp(net_uuid, nic.ip, self.proc.GetECId())
             except errors.ReservationError:
               raise errors.OpPrereqError("IP address %s already in use"
                                          " or does not belong to network %s" %
-                                         (nic.ip, net),
+                                         (nic.ip, nobj.name),
                                          errors.ECODE_NOTUNIQUE)
 
       # net is None, ip None or given
@@ -12815,12 +12830,13 @@ class LUInstanceQueryData(NoHooksLU):
 
       self.needed_locks[locking.LEVEL_NODEGROUP] = []
       self.needed_locks[locking.LEVEL_NODE] = []
+      self.needed_locks[locking.LEVEL_NETWORK] = []
       self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
 
   def DeclareLocks(self, level):
     if self.op.use_locking:
+      owned_instances = self.owned_locks(locking.LEVEL_INSTANCE)
       if level == locking.LEVEL_NODEGROUP:
-        owned_instances = self.owned_locks(locking.LEVEL_INSTANCE)
 
         # Lock all groups used by instances optimistically; this requires going
         # via the node before it's locked, requiring verification later on
@@ -12833,6 +12849,13 @@ class LUInstanceQueryData(NoHooksLU):
       elif level == locking.LEVEL_NODE:
         self._LockInstancesNodes()
 
+      elif level == locking.LEVEL_NETWORK:
+        self.needed_locks[locking.LEVEL_NETWORK] = \
+          frozenset(net_uuid
+                    for instance_name in owned_instances
+                    for net_uuid in
+                       self.cfg.GetInstanceNetworks(instance_name))
+
   def CheckPrereq(self):
     """Check prerequisites.
 
@@ -12842,6 +12865,7 @@ class LUInstanceQueryData(NoHooksLU):
     owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE))
     owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP))
     owned_nodes = frozenset(self.owned_locks(locking.LEVEL_NODE))
+    owned_networks = frozenset(self.owned_locks(locking.LEVEL_NETWORK))
 
     if self.wanted_names is None:
       assert self.op.use_locking, "Locking was not used"
@@ -12853,7 +12877,8 @@ class LUInstanceQueryData(NoHooksLU):
       _CheckInstancesNodeGroups(self.cfg, instances, owned_groups, owned_nodes,
                                 None)
     else:
-      assert not (owned_instances or owned_groups or owned_nodes)
+      assert not (owned_instances or owned_groups or
+                  owned_nodes or owned_networks)
 
     self.wanted_instances = instances.values()
 
@@ -12937,7 +12962,6 @@ class LUInstanceQueryData(NoHooksLU):
                                                  for node in nodes.values()))
 
     group2name_fn = lambda uuid: groups[uuid].name
-
     for instance in self.wanted_instances:
       pnode = nodes[instance.primary_node]
 
@@ -13381,7 +13405,7 @@ class LUInstanceSetParams(LogicalUnit):
     nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes)
     return (nl, nl)
 
-  def _PrepareNicModification(self, params, private, old_ip, old_net,
+  def _PrepareNicModification(self, params, private, old_ip, old_net_uuid,
                               old_params, cluster, pnode):
 
     update_params_dict = dict([(key, params[key])
@@ -13391,13 +13415,21 @@ class LUInstanceSetParams(LogicalUnit):
     req_link = update_params_dict.get(constants.NIC_LINK, None)
     req_mode = update_params_dict.get(constants.NIC_MODE, None)
 
-    new_net = params.get(constants.INIC_NETWORK, old_net)
-    if new_net is not None:
-      netparams = self.cfg.GetGroupNetParams(new_net, pnode)
-      if netparams is None:
+    new_net_uuid = None
+    new_net_uuid_or_name = params.get(constants.INIC_NETWORK, old_net_uuid)
+    if new_net_uuid_or_name:
+      new_net_uuid = self.cfg.LookupNetwork(new_net_uuid_or_name)
+      new_net_obj = self.cfg.GetNetwork(new_net_uuid)
+
+    if old_net_uuid:
+      old_net_obj = self.cfg.GetNetwork(old_net_uuid)
+
+    if new_net_uuid:
+      netparams = self.cfg.GetGroupNetParams(new_net_uuid, pnode)
+      if not netparams:
         raise errors.OpPrereqError("No netparams found for the network"
-                                   " %s, probably not connected" % new_net,
-                                   errors.ECODE_INVAL)
+                                   " %s, probably not connected" %
+                                   new_net_obj.name, errors.ECODE_INVAL)
       new_params = dict(netparams)
     else:
       new_params = _GetUpdatedParams(old_params, update_params_dict)
@@ -13436,7 +13468,7 @@ class LUInstanceSetParams(LogicalUnit):
       elif mac in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
         # otherwise generate the MAC address
         params[constants.INIC_MAC] = \
-          self.cfg.GenerateMAC(new_net, self.proc.GetECId())
+          self.cfg.GenerateMAC(new_net_uuid, self.proc.GetECId())
       else:
         # or validate/reserve the current one
         try:
@@ -13445,61 +13477,61 @@ class LUInstanceSetParams(LogicalUnit):
           raise errors.OpPrereqError("MAC address '%s' already in use"
                                      " in cluster" % mac,
                                      errors.ECODE_NOTUNIQUE)
-    elif new_net != old_net:
+    elif new_net_uuid != old_net_uuid:
 
-      def get_net_prefix(net):
+      def get_net_prefix(net_uuid):
         mac_prefix = None
-        if net:
-          uuid = self.cfg.LookupNetwork(net)
-          mac_prefix = self.cfg.GetNetwork(uuid).mac_prefix
+        if net_uuid:
+          nobj = self.cfg.GetNetwork(net_uuid)
+          mac_prefix = nobj.mac_prefix
 
         return mac_prefix
 
-      new_prefix = get_net_prefix(new_net)
-      old_prefix = get_net_prefix(old_net)
+      new_prefix = get_net_prefix(new_net_uuid)
+      old_prefix = get_net_prefix(old_net_uuid)
       if old_prefix != new_prefix:
         params[constants.INIC_MAC] = \
-          self.cfg.GenerateMAC(new_net, self.proc.GetECId())
+          self.cfg.GenerateMAC(new_net_uuid, self.proc.GetECId())
 
-    #if there is a change in nic-network configuration
+    #if there is a change in nic's ip/network configuration
     new_ip = params.get(constants.INIC_IP, old_ip)
-    if (new_ip, new_net) != (old_ip, old_net):
+    if (new_ip, new_net_uuid) != (old_ip, old_net_uuid):
       if new_ip:
-        if new_net:
-          if new_ip.lower() == constants.NIC_IP_POOL:
-            try:
-              new_ip = self.cfg.GenerateIp(new_net, self.proc.GetECId())
-            except errors.ReservationError:
-              raise errors.OpPrereqError("Unable to get a free IP"
-                                         " from the address pool",
-                                         errors.ECODE_STATE)
-            self.LogInfo("Chose IP %s from pool %s", new_ip, new_net)
-            params[constants.INIC_IP] = new_ip
-          elif new_ip != old_ip or new_net != old_net:
-            try:
-              self.LogInfo("Reserving IP %s in pool %s", new_ip, new_net)
-              self.cfg.ReserveIp(new_net, new_ip, self.proc.GetECId())
-            except errors.ReservationError:
-              raise errors.OpPrereqError("IP %s not available in network %s" %
-                                         (new_ip, new_net),
-                                         errors.ECODE_NOTUNIQUE)
-        elif new_ip.lower() == constants.NIC_IP_POOL:
-          raise errors.OpPrereqError("ip=pool, but no network found",
-                                     errors.ECODE_INVAL)
+        if new_ip.lower() == constants.NIC_IP_POOL:
+          if not new_net_uuid:
+            raise errors.OpPrereqError("ip=pool, but no network found",
+                                       errors.ECODE_INVAL)
+          try:
+            new_ip = self.cfg.GenerateIp(new_net_uuid, self.proc.GetECId())
+          except errors.ReservationError:
+            raise errors.OpPrereqError("Unable to get a free IP"
+                                       " from the address pool",
+                                       errors.ECODE_STATE)
+          self.LogInfo("Chose IP %s from network %s", new_ip, new_net_obj.name)
+          params[constants.INIC_IP] = new_ip
+        elif new_ip != old_ip or new_net_uuid != old_net_uuid:
+          try:
+            self.cfg.ReserveIp(new_net_uuid, new_ip, self.proc.GetECId())
+            self.LogInfo("Reserving IP %s in network %s",
+                         new_ip, new_net_obj.name)
+          except errors.ReservationError:
+            raise errors.OpPrereqError("IP %s not available in network %s" %
+                                       (new_ip, new_net_obj.name),
+                                       errors.ECODE_NOTUNIQUE)
 
         # new net is None
-        elif self.op.conflicts_check:
+        elif not new_net_uuid and self.op.conflicts_check:
           _CheckForConflictingIp(self, new_ip, pnode)
 
-      if old_ip and old_net:
+      if old_ip:
         try:
-          self.cfg.ReleaseIp(old_net, old_ip, self.proc.GetECId())
-        except errors.AddressPoolError, err:
-          logging.warning("Releasing IP address '%s' from network '%s'"
-                          " failed: %s", old_ip, old_net, err)
+          self.cfg.ReleaseIp(old_net_uuid, old_ip, self.proc.GetECId())
+        except errors.AddressPoolError:
+          logging.warning("Release IP %s not contained in network %s",
+                          old_ip, old_net_obj.name)
 
     # there are no changes in (net, ip) tuple
-    elif (old_net is not None and
+    elif (old_net_uuid is not None and
           (req_link is not None or req_mode is not None)):
       raise errors.OpPrereqError("Not allowed to change link or mode of"
                                  " a NIC that is connected to a network",
@@ -16534,8 +16566,6 @@ class _NetworkQuery(_QueryBase):
     network_uuids = self._GetNames(lu, all_networks.keys(),
                                    locking.LEVEL_NETWORK)
 
-    name_to_uuid = dict((n.name, n.uuid) for n in all_networks.values())
-
     do_instances = query.NETQ_INST in self.requested_data
     do_groups = query.NETQ_GROUP in self.requested_data
 
@@ -16560,10 +16590,8 @@ class _NetworkQuery(_QueryBase):
       network_to_instances = dict((uuid, []) for uuid in network_uuids)
       for instance in all_instances.values():
         for nic in instance.nics:
-          if nic.network:
-            net_uuid = name_to_uuid[nic.network]
-            if net_uuid in network_uuids:
-              network_to_instances[net_uuid].append(instance.name)
+          if nic.network in network_uuids:
+            network_to_instances[nic.network].append(instance.name)
             break
 
     if query.NETQ_STATS in self.requested_data:
@@ -16795,7 +16823,7 @@ class LUNetworkDisconnect(LogicalUnit):
       self.connected = False
       return
 
-    _NetworkConflictCheck(self, lambda nic: nic.network == self.network_name,
+    _NetworkConflictCheck(self, lambda nic: nic.network == self.network_uuid,
                           "disconnect from")
 
   def Exec(self, feedback_fn):
diff --git a/lib/config.py b/lib/config.py
index 4f8c36d..3b20177 100644
--- a/lib/config.py
+++ b/lib/config.py
@@ -270,13 +270,12 @@ class ConfigWriter:
     """
     return self._config_data.cluster.SimpleFillDP(group.diskparams)
 
-  def _UnlockedGetNetworkMACPrefix(self, net):
+  def _UnlockedGetNetworkMACPrefix(self, net_uuid):
     """Return the network mac prefix if it exists or the cluster level default.
 
     """
     prefix = None
-    if net:
-      net_uuid = self._UnlockedLookupNetwork(net)
+    if net_uuid:
       nobj = self._UnlockedGetNetwork(net_uuid)
       if nobj.mac_prefix:
         prefix = nobj.mac_prefix
@@ -302,14 +301,14 @@ class ConfigWriter:
     return GenMac
 
   @locking.ssynchronized(_config_lock, shared=1)
-  def GenerateMAC(self, net, ec_id):
+  def GenerateMAC(self, net_uuid, ec_id):
     """Generate a MAC for an instance.
 
     This should check the current instances for duplicates.
 
     """
     existing = self._AllMACs()
-    prefix = self._UnlockedGetNetworkMACPrefix(net)
+    prefix = self._UnlockedGetNetworkMACPrefix(net_uuid)
     gen_mac = self._GenerateOneMAC(prefix)
     return self._temporary_ids.Generate(existing, gen_mac, ec_id)
 
@@ -358,21 +357,20 @@ class ConfigWriter:
                                 (constants.RELEASE_ACTION, address, net_uuid))
 
   @locking.ssynchronized(_config_lock, shared=1)
-  def ReleaseIp(self, net, address, ec_id):
+  def ReleaseIp(self, net_uuid, address, ec_id):
     """Give a specified IP address back to an IP pool.
 
     This is just a wrapper around _UnlockedReleaseIp.
 
     """
-    net_uuid = self._UnlockedLookupNetwork(net)
-    self._UnlockedReleaseIp(net_uuid, address, ec_id)
+    if net_uuid:
+      self._UnlockedReleaseIp(net_uuid, address, ec_id)
 
   @locking.ssynchronized(_config_lock, shared=1)
-  def GenerateIp(self, net, ec_id):
+  def GenerateIp(self, net_uuid, ec_id):
     """Find a free IPv4 address for an instance.
 
     """
-    net_uuid = self._UnlockedLookupNetwork(net)
     nobj = self._UnlockedGetNetwork(net_uuid)
     pool = network.AddressPool(nobj)
 
@@ -404,12 +402,12 @@ class ConfigWriter:
                                         address, net_uuid))
 
   @locking.ssynchronized(_config_lock, shared=1)
-  def ReserveIp(self, net, address, ec_id):
+  def ReserveIp(self, net_uuid, address, ec_id):
     """Reserve a given IPv4 address for use by an instance.
 
     """
-    net_uuid = self._UnlockedLookupNetwork(net)
-    return self._UnlockedReserveIp(net_uuid, address, ec_id)
+    if net_uuid:
+      return self._UnlockedReserveIp(net_uuid, address, ec_id)
 
   @locking.ssynchronized(_config_lock, shared=1)
   def ReserveLV(self, lv_name, ec_id):
@@ -1574,6 +1572,24 @@ class ConfigWriter:
                      for node_name in nodes)
 
   @locking.ssynchronized(_config_lock, shared=1)
+  def GetInstanceNetworks(self, instance_name):
+    """Returns set of network UUIDs for instance's nics.
+
+    @rtype: frozenset
+
+    """
+    instance = self._UnlockedGetInstanceInfo(instance_name)
+    if not instance:
+      raise errors.ConfigurationError("Unknown instance '%s'" % instance_name)
+
+    networks = set()
+    for nic in instance.nics:
+      if nic.network:
+        networks.add(nic.network)
+
+    return frozenset(networks)
+
+  @locking.ssynchronized(_config_lock, shared=1)
   def GetMultiInstanceInfo(self, instances):
     """Get the configuration of multiple instances.
 
@@ -2526,20 +2542,19 @@ class ConfigWriter:
     self._config_data.cluster.serial_no += 1
     self._WriteConfig()
 
-  def _UnlockedGetGroupNetParams(self, net, node):
+  def _UnlockedGetGroupNetParams(self, net_uuid, node):
     """Get the netparams (mode, link) of a network.
 
     Get a network's netparams for a given node.
 
     @type net: string
-    @param net: network name
+    @param net: network uuid
     @type node: string
     @param node: node name
     @rtype: dict or None
     @return: netparams
 
     """
-    net_uuid = self._UnlockedLookupNetwork(net)
     node_info = self._UnlockedGetNodeInfo(node)
     nodegroup_info = self._UnlockedGetNodeGroup(node_info.group)
     netparams = nodegroup_info.networks.get(net_uuid, None)
@@ -2547,11 +2562,11 @@ class ConfigWriter:
     return netparams
 
   @locking.ssynchronized(_config_lock, shared=1)
-  def GetGroupNetParams(self, net, node):
+  def GetGroupNetParams(self, net_uuid, node):
     """Locking wrapper of _UnlockedGetGroupNetParams()
 
     """
-    return self._UnlockedGetGroupNetParams(net, node)
+    return self._UnlockedGetGroupNetParams(net_uuid, node)
 
   @locking.ssynchronized(_config_lock, shared=1)
   def CheckIPInNodeGroup(self, ip, node):
diff --git a/lib/query.py b/lib/query.py
index ef52d08..a9e0274 100644
--- a/lib/query.py
+++ b/lib/query.py
@@ -90,7 +90,8 @@ from ganeti.constants import (QFT_UNKNOWN, QFT_TEXT, 
QFT_BOOL, QFT_NUMBER,
  IQ_LIVE,
  IQ_DISKUSAGE,
  IQ_CONSOLE,
- IQ_NODES) = range(100, 105)
+ IQ_NODES,
+ IQ_NETWORKS) = range(100, 106)
 
 (LQ_MODE,
  LQ_OWNER,
@@ -1383,7 +1384,7 @@ class InstanceQueryData:
 
   """
   def __init__(self, instances, cluster, disk_usage, offline_nodes, bad_nodes,
-               live_data, wrongnode_inst, console, nodes, groups):
+               live_data, wrongnode_inst, console, nodes, groups, networks):
     """Initializes this class.
 
     @param instances: List of instance objects
@@ -1402,6 +1403,8 @@ class InstanceQueryData:
     @param console: Per-instance console information
     @type nodes: dict; node name as key
     @param nodes: Node objects
+    @type networks: dict; net_uuid as key
+    @param networks: Network objects
 
     """
     assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
@@ -1419,6 +1422,7 @@ class InstanceQueryData:
     self.console = console
     self.nodes = nodes
     self.groups = groups
+    self.networks = networks
 
     # Used for individual rows
     self.inst_hvparams = None
@@ -1569,6 +1573,20 @@ def _GetInstNic(index, cb):
   return fn
 
 
+def _GetInstNicNetworkName(ctx, _, nic): # pylint: disable=W0613
+  """Get a NIC's Network.
+
+  @type ctx: L{InstanceQueryData}
+  @type nic: L{objects.NIC}
+  @param nic: NIC object
+
+  """
+  if nic.network is None:
+    return _FS_UNAVAIL
+  else:
+    return ctx.networks[nic.network].name
+
+
 def _GetInstNicNetwork(ctx, _, nic): # pylint: disable=W0613
   """Get a NIC's Network.
 
@@ -1615,6 +1633,27 @@ def _GetInstNicBridge(ctx, index, _):
     return _FS_UNAVAIL
 
 
+def _GetInstAllNicNetworkNames(ctx, inst):
+  """Get all network names for an instance.
+
+  @type ctx: L{InstanceQueryData}
+  @type inst: L{objects.Instance}
+  @param inst: Instance object
+
+  """
+  result = []
+
+  for nic in inst.nics:
+    name = None
+    if nic.network:
+      name = ctx.networks[nic.network].name
+    result.append(name)
+
+  assert len(result) == len(inst.nics)
+
+  return result
+
+
 def _GetInstAllNicBridges(ctx, inst):
   """Get all network bridges for an instance.
 
@@ -1697,6 +1736,9 @@ def _GetInstanceNetworkFields():
     (_MakeField("nic.networks", "NIC_networks", QFT_OTHER,
                 "List containing each interface's network"), IQ_CONFIG, 0,
      lambda ctx, inst: [nic.network for nic in inst.nics]),
+    (_MakeField("nic.networks.names", "NIC_networks_names", QFT_OTHER,
+                "List containing each interface's network"),
+     IQ_NETWORKS, 0, _GetInstAllNicNetworkNames)
     ]
 
   # NICs by number
@@ -1721,6 +1763,9 @@ def _GetInstanceNetworkFields():
       (_MakeField("nic.network/%s" % i, "NicNetwork/%s" % i, QFT_TEXT,
                   "Network of %s network interface" % numtext),
        IQ_CONFIG, 0, _GetInstNic(i, _GetInstNicNetwork)),
+      (_MakeField("nic.network.name/%s" % i, "NicNetworkName/%s" % i, QFT_TEXT,
+                  "Network name of %s network interface" % numtext),
+       IQ_NETWORKS, 0, _GetInstNic(i, _GetInstNicNetworkName)),
       ])
 
   aliases = [
-- 
1.7.10.4

Reply via email to