Bailey Henry 2d8e2fbaae libvirt: Yaml validator
Test plan:
    PASS: No pylint errors
    PASS: No pep8 errors
    PASS: All data validation accurate
    PASS: Misc Fixes relating to efficiency

Story: 2010816
Task: 48424

Change-Id: I54b48ca0f05c48989c5ae8fb7d18c7ae12d2faad
Signed-off-by: Bailey Henry <Henry.Bailey@windriver.com>
2023-07-25 14:42:20 +00:00

173 lines
4.4 KiB
Python
Executable File

#!/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("use: ./config.py <config_file> <key>"
" or use: ./config.py --validate <config_file>",
file=sys.stderr)
# 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:
content = yaml.load(f, Loader=yaml.Loader)
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)
if __name__ == "__main__":
args = sys.argv[1:]
if '--help' in args:
print_help()
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]
input_key = args[1]
readvalue(input_file, input_key)
elif len(args) < 2:
print("Error: missing required arguments.",
file=sys.stderr)
print_help()
sys.exit(1)
else:
print("Error: too many arguments.",
file=sys.stderr)
print_help()
sys.exit(1)