diff --git a/lib/cli.py b/lib/cli.py
index b95b6ae07901b03e1bfdb29b7b778b39a5685dbb..d19ca986e97f6f45bfbd09d628b13a4c9ca0b195 100644
--- a/lib/cli.py
+++ b/lib/cli.py
@@ -755,8 +755,10 @@ def GenerateTable(headers, fields, separator, data,
   format_fields = []
   for field in fields:
     if headers and field not in headers:
-      raise errors.ProgrammerError("Missing header description for field '%s'"
-                                   % field)
+      # FIXME: handle better unknown fields (either revert to old
+      # style of raising exception, or deal more intelligently with
+      # variable fields)
+      headers[field] = field
     if separator is not None:
       format_fields.append("%s")
     elif field in numfields:
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 289e4c8b9c26da1a5ee88ee316560a6fca4a2c55..ee7af81eaca7d826fd84b8f85cb18c27fdd76579 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -2719,6 +2719,9 @@ class LUQueryInstances(NoHooksLU):
                                "disk_template", "ip", "mac", "bridge",
                                "sda_size", "sdb_size", "vcpus", "tags",
                                "network_port", "beparams",
+                               "(disk).(size)/([0-9]+)",
+                               "(nic).(mac|ip|bridge)/([0-9]+)",
+                               "(disk|nic).(count)",
                                "serial_no", "hypervisor", "hvparams",] +
                              ["hv/%s" % name
                               for name in constants.HVS_PARAMETERS] +
@@ -2806,6 +2809,7 @@ class LUQueryInstances(NoHooksLU):
       i_hv = self.cfg.GetClusterInfo().FillHV(instance)
       i_be = self.cfg.GetClusterInfo().FillBE(instance)
       for field in self.op.output_fields:
+        st_match = self._FIELDS_STATIC.Matches(field)
         if field == "name":
           val = instance.name
         elif field == "os":
@@ -2875,6 +2879,39 @@ class LUQueryInstances(NoHooksLU):
         elif (field.startswith(BEPREFIX) and
               field[len(BEPREFIX):] in constants.BES_PARAMETERS):
           val = i_be.get(field[len(BEPREFIX):], None)
+        elif st_match and st_match.groups():
+          # matches a variable list
+          st_groups = st_match.groups()
+          if st_groups and st_groups[0] == "disk":
+            if st_groups[1] == "count":
+              val = len(instance.disks)
+            elif st_groups[1] == "size":
+              disk_idx = int(st_groups[2])
+              if disk_idx >= len(instance.disks):
+                val = None
+              else:
+                val = instance.disks[disk_idx].size
+            else:
+              assert False, "Unhandled disk parameter"
+          elif st_groups[0] == "nic":
+            if st_groups[1] == "count":
+              val = len(instance.nics)
+            else:
+              # index-based item
+              nic_idx = int(st_groups[2])
+              if nic_idx >= len(instance.nics):
+                val = None
+              else:
+                if st_groups[1] == "mac":
+                  val = instance.nics[nic_idx].mac
+                elif st_groups[1] == "ip":
+                  val = instance.nics[nic_idx].ip
+                elif st_groups[1] == "bridge":
+                  val = instance.nics[nic_idx].bridge
+                else:
+                  assert False, "Unhandled NIC parameter"
+          else:
+            assert False, "Unhandled variable parameter"
         else:
           raise errors.ParameterError(field)
         iout.append(val)