b4457e4258b41f5e1ad93c71e9529823b301e447
[releng/global-jjb.git] / shell / jjb-verify-build-nodes.sh
1 #!/bin/bash -l
2 # SPDX-License-Identifier: EPL-1.0
3 ##############################################################################
4 # Copyright (c) 2020 The Linux Foundation and others.
5 #
6 # All rights reserved. This program and the accompanying materials
7 # are made available under the terms of the Eclipse Public License v1.0
8 # which accompanies this distribution, and is available at
9 # http://www.eclipse.org/legal/epl-v10.html
10 ##############################################################################
11 echo "---> jjb-verify-build-nodes.sh"
12
13 # Checks build-node labels used in ci-management templates and projects,
14 # and prints file names with invalid values.
15 #
16 # Uses -l to get $HOME/.local/bin on path, where pip puts yq
17 # Prereqs:
18 # - Bash version 3+
19 # - Python tool yq is installed; e.g., by python-tools-install.sh
20 # - Working directory is a ci-management repo with subdirs named below
21 # Environment variable:
22 # - EXTERNAL_LABELS - a space-separated list of build-node labels
23 #   for nodes not managed in the jenkins-config area (optional)
24
25 set -eu -o pipefail
26
27 # expected suffix on build-node config files
28 suffix=".cfg"
29 # subdir with cloud config files
30 configdir="jenkins-config/clouds/openstack"
31 # subdir with JJB yaml files
32 jjbdir="jjb"
33
34 # function to test if the argument is empty,
35 # is two double quotes, or has unwanted suffix
36 isBadLabel () {
37   local label="$1"
38   [[ -z "$label" ]] || [[ $label = "\"\"" ]] || [[ $label = *"$suffix" ]]
39 }
40
41 # function to search an array for a value
42 # $1 is value
43 # $2 is array, passed via ${array[@]}
44 isValueInArray () {
45   local e match="$1"
46   shift
47   for e; do [[ "$e" == "$match" ]] && return 0; done
48   return 1
49 }
50
51 # check prereqs
52 if [ ! -d "$configdir" ] || [ ! -d "$jjbdir" ]; then
53     echo "ERROR: failed to find subdirs $configdir and $jjbdir"
54     exit 1
55 fi
56
57 # find cloud config node names by recursive descent
58 declare -a labels=()
59 while IFS= read -r ; do
60     file="$REPLY"
61     # valid files contain IMAGE_NAME; skip the cloud config file
62     if grep -q "IMAGE_NAME" "$file" && ! grep -q "CLOUD_CREDENTIAL_ID" "$file"; then
63         # file name without prefix or suffix is a valid label
64         name=$(basename -s "$suffix" "$file")
65         echo "INFO: add label $name for $file"
66         labels+=("$name")
67         # add custom labels from file
68         if custom=$(grep "LABELS=" "$file" | cut -d= -f2); then
69             # TODO: confirm separator for multiple labels
70             read -r -a customarray <<< "$custom"
71             for l in "${customarray[@]}"; do
72                 if isBadLabel "$l"; then
73                     echo "WARN: skip custom label $l from $file"
74                 elif isValueInArray "$l" "${labels[@]}"; then
75                     echo "INFO: skip repeat custom label $l from $file"
76                 else
77                     echo "INFO: add custom label $l from $file"
78                     labels+=("$l")
79                 fi
80             done
81         fi
82     fi
83 done < <(find "$configdir" -name \*$suffix)
84
85 # add external build-node labels
86 if [[ -n ${EXTERNAL_LABELS:-} ]]; then
87     read -r -a externals <<< "$EXTERNAL_LABELS"
88     # defend against empty, quotes-only and repeated values
89     for l in "${externals[@]}"; do
90         if isBadLabel "$l"; then
91             echo "WARN: skip external label $l"
92         elif isValueInArray "$l" "${labels[@]}"; then
93             echo "INFO: skip repeat label $l from environment"
94         else
95             echo "INFO: add label $l from environment"
96             labels+=("$l")
97         fi
98     done
99 fi
100
101 echo "INFO: label list has ${#labels[@]} entries:"
102 echo "INFO:" "${labels[@]}"
103
104 # check build-node label uses
105 count=0
106 errs=0
107 while IFS= read -r ; do
108     file="$REPLY"
109     echo "INFO: checking $file"
110     # includes job-template AND project entries
111     nodes=$(yq 'recurse | ."build-node"? | values' "$file" | sort -u | tr -d '"')
112     # nodes may be a yaml list; e.g., '[ foo, bar, baz ]'
113     for node in $nodes; do
114         node="${node//[\[\],]/}"
115         if [[ -n $node ]] && ! isValueInArray "$node" "${labels[@]}"; then
116             echo "ERROR: unknown build-node $node in $file"
117             errs=$((errs+1))
118         else
119             count=$((count+1))
120         fi
121     done
122 done < <(find "$jjbdir" -name '*.yaml')
123
124 echo "INFO: $count valid label(s), $errs invalid label(s)"
125 echo "---> jjb-verify-build-nodes.sh ends"
126 exit $errs