diff --git a/README.md b/README.md index c5c78e972..facbd9e91 100644 --- a/README.md +++ b/README.md @@ -286,7 +286,7 @@ Generic templated configuration management for Kubernetes, Terraform and other things positional arguments: - {eval,compile,inventory,searchvar,secrets,lint,init} + {eval,compile,inventory,searchvar,secrets,lint,init,validate} commands eval evaluate jsonnet file compile compile targets @@ -296,6 +296,8 @@ positional arguments: lint linter for inventory and secrets init initialize a directory with the recommended kapitan project skeleton. + validate validates the compile output against schemas as + specified in inventory optional arguments: -h, --help show this help message and exit @@ -637,6 +639,41 @@ $ kapitan searchvar parameters.elasticsearch.replicas ./inventory/classes/component/elasticsearch.yml 1 ``` +### kapitan validate + +Validates the schema of compiled output (currently supports Kubernetes manifests). + +Refer to the `minikube-es` inventory in [kapitan inventory](###kapitan-inventory). To validate the schema of the compiled StatefulSet manifest at `compiled/minikube-es/manifests/es-client.yml` (created by `components/elasticsearch/maiin.jsonnet`), add `kapitan.validate` parameters in `minikube-es` inventory. + +```yaml +kapitan: + vars: + target: ${target_name} + namespace: ${target_name} + compile: + - output_path: manifests + input_type: jsonnet + input_paths: + - components/elasticsearch/main.jsonnet + + ### other inputs abbreviated for clarity ### + validate: + - output_paths: + - manifests/es-client.yml + type: kubernetes + kind: statefulset + version: 1.14.0 # optional, defaults to 1.14.0 +``` + +Then run: + +``` +$ kapitan validate -t minikube-es +invalid 'statefulset' manifest at ./compiled/minikube-es/manifests/es-client.yml +['spec'] 'selector' is a required property +``` + + # Kapitan feature proposals See [kapitan_proposals/](docs/kap_proposals/). diff --git a/kapitan/targets.py b/kapitan/targets.py index 07025d7d8..144c09377 100644 --- a/kapitan/targets.py +++ b/kapitan/targets.py @@ -554,7 +554,7 @@ def create_validate_mapping(target_objs, compiled_path): full_output_path = os.path.join(compiled_path, target_name, output_path) if not os.path.isfile(full_output_path): logger.warning("{} does not exist for target '{}'. skipping". - format(full_output_path, target_name)) + format(output_path, target_name)) continue validate_files_map[kind_version_pair].append(full_output_path) else: diff --git a/kapitan/validator/kubernetes_validator.py b/kapitan/validator/kubernetes_validator.py index 1c557a51d..a159dbf78 100644 --- a/kapitan/validator/kubernetes_validator.py +++ b/kapitan/validator/kubernetes_validator.py @@ -42,7 +42,7 @@ def validate(self, validate_paths, **kwargs): validate_instance = yaml.safe_load(fp.read()) errors = sorted(validator.iter_errors(validate_instance), key=lambda e: e.path) if errors: - error_message = 'invalid manifest for {}\n'.format(validate_path) + error_message = "invalid '{}' manifest at {}\n".format(kind, validate_path) error_message += '\n'.join(['{} {}'.format(list(error.path), error.message) for error in errors]) raise KubernetesManifestValidationError(error_message) else: diff --git a/tests/test_kubernetes_validator.py b/tests/test_kubernetes_validator.py index e71d45fbc..53dfcaad6 100644 --- a/tests/test_kubernetes_validator.py +++ b/tests/test_kubernetes_validator.py @@ -79,10 +79,11 @@ def test_validate_command_fail(self): original_file = file_name_format.format('') copied_file = file_name_format.format('_copy') copyfile(original_file, copied_file) + wrong_manifest_kind = 'deployment' with open(original_file, 'r') as fp: d = yaml.safe_load(fp) # change kind from service to deployment - d['parameters']['kapitan']['validate'][0]['kind'] = 'deployment' + d['parameters']['kapitan']['validate'][0]['kind'] = wrong_manifest_kind with open(original_file, 'w') as fp: yaml.dump(d, fp, default_flow_style=False) @@ -94,7 +95,7 @@ def test_validate_command_fail(self): # copy back the original file copyfile(copied_file, original_file) os.remove(copied_file) - self.assertTrue(' '.join(log.output).find('invalid manifest') != -1) + self.assertTrue(' '.join(log.output).find("invalid '{}' manifest".format(wrong_manifest_kind)) != -1) def test_validate_after_compile(self): sys.argv = ['kapitan', 'compile', '-t', 'minikube-mysql', '--validate', '--schemas-path', self.cache_dir]