summaryrefslogtreecommitdiffstats
path: root/compass-tasks/db/config_validation/default_validator.py
blob: 224447f7242532c730bf83e569d758d5c8d0cc3f (plain)
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
# Copyright 2014 Huawei Technologies Co. Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Default config validation function."""

from sqlalchemy import or_

from compass.db.models import OSConfigField
from compass.db.models import OSConfigMetadata
from compass.db import validator

MAPPER = {
    "os_id": {
        "metaTable": OSConfigMetadata,
        "metaFieldTable": OSConfigField
    }
    # "adapter_id": {
    #     "metaTable": AdapterConfigMetadata,
    #     "metaFieldTable": AdapterConfigField
    # }
}


def validate_config(session, config, id_name, id_value, patch=True):
    """Validates config.

    Validates the given config value according to the config
    metadata of the asscoiated os_id or adapter_id. Returns
    a tuple (status, message).
    """
    if id_name not in MAPPER.keys():
        return (False, "Invalid id type %s" % id_name)

    meta_table = MAPPER[id_name]['metaTable']
    metafield_table = MAPPER[id_name]['metaFieldTable']
    with session.begin(subtransactions=True):
        name_col = name_col = getattr(meta_table, 'name')
        id_col = getattr(meta_table, id_name)

        return _validate_config_helper(session, config,
                                       name_col, id_col, id_value,
                                       meta_table, metafield_table,
                                       patch)


def _validate_config_helper(session, config,
                            name_col, id_col, id_value,
                            meta_table, metafield_table, patch=True):

    with session.begin(subtransactions=True):
        for elem in config:

            obj = session.query(meta_table).filter(name_col == elem)\
                         .filter(or_(id_col is None,
                                     id_col == id_value)).first()

            if not obj and "_type" not in config[elem]:
                return (False, "Invalid metadata '%s'!" % elem)

            if "_type" in config[elem]:
                # Metadata is a variable
                metadata_name = config[elem]['_type']
                obj = session.query(meta_table).filter_by(name=metadata_name)\
                                               .first()

                if not obj:
                    err_msg = ("Invalid metatdata '%s' or missing '_type'"
                               "to indicate this is a variable metatdata."
                               % elem)
                    return (False, err_msg)

                # TODO(Grace): validate metadata here
                del config[elem]['_type']

            fields = obj.fields

            if not fields:
                is_valid, message = _validate_config_helper(session,
                                                            config[elem],
                                                            name_col, id_col,
                                                            id_value,
                                                            meta_table,
                                                            metafield_table,
                                                            patch)
                if not is_valid:
                    return (False, message)

            else:
                field_config = config[elem]
                for key in field_config:
                    field = session.query(metafield_table)\
                                   .filter_by(field=key).first()
                    if not field:
                        # The field is not in schema
                        return (False, "Invalid field '%s'!" % key)

                    value = field_config[key]
                    if field.is_required and value is None:
                        # The value of this field is required
                        # and cannot be none
                        err = "The value of field '%s' cannot be null!" % key
                        return (False, err)

                    if field.validator:
                        func = getattr(validator, field.validator)
                        if not func or not func(value):
                            err_msg = ("The value of the field '%s' is "
                                       "invalid format or None!" % key)
                            return (False, err_msg)

                # This is a PUT request. We need to check presence of all
                # required fields.
                if not patch:
                    for field in fields:
                        name = field.field
                        if field.is_required and name not in field_config:
                            return (False,
                                    "Missing required field '%s'" % name)

        return (True, None)