+import logging
+import re
+
+from ganeti import constants
+from ganeti import errors
+from ganeti import ht
+
+
+# Common opcode attributes
+
+#: output fields for a query operation
+_POutputFields = ("output_fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString))
+
+#: the shutdown timeout
+_PShutdownTimeout = ("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT,
+ ht.TPositiveInt)
+
+#: the force parameter
+_PForce = ("force", False, ht.TBool)
+
+#: a required instance name (for single-instance LUs)
+_PInstanceName = ("instance_name", ht.NoDefault, ht.TNonEmptyString)
+
+#: Whether to ignore offline nodes
+_PIgnoreOfflineNodes = ("ignore_offline_nodes", False, ht.TBool)
+
+#: a required node name (for single-node LUs)
+_PNodeName = ("node_name", ht.NoDefault, ht.TNonEmptyString)
+
+#: a required node group name (for single-group LUs)
+_PGroupName = ("group_name", ht.NoDefault, ht.TNonEmptyString)
+
+#: Migration type (live/non-live)
+_PMigrationMode = ("mode", None,
+ ht.TOr(ht.TNone, ht.TElemOf(constants.HT_MIGRATION_MODES)))
+
+#: Obsolete 'live' migration mode (boolean)
+_PMigrationLive = ("live", None, ht.TMaybeBool)
+
+#: Tag type
+_PTagKind = ("kind", ht.NoDefault, ht.TElemOf(constants.VALID_TAG_TYPES))
+
+#: List of tag strings
+_PTags = ("tags", ht.NoDefault, ht.TListOf(ht.TNonEmptyString))
+
+#: OP_ID conversion regular expression
+_OPID_RE = re.compile("([a-z])([A-Z])")
+
+
+def _NameToId(name):
+ """Convert an opcode class name to an OP_ID.
+
+ @type name: string
+ @param name: the class name, as OpXxxYyy
+ @rtype: string
+ @return: the name in the OP_XXXX_YYYY format
+
+ """
+ if not name.startswith("Op"):
+ return None
+ # Note: (?<=[a-z])(?=[A-Z]) would be ideal, since it wouldn't
+ # consume any input, and hence we would just have all the elements
+ # in the list, one by one; but it seems that split doesn't work on
+ # non-consuming input, hence we have to process the input string a
+ # bit
+ name = _OPID_RE.sub(r"\1,\2", name)
+ elems = name.split(",")
+ return "_".join(n.upper() for n in elems)
+
+
+def RequireFileStorage():
+ """Checks that file storage is enabled.
+
+ While it doesn't really fit into this module, L{utils} was deemed too large
+ of a dependency to be imported for just one or two functions.
+
+ @raise errors.OpPrereqError: when file storage is disabled
+
+ """
+ if not constants.ENABLE_FILE_STORAGE:
+ raise errors.OpPrereqError("File storage disabled at configure time",
+ errors.ECODE_INVAL)
+
+
+def _CheckDiskTemplate(template):
+ """Ensure a given disk template is valid.
+
+ """
+ if template not in constants.DISK_TEMPLATES:
+ # Using str.join directly to avoid importing utils for CommaJoin
+ msg = ("Invalid disk template name '%s', valid templates are: %s" %
+ (template, ", ".join(constants.DISK_TEMPLATES)))
+ raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
+ if template == constants.DT_FILE:
+ RequireFileStorage()
+ return True
+
+
+def _CheckStorageType(storage_type):
+ """Ensure a given storage type is valid.
+
+ """
+ if storage_type not in constants.VALID_STORAGE_TYPES:
+ raise errors.OpPrereqError("Unknown storage type: %s" % storage_type,
+ errors.ECODE_INVAL)
+ if storage_type == constants.ST_FILE:
+ RequireFileStorage()
+ return True
+
+
+#: Storage type parameter
+_PStorageType = ("storage_type", ht.NoDefault, _CheckStorageType)
+
+
+class _AutoOpParamSlots(type):
+ """Meta class for opcode definitions.
+
+ """
+ def __new__(mcs, name, bases, attrs):
+ """Called when a class should be created.
+
+ @param mcs: The meta class
+ @param name: Name of created class
+ @param bases: Base classes
+ @type attrs: dict
+ @param attrs: Class attributes
+
+ """
+ assert "__slots__" not in attrs, \
+ "Class '%s' defines __slots__ when it should use OP_PARAMS" % name
+ assert "OP_ID" not in attrs, "Class '%s' defining OP_ID" % name
+
+ attrs["OP_ID"] = _NameToId(name)
+
+ # Always set OP_PARAMS to avoid duplicates in BaseOpCode.GetAllParams
+ params = attrs.setdefault("OP_PARAMS", [])
+
+ # Use parameter names as slots
+ slots = [pname for (pname, _, _) in params]
+
+ assert "OP_DSC_FIELD" not in attrs or attrs["OP_DSC_FIELD"] in slots, \
+ "Class '%s' uses unknown field in OP_DSC_FIELD" % name
+
+ attrs["__slots__"] = slots
+
+ return type.__new__(mcs, name, bases, attrs)
+