xref: /openbmc/phosphor-power/phosphor-regulators/tools/validate-regulators-config.py (revision 5b27a95bec8bdcd84728fbf3415e1760aa95ebe5)
1#!/usr/bin/env python
2
3import argparse
4import json
5import sys
6import jsonschema
7
8r"""
9Validates the phosphor-regulators configuration file. Checks it against a JSON
10schema as well as doing some extra checks that can't be encoded in the schema.
11"""
12
13def handle_validation_error():
14    sys.exit("Validation failed.")
15
16def check_duplicate_object_id(config_json):
17    r"""
18    Check that there aren't any JSON objects with the same 'id' property value.
19    config_json: Configuration file JSON
20    """
21
22    json_ids = check_duplicate_rule_id(config_json)+\
23               check_duplicate_device_id(config_json)+\
24               check_duplicate_rail_id(config_json)
25    unique_ids = set()
26    for id in json_ids:
27        if id in unique_ids:
28           sys.stderr.write("Error: Duplicate ID.\n"+\
29           "Found multiple objects with the ID "+id+'\n')
30           handle_validation_error()
31        else:
32            unique_ids.add(id)
33
34def check_duplicate_rule_id(config_json):
35    r"""
36    Check that there aren't any "rule" elements with the same 'id' field.
37    config_json: Configuration file JSON
38    """
39    rule_ids = []
40    for rule in config_json.get('rules', {}):
41        rule_id = rule['id']
42        if rule_id in rule_ids:
43            sys.stderr.write("Error: Duplicate rule ID.\n"+\
44            "Found multiple rules with the ID "+rule_id+'\n')
45            handle_validation_error()
46        else:
47            rule_ids.append(rule_id)
48    return rule_ids
49
50def check_duplicate_chassis_number(config_json):
51    r"""
52    Check that there aren't any "chassis" elements with the same 'number' field.
53    config_json: Configuration file JSON
54    """
55    numbers = []
56    for chassis in config_json.get('chassis', {}):
57        number = chassis['number']
58        if number in numbers:
59            sys.stderr.write("Error: Duplicate chassis number.\n"+\
60            "Found multiple chassis with the number "+str(number)+'\n')
61            handle_validation_error()
62        else:
63            numbers.append(number)
64
65def check_duplicate_device_id(config_json):
66    r"""
67    Check that there aren't any "devices" with the same 'id' field.
68    config_json: Configuration file JSON
69    """
70    device_ids = []
71    for chassis in config_json.get('chassis', {}):
72        for device in chassis.get('devices', {}):
73            device_id = device['id']
74            if device_id in device_ids:
75                sys.stderr.write("Error: Duplicate device ID.\n"+\
76                "Found multiple devices with the ID "+device_id+'\n')
77                handle_validation_error()
78            else:
79                device_ids.append(device_id)
80    return device_ids
81
82def check_duplicate_rail_id(config_json):
83    r"""
84    Check that there aren't any "rails" with the same 'id' field.
85    config_json: Configuration file JSON
86    """
87    rail_ids = []
88    for chassis in config_json.get('chassis', {}):
89        for device in chassis.get('devices', {}):
90            for rail in device.get('rails', {}):
91                rail_id = rail['id']
92                if rail_id in rail_ids:
93                    sys.stderr.write("Error: Duplicate rail ID.\n"+\
94                    "Found multiple rails with the ID "+rail_id+'\n')
95                    handle_validation_error()
96                else:
97                    rail_ids.append(rail_id)
98    return rail_ids
99
100def check_for_duplicates(config_json):
101    r"""
102    Check for duplicate ID.
103    """
104    check_duplicate_rule_id(config_json)
105
106    check_duplicate_chassis_number(config_json)
107
108    check_duplicate_device_id(config_json)
109
110    check_duplicate_rail_id(config_json)
111
112    check_duplicate_object_id(config_json)
113
114def validate_schema(config, schema):
115    r"""
116    Validates the specified config file using the specified
117    schema file.
118
119    config:   Path of the file containing the config JSON
120    schema:   Path of the file containing the schema JSON
121    """
122
123    with open(config) as config_handle:
124        config_json = json.load(config_handle)
125
126        with open(schema) as schema_handle:
127            schema_json = json.load(schema_handle)
128
129            try:
130                jsonschema.validate(config_json, schema_json)
131            except jsonschema.ValidationError as e:
132                print(e)
133                handle_validation_error()
134
135    return config_json
136
137if __name__ == '__main__':
138
139    parser = argparse.ArgumentParser(
140        description='phosphor-regulators configuration file validator')
141
142    parser.add_argument('-s', '--schema-file', dest='schema_file',
143                        help='The phosphor-regulators schema file')
144
145    parser.add_argument('-c', '--configuration-file', dest='configuration_file',
146                        help='The phosphor-regulators configuration file')
147
148    args = parser.parse_args()
149
150    if not args.schema_file:
151        parser.print_help()
152        sys.exit("Error: Schema file is required.")
153    if not args.configuration_file:
154        parser.print_help()
155        sys.exit("Error: Configuration file is required.")
156
157    config_json = validate_schema(args.configuration_file, args.schema_file)
158    check_for_duplicates(config_json)
159