diff --git a/libvirt/config.py b/libvirt/config.py index 0af8006..f58931d 100755 --- a/libvirt/config.py +++ b/libvirt/config.py @@ -1,25 +1,137 @@ #!/usr/bin/python3 +import ipaddress import sys import yaml +# Interface names are limited to 15 characters. 5 are reserved for VLANS +# ('.####'), it also add a single digit for the four enumerated bridges +# of the virtual lab. Meaning that 9 characters are left for the end +# user to choose. +BRIDGE_LIMIT = 9 + +# Fields that should be set in a Yaml configuration file + +GEN_FIELDS = ('bridge_interface', 'controller', 'worker', + 'domain_dir', 'storage') + +IP_FIELDS = ('ext_network', 'ext_IP') + +NODES_NUM = ('worker_nodes_num', 'storage_nodes_num') + +FIELDS = GEN_FIELDS + IP_FIELDS + NODES_NUM + + +# Allows the user to see how this script is used def print_help(): - print("./config.py ", + print("use: ./config.py " + " or use: ./config.py --validate ", file=sys.stderr) -def readvalue(config_file, key): +# Checks if there are any unexpected fields in the file +def existence_check(data): + for key in data: + if key not in FIELDS: + print('unexpected field: %s' % key) + +# Opens the config file and returns its contents +def reader(config_file): try: with open(config_file, 'r', encoding="utf-8") as f: - data = yaml.load(f, Loader=yaml.Loader) + content = yaml.load(f, Loader=yaml.Loader) - value = data[key] - print(value) + return content except yaml.YAMLError as e: print('YAMLError: %s' % e, file=sys.stderr) + sys.exit(1) + except OSError as e: + print('OSError: %s' % e, file=sys.stderr) + sys.exit(1) + + +# Allows the user to check if their configuration values +# exist and are valid +def validator(config_file): + + ERROR = 0 + + data = reader(config_file) + + existence_check(data) + + # For every field checks if they exist and has various checks to + # ensure all values are valid + for field in FIELDS: + + try: + value = data[field] + except KeyError: + print(' %s does not exist' % field) + ERROR += 1 + continue + + # Checking that most fields are alphanumerical + if (field in GEN_FIELDS): + + # Checks if bridge_interface is smaller that nine + # characters long + + if (field == 'bridge_interface' and len(value) > BRIDGE_LIMIT): + + print(field + ' variable too long') + ERROR += 1 + + if value.isalnum() is False: + print(field + ' is not alphanumerical') + ERROR += 1 + + # Checking that there are valid IPv4 addresses + elif (field in IP_FIELDS): + # Removing the /24 subnet mask + try: + IP, netmask = value.split('/') + except ValueError: + print(field + ' does not look like IP/mask', file=sys.stderr) + ERROR += 1 + continue + + try: + netmask = int(netmask) + except ValueError: + print(field + ': not a valid netmask') + ERROR += 1 + + try: + ipaddress.ip_address(IP) + except (ValueError): + print(field + ' is not a valid IP address', file=sys.stderr) + ERROR += 1 + + # Checking that node counts are numbers + elif (field in NODES_NUM): + try: + int(value) + except ValueError: + print(field + ' does not have an integer', file=sys.stderr) + ERROR += 1 + + if ERROR > 0: + print('total errors: %s ' % ERROR) + sys.exit(1) + + +# Allows the user to read any value in their configuration file +def readvalue(config_file, key): + data = reader(config_file) + + try: + value = data[key] + print(value) + except KeyError as e: print('KeyError: %s' % e, file=sys.stderr) @@ -29,7 +141,18 @@ if __name__ == "__main__": if '--help' in args: print_help() - sys.exit(1) + sys.exit(0) + + if '--validate' == args[0]: + if len(args) == 2: + validator(args[1]) + sys.exit(0) + + else: + print('Validate requires only one parameter: config_file', + file=sys.stderr) + print_help() + sys.exit(1) if len(args) == 2: input_file = args[0]