示例#1
0
class PulpSearch(object):
    # Helper class representing a prepared Pulp search.
    # Usually just a filters dict, but may include type_ids
    # and fields for unit searches.
    filters = attr.ib(type=dict)
    type_ids = attr.ib(type=list, default=None)
    unit_fields = attr.ib(type=list, default=None)
class FieldMatchCriteria(Criteria):
    _field = attr.ib()
    _matcher = attr.ib(converter=coerce_to_matcher)

    def __str__(self):
        matcher = str(self._matcher)
        out = "%s%s" % (self._field, matcher)

        if " " in matcher:
            out = "(%s)" % out
        return out
示例#3
0
def pulp_attrib(pulp_field=None,
                pulp_py_converter=None,
                py_pulp_converter=None,
                **kwargs):
    """Drop-in replacement for attr.ib with added features:

    - applies a validator based on type automatically
    - supports pulplib-specific metadata via extra keyword arguments
    """
    metadata = kwargs.get("metadata") or {}

    if pulp_field:
        metadata[PULP2_FIELD] = pulp_field

    if pulp_py_converter:
        metadata[PULP2_PY_CONVERTER] = pulp_py_converter

    if py_pulp_converter:
        metadata[PY_PULP2_CONVERTER] = py_pulp_converter

    if "type" in kwargs:
        # As a convenience, you may define string types as type=str
        # on any python version, but what you'll actually get is
        # whatever's the primary string type (e.g. basestr on py2)
        if kwargs["type"] is str:
            kwargs["type"] = six.string_types[0]

        # If you haven't defined a validator, you get one automatically
        # for your requested type
        if "validator" not in kwargs:
            kwargs["validator"] = attr.validators.optional(
                attr.validators.instance_of(kwargs["type"]))

    kwargs["metadata"] = metadata
    return attr.ib(**kwargs)
class LessThanMatcher(Matcher):
    _value = attr.ib()

    def _map(self, fn):
        return attr.evolve(self, value=fn(self._value))

    def __str__(self):
        return "<%s" % repr(self._value)
class OrCriteria(Criteria):
    _operands = attr.ib()

    def __str__(self):
        if not self._operands:
            return "<empty OR>"

        if len(self._operands) == 1:
            return str(self._operands[0])

        return "(" + " OR ".join([str(o) for o in self._operands]) + ")"
示例#6
0
class WithClient(object):
    # A mixin for objects holding a private reference to client.

    _client = attr.ib(default=None,
                      init=False,
                      repr=False,
                      cmp=False,
                      hash=False)

    def _set_client(self, client):
        self.__dict__["_client"] = client
示例#7
0
class InMatcher(Matcher):
    _values = attr.ib()

    @_values.validator
    def _check_values(self, _, values):
        if isinstance(values,
                      Iterable) and not isinstance(values, six.string_types):
            return
        raise ValueError("Must be an iterable: %s" % repr(values))

    def _map(self, fn):
        return attr.evolve(self, values=[fn(x) for x in self._values])
示例#8
0
class RegexMatcher(Matcher):
    _pattern = attr.ib()

    @_pattern.validator
    def _check_pattern(self, _, pattern):
        # It must be a string.
        # Need an explicit check here because re.compile also succeeds
        # on already-compiled regex objects.
        if not isinstance(pattern, six.string_types):
            raise TypeError("Regex matcher expected string, got: %s" %
                            repr(pattern))

        # Verify that the given value can really be compiled as a regex.
        re.compile(pattern)
示例#9
0
def pulp_attrib(pulp_field=None,
                pulp_py_converter=None,
                py_pulp_converter=None,
                **kwargs):
    metadata = kwargs.get("metadata") or {}

    if pulp_field:
        metadata[PULP2_FIELD] = pulp_field

    if pulp_py_converter:
        metadata[PULP2_PY_CONVERTER] = pulp_py_converter

    if py_pulp_converter:
        metadata[PY_PULP2_CONVERTER] = py_pulp_converter

    kwargs["metadata"] = metadata
    return attr.ib(**kwargs)
示例#10
0
class RegexMatcher(Matcher):
    _pattern = attr.ib()

    @_pattern.validator
    def _check_pattern(self, _, pattern):
        # It must be a string.
        # Need an explicit check here because re.compile also succeeds
        # on already-compiled regex objects.
        if not isinstance(pattern, six.string_types):
            raise TypeError("Regex matcher expected string, got: %s" %
                            repr(pattern))

        # Verify that the given value can really be compiled as a regex.
        re.compile(pattern)

    # Note: regex matcher does not implement _map since regex is defined only
    # in terms of strings, there are no meaningful conversions.

    def __str__(self):
        return "=~/%s/" % self._pattern
