confdbquery.py 5.2 KB
Newer Older
Dmitry Volodin's avatar
Dmitry Volodin committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# -*- coding: utf-8 -*-
# ----------------------------------------------------------------------
# ConfDBQuery model
# ----------------------------------------------------------------------
# Copyright (C) 2007-2019 The NOC Project
# See LICENSE for details
# ----------------------------------------------------------------------

# Python modules
import threading
import operator
import os

# Third-party modules
Dmitry Volodin's avatar
Dmitry Volodin committed
15
16
17
18
19
20
21
22
from mongoengine.document import Document, EmbeddedDocument
from mongoengine.fields import (
    StringField,
    UUIDField,
    BooleanField,
    ListField,
    EmbeddedDocumentField,
)
Dmitry Volodin's avatar
Dmitry Volodin committed
23
24
25
26
27
28
29
import six
import cachetools

# NOC modules
from noc.lib.prettyjson import to_json
from noc.lib.text import quote_safe_path
from noc.core.model.decorator import on_delete_check
Dmitry Volodin's avatar
Dmitry Volodin committed
30
from noc.sa.interfaces.base import StringParameter, IntParameter, BooleanParameter
Dmitry Volodin's avatar
Dmitry Volodin committed
31
32

id_lock = threading.Lock()
Dmitry Volodin's avatar
Dmitry Volodin committed
33
34
35
36
37
TYPE_MAP = {"str": StringParameter(), "int": IntParameter(), "bool": BooleanParameter()}


@six.python_2_unicode_compatible
class ConfDBQueryParam(EmbeddedDocument):
38
    meta = {"strict": False}
Dmitry Volodin's avatar
Dmitry Volodin committed
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    name = StringField()
    type = StringField(choices=["str", "int", "bool"])
    default = StringField()
    description = StringField()

    def __str__(self):
        return self.name

    def to_json(self):
        return {
            "name": self.name,
            "type": self.type,
            "description": self.description,
            "default": self.default,
        }

    def get_parameter(self):
        return TYPE_MAP[self.type]
Dmitry Volodin's avatar
Dmitry Volodin committed
57
58


59
60
@on_delete_check(
    check=[
Dmitry Volodin's avatar
Dmitry Volodin committed
61
62
63
        ("cm.InterfaceValidationPolicy", "filter_query"),
        # ("cm.InterfaceValidationPolicy", "rules.query"),
        # ("cm.InterfaceValidationPolicy", "rules.filer_query"),
Andrey Vertiprahov's avatar
Andrey Vertiprahov committed
64
        ("cm.ObjectValidationPolicy", "filter_query"),
Dmitry Volodin's avatar
Dmitry Volodin committed
65
66
        # ("cm.ObjectValidationPolicy", "rules.query"),
        # ("cm.ObjectValidationPolicy", "rules.filer_query"),
67
68
    ]
)
Dmitry Volodin's avatar
Dmitry Volodin committed
69
70
71
72
@six.python_2_unicode_compatible
class ConfDBQuery(Document):
    meta = {
        "collection": "confdbqueries",
Dmitry Volodin's avatar
Dmitry Volodin committed
73
        "strict": False,
Dmitry Volodin's avatar
Dmitry Volodin committed
74
75
76
77
78
79
80
81
82
        "auto_create_index": False,
        "json_collection": "cm.confdbqueries",
        "json_unique_fields": ["name"],
    }

    name = StringField(unique=True)
    uuid = UUIDField(binary=True)
    description = StringField()
    source = StringField()
Dmitry Volodin's avatar
Dmitry Volodin committed
83
    params = ListField(EmbeddedDocumentField(ConfDBQueryParam))
84
85
    allow_object_filter = BooleanField(default=False)
    allow_interface_filter = BooleanField(default=False)
Dmitry Volodin's avatar
Dmitry Volodin committed
86
87
88
89
    allow_object_validation = BooleanField(default=False)
    allow_interface_validation = BooleanField(default=False)
    allow_object_classification = BooleanField(default=False)
    allow_interface_classification = BooleanField(default=False)
90
    require_raw = BooleanField(default=False)
Dmitry Volodin's avatar
Dmitry Volodin committed
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

    _id_cache = cachetools.TTLCache(maxsize=100, ttl=60)

    def __str__(self):
        return self.name

    @classmethod
    @cachetools.cachedmethod(operator.attrgetter("_id_cache"), lock=lambda _: id_lock)
    def get_by_id(cls, id):
        return ConfDBQuery.objects.filter(id=id).first()

    def get_json_path(self):
        p = [quote_safe_path(n.strip()) for n in self.name.split("|")]
        return os.path.join(*p) + ".json"

    def query(self, engine, **kwargs):
        """
        Run query against ConfDB engine
        :param engine: ConfDB engine
        :param kwargs: Optional arguments
        :return:
        """
Dmitry Volodin's avatar
Dmitry Volodin committed
113
114
115
116
        params = kwargs.copy()
        for p in self.params:
            params[p.name] = p.get_parameter().clean(params.get(p.name, p.default))
        for ctx in engine.query(self.source, **params):
Dmitry Volodin's avatar
Dmitry Volodin committed
117
118
            yield ctx

119
120
121
122
123
124
125
126
127
    def any(self, engine, **kwargs):
        """
        Run query agains ConfDB engine and return True if any result found
        :param engine: ConfDB engine
        :param kwargs: Optional arguments
        :return: True if any result found
        """
        return engine.any(self.source, **kwargs)

Dmitry Volodin's avatar
Dmitry Volodin committed
128
129
130
131
132
133
    def to_json(self):
        r = {
            "name": self.name,
            "$collection": self._meta["json_collection"],
            "uuid": self.uuid,
            "source": self.source,
Dmitry Volodin's avatar
Dmitry Volodin committed
134
            "params": [p.to_json() for p in self.params],
135
136
            "allow_object_filter": self.allow_object_filter,
            "allow_interface_filter": self.allow_interface_filter,
Dmitry Volodin's avatar
Dmitry Volodin committed
137
138
139
140
            "allow_object_validation": self.allow_object_validation,
            "allow_interface_validation": self.allow_interface_validation,
            "allow_object_classification": self.allow_object_classification,
            "allow_interface_classification": self.allow_interface_classification,
141
            "require_raw": self.require_raw,
Dmitry Volodin's avatar
Dmitry Volodin committed
142
143
144
145
146
147
148
149
150
151
152
        }
        if self.description:
            r["description"] = self.description
        return to_json(
            r,
            order=[
                "name",
                "$collection",
                "uuid",
                "description",
                "source",
Dmitry Volodin's avatar
Dmitry Volodin committed
153
                "params",
154
155
                "allow_object_filter",
                "allow_interface_filter",
Dmitry Volodin's avatar
Dmitry Volodin committed
156
157
158
159
                "allow_object_validation",
                "allow_interface_validation",
                "allow_object_classification",
                "allow_interface_classification",
160
                "require_raw",
Dmitry Volodin's avatar
Dmitry Volodin committed
161
162
            ],
        )