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_rule_id(config_json): 17 r""" 18 Check that there aren't any "rule" elements with the same 'id' field. 19 config_json: Configuration file JSON 20 """ 21 rule_ids = [] 22 for rule in config_json.get('rules', {}): 23 rule_id = rule['id'] 24 if rule_id in rule_ids: 25 sys.stderr.write("Error: Duplicate rule ID.\n"+\ 26 "Found multiple rules with the ID "+rule_id+'\n') 27 handle_validation_error() 28 else: 29 rule_ids.append(rule_id) 30 31def check_duplicate_chassis_number(config_json): 32 r""" 33 Check that there aren't any "chassis" elements with the same 'number' field. 34 config_json: Configuration file JSON 35 """ 36 numbers = [] 37 for chassis in config_json.get('chassis', {}): 38 number = chassis['number'] 39 if number in numbers: 40 sys.stderr.write("Error: Duplicate chassis number.\n"+\ 41 "Found multiple chassis with the number "+str(number)+'\n') 42 handle_validation_error() 43 else: 44 numbers.append(number) 45 46def check_duplicate_device_id(config_json): 47 r""" 48 Check that there aren't any "devices" with the same 'id' field. 49 config_json: Configuration file JSON 50 """ 51 device_ids = [] 52 for chassis in config_json.get('chassis', {}): 53 for device in chassis.get('devices', {}): 54 device_id = device['id'] 55 if device_id in device_ids: 56 sys.stderr.write("Error: Duplicate device ID.\n"+\ 57 "Found multiple devices with the ID "+device_id+'\n') 58 handle_validation_error() 59 else: 60 device_ids.append(device_id) 61 62def check_duplicate_rail_id(config_json): 63 r""" 64 Check that there aren't any "rails" with the same 'id' field. 65 config_json: Configuration file JSON 66 """ 67 rail_ids = [] 68 for chassis in config_json.get('chassis', {}): 69 for device in chassis.get('devices', {}): 70 for rail in device.get('rails', {}): 71 rail_id = rail['id'] 72 if rail_id in rail_ids: 73 sys.stderr.write("Error: Duplicate rail ID.\n"+\ 74 "Found multiple rails with the ID "+rail_id+'\n') 75 handle_validation_error() 76 else: 77 rail_ids.append(rail_id) 78 79def check_for_duplicates(config_json): 80 r""" 81 Check for duplicate ID. 82 """ 83 check_duplicate_rule_id(config_json) 84 85 check_duplicate_chassis_number(config_json) 86 87 check_duplicate_device_id(config_json) 88 89 check_duplicate_rail_id(config_json) 90 91def validate_schema(config, schema): 92 r""" 93 Validates the specified config file using the specified 94 schema file. 95 96 config: Path of the file containing the config JSON 97 schema: Path of the file containing the schema JSON 98 """ 99 100 with open(config) as config_handle: 101 config_json = json.load(config_handle) 102 103 with open(schema) as schema_handle: 104 schema_json = json.load(schema_handle) 105 106 try: 107 jsonschema.validate(config_json, schema_json) 108 except jsonschema.ValidationError as e: 109 print(e) 110 handle_validation_error() 111 112 return config_json 113 114if __name__ == '__main__': 115 116 parser = argparse.ArgumentParser( 117 description='phosphor-regulators configuration file validator') 118 119 parser.add_argument('-s', '--schema-file', dest='schema_file', 120 help='The phosphor-regulators schema file') 121 122 parser.add_argument('-c', '--configuration-file', dest='configuration_file', 123 help='The phosphor-regulators configuration file') 124 125 args = parser.parse_args() 126 127 if not args.schema_file: 128 parser.print_help() 129 sys.exit("Error: Schema file is required.") 130 if not args.configuration_file: 131 parser.print_help() 132 sys.exit("Error: Configuration file is required.") 133 134 config_json = validate_schema(args.configuration_file, args.schema_file) 135 check_for_duplicates(config_json) 136