示例#11
0
class Task(PulpObject):
    """Represents a Pulp task."""

    _SCHEMA = load_schema("task")

    id = pulp_attrib(type=str, pulp_field="task_id")
    """ID of this task (str)."""

    completed = attr.ib(default=None, type=bool)
    """True if this task has completed, successfully or otherwise.

    May be `None` if the state of this task is unknown.
    """

    succeeded = attr.ib(default=None, type=bool)
    """True if this task has completed successfully.

    May be `None` if the state of this task is unknown.
    """

    error_summary = attr.ib(default=None, type=str)
    """A summary of the reason for this task's failure (if any).

    This is a short string, generally a single line, suitable for display to users.
    The string includes the ID of the failed task.
    """

    error_details = attr.ib(default=None, type=str)
    """Detailed information for this task's failure (if any).

    This may be a multi-line string and may include technical information such as
    a Python backtrace generated by Pulp.

    ``error_details`` is a superset of the information available via ``error_summary``,
    so it is not necessary to display both.
    """

    tags = pulp_attrib(default=attr.Factory(list),
                       type=list,
                       pulp_field="tags")
    """The tags for this task.

    Typically includes info on the task's associated action and
    repo, such as:

    .. code-block:: python

        ["pulp:repository:rhel-7-server-rpms__7Server_x86_64",
         "pulp:action:publish"]
    """

    repo_id = attr.ib(type=str)
    """The ID of the repository associated with this task, otherwise None."""

    units_data = pulp_attrib(default=attr.Factory(list),
                             type=list,
                             pulp_field="result.units_successful")
    """Info on the units which were processed as part of this task
    (e.g. associated or unassociated).

    This is a list. The list elements are the raw dicts as returned
    by Pulp. These should at least contain a 'type_id' and a 'unit_key'.
    """
    @repo_id.default
    def _repo_id_default(self):
        prefix = "pulp:repository:"
        for tag in self.tags or []:
            if tag.startswith(prefix):
                return tag[len(prefix):]
        return None

    @succeeded.validator
    def _check_succeeded(self, _, value):
        if value and not self.completed:
            raise ValueError(
                "Cannot have task with completed=False, succeeded=True")

    @classmethod
    def _data_to_init_args(cls, data):
        out = super(Task, cls)._data_to_init_args(data)

        state = data["state"]
        out["completed"] = state in ("finished", "error", "canceled",
                                     "skipped")
        out["succeeded"] = state in ("finished", "skipped")

        if state == "canceled":
            out["error_summary"] = "Pulp task [%s] was canceled" % data[
                "task_id"]
            out["error_details"] = out["error_summary"]

        elif state == "error":
            out["error_summary"] = cls._error_summary(data)
            out["error_details"] = cls._error_details(data)

        return out

    @classmethod
    def _error_summary(cls, data):
        prefix = "Pulp task [%s] failed" % data["task_id"]
        error = data.get("error")
        if not error:
            return "%s: <unknown error>" % prefix
        return "%s: %s: %s" % (prefix, error["code"], error["description"])

    @classmethod
    def _error_details(cls, data):
        out = cls._error_summary(data)

        error = data.get("error")
        if not error:
            return out

        # Error looks like this:
        #
        # {
        #   'code': u'PLP0001',
        #   'data': {
        #     'message': 'a message'
        #   },
        #   'description': 'A general pulp exception occurred',
        #   'sub_errors': []
        # }
        #
        # See: https://docs.pulpproject.org/en/2.9/dev-guide/conventions/exceptions.html#error-details
        #
        # data can contain anything, or nothing.
        # It's only a convention that it often contains a message.
        #
        # sub_errors is currently ignored because I've never seen a non-empty
        # sub_errors yet.

        error_data = error.get("data") or {}
        messages = []

        # Message in a general exception
        if error_data.get("message"):
            messages.append(error_data["message"])

        # Some exceptions stash additional strings under details.errors
        if (error_data.get("details") or {}).get("errors"):
            error_messages = error_data["details"]["errors"]
            if isinstance(error_messages, list):
                messages.extend(error_messages)

        # Pulp docs refer to this as deprecated, but actually it's still
        # used and no alternative is provided.
        if data.get("traceback"):
            messages.append(data["traceback"])

        message = "\n".join(messages)
        if message:
            # message can have CRLF line endings in rare cases.
            message = message.replace("\r\n", "\n").strip()
            out = "%s:\n%s" % (out, _indent(message))

        return out
示例#12
0
class EqMatcher(Matcher):
    _value = attr.ib()

    def _map(self, fn):
        return attr.evolve(self, value=fn(self._value))
示例#13
0
class RegexMatcher(Matcher):
    _pattern = attr.ib()

    @_pattern.validator
    def _check_pattern(self, _, pattern):
        re.compile(pattern)
示例#14
0
class UnitTypeMatchCriteria(FieldMatchCriteria):
    # This specialization of FieldMatchCriteria is used to match on unit types
    # while also keeping info on the fields of interest to the user.
    _unit_fields = attr.ib()
示例#15
0
class OrCriteria(Criteria):
    _operands = attr.ib()
示例#16
0
class AndCriteria(Criteria):
    _operands = attr.ib()
示例#17
0
class FieldMatchCriteria(Criteria):
    _field = attr.ib()
    _matcher = attr.ib(converter=coerce_to_matcher)