From 58776ad5961580fcdc1cc56a9309e9da52e7673c Mon Sep 17 00:00:00 2001 From: "Lott, Christopher (cl778h)" Date: Tue, 7 Apr 2020 09:11:26 -0400 Subject: [PATCH] Add doc for jjb-verify build-node label check Document the jjb-verify feature that checks build-node labels named in JJB YAML files against nodes in cloud config files. Change the feature's JJB configuration variables to share a prefix. Improve the shell script to be robust to errors such as a suffix of ".cfg" or an external label of "" (just two double quotes). Change-Id: I8beb5669531fe2b7f59a9bcf3706b27ede3965b9 Issue-ID: RELENG-2828 Signed-off-by: Lott, Christopher (cl778h) --- docs/jjb/lf-ci-jobs.rst | 7 +- jjb/lf-ci-jobs.yaml | 8 +-- ...b-verify-build-nodes-doc-cdb47bfa721775923.yaml | 8 +++ shell/jjb-verify-build-nodes.sh | 82 ++++++++++++++++------ 4 files changed, 78 insertions(+), 27 deletions(-) create mode 100644 releasenotes/notes/jjb-verify-build-nodes-doc-cdb47bfa721775923.yaml diff --git a/docs/jjb/lf-ci-jobs.rst b/docs/jjb/lf-ci-jobs.rst index 65568e2d..0323bd2e 100644 --- a/docs/jjb/lf-ci-jobs.rst +++ b/docs/jjb/lf-ci-jobs.rst @@ -443,7 +443,8 @@ Runs `jenkins-jobs update` to update production job configuration JJB Verify ---------- -Runs `jenkins-jobs test` to validate JJB syntax +Runs `jenkins-jobs test` to validate JJB syntax. Optionally validates +build-node labels used in templates and job definitions. :Template Names: - {project-name}-jjb-verify @@ -464,6 +465,10 @@ Runs `jenkins-jobs test` to validate JJB syntax :build-concurrent: Whether or not to allow this job to run multiple jobs simultaneously. (default: true) :build-days-to-keep: Days to keep build logs in Jenkins. (default: 7) + :build-node-label-check: Whether to check build-node labels in jobs + against node names in cloud config files (default: false) + :build-node-label-list: Space-separated list of external build-node + labels not present in cloud config files (default: "") :build-timeout: Timeout in minutes before aborting build. (default: 10) :git-url: URL clone project from. (default: $GIT_URL/$PROJECT) :jjb-cache: JJB cache location. (default: $HOME/.cache/jenkins_jobs) diff --git a/jjb/lf-ci-jobs.yaml b/jjb/lf-ci-jobs.yaml index 9ecd38fc..635bc67e 100644 --- a/jjb/lf-ci-jobs.yaml +++ b/jjb/lf-ci-jobs.yaml @@ -822,8 +822,8 @@ ###################### build-concurrent: true - check-build-node-labels: false - external-build-node-labels: "" + build-node-label-check: false + build-node-label-list: "" gerrit_verify_triggers: - patchset-created-event: @@ -847,11 +847,11 @@ - ../shell/jjb-verify-job.sh - conditional-step: condition-kind: boolean-expression - condition-expression: "{check-build-node-labels}" + condition-expression: "{build-node-label-check}" on-evaluation-failure: dont-run steps: - inject: - properties-content: EXTERNAL_LABELS="{external-build-node-labels}" + properties-content: EXTERNAL_LABELS="{build-node-label-list}" - shell: !include-raw-escape: - ../shell/jjb-verify-build-nodes.sh - lf-infra-gpg-verify-git-signature diff --git a/releasenotes/notes/jjb-verify-build-nodes-doc-cdb47bfa721775923.yaml b/releasenotes/notes/jjb-verify-build-nodes-doc-cdb47bfa721775923.yaml new file mode 100644 index 00000000..69d13ecd --- /dev/null +++ b/releasenotes/notes/jjb-verify-build-nodes-doc-cdb47bfa721775923.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Document the jjb-verify feature that checks build-node labels named + in JJB YAML files against nodes in cloud config files. + Change the feature's JJB configuration variables to share a prefix. + Improve the shell script to be robust to errors such as a suffix of + ".cfg" or an external label of "" (just two double quotes). diff --git a/shell/jjb-verify-build-nodes.sh b/shell/jjb-verify-build-nodes.sh index 94831181..b4457e42 100644 --- a/shell/jjb-verify-build-nodes.sh +++ b/shell/jjb-verify-build-nodes.sh @@ -17,14 +17,27 @@ echo "---> jjb-verify-build-nodes.sh" # Prereqs: # - Bash version 3+ # - Python tool yq is installed; e.g., by python-tools-install.sh -# - Working directory is a ci-management repo with subdirs -# jenkins-config/clouds/openstack and jjb +# - Working directory is a ci-management repo with subdirs named below # Environment variable: # - EXTERNAL_LABELS - a space-separated list of build-node labels # for nodes not managed in the jenkins-config area (optional) set -eu -o pipefail +# expected suffix on build-node config files +suffix=".cfg" +# subdir with cloud config files +configdir="jenkins-config/clouds/openstack" +# subdir with JJB yaml files +jjbdir="jjb" + +# function to test if the argument is empty, +# is two double quotes, or has unwanted suffix +isBadLabel () { + local label="$1" + [[ -z "$label" ]] || [[ $label = "\"\"" ]] || [[ $label = *"$suffix" ]] +} + # function to search an array for a value # $1 is value # $2 is array, passed via ${array[@]} @@ -35,54 +48,79 @@ isValueInArray () { return 1 } -# discover build node labels +# check prereqs +if [ ! -d "$configdir" ] || [ ! -d "$jjbdir" ]; then + echo "ERROR: failed to find subdirs $configdir and $jjbdir" + exit 1 +fi + +# find cloud config node names by recursive descent declare -a labels=() -suffix=".cfg" while IFS= read -r ; do file="$REPLY" # valid files contain IMAGE_NAME; skip the cloud config file if grep -q "IMAGE_NAME" "$file" && ! grep -q "CLOUD_CREDENTIAL_ID" "$file"; then - # file name is a valid label, without path prefix and suffix + # file name without prefix or suffix is a valid label name=$(basename -s "$suffix" "$file") + echo "INFO: add label $name for $file" labels+=("$name") - # a file can define custom labels + # add custom labels from file if custom=$(grep "LABELS=" "$file" | cut -d= -f2); then # TODO: confirm separator for multiple labels read -r -a customarray <<< "$custom" - for c in "${customarray[@]}"; do - if ! isValueInArray "$c" "${labels[@]}"; then - labels+=("$c") + for l in "${customarray[@]}"; do + if isBadLabel "$l"; then + echo "WARN: skip custom label $l from $file" + elif isValueInArray "$l" "${labels[@]}"; then + echo "INFO: skip repeat custom label $l from $file" + else + echo "INFO: add custom label $l from $file" + labels+=("$l") fi done fi fi -done < <(find "jenkins-config/clouds/openstack" -name \*$suffix) -echo "Found ${#labels[@]} configured label(s):" -echo "${labels[@]}" -declare -a externals=() +done < <(find "$configdir" -name \*$suffix) + +# add external build-node labels if [[ -n ${EXTERNAL_LABELS:-} ]]; then read -r -a externals <<< "$EXTERNAL_LABELS" - echo "Received ${#externals[@]} external label(s):" - echo "${externals[@]}" - labels=("${externals[@]}" "${labels[@]}") + # defend against empty, quotes-only and repeated values + for l in "${externals[@]}"; do + if isBadLabel "$l"; then + echo "WARN: skip external label $l" + elif isValueInArray "$l" "${labels[@]}"; then + echo "INFO: skip repeat label $l from environment" + else + echo "INFO: add label $l from environment" + labels+=("$l") + fi + done fi -# check build node label uses +echo "INFO: label list has ${#labels[@]} entries:" +echo "INFO:" "${labels[@]}" + +# check build-node label uses +count=0 errs=0 while IFS= read -r ; do file="$REPLY" - echo "Checking $file" - # this includes job-templates which may be annoying + echo "INFO: checking $file" + # includes job-template AND project entries nodes=$(yq 'recurse | ."build-node"? | values' "$file" | sort -u | tr -d '"') + # nodes may be a yaml list; e.g., '[ foo, bar, baz ]' for node in $nodes; do - # may be a yaml list; e.g., '[ foo, bar, baz ]' node="${node//[\[\],]/}" if [[ -n $node ]] && ! isValueInArray "$node" "${labels[@]}"; then - echo "ERROR: file $file uses unknown build-node $node" + echo "ERROR: unknown build-node $node in $file" errs=$((errs+1)) + else + count=$((count+1)) fi done -done < <(find "jjb" -name '*.yaml') +done < <(find "$jjbdir" -name '*.yaml') +echo "INFO: $count valid label(s), $errs invalid label(s)" echo "---> jjb-verify-build-nodes.sh ends" exit $errs -- 2.16.6