| Lei YU | 43082e7 | 2020-03-09 10:32:48 +0800 | [diff] [blame] | 1 | #!/usr/bin/env python3 | 
| Bob King | 5cc0128 | 2019-12-17 18:11:57 +0800 | [diff] [blame] | 2 |  | 
|  | 3 | import argparse | 
|  | 4 | import json | 
| Bob King | b7552f0 | 2020-10-15 14:34:17 +0800 | [diff] [blame] | 5 | import os | 
|  | 6 | import sys | 
| Bob King | 5cc0128 | 2019-12-17 18:11:57 +0800 | [diff] [blame] | 7 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 8 | import jsonschema | 
|  | 9 |  | 
| Bob King | 5cc0128 | 2019-12-17 18:11:57 +0800 | [diff] [blame] | 10 | r""" | 
|  | 11 | Validates the phosphor-regulators configuration file. Checks it against a JSON | 
|  | 12 | schema as well as doing some extra checks that can't be encoded in the schema. | 
|  | 13 | """ | 
|  | 14 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 15 |  | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 16 | def handle_validation_error(): | 
|  | 17 | sys.exit("Validation failed.") | 
|  | 18 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 19 |  | 
|  | 20 | def get_values(json_element, key, result=None): | 
| Bob King | 23dd60b | 2020-02-26 10:23:21 +0800 | [diff] [blame] | 21 | r""" | 
|  | 22 | Finds all occurrences of a key within the specified JSON element and its | 
|  | 23 | children. Returns the associated values. | 
|  | 24 | To search the entire configuration file, pass the root JSON element | 
|  | 25 | json_element: JSON element within the config file. | 
|  | 26 | key: key name. | 
|  | 27 | result: list of values found with the specified key. | 
|  | 28 | """ | 
|  | 29 |  | 
|  | 30 | if result is None: | 
|  | 31 | result = [] | 
|  | 32 | if type(json_element) is dict: | 
|  | 33 | for json_key in json_element: | 
|  | 34 | if json_key == key: | 
|  | 35 | result.append(json_element[json_key]) | 
|  | 36 | elif type(json_element[json_key]) in (list, dict): | 
|  | 37 | get_values(json_element[json_key], key, result) | 
|  | 38 | elif type(json_element) is list: | 
|  | 39 | for item in json_element: | 
|  | 40 | if type(item) in (list, dict): | 
|  | 41 | get_values(item, key, result) | 
|  | 42 | return result | 
|  | 43 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 44 |  | 
| Bob King | 23dd60b | 2020-02-26 10:23:21 +0800 | [diff] [blame] | 45 | def get_rule_ids(config_json): | 
|  | 46 | r""" | 
|  | 47 | Get all rule IDs in the configuration file. | 
|  | 48 | config_json: Configuration file JSON | 
|  | 49 | """ | 
|  | 50 | rule_ids = [] | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 51 | for rule in config_json.get("rules", {}): | 
|  | 52 | rule_ids.append(rule["id"]) | 
| Bob King | 23dd60b | 2020-02-26 10:23:21 +0800 | [diff] [blame] | 53 | return rule_ids | 
|  | 54 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 55 |  | 
| Bob King | e959754 | 2020-02-26 10:47:40 +0800 | [diff] [blame] | 56 | def get_device_ids(config_json): | 
|  | 57 | r""" | 
|  | 58 | Get all device IDs in the configuration file. | 
|  | 59 | config_json: Configuration file JSON | 
|  | 60 | """ | 
|  | 61 | device_ids = [] | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 62 | for chassis in config_json.get("chassis", {}): | 
|  | 63 | for device in chassis.get("devices", {}): | 
|  | 64 | device_ids.append(device["id"]) | 
| Bob King | e959754 | 2020-02-26 10:47:40 +0800 | [diff] [blame] | 65 | return device_ids | 
|  | 66 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 67 |  | 
| Bob King | a533d70 | 2020-02-26 10:51:24 +0800 | [diff] [blame] | 68 | def check_number_of_elements_in_masks(config_json): | 
|  | 69 | r""" | 
|  | 70 | Check if the number of bit masks in the 'masks' property matches the number | 
|  | 71 | of byte values in the 'values' property. | 
|  | 72 | config_json: Configuration file JSON | 
|  | 73 | """ | 
|  | 74 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 75 | i2c_write_bytes = get_values(config_json, "i2c_write_bytes") | 
|  | 76 | i2c_compare_bytes = get_values(config_json, "i2c_compare_bytes") | 
| Bob King | a533d70 | 2020-02-26 10:51:24 +0800 | [diff] [blame] | 77 |  | 
|  | 78 | for object in i2c_write_bytes: | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 79 | if "masks" in object: | 
|  | 80 | if len(object.get("masks", [])) != len(object.get("values", [])): | 
|  | 81 | sys.stderr.write( | 
|  | 82 | "Error: Invalid i2c_write_bytes action.\n" | 
|  | 83 | + "The masks array must have the same size as the values" | 
|  | 84 | + " array. masks: " | 
|  | 85 | + str(object.get("masks", [])) | 
|  | 86 | + ", values: " | 
|  | 87 | + str(object.get("values", [])) | 
|  | 88 | + ".\n" | 
|  | 89 | ) | 
| Bob King | a533d70 | 2020-02-26 10:51:24 +0800 | [diff] [blame] | 90 | handle_validation_error() | 
|  | 91 |  | 
|  | 92 | for object in i2c_compare_bytes: | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 93 | if "masks" in object: | 
|  | 94 | if len(object.get("masks", [])) != len(object.get("values", [])): | 
|  | 95 | sys.stderr.write( | 
|  | 96 | "Error: Invalid i2c_compare_bytes action.\n" | 
|  | 97 | + "The masks array must have the same size as the values " | 
|  | 98 | + "array. masks: " | 
|  | 99 | + str(object.get("masks", [])) | 
|  | 100 | + ", values: " | 
|  | 101 | + str(object.get("values", [])) | 
|  | 102 | + ".\n" | 
|  | 103 | ) | 
| Bob King | a533d70 | 2020-02-26 10:51:24 +0800 | [diff] [blame] | 104 | handle_validation_error() | 
|  | 105 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 106 |  | 
| Bob King | 9146df2 | 2020-02-26 10:49:33 +0800 | [diff] [blame] | 107 | def check_rule_id_exists(config_json): | 
|  | 108 | r""" | 
|  | 109 | Check if a rule_id property specifies a rule ID that does not exist. | 
|  | 110 | config_json: Configuration file JSON | 
|  | 111 | """ | 
|  | 112 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 113 | rule_ids = get_values(config_json, "rule_id") | 
| Bob King | 9146df2 | 2020-02-26 10:49:33 +0800 | [diff] [blame] | 114 | valid_rule_ids = get_rule_ids(config_json) | 
|  | 115 | for rule_id in rule_ids: | 
|  | 116 | if rule_id not in valid_rule_ids: | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 117 | sys.stderr.write( | 
|  | 118 | "Error: Rule ID does not exist.\n" | 
|  | 119 | + "Found rule_id value that specifies invalid rule ID " | 
|  | 120 | + rule_id | 
|  | 121 | + "\n" | 
|  | 122 | ) | 
| Bob King | 9146df2 | 2020-02-26 10:49:33 +0800 | [diff] [blame] | 123 | handle_validation_error() | 
|  | 124 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 125 |  | 
| Shawn McCarney | 5d4a9c7 | 2021-08-19 18:45:59 -0500 | [diff] [blame] | 126 | def check_device_id_exists(config_json): | 
|  | 127 | r""" | 
|  | 128 | Check if a device_id property specifies a device ID that does not exist. | 
|  | 129 | config_json: Configuration file JSON | 
|  | 130 | """ | 
|  | 131 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 132 | device_ids = get_values(config_json, "device_id") | 
| Shawn McCarney | 5d4a9c7 | 2021-08-19 18:45:59 -0500 | [diff] [blame] | 133 | valid_device_ids = get_device_ids(config_json) | 
|  | 134 | for device_id in device_ids: | 
|  | 135 | if device_id not in valid_device_ids: | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 136 | sys.stderr.write( | 
|  | 137 | "Error: Device ID does not exist.\n" | 
|  | 138 | + "Found device_id value that specifies invalid device ID " | 
|  | 139 | + device_id | 
|  | 140 | + "\n" | 
|  | 141 | ) | 
| Shawn McCarney | 5d4a9c7 | 2021-08-19 18:45:59 -0500 | [diff] [blame] | 142 | handle_validation_error() | 
|  | 143 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 144 |  | 
| Bob King | e959754 | 2020-02-26 10:47:40 +0800 | [diff] [blame] | 145 | def check_set_device_value_exists(config_json): | 
|  | 146 | r""" | 
|  | 147 | Check if a set_device action specifies a device ID that does not exist. | 
|  | 148 | config_json: Configuration file JSON | 
|  | 149 | """ | 
|  | 150 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 151 | device_ids = get_values(config_json, "set_device") | 
| Bob King | e959754 | 2020-02-26 10:47:40 +0800 | [diff] [blame] | 152 | valid_device_ids = get_device_ids(config_json) | 
|  | 153 | for device_id in device_ids: | 
|  | 154 | if device_id not in valid_device_ids: | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 155 | sys.stderr.write( | 
|  | 156 | "Error: Device ID does not exist.\n" | 
|  | 157 | + "Found set_device action that specifies invalid device ID " | 
|  | 158 | + device_id | 
|  | 159 | + "\n" | 
|  | 160 | ) | 
| Bob King | e959754 | 2020-02-26 10:47:40 +0800 | [diff] [blame] | 161 | handle_validation_error() | 
|  | 162 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 163 |  | 
| Bob King | 23dd60b | 2020-02-26 10:23:21 +0800 | [diff] [blame] | 164 | def check_run_rule_value_exists(config_json): | 
|  | 165 | r""" | 
|  | 166 | Check if any run_rule actions specify a rule ID that does not exist. | 
|  | 167 | config_json: Configuration file JSON | 
|  | 168 | """ | 
|  | 169 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 170 | rule_ids = get_values(config_json, "run_rule") | 
| Bob King | 23dd60b | 2020-02-26 10:23:21 +0800 | [diff] [blame] | 171 | valid_rule_ids = get_rule_ids(config_json) | 
|  | 172 | for rule_id in rule_ids: | 
|  | 173 | if rule_id not in valid_rule_ids: | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 174 | sys.stderr.write( | 
|  | 175 | "Error: Rule ID does not exist.\n" | 
|  | 176 | + "Found run_rule action that specifies invalid rule ID " | 
|  | 177 | + rule_id | 
|  | 178 | + "\n" | 
|  | 179 | ) | 
| Bob King | 23dd60b | 2020-02-26 10:23:21 +0800 | [diff] [blame] | 180 | handle_validation_error() | 
|  | 181 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 182 |  | 
| Bob King | d114cd9 | 2020-02-10 13:56:02 +0800 | [diff] [blame] | 183 | def check_infinite_loops_in_rule(config_json, rule_json, call_stack=[]): | 
|  | 184 | r""" | 
|  | 185 | Check if a 'run_rule' action in the specified rule causes an | 
|  | 186 | infinite loop. | 
|  | 187 | config_json: Configuration file JSON. | 
|  | 188 | rule_json: A rule in the JSON config file. | 
|  | 189 | call_stack: Current call stack of rules. | 
|  | 190 | """ | 
|  | 191 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 192 | call_stack.append(rule_json["id"]) | 
|  | 193 | for action in rule_json.get("actions", {}): | 
|  | 194 | if "run_rule" in action: | 
|  | 195 | run_rule_id = action["run_rule"] | 
| Bob King | d114cd9 | 2020-02-10 13:56:02 +0800 | [diff] [blame] | 196 | if run_rule_id in call_stack: | 
|  | 197 | call_stack.append(run_rule_id) | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 198 | sys.stderr.write( | 
|  | 199 | "Infinite loop caused by run_rule actions.\n" | 
|  | 200 | + str(call_stack) | 
|  | 201 | + "\n" | 
|  | 202 | ) | 
| Bob King | d114cd9 | 2020-02-10 13:56:02 +0800 | [diff] [blame] | 203 | handle_validation_error() | 
|  | 204 | else: | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 205 | for rule in config_json.get("rules", {}): | 
|  | 206 | if rule["id"] == run_rule_id: | 
|  | 207 | check_infinite_loops_in_rule( | 
|  | 208 | config_json, rule, call_stack | 
|  | 209 | ) | 
| Bob King | d114cd9 | 2020-02-10 13:56:02 +0800 | [diff] [blame] | 210 | call_stack.pop() | 
|  | 211 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 212 |  | 
| Bob King | d114cd9 | 2020-02-10 13:56:02 +0800 | [diff] [blame] | 213 | def check_infinite_loops(config_json): | 
|  | 214 | r""" | 
|  | 215 | Check if rule in config file is called recursively, causing an | 
|  | 216 | infinite loop. | 
|  | 217 | config_json: Configuration file JSON | 
|  | 218 | """ | 
|  | 219 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 220 | for rule in config_json.get("rules", {}): | 
| Bob King | d114cd9 | 2020-02-10 13:56:02 +0800 | [diff] [blame] | 221 | check_infinite_loops_in_rule(config_json, rule) | 
|  | 222 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 223 |  | 
| Bob King | 5b27a95 | 2020-01-20 18:04:15 +0800 | [diff] [blame] | 224 | def check_duplicate_object_id(config_json): | 
|  | 225 | r""" | 
|  | 226 | Check that there aren't any JSON objects with the same 'id' property value. | 
|  | 227 | config_json: Configuration file JSON | 
|  | 228 | """ | 
|  | 229 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 230 | json_ids = get_values(config_json, "id") | 
| Bob King | 5b27a95 | 2020-01-20 18:04:15 +0800 | [diff] [blame] | 231 | unique_ids = set() | 
|  | 232 | for id in json_ids: | 
|  | 233 | if id in unique_ids: | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 234 | sys.stderr.write( | 
|  | 235 | "Error: Duplicate ID.\n" | 
|  | 236 | + "Found multiple objects with the ID " | 
|  | 237 | + id | 
|  | 238 | + "\n" | 
|  | 239 | ) | 
|  | 240 | handle_validation_error() | 
| Bob King | 5b27a95 | 2020-01-20 18:04:15 +0800 | [diff] [blame] | 241 | else: | 
|  | 242 | unique_ids.add(id) | 
|  | 243 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 244 |  | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 245 | def check_duplicate_rule_id(config_json): | 
|  | 246 | r""" | 
|  | 247 | Check that there aren't any "rule" elements with the same 'id' field. | 
|  | 248 | config_json: Configuration file JSON | 
|  | 249 | """ | 
|  | 250 | rule_ids = [] | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 251 | for rule in config_json.get("rules", {}): | 
|  | 252 | rule_id = rule["id"] | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 253 | if rule_id in rule_ids: | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 254 | sys.stderr.write( | 
|  | 255 | "Error: Duplicate rule ID.\n" | 
|  | 256 | + "Found multiple rules with the ID " | 
|  | 257 | + rule_id | 
|  | 258 | + "\n" | 
|  | 259 | ) | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 260 | handle_validation_error() | 
|  | 261 | else: | 
|  | 262 | rule_ids.append(rule_id) | 
|  | 263 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 264 |  | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 265 | def check_duplicate_chassis_number(config_json): | 
|  | 266 | r""" | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 267 | Check that there aren't any "chassis" elements with the same 'number' | 
|  | 268 | field. | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 269 | config_json: Configuration file JSON | 
|  | 270 | """ | 
|  | 271 | numbers = [] | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 272 | for chassis in config_json.get("chassis", {}): | 
|  | 273 | number = chassis["number"] | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 274 | if number in numbers: | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 275 | sys.stderr.write( | 
|  | 276 | "Error: Duplicate chassis number.\n" | 
|  | 277 | + "Found multiple chassis with the number " | 
|  | 278 | + str(number) | 
|  | 279 | + "\n" | 
|  | 280 | ) | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 281 | handle_validation_error() | 
|  | 282 | else: | 
|  | 283 | numbers.append(number) | 
|  | 284 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 285 |  | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 286 | def check_duplicate_device_id(config_json): | 
|  | 287 | r""" | 
|  | 288 | Check that there aren't any "devices" with the same 'id' field. | 
|  | 289 | config_json: Configuration file JSON | 
|  | 290 | """ | 
|  | 291 | device_ids = [] | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 292 | for chassis in config_json.get("chassis", {}): | 
|  | 293 | for device in chassis.get("devices", {}): | 
|  | 294 | device_id = device["id"] | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 295 | if device_id in device_ids: | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 296 | sys.stderr.write( | 
|  | 297 | "Error: Duplicate device ID.\n" | 
|  | 298 | + "Found multiple devices with the ID " | 
|  | 299 | + device_id | 
|  | 300 | + "\n" | 
|  | 301 | ) | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 302 | handle_validation_error() | 
|  | 303 | else: | 
|  | 304 | device_ids.append(device_id) | 
|  | 305 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 306 |  | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 307 | def check_duplicate_rail_id(config_json): | 
|  | 308 | r""" | 
|  | 309 | Check that there aren't any "rails" with the same 'id' field. | 
|  | 310 | config_json: Configuration file JSON | 
|  | 311 | """ | 
|  | 312 | rail_ids = [] | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 313 | for chassis in config_json.get("chassis", {}): | 
|  | 314 | for device in chassis.get("devices", {}): | 
|  | 315 | for rail in device.get("rails", {}): | 
|  | 316 | rail_id = rail["id"] | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 317 | if rail_id in rail_ids: | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 318 | sys.stderr.write( | 
|  | 319 | "Error: Duplicate rail ID.\n" | 
|  | 320 | + "Found multiple rails with the ID " | 
|  | 321 | + rail_id | 
|  | 322 | + "\n" | 
|  | 323 | ) | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 324 | handle_validation_error() | 
|  | 325 | else: | 
|  | 326 | rail_ids.append(rail_id) | 
|  | 327 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 328 |  | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 329 | def check_for_duplicates(config_json): | 
|  | 330 | r""" | 
|  | 331 | Check for duplicate ID. | 
|  | 332 | """ | 
|  | 333 | check_duplicate_rule_id(config_json) | 
|  | 334 |  | 
|  | 335 | check_duplicate_chassis_number(config_json) | 
|  | 336 |  | 
|  | 337 | check_duplicate_device_id(config_json) | 
|  | 338 |  | 
|  | 339 | check_duplicate_rail_id(config_json) | 
|  | 340 |  | 
| Bob King | 5b27a95 | 2020-01-20 18:04:15 +0800 | [diff] [blame] | 341 | check_duplicate_object_id(config_json) | 
|  | 342 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 343 |  | 
| Bob King | 5cc0128 | 2019-12-17 18:11:57 +0800 | [diff] [blame] | 344 | def validate_schema(config, schema): | 
|  | 345 | r""" | 
|  | 346 | Validates the specified config file using the specified | 
|  | 347 | schema file. | 
|  | 348 |  | 
|  | 349 | config:   Path of the file containing the config JSON | 
|  | 350 | schema:   Path of the file containing the schema JSON | 
|  | 351 | """ | 
|  | 352 |  | 
|  | 353 | with open(config) as config_handle: | 
|  | 354 | config_json = json.load(config_handle) | 
|  | 355 |  | 
|  | 356 | with open(schema) as schema_handle: | 
|  | 357 | schema_json = json.load(schema_handle) | 
|  | 358 |  | 
|  | 359 | try: | 
|  | 360 | jsonschema.validate(config_json, schema_json) | 
|  | 361 | except jsonschema.ValidationError as e: | 
|  | 362 | print(e) | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 363 | handle_validation_error() | 
|  | 364 |  | 
|  | 365 | return config_json | 
| Bob King | 5cc0128 | 2019-12-17 18:11:57 +0800 | [diff] [blame] | 366 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 367 |  | 
| Bob King | b7552f0 | 2020-10-15 14:34:17 +0800 | [diff] [blame] | 368 | def validate_JSON_format(file): | 
|  | 369 | with open(file) as json_data: | 
|  | 370 | try: | 
|  | 371 | return json.load(json_data) | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 372 | except ValueError: | 
| Bob King | b7552f0 | 2020-10-15 14:34:17 +0800 | [diff] [blame] | 373 | return False | 
|  | 374 | return True | 
|  | 375 |  | 
| Bob King | 5cc0128 | 2019-12-17 18:11:57 +0800 | [diff] [blame] | 376 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 377 | if __name__ == "__main__": | 
| Bob King | 5cc0128 | 2019-12-17 18:11:57 +0800 | [diff] [blame] | 378 | parser = argparse.ArgumentParser( | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 379 | description="phosphor-regulators configuration file validator" | 
|  | 380 | ) | 
| Bob King | 5cc0128 | 2019-12-17 18:11:57 +0800 | [diff] [blame] | 381 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 382 | parser.add_argument( | 
|  | 383 | "-s", | 
|  | 384 | "--schema-file", | 
|  | 385 | dest="schema_file", | 
|  | 386 | help="The phosphor-regulators schema file", | 
|  | 387 | ) | 
| Bob King | 5cc0128 | 2019-12-17 18:11:57 +0800 | [diff] [blame] | 388 |  | 
| Patrick Williams | a93243d | 2022-12-05 09:20:34 -0600 | [diff] [blame] | 389 | parser.add_argument( | 
|  | 390 | "-c", | 
|  | 391 | "--configuration-file", | 
|  | 392 | dest="configuration_file", | 
|  | 393 | help="The phosphor-regulators configuration file", | 
|  | 394 | ) | 
| Bob King | 5cc0128 | 2019-12-17 18:11:57 +0800 | [diff] [blame] | 395 |  | 
|  | 396 | args = parser.parse_args() | 
|  | 397 |  | 
|  | 398 | if not args.schema_file: | 
|  | 399 | parser.print_help() | 
|  | 400 | sys.exit("Error: Schema file is required.") | 
| Bob King | b7552f0 | 2020-10-15 14:34:17 +0800 | [diff] [blame] | 401 | if not os.path.exists(args.schema_file): | 
|  | 402 | parser.print_help() | 
|  | 403 | sys.exit("Error: Schema file does not exist.") | 
|  | 404 | if not os.access(args.schema_file, os.R_OK): | 
|  | 405 | parser.print_help() | 
|  | 406 | sys.exit("Error: Schema file is not readable.") | 
|  | 407 | if not validate_JSON_format(args.schema_file): | 
|  | 408 | parser.print_help() | 
|  | 409 | sys.exit("Error: Schema file is not in the JSON format.") | 
| Bob King | 5cc0128 | 2019-12-17 18:11:57 +0800 | [diff] [blame] | 410 | if not args.configuration_file: | 
|  | 411 | parser.print_help() | 
|  | 412 | sys.exit("Error: Configuration file is required.") | 
| Bob King | b7552f0 | 2020-10-15 14:34:17 +0800 | [diff] [blame] | 413 | if not os.path.exists(args.configuration_file): | 
|  | 414 | parser.print_help() | 
|  | 415 | sys.exit("Error: Configuration file does not exist.") | 
|  | 416 | if not os.access(args.configuration_file, os.R_OK): | 
|  | 417 | parser.print_help() | 
|  | 418 | sys.exit("Error: Configuration file is not readable.") | 
|  | 419 | if not validate_JSON_format(args.configuration_file): | 
|  | 420 | parser.print_help() | 
|  | 421 | sys.exit("Error: Configuration file is not in the JSON format.") | 
| Bob King | 5cc0128 | 2019-12-17 18:11:57 +0800 | [diff] [blame] | 422 |  | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 423 | config_json = validate_schema(args.configuration_file, args.schema_file) | 
| Bob King | d114cd9 | 2020-02-10 13:56:02 +0800 | [diff] [blame] | 424 |  | 
| Bob King | 95b796a | 2020-01-15 14:45:06 +0800 | [diff] [blame] | 425 | check_for_duplicates(config_json) | 
| Bob King | d114cd9 | 2020-02-10 13:56:02 +0800 | [diff] [blame] | 426 |  | 
|  | 427 | check_infinite_loops(config_json) | 
|  | 428 |  | 
| Bob King | 23dd60b | 2020-02-26 10:23:21 +0800 | [diff] [blame] | 429 | check_run_rule_value_exists(config_json) | 
| Bob King | e959754 | 2020-02-26 10:47:40 +0800 | [diff] [blame] | 430 |  | 
|  | 431 | check_set_device_value_exists(config_json) | 
| Bob King | 9146df2 | 2020-02-26 10:49:33 +0800 | [diff] [blame] | 432 |  | 
|  | 433 | check_rule_id_exists(config_json) | 
| Bob King | a533d70 | 2020-02-26 10:51:24 +0800 | [diff] [blame] | 434 |  | 
| Shawn McCarney | 5d4a9c7 | 2021-08-19 18:45:59 -0500 | [diff] [blame] | 435 | check_device_id_exists(config_json) | 
|  | 436 |  | 
| Bob King | a533d70 | 2020-02-26 10:51:24 +0800 | [diff] [blame] | 437 | check_number_of_elements_in_masks(config_json) |