From c713c483357b097273bc1e46d79aa1c9ab6ea9d1 Mon Sep 17 00:00:00 2001 From: suiguoxin Date: Thu, 17 Dec 2020 17:54:27 +0800 Subject: [PATCH 1/2] layout schema check --- contrib/kubespray/quick-start-kubespray.sh | 3 + contrib/kubespray/script/environment.sh | 7 +- .../script/validate_layout_schema.py | 118 ++++++++++++++++++ 3 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 contrib/kubespray/script/validate_layout_schema.py diff --git a/contrib/kubespray/quick-start-kubespray.sh b/contrib/kubespray/quick-start-kubespray.sh index 1ec5346cad..b8c5bb9999 100644 --- a/contrib/kubespray/quick-start-kubespray.sh +++ b/contrib/kubespray/quick-start-kubespray.sh @@ -7,6 +7,9 @@ CLUSTER_CONFIG="$PWD/config/config.yaml" echo "layout config file path: ${LAYOUT}" echo "cluster config file path: ${CLUSTER_CONFIG}" +echo "Checking layout.yaml schema..." +python3 script/validate_layout_schema.py -l ${LAYOUT} + echo "Setting up environment..." /bin/bash script/environment.sh -c ${CLUSTER_CONFIG} || exit $? diff --git a/contrib/kubespray/script/environment.sh b/contrib/kubespray/script/environment.sh index fa6840b9d8..6a36a51226 100644 --- a/contrib/kubespray/script/environment.sh +++ b/contrib/kubespray/script/environment.sh @@ -33,11 +33,8 @@ sudo apt-get -y install software-properties-common python3 python3-dev curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py sudo python3 get-pip.py -echo "Install paramiko" -sudo pip3 install paramiko - -echo "Install kubernetes package" -sudo pip3 install kubernetes +echo "Install python packages" +sudo pip3 install paramiko kubernetes schema echo "Install sshpass" sudo apt-get -y install sshpass diff --git a/contrib/kubespray/script/validate_layout_schema.py b/contrib/kubespray/script/validate_layout_schema.py new file mode 100644 index 0000000000..333e22930e --- /dev/null +++ b/contrib/kubespray/script/validate_layout_schema.py @@ -0,0 +1,118 @@ +import argparse +import logging +import logging.config +import sys +from schema import Schema, Or, Optional, Regex +import yaml + + +def setup_logger_config(logger): + """ + Setup logging configuration. + """ + if len(logger.handlers) == 0: + logger.propagate = False + logger.setLevel(logging.DEBUG) + consoleHandler = logging.StreamHandler() + consoleHandler.setLevel(logging.DEBUG) + formatter = logging.Formatter('%(asctime)s [%(levelname)s] - %(filename)s:%(lineno)s : %(message)s') + consoleHandler.setFormatter(formatter) + logger.addHandler(consoleHandler) + +logger = logging.getLogger(__name__) +setup_logger_config(logger) + + +def load_yaml_config(config_path): + with open(config_path, "r") as f: + config_data = yaml.load(f, yaml.SafeLoader) + return config_data + + +def validate_layout_schema(layout): + schema = Schema( + { + 'machine-sku': { + str: { + 'mem': str, + 'cpu': { + 'vcore': int, + }, + Optional('computing-device'): { + 'type': str, + 'model': str, + 'count': int, + } + } + }, + 'machine-list': [ + { + 'hostname': str, + 'hostip': Regex(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"), + 'machine-type': str, + Optional('pai-master'): Or('true', 'false'), + Optional('pai-worker'): Or('true', 'false'), + Optional('pai-storage'): Or('true', 'false'), + } + ] + } + ) + return schema.validate(layout) + + +def check_layout(layout): + # hostname / hostip should be unique + hostnames = [elem['hostname'] for elem in layout['machine-list']] + if len(hostnames) != len(set(hostnames)): + logger.error("hostname should be unique") + return False + hostips = [elem['hostip'] for elem in layout['machine-list']] + if len(hostips) != len(set(hostips)): + logger.error("hostip should be unique") + return False + + # machine-type should be defined in machine-sku + for machine in layout['machine-list']: + if machine['machine-type'] not in layout['machine-sku']: + logger.error("machine-type {} is not defined".format(machine['machine-type'])) + return False + + masters = list(filter(lambda elem: 'pai-master' in elem and elem["pai-master"] == 'true', layout['machine-list'])) + # only one pai-master + if len(masters) == 0: + logger.error('No master machine specified.') + return False + if len(masters) > 1: + logger.error('More than one master machine specified.') + return False + + # pai-master / pai-worker cannot be true at the same time + if 'pai-worker' in masters[0] and masters[0]['pai-worker'] == 'true': + logger.error("One machine can not be pai-master and pai-worker at the same time.") + return False + + return True + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('-l', '--layout', dest="layout", required=True, + help="layout.yaml") + args = parser.parse_args() + + layout = load_yaml_config(args.layout) + try: + validate_layout_schema(layout) + except Exception as exp: + logger.error("layout.yaml schema validation failed: \n %s", exp) + sys.exit(1) + + if not check_layout(layout): + logger.error("layout.yaml schema validation failed") + sys.exit(1) + + logger.info("layout.yaml schema validation succeeded.") + + +if __name__ == "__main__": + main() From 1e6fbeff51ebd9bd14ca9d20a8d6b8d7d33ae0ab Mon Sep 17 00:00:00 2001 From: suiguoxin Date: Mon, 21 Dec 2020 12:56:32 +0800 Subject: [PATCH 2/2] fix --- contrib/kubespray/script/pre-check-generator.py | 1 - contrib/kubespray/script/validate_layout_schema.py | 9 +++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/contrib/kubespray/script/pre-check-generator.py b/contrib/kubespray/script/pre-check-generator.py index bbfb191f31..8f0f0019b0 100644 --- a/contrib/kubespray/script/pre-check-generator.py +++ b/contrib/kubespray/script/pre-check-generator.py @@ -76,7 +76,6 @@ def main(): # fill in cpu, memory, computing_device information in both masters and workers # we assume the layout file the user gives is correct - # TO DO: check layout file before this step all_machines = masters + workers for machine in all_machines: sku_info = layout['machine-sku'][machine['machine-type']] diff --git a/contrib/kubespray/script/validate_layout_schema.py b/contrib/kubespray/script/validate_layout_schema.py index 333e22930e..7872f660e2 100644 --- a/contrib/kubespray/script/validate_layout_schema.py +++ b/contrib/kubespray/script/validate_layout_schema.py @@ -47,7 +47,8 @@ def validate_layout_schema(layout): }, 'machine-list': [ { - 'hostname': str, + # https://github.com/kubernetes-sigs/kubespray/blob/release-2.11/roles/kubernetes/preinstall/tasks/0020-verify-settings.yml#L124 + 'hostname': Regex(r"^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"), 'hostip': Regex(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"), 'machine-type': str, Optional('pai-master'): Or('true', 'false'), @@ -78,6 +79,7 @@ def check_layout(layout): return False masters = list(filter(lambda elem: 'pai-master' in elem and elem["pai-master"] == 'true', layout['machine-list'])) + workers = list(filter(lambda elem: 'pai-worker' in elem and elem["pai-worker"] == 'true', layout['machine-list'])) # only one pai-master if len(masters) == 0: logger.error('No master machine specified.') @@ -85,7 +87,10 @@ def check_layout(layout): if len(masters) > 1: logger.error('More than one master machine specified.') return False - + # at least one pai-worker + if len(workers) == 0: + logger.error('No worker machine specified.') + return False # pai-master / pai-worker cannot be true at the same time if 'pai-worker' in masters[0] and masters[0]['pai-worker'] == 'true': logger.error("One machine can not be pai-master and pai-worker at the same time.")