Make 'gnt-node list-storage' use default storage type
authorHelga Velroyen <helgav@google.com>
Thu, 10 Oct 2013 12:40:23 +0000 (14:40 +0200)
committerHelga Velroyen <helgav@google.com>
Tue, 15 Oct 2013 11:13:46 +0000 (13:13 +0200)
Currently, when no explicit storage type is given, the
'gnt-node list-storage' command defaults to file storage
whether or not file storage is enabled on the cluster
or not. This patch fixes it by defaulting to the default
storage type (which is the storage type of the default
disk template). If this storage type does not support
space reporting, an error message is emitted.

Signed-off-by: Helga Velroyen <helgav@google.com>
Reviewed-by: Klaus Aehlig <aehlig@google.com>

NEWS
lib/client/gnt_node.py
lib/cmdlib/node.py
src/Ganeti/OpCodes.hs
src/Ganeti/OpParams.hs
test/py/ganeti.rapi.rlib2_unittest.py

diff --git a/NEWS b/NEWS
index 7bc53c8..ca84870 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -19,6 +19,8 @@ Incompatible/important changes
   when allocating space for a file/sharedfile instance.
 - When disabling disk templates cluster-wide, the cluster now first
   checks whether there are instances still using those templates.
+- 'gnt-node list-storage' now also reports storage information about
+  file-based storage types.
 
 New features
 ~~~~~~~~~~~~
index 516eef9..fbfab30 100644 (file)
@@ -817,16 +817,10 @@ def ListStorage(opts, args):
   @return: the desired exit code
 
   """
-  # TODO: Default to ST_FILE if LVM is disabled on the cluster
-  if opts.user_storage_type is None:
-    opts.user_storage_type = constants.ST_LVM_PV
-
-  storage_type = ConvertStorageType(opts.user_storage_type)
-
   selected_fields = ParseFields(opts.output, _LIST_STOR_DEF_FIELDS)
 
   op = opcodes.OpNodeQueryStorage(nodes=args,
-                                  storage_type=storage_type,
+                                  storage_type=opts.user_storage_type,
                                   output_fields=selected_fields)
   output = SubmitOpCode(op, opts=opts)
 
index d16fb8c..89155ac 100644 (file)
@@ -1396,16 +1396,41 @@ class LUNodeQueryStorage(NoHooksLU):
         locking.LEVEL_NODE_ALLOC: locking.ALL_SET,
         }
 
+  def _DetermineStorageType(self):
+    """Determines the default storage type of the cluster.
+
+    """
+    enabled_disk_templates = self.cfg.GetClusterInfo().enabled_disk_templates
+    default_storage_type = \
+        constants.MAP_DISK_TEMPLATE_STORAGE_TYPE[enabled_disk_templates[0]]
+    return default_storage_type
+
   def CheckPrereq(self):
     """Check prerequisites.
 
     """
-    CheckStorageTypeEnabled(self.cfg.GetClusterInfo(), self.op.storage_type)
+    if self.op.storage_type:
+      CheckStorageTypeEnabled(self.cfg.GetClusterInfo(), self.op.storage_type)
+      self.storage_type = self.op.storage_type
+    else:
+      self.storage_type = self._DetermineStorageType()
+      if self.storage_type not in constants.STS_REPORT:
+        raise errors.OpPrereqError(
+            "Storage reporting for storage type '%s' is not supported. Please"
+            " use the --storage-type option to specify one of the supported"
+            " storage types (%s) or set the default disk template to one that"
+            " supports storage reporting." %
+            (self.storage_type, utils.CommaJoin(constants.STS_REPORT)))
 
   def Exec(self, feedback_fn):
     """Computes the list of nodes and their attributes.
 
     """
+    if self.op.storage_type:
+      self.storage_type = self.op.storage_type
+    else:
+      self.storage_type = self._DetermineStorageType()
+
     self.node_uuids = self.owned_locks(locking.LEVEL_NODE)
 
     # Always get name to sort by
@@ -1422,9 +1447,9 @@ class LUNodeQueryStorage(NoHooksLU):
     field_idx = dict([(name, idx) for (idx, name) in enumerate(fields)])
     name_idx = field_idx[constants.SF_NAME]
 
-    st_args = _GetStorageTypeArgs(self.cfg, self.op.storage_type)
+    st_args = _GetStorageTypeArgs(self.cfg, self.storage_type)
     data = self.rpc.call_storage_list(self.node_uuids,
-                                      self.op.storage_type, st_args,
+                                      self.storage_type, st_args,
                                       self.op.name, fields)
 
     result = []
@@ -1452,7 +1477,7 @@ class LUNodeQueryStorage(NoHooksLU):
           if field == constants.SF_NODE:
             val = node_name
           elif field == constants.SF_TYPE:
-            val = self.op.storage_type
+            val = self.storage_type
           elif field in field_idx:
             val = row[field_idx[field]]
           else:
index aea41c0..b70c658 100644 (file)
@@ -332,7 +332,7 @@ $(genOpCode "OpCode"
      [t| [[JSValue]] |],
      OpDoc.opNodeQueryStorage,
      [ pOutputFields
-     , pStorageType
+     , pStorageTypeOptional
      , withDoc
        "Empty list to query all, list of names to query otherwise"
        pNodes
index 1b70794..9144aa4 100644 (file)
@@ -150,6 +150,7 @@ module Ganeti.OpParams
   , pRequiredNodes
   , pRequiredNodeUuids
   , pStorageType
+  , pStorageTypeOptional
   , pStorageChanges
   , pMasterCandidate
   , pOffline
@@ -834,8 +835,13 @@ pNodes =
 
 pStorageType :: Field
 pStorageType =
-  withDoc "Storage type" $
-  simpleField "storage_type" [t| StorageType |]
+  withDoc "Storage type" $ simpleField "storage_type" [t| StorageType |]
+
+pStorageTypeOptional :: Field
+pStorageTypeOptional =
+  withDoc "Storage type" .
+  renameField "StorageTypeOptional" .
+  optionalField $ simpleField "storage_type" [t| StorageType |]
 
 pStorageName :: Field
 pStorageName =
index 2e8e987..0109f02 100755 (executable)
@@ -630,11 +630,12 @@ class TestStorageQuery(unittest.TestCase):
   def testErrors(self):
     clfactory = _FakeClientFactory(_FakeClient)
 
+    # storage type which does not support space reporting
     queryargs = {
-      "output_fields": "name,other",
+      "storage_type": constants.ST_DISKLESS,
       }
     handler = _CreateHandler(rlib2.R_2_nodes_name_storage,
-                             ["node10538"], queryargs, {}, clfactory)
+                             ["node21273"], queryargs, {}, clfactory)
     self.assertRaises(http.HttpBadRequest, handler.GET)
 
     queryargs = {