Fix /proc/drbd parsing in presence of gaps
[ganeti-local] / lib / cli.py
index 1bf419b..d351f2f 100644 (file)
@@ -50,8 +50,8 @@ __all__ = ["DEBUG_OPT", "NOHDR_OPT", "SEP_OPT", "GenericMain",
            "ListTags", "AddTags", "RemoveTags", "TAG_SRC_OPT",
            "FormatError", "SplitNodeOption", "SubmitOrSend",
            "JobSubmittedException", "FormatTimestamp", "ParseTimespec",
-           "ValidateBeParams", "ToStderr", "ToStdout", "UsesRPC",
-           "GetOnlineNodes", "JobExecutor",
+           "ToStderr", "ToStdout", "UsesRPC",
+           "GetOnlineNodes", "JobExecutor", "SYNC_OPT",
            ]
 
 
@@ -190,6 +190,11 @@ SUBMIT_OPT = make_option("--submit", dest="submit_only",
                          help="Submit the job and return the job ID, but"
                          " don't wait for the job to finish")
 
+SYNC_OPT = make_option("--sync", dest="do_locking",
+                       default=False, action="store_true",
+                       help="Grab locks while doing the queries"
+                       " in order to ensure more consistent results")
+
 
 def ARGS_FIXED(val):
   """Macro-like function denoting a fixed number of arguments"""
@@ -404,27 +409,6 @@ def SplitNodeOption(value):
     return (value, None)
 
 
-def ValidateBeParams(bep):
-  """Parse and check the given beparams.
-
-  The function will update in-place the given dictionary.
-
-  @type bep: dict
-  @param bep: input beparams
-  @raise errors.ParameterError: if the input values are not OK
-  @raise errors.UnitParseError: if the input values are not OK
-
-  """
-  if constants.BE_MEMORY in bep:
-    bep[constants.BE_MEMORY] = utils.ParseUnit(bep[constants.BE_MEMORY])
-
-  if constants.BE_VCPUS in bep:
-    try:
-      bep[constants.BE_VCPUS] = int(bep[constants.BE_VCPUS])
-    except ValueError:
-      raise errors.ParameterError("Invalid number of VCPUs")
-
-
 def UsesRPC(fn):
   def wrapper(*args, **kwargs):
     rpc.Init()
@@ -554,7 +538,8 @@ def PollJob(job_id, cl=None, feedback_fn=None):
         if callable(feedback_fn):
           feedback_fn(log_entry[1:])
         else:
-          print "%s %s" % (time.ctime(utils.MergeTime(timestamp)), message)
+          encoded = utils.SafeEncode(message)
+          print "%s %s" % (time.ctime(utils.MergeTime(timestamp)), encoded)
         prev_logmsg_serial = max(prev_logmsg_serial, serial)
 
     # TODO: Handle canceled and archived jobs
@@ -689,6 +674,10 @@ def FormatError(err):
   elif isinstance(err, errors.JobQueueFull):
     obuf.write("Failure: the job queue is full and doesn't accept new"
                " job submissions until old jobs are archived\n")
+  elif isinstance(err, errors.TypeEnforcementError):
+    obuf.write("Parameter Error: %s" % msg)
+  elif isinstance(err, errors.ParameterError):
+    obuf.write("Failure: unknown/wrong parameter name '%s'" % msg)
   elif isinstance(err, errors.GenericError):
     obuf.write("Unhandled Ganeti error: %s" % msg)
   elif isinstance(err, luxi.NoMasterError):
@@ -810,7 +799,7 @@ def GenerateTable(headers, fields, separator, data,
   format_fields = []
   for field in fields:
     if headers and field not in headers:
-      # FIXME: handle better unknown fields (either revert to old
+      # TODO: handle better unknown fields (either revert to old
       # style of raising exception, or deal more intelligently with
       # variable fields)
       headers[field] = field
@@ -828,6 +817,8 @@ def GenerateTable(headers, fields, separator, data,
     format = separator.replace("%", "%%").join(format_fields)
 
   for row in data:
+    if row is None:
+      continue
     for idx, val in enumerate(row):
       if unitfields.Matches(fields[idx]):
         try:
@@ -853,6 +844,8 @@ def GenerateTable(headers, fields, separator, data,
 
   for line in data:
     args = []
+    if line is None:
+      line = ['-' for _ in fields]
     for idx in xrange(len(fields)):
       if separator is None:
         args.append(mlens[idx])
@@ -869,7 +862,7 @@ def FormatTimestamp(ts):
   @param ts: a timeval-type timestamp, a tuple of seconds and microseconds
 
   @rtype: string
-  @returns: a string with the formatted timestamp
+  @return: a string with the formatted timestamp
 
   """
   if not isinstance (ts, (tuple, list)) or len(ts) != 2:
@@ -938,9 +931,8 @@ def GetOnlineNodes(nodes, cl=None, nowarn=False):
   if cl is None:
     cl = GetClient()
 
-  op = opcodes.OpQueryNodes(output_fields=["name", "offline"],
-                            names=nodes)
-  result = SubmitOpCode(op, cl=cl)
+  result = cl.QueryNodes(names=nodes, fields=["name", "offline"],
+                         use_locking=False)
   offline = [row[0] for row in result if row[1]]
   if offline and not nowarn:
     ToStderr("Note: skipping offline node(s): %s" % ", ".join(offline))