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