rpc._RpcClientBase: Add check for number of arguments
[ganeti-local] / lib / utils / __init__.py
index d808ce4..9f7cb24 100644 (file)
@@ -26,52 +26,40 @@ the command line scripts.
 
 """
 
+# Allow wildcard import in pylint: disable=W0401
 
 import os
-import sys
-import time
-import subprocess
 import re
-import socket
-import tempfile
-import shutil
 import errno
 import pwd
+import time
 import itertools
 import select
-import fcntl
-import resource
 import logging
 import signal
-import datetime
-import calendar
-
-from cStringIO import StringIO
 
 from ganeti import errors
 from ganeti import constants
 from ganeti import compat
 
-from ganeti.utils.algo import * # pylint: disable-msg=W0401
-from ganeti.utils.retry import * # pylint: disable-msg=W0401
-from ganeti.utils.text import * # pylint: disable-msg=W0401
-from ganeti.utils.mlock import * # pylint: disable-msg=W0401
-from ganeti.utils.log import * # pylint: disable-msg=W0401
-from ganeti.utils.hash import * # pylint: disable-msg=W0401
-from ganeti.utils.wrapper import * # pylint: disable-msg=W0401
-from ganeti.utils.filelock import * # pylint: disable-msg=W0401
-from ganeti.utils.io import * # pylint: disable-msg=W0401
-from ganeti.utils.x509 import * # pylint: disable-msg=W0401
-from ganeti.utils.nodesetup import * # pylint: disable-msg=W0401
-from ganeti.utils.process import * # pylint: disable-msg=W0401
-
+from ganeti.utils.algo import *
+from ganeti.utils.filelock import *
+from ganeti.utils.hash import *
+from ganeti.utils.io import *
+from ganeti.utils.log import *
+from ganeti.utils.mlock import *
+from ganeti.utils.nodesetup import *
+from ganeti.utils.process import *
+from ganeti.utils.retry import *
+from ganeti.utils.text import *
+from ganeti.utils.wrapper import *
+from ganeti.utils.x509 import *
 
-_RANDOM_UUID_FILE = "/proc/sys/kernel/random/uuid"
 
 _VALID_SERVICE_NAME_RE = re.compile("^[-_.a-zA-Z0-9]{1,128}$")
 
-UUID_RE = re.compile('^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-'
-                     '[a-f0-9]{4}-[a-f0-9]{12}$')
+UUID_RE = re.compile("^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-"
+                     "[a-f0-9]{4}-[a-f0-9]{12}$")
 
 
 def ForceDictType(target, key_types, allowed_values=None):
@@ -95,7 +83,7 @@ def ForceDictType(target, key_types, allowed_values=None):
 
   for key in target:
     if key not in key_types:
-      msg = "Unknown key '%s'" % key
+      msg = "Unknown parameter '%s'" % key
       raise errors.TypeEnforcementError(msg)
 
     if target[key] in allowed_values:
@@ -111,7 +99,7 @@ def ForceDictType(target, key_types, allowed_values=None):
         pass
       elif not isinstance(target[key], basestring):
         if isinstance(target[key], bool) and not target[key]:
-          target[key] = ''
+          target[key] = ""
         else:
           msg = "'%s' (value %s) is not a valid string" % (key, target[key])
           raise errors.TypeEnforcementError(msg)
@@ -268,6 +256,32 @@ def ParseCpuMask(cpu_mask):
   return cpu_list
 
 
+def ParseMultiCpuMask(cpu_mask):
+  """Parse a multiple CPU mask definition and return the list of CPU IDs.
+
+  CPU mask format: colon-separated list of comma-separated list of CPU IDs
+  or dash-separated ID ranges, with optional "all" as CPU value
+  Example: "0-2,5:all:1,5,6:2" -> [ [ 0,1,2,5 ], [ -1 ], [ 1, 5, 6 ], [ 2 ] ]
+
+  @type cpu_mask: str
+  @param cpu_mask: multiple CPU mask definition
+  @rtype: list of lists of int
+  @return: list of lists of CPU IDs
+
+  """
+  if not cpu_mask:
+    return []
+  cpu_list = []
+  for range_def in cpu_mask.split(constants.CPU_PINNING_SEP):
+    if range_def == constants.CPU_PINNING_ALL:
+      cpu_list.append([constants.CPU_PINNING_ALL_VAL, ])
+    else:
+      # Uniquify and sort the list before adding
+      cpu_list.append(sorted(set(ParseCpuMask(range_def))))
+
+  return cpu_list
+
+
 def GetHomeDir(user, default=None):
   """Try to get the homedir of the given user.
 
@@ -289,17 +303,6 @@ def GetHomeDir(user, default=None):
   return result.pw_dir
 
 
-def NewUUID():
-  """Returns a random UUID.
-
-  @note: This is a Linux-specific method as it uses the /proc
-      filesystem.
-  @rtype: str
-
-  """
-  return ReadFile(_RANDOM_UUID_FILE, size=128).rstrip("\n")
-
-
 def FirstFree(seq, base=0):
   """Returns the first non-existing integer from seq.
 
@@ -570,15 +573,15 @@ def SignalHandled(signums):
   """
   def wrap(fn):
     def sig_function(*args, **kwargs):
-      assert 'signal_handlers' not in kwargs or \
-             kwargs['signal_handlers'] is None or \
-             isinstance(kwargs['signal_handlers'], dict), \
+      assert "signal_handlers" not in kwargs or \
+             kwargs["signal_handlers"] is None or \
+             isinstance(kwargs["signal_handlers"], dict), \
              "Wrong signal_handlers parameter in original function call"
-      if 'signal_handlers' in kwargs and kwargs['signal_handlers'] is not None:
-        signal_handlers = kwargs['signal_handlers']
+      if "signal_handlers" in kwargs and kwargs["signal_handlers"] is not None:
+        signal_handlers = kwargs["signal_handlers"]
       else:
         signal_handlers = {}
-        kwargs['signal_handlers'] = signal_handlers
+        kwargs["signal_handlers"] = signal_handlers
       sighandler = SignalHandler(signums)
       try:
         for sig in signums:
@@ -590,6 +593,13 @@ def SignalHandled(signums):
   return wrap
 
 
+def TimeoutExpired(epoch, timeout, _time_fn=time.time):
+  """Checks whether a timeout has expired.
+
+  """
+  return _time_fn() > (epoch + timeout)
+
+
 class SignalWakeupFd(object):
   try:
     # This is only supported in Python 2.5 and above (some distributions
@@ -597,7 +607,7 @@ class SignalWakeupFd(object):
     _set_wakeup_fd_fn = signal.set_wakeup_fd
   except AttributeError:
     # Not supported
-    def _SetWakeupFd(self, _): # pylint: disable-msg=R0201
+    def _SetWakeupFd(self, _): # pylint: disable=R0201
       return -1
   else:
     def _SetWakeupFd(self, fd):