9c5bfecb48d98c3978a7a53fd8a1a049f0d82516
[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
48         [[ "$e" == "$match" ]] && return 0
49     done
50     return 1
51 }
52
53 # check prereqs
54 if [ ! -d "$configdir" ] || [ ! -d "$jjbdir" ]; then
55     echo "ERROR: failed to find subdirs $configdir and $jjbdir"
56     exit 1
57 fi
58
59 # find cloud config node names by recursive descent
60 declare -a labels=()
61 while IFS= read -r ; do
62     file="$REPLY"
63     # valid files contain IMAGE_NAME; skip the cloud config file
64     if grep -q "IMAGE_NAME" "$file" && ! grep -q "CLOUD_CREDENTIAL_ID" "$file"; then
65         # file name without prefix or suffix is a valid label
66         name=$(basename -s "$suffix" "$file")
67         echo "INFO: add label $name for $file"
68         labels+=("$name")
69         # add custom labels from file
70         if custom=$(grep "LABELS=" "$file" | cut -d= -f2); then
71             # TODO: confirm separator for multiple labels
72             read -r -a customarray <<< "$custom"
73             for l in "${customarray[@]}"; do
74                 if isBadLabel "$l"; then
75                     echo "WARN: skip custom label $l from $file"
76                 elif isValueInArray "$l" "${labels[@]}"; then
77                     echo "INFO: skip repeat custom label $l from $file"
78                 else
79                     echo "INFO: add custom label $l from $file"
80                     labels+=("$l")
81                 fi
82             done
83         fi
84     fi
85 done < <(find "$configdir" -name \*$suffix)
86
87 # add external build-node labels
88 if [[ -n ${EXTERNAL_LABELS:-} ]]; then
89     read -r -a externals <<< "$EXTERNAL_LABELS"
90     # defend against empty, quotes-only and repeated values
91     for l in "${externals[@]}"; do
92         if isBadLabel "$l"; then
93             echo "WARN: skip external label $l"
94         elif isValueInArray "$l" "${labels[@]}"; then
95             echo "INFO: skip repeat label $l from environment"
96         else
97             echo "INFO: add label $l from environment"
98             labels+=("$l")
99         fi
100     done
101 fi
102
103 echo "INFO: label list has ${#labels[@]} entries:"
104 echo "INFO:" "${labels[@]}"
105
106 # check build-node label uses
107 count=0
108 errs=0
109 while IFS= read -r ; do
110     file="$REPLY"
111     echo "INFO: checking $file"
112     # includes job-template AND project entries
113     nodes=$(yq 'recurse | ."build-node"? | values' "$file" | sort -u | tr -d '"')
114     # nodes may be a yaml list; e.g., '[ foo, bar, baz ]'
115     for node in $nodes; do
116         node="${node//[\[\],]/}"
117         if [[ -n $node ]] && ! isValueInArray "$node" "${labels[@]}"; then
118             echo "ERROR: unknown build-node $node in $file"
119             errs=$((errs+1))
120         else
121             count=$((count+1))
122         fi
123     done
124 done < <(find "$jjbdir" -name '*.yaml')
125
126 echo "INFO: $count valid label(s), $errs invalid label(s)"
127 echo "---> jjb-verify-build-nodes.sh ends"
128 exit $errs