#
#

# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


"""OpCodes module

Note that this file is autogenerated using @src/hs2py@ with a header
from @lib/opcodes.py.in_before@ and a footer from @lib/opcodes.py.in_after@.

This module implements part of the data structures which define the
cluster operations - the so-called opcodes.

Every operation which modifies the cluster state is expressed via
opcodes.

"""

# this are practically structures, so disable the message about too
# few public methods:
# pylint: disable=R0903
# pylint: disable=C0301

from ganeti import constants
from ganeti import ht

from ganeti import opcodes_base


class OpCode(opcodes_base.BaseOpCode):
  """Abstract OpCode.

  This is the root of the actual OpCode hierarchy. All clases derived
  from this class should override OP_ID.

  @cvar OP_ID: The ID of this opcode. This should be unique amongst all
               children of this class.
  @cvar OP_DSC_FIELD: The name of a field whose value will be included in the
                      string returned by Summary(); see the docstring of that
                      method for details).
  @cvar OP_DSC_FORMATTER: A callable that should format the OP_DSC_FIELD; if
                          not present, then the field will be simply converted
                          to string
  @cvar OP_PARAMS: List of opcode attributes, the default values they should
                   get if not already defined, and types they must match.
  @cvar OP_RESULT: Callable to verify opcode result
  @cvar WITH_LU: Boolean that specifies whether this should be included in
      mcpu's dispatch table
  @ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just
                 the check steps
  @ivar priority: Opcode priority for queue

  """
  # pylint: disable=E1101
  # as OP_ID is dynamically defined
  WITH_LU = True
  OP_PARAMS = [
    ("dry_run", None, ht.TMaybe(ht.TBool), "Run checks only, don't execute"),
    ("debug_level", None, ht.TMaybe(ht.TNonNegative(ht.TInt)), "Debug level"),
    ("priority", constants.OP_PRIO_DEFAULT,
     ht.TElemOf(constants.OP_PRIO_SUBMIT_VALID), "Opcode priority"),
    (opcodes_base.DEPEND_ATTR, None, opcodes_base.BuildJobDepCheck(True),
     "Job dependencies; if used through ``SubmitManyJobs`` relative (negative)"
     " job IDs can be used; see :doc:`design document <design-chained-jobs>`"
     " for details"),
    (opcodes_base.COMMENT_ATTR, None, ht.TMaybe(ht.TString),
     "Comment describing the purpose of the opcode"),
    (constants.OPCODE_REASON, [], ht.TMaybe(ht.TListOf(ht.TAny)),
     "The reason trail, describing why the OpCode is executed"),
    ]
  OP_RESULT = None

  def __getstate__(self):
    """Specialized getstate for opcodes.

    This method adds to the state dictionary the OP_ID of the class,
    so that on unload we can identify the correct class for
    instantiating the opcode.

    @rtype:   C{dict}
    @return:  the state as a dictionary

    """
    data = opcodes_base.BaseOpCode.__getstate__(self)
    data["OP_ID"] = self.OP_ID
    return data

  @classmethod
  def LoadOpCode(cls, data):
    """Generic load opcode method.

    The method identifies the correct opcode class from the dict-form
    by looking for a OP_ID key, if this is not found, or its value is
    not available in this module as a child of this class, we fail.

    @type data:  C{dict}
    @param data: the serialized opcode

    """
    if not isinstance(data, dict):
      raise ValueError("Invalid data to LoadOpCode (%s)" % type(data))
    if "OP_ID" not in data:
      raise ValueError("Invalid data to LoadOpcode, missing OP_ID")
    op_id = data["OP_ID"]
    op_class = None
    if op_id in OP_MAPPING:
      op_class = OP_MAPPING[op_id]
    else:
      raise ValueError("Invalid data to LoadOpCode: OP_ID %s unsupported" %
                       op_id)
    op = op_class()
    new_data = data.copy()
    del new_data["OP_ID"]
    op.__setstate__(new_data)
    return op

  def Summary(self):
    """Generates a summary description of this opcode.

    The summary is the value of the OP_ID attribute (without the "OP_"
    prefix), plus the value of the OP_DSC_FIELD attribute, if one was
    defined; this field should allow to easily identify the operation
    (for an instance creation job, e.g., it would be the instance
    name).

    """
    assert self.OP_ID is not None and len(self.OP_ID) > 3
    # all OP_ID start with OP_, we remove that
    txt = self.OP_ID[3:]
    field_name = getattr(self, "OP_DSC_FIELD", None)
    if field_name:
      field_value = getattr(self, field_name, None)
      field_formatter = getattr(self, "OP_DSC_FORMATTER", None)
      if callable(field_formatter):
        field_value = field_formatter(field_value)
      elif isinstance(field_value, (list, tuple)):
        field_value = ",".join(str(i) for i in field_value)
      txt = "%s(%s)" % (txt, field_value)
    return txt

  def TinySummary(self):
    """Generates a compact summary description of the opcode.

    """
    assert self.OP_ID.startswith("OP_")

    text = self.OP_ID[3:]

    for (prefix, supplement) in opcodes_base.SUMMARY_PREFIX.items():
      if text.startswith(prefix):
        return supplement + text[len(prefix):]

    return text


class OpInstanceMultiAllocBase(OpCode):
  """Allocates multiple instances.

  """
  def __getstate__(self):
    """Generic serializer.

    """
    state = OpCode.__getstate__(self)
    if hasattr(self, "instances"):
      # pylint: disable=E1101
      state["instances"] = [inst.__getstate__() for inst in self.instances]
    return state

  def __setstate__(self, state):
    """Generic unserializer.

    This method just restores from the serialized state the attributes
    of the current instance.

    @param state: the serialized opcode data
    @type state: C{dict}

    """
    if not isinstance(state, dict):
      raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
                       type(state))

    if "instances" in state:
      state["instances"] = map(OpCode.LoadOpCode, state["instances"])

    return OpCode.__setstate__(self, state)

  def Validate(self, set_defaults):
    """Validates this opcode.

    We do this recursively.

    """
    OpCode.Validate(self, set_defaults)

    for inst in self.instances: # pylint: disable=E1101
      inst.Validate(set_defaults)
