From 4f864eedc2dd9dd14e7602e81568fec4f0f9d4d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20K=C3=A4sser?= Date: Wed, 13 Nov 2024 10:57:39 +0100 Subject: [PATCH] Add functionality for `crossplane validate` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tobias Kässer --- makelib/uptest.mk | 84 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 5 deletions(-) diff --git a/makelib/uptest.mk b/makelib/uptest.mk index 0937ffa..1708ec0 100644 --- a/makelib/uptest.mk +++ b/makelib/uptest.mk @@ -63,7 +63,7 @@ e2e: build controlplane.down controlplane.up $(UPTEST_LOCAL_DEPLOY_TARGET) uptes # # Composition and Function must be defined, Environment and Observeed Resources are optionally available. # The command discovers sees by parsing the `render.crossplane.io/*`-annotations of file found in the -# examples-directorry, usually: `/examples` +# examples-directorry, usually: `/examples`. This folder can be overwritten: UPTEST_EXAMPLES_FOLDER='other-examples/' # # Possible values are: # - composition-path (Composition) @@ -73,17 +73,33 @@ e2e: build controlplane.down controlplane.up $(UPTEST_LOCAL_DEPLOY_TARGET) uptes # # Example: `render.crossplane.io/composition-path: "apis/kcl/composition.yaml"` # +# Alternatively the user is able to specify `UPTEST_RENDER_FILES` with a comma or space-separated list +# of files to render. +# +# Example: `make render UPTEST_RENDER_FILES="path/to/example.yaml,another-example.yaml` +UPTEST_RENDER_FILES ?= +UPTEST_EXAMPLES_FOLDER ?= ./examples render: $(CROSSPLANE_CLI) ${YQ} - @indir="./examples"; \ + @indir="$(UPTEST_EXAMPLES_FOLDER)"; \ rm -rf "$(CACHE_DIR)/render"; \ mkdir -p "$(CACHE_DIR)/render" || true; \ - for file in $$(find $$indir -type f -name '*.yaml' ); do \ + if [ -z $${UPTEST_RENDER_FILES} ]; then \ + FILES=$$(find $$indir -type f -name '*.yaml' ); \ + else \ + FILES=$$(echo $${UPTEST_RENDER_FILES} | sed 's/,/ /g'); \ + fi; \ + $(INFO) Files to render: $${FILES}; \ + for file in $${FILES}; do \ doc_count=$$(${YQ} eval 'documentIndex' $$file | wc -l); \ for i in $$(seq 0 $$(($$doc_count - 1))); do \ COMPOSITION=$$(${YQ} eval "select(documentIndex == $$i) | .metadata.annotations.\"render.crossplane.io/composition-path\"" $$file); \ FUNCTION=$$(${YQ} eval "select(documentIndex == $$i) | .metadata.annotations.\"render.crossplane.io/function-path\"" $$file); \ ENVIRONMENT=$$(${YQ} eval "select(documentIndex == $$i) | .metadata.annotations.\"render.crossplane.io/environment-path\"" $$file); \ OBSERVE=$$(${YQ} eval "select(documentIndex == $$i) | .metadata.annotations.\"render.crossplane.io/observe-path\"" $$file); \ + IS_CROSSPLANE_OBJ=$$(${YQ} eval "select(documentIndex == $$i).apiVersion" $$file | grep -E "^pkg\.crossplane\.io|^apiextensions\.crossplane\.io"); \ + if [ ! -z "$$IS_CROSSPLANE_OBJ" ]; then \ + continue; \ + fi; \ if [[ "$$ENVIRONMENT" == "null" ]]; then \ ENVIRONMENT=""; \ fi; \ @@ -91,19 +107,77 @@ render: $(CROSSPLANE_CLI) ${YQ} OBSERVE=""; \ fi; \ if [[ "$$COMPOSITION" == "null" || "$$FUNCTION" == "null" ]]; then \ + $(WARN) file $$file has document with no annotations for rendering, skipping; \ continue; \ fi; \ OUT_FILE=$$(echo $$file | md5sum | head -c5); \ ENVIRONMENT=$${ENVIRONMENT=="null" ? "" : $$ENVIRONMENT}; \ OBSERVE=$${OBSERVE=="null" ? "" : $$OBSERVE}; \ + $(INFO) rendering $$file; \ $(CROSSPLANE_CLI) render $$file $$COMPOSITION $$FUNCTION $${ENVIRONMENT:+-e $$ENVIRONMENT} $${OBSERVE:+-o $$OBSERVE} -x >> "$(CACHE_DIR)/render/$${OUT_FILE}.yaml"; \ + if [ $$? != 0 ]; then \ + $(ERR) fail rendering $$file; \ + exit 1; \ + fi; \ + $(OK) rendered $$file; \ done; \ done # Prints the raw rendered yaml to stdout +# +# User can restrict the files to be shown with a comma or space-separated list +# of files to render. +# +# Example: `make render.show UPTEST_RENDER_FILES="path/to/example.yaml,another-example.yaml` render.show: - @$(MAKE) render > /dev/null - @find "$(CACHE_DIR)/render" -type f -name "*.yaml" -exec cat {} \; + @$(MAKE) render UPTEST_RENDER_FILES=$${UPTEST_RENDER_FILES} >/dev/null + @if [ -z $${UPTEST_RENDER_FILES} ]; then \ + find "$(CACHE_DIR)/render" -type f -name "*.yaml" -exec cat {} \; ; \ + else \ + EXAMPLE_FILES=$$(echo $${UPTEST_RENDER_FILES} | sed 's/,/ /g'); \ + for file in $${EXAMPLE_FILES}; do \ + OUT_FILE=$$(echo $$file | md5sum | head -c5); \ + OUT_FILE="$(CACHE_DIR)/render/$${OUT_FILE}.yaml"; \ + if [ -f $${OUT_FILE} ]; then \ + cat "$${OUT_FILE}"; \ + fi; \ + done; \ + fi; \ + +# Validates the rendered output +# +# User can supply custom extensions-folder or file with UPTEST_VALIDATE_EXTENSIONS=path/to/extension +# Additionally there is the ability to restrict which files should be rendered. Samne rules apply as +# for `render` and `render.show` command +# +# Note: Extension in this context means: +# - an XRD +# - any provider of function-definition (providers.yaml, functions.yaml) +# - a `crossplane.yaml` +# +# Examle: `make render.validate UPTEST_VALIDATE_EXTENSIONS='some/folder` +UPTEST_VALIDATE_EXTENSIONS ?= crossplane.yaml +render.validate: + @if [ -z $${UPTEST_RENDER_FILES} ]; then \ + EXAMPLE_FILES=$$(find $(UPTEST_EXAMPLES_FOLDER) -type f -name '*.yaml' ); \ + else \ + EXAMPLE_FILES=$$(echo $${UPTEST_RENDER_FILES} | sed 's/,/ /g'); \ + fi; \ + for file in $${EXAMPLE_FILES}; do \ + $(INFO) validating $$file; \ + RENDERED=$$($(MAKE) render.show UPTEST_RENDER_FILES=$${file}); \ + if [ -z "$${RENDERED}" ]; then \ + $(WARN) render produced empty output for: $$file; \ + continue; \ + fi; \ + echo "$${RENDERED}" | $(CROSSPLANE_CLI) beta validate $(UPTEST_VALIDATE_EXTENSIONS) - ; \ + if [ $$? -ne 0 ]; then \ + $(ERR) fail validating $$file; \ + exit 1; \ + fi; \ + $(OK) validated $$file; \ + done; + YAMLLINT_FOLDER ?= ./apis yamllint: ## Static yamllint check