This file is indexed.

/usr/share/pyshared/maasserver/models/tag.py is in python-django-maas 1.2+bzr1373+dfsg-0ubuntu1~12.04.6.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# Copyright 2012 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

"""Node objects."""

from __future__ import (
    absolute_import,
    print_function,
    unicode_literals,
    )

__metaclass__ = type
__all__ = [
    "Tag",
    ]

from django.core.exceptions import (
    PermissionDenied,
    ValidationError,
    )
from django.core.validators import RegexValidator
from django.db.models import (
    CharField,
    Manager,
    TextField,
    Q,
    )
from django.shortcuts import get_object_or_404
from lxml import etree
from maasserver import DefaultMeta
from maasserver.models.cleansave import CleanSave
from maasserver.models.timestampedmodel import TimestampedModel


# Permission model for tags. Everyone can see all tags, but only superusers can
# edit tags.
class TagManager(Manager):
    """A utility to manage the collection of Tags."""

    def get_tag_or_404(self, name, user, to_edit=False):
        """Fetch a `Tag` by name.  Raise exceptions if no `Tag` with
        this name exist.

        :param name: The Tag.name.
        :type name: str
        :param user: The user that should be used in the permission check.
        :type user: django.contrib.auth.models.User
        :param to_edit: Are we going to edit this tag, or just view it?
        :type to_edit: bool
        :raises: django.http.Http404_,
            :class:`maasserver.exceptions.PermissionDenied`.

        .. _django.http.Http404: https://
           docs.djangoproject.com/en/dev/topics/http/views/
           #the-http404-exception
        """
        if to_edit and not user.is_superuser:
            raise PermissionDenied()
        tag = get_object_or_404(Tag, name=name)
        return tag

    def get_nodes(self, tag, user, prefetch_mac=False):
        """Get the list of nodes that have this tag.

        This list is restricted to only nodes that the user has VIEW permission
        for.
        """
        if isinstance(tag, basestring):
            tag = self.get_tag_or_404(name=tag, user=user)
        # The privacy logic is taken from Node. Note that we could filter in
        # python by iterating over all nodes and checking
        #   user.has_perm(VIEW, node)
        # It seems better to do this in the DB, though.
        if user.is_superuser:
            nodes = tag.node_set.all()
        else:
            nodes = tag.node_set.filter(
                Q(owner__isnull=True) | Q(owner=user))
        if prefetch_mac:
            nodes = nodes.prefetch_related('macaddress_set')
        return nodes


class Tag(CleanSave, TimestampedModel):
    """A `Tag` is a label applied to a `Node`.

    :ivar name: The short-human-identifiable name for this tag.
    :ivar definition: The XPATH string identifying what nodes should match this
        tag.
    :ivar comment: A long-form description for humans about what this tag is
        trying to accomplish.
    :ivar objects: The :class:`TagManager`.
    """

    _tag_name_regex = '^[\w-]+$'

    class Meta(DefaultMeta):
        """Needed for South to recognize this model."""

    name = CharField(max_length=256, unique=True, editable=True,
                     validators=[RegexValidator(_tag_name_regex)])
    definition = TextField(blank=True)
    comment = TextField(blank=True)

    objects = TagManager()

    def __init__(self, *args, **kwargs):
        super(Tag, self).__init__(*args, **kwargs)
        # Track what the original definition is, so we can detect when it
        # changes and we need to repopulate the node<=>tag mapping.
        # We have to check for self.id, otherwise we don't see the creation of
        # a new definition.
        if self.id is None:
            self._original_definition = None
        else:
            self._original_definition = self.definition

    def __unicode__(self):
        return self.name

    def populate_nodes(self):
        """Find all nodes that match this tag, and update them."""
        from maasserver.populate_tags import populate_tags
        if not self.definition:
            return
        # before we pass off any work, ensure the definition is valid XPATH
        try:
            etree.XPath(self.definition)
        except etree.XPathSyntaxError as e:
            msg = 'Invalid xpath expression: %s' % (e,)
            raise ValidationError({'definition': [msg]})
        # Now delete the existing tags
        self.node_set.clear()
        populate_tags(self)

    def save(self, *args, **kwargs):
        super(Tag, self).save(*args, **kwargs)
        if self.definition != self._original_definition:
            self.populate_nodes()
        self._original_definition = self.definition