forked from GoogleCloudPlatform/professional-services
-
Notifications
You must be signed in to change notification settings - Fork 0
/
setup.sh
executable file
·405 lines (352 loc) · 14.1 KB
/
setup.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
#!/bin/bash
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# Precommit Hook for K8s Manifest Validation pre-CI/CD pipeline.
# Janine Bariuan and Thomas Desrosiers
#########################################################
####### STEP 0 - DEPENDENCY INSTALLATION PRE-WORK #######
#########################################################
# Unset CDPATH to restore default cd behavior. An exported CDPATH can
# cause cd to output the current directory to STDOUT.
unset CDPATH
# Send errors to STDERR
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
# Define tput sequences for bold text output to terminal
bold=$(tput bold)
normal=$(tput sgr0)
# Define a location to install dependencies
readonly INSTALL_DIR=".oss_dependencies"
readonly KUSTOMIZE_DOWNLOAD_BASE_URL="https://api.github.com/repos/kubernetes-sigs/kustomize/releases"
readonly GATORCLI_DOWNLOAD_BASE_URL="https://api.github.com/repos/open-policy-agent/gatekeeper/releases"
readonly KPT_DOWNLOAD_BASE_URL="https://api.github.com/repos/GoogleContainerTools/kpt/releases"
# Determine OS and System Architecture
opsys=windows
if [[ "$OSTYPE" == linux* ]]; then
opsys=linux
elif [[ "$OSTYPE" == darwin* ]]; then
opsys=darwin
fi
case $(uname -m) in
x86_64)
arch=amd64
;;
arm64)
arch=arm64
;;
ppc64le)
arch=ppc64le
;;
s390x)
arch=s390x
;;
*)
arch=amd64
;;
esac
########################################################
########### STEP 1 - DEPENDENCY INSTALLATION ###########
########################################################
printf "\\nInstalling Dependencies\\n"
# Create install directory and create a file to track versions/defaults
mkdir -p "$PWD/$INSTALL_DIR/"
cd "$PWD/$INSTALL_DIR/" || exit 1
# create empty config.json file if it doesn't exits already.
# if it does exist, store value of each line in the file to a variable
touch dependency_info.txt
# shellcheck disable=SC1091
source dependency_info.txt &>/dev/null
system_info=$SYS_INFO
last_kpt_version=$KPT_VERSION
last_kustomize_version=$KUSTOMIZE_VERSION
last_gator_version=$GATOR_VERSION
#######################################################
################### DEFINE FUNCTIONS ##################
#######################################################
#######################################
# Emulates `readlink -f` behavior, as this is not available by default on MacOS.
# Helps rationalize symlinks or canonical files to the path it represents.
# See: https://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac
# Arguments:
# TARGET_FILE ($1)
# Outputs:
# Writes full path to stdout
#######################################
function readlink_f {
TARGET_FILE=$1
cd "$(dirname "$TARGET_FILE")" || exit 1
TARGET_FILE=$(basename "$TARGET_FILE")
# Iterate down a (possible) chain of symlinks
while [ -L "$TARGET_FILE" ]; do
TARGET_FILE=$(readlink "$TARGET_FILE")
cd "$(dirname "$TARGET_FILE")" || exit 1
TARGET_FILE=$(readlink "$TARGET_FILE")
done
# Compute the canonicalized name by finding the physical path
# for the directory we're in and appending the target file.
PHYS_DIR=$(pwd -P)
RESULT=$PHYS_DIR/$TARGET_FILE
echo "$RESULT"
}
#######################################
# Check if a dependency needs an update.
# If it's determined the dependency doesn't exist or is out of date,
# it will install the latest version.
# Arguments:
# $1 = Base URL of the Github repo
# $2 = Name of tool (ie. kpt, gator, etc.)
# $3 = Format of compressed file (ie. kustomize_v*_${opsys}_${arch}.tar.gz)
# $4 = Format of download url to grep (ie. grep browser_download.*${opsys}_${arch} for Kustomize)
# Outputs:
# Stores the new version in global variable, if changed
#######################################
function install_dependency {
# Need this exact command to work with directory names with spaces.
# shellcheck disable=SC2046
where="$(readlink_f $(printf "%q\\n" "$(PWD)"))/"
# Verify the script can rationalize the current directory into an absolute path
if ! test -d "$where"; then
err "Could not locate your current directory, $where"
exit 1
fi
if [ -d "${where}/$2" ]; then
err "${where}/$2 exists and is a directory. Remove or rename it first."
exit 1
fi
# Create temp directory to pull release history into
tmpDir=$(mktemp -d)
if [[ ! "$tmpDir" || ! -d "$tmpDir" ]]; then
err "Could not create temp dir."
exit 1
fi
# Run installation in temp directory to enable parallel installations
function cleanup {
rm -rf "$tmpDir"
}
trap cleanup EXIT ERR
pushd "$tmpDir" >&/dev/null || exit 1
# Find Latest Release and pull down from repo history
releases=$(curl -s "$1")
if [[ $releases == *"API rate limit exceeded"* ]]; then
err $'\\\nGithub rate-limiter failed the request. Either authenticate or wait a couple of minutes.'
exit 1
fi
# Find most up-to-date release URL and compare to what exists in dependency_info already
# This step will determine if the latest version is already installed, or if it needs to update
RELEASE_URL=$(echo "${releases}" |
grep "$4" |
cut -d '"' -f 4 |
sort -V | tail -n 1)
# Grab the latest version from dependency_info.txt
# If dependency_info.txt shows a version, but the command doesn't exist, download it.
# If neither the command nor the information in dependency_info.txt exist, download it.
if [[ -f "${where}/$2" ]]; then
if [[ "$5" == "$RELEASE_URL" ]]; then
echo "Already have the latest version of $2"
else
echo "Version Change Detected. Installing $2"
# Get latest release from github
curl -sLO "$RELEASE_URL"
# extract file and overwrite the older file if it exists in here
tar -xvf "$3"
# delete source file when finished extracting
rm "$3"
# Bring function into depency folder
cp ./"$2" "$where"
chmod 775 "${where}$2"
printf "\\n"
echo "$2 installed to $where/$2"
# Figure out which var to update in dependency_info.txt
case $2 in
kustomize)
last_kustomize_version=$RELEASE_URL
;;
gator)
last_gator_version=$RELEASE_URL
;;
kpt)
last_kpt_version=$RELEASE_URL
;;
*)
err "Something's not quite right with these Versions"
;;
esac
fi
else
echo "Config lists version, but it is not installed. Installing $2"
# Get latest release from github
curl -sLO "$RELEASE_URL"
# extract file and overwrite the older file if it exists in here
tar -xvf "$3"
# delete source file when finished extracting
rm "$3"
# Bring function into depency folder
cp ./"$2" "$where"
chmod +x "${where}$2"
printf "\\n"
echo "$2 installed to $where/$2"
# Figure out which var to update in dependency_info.txt
case $2 in
kustomize)
last_kustomize_version=$RELEASE_URL
;;
gator)
last_gator_version=$RELEASE_URL
;;
kpt)
last_kpt_version=$RELEASE_URL
;;
*)
err "Something's not quite right with these Versions"
;;
esac
fi
popd >&/dev/null || exit 1
}
######################################################
########## STEP 2 - Install Each Dependency ##########
######################################################
install_dependency \
$KUSTOMIZE_DOWNLOAD_BASE_URL \
kustomize \
kustomize_v*_${opsys}_${arch}.tar.gz \
browser_download.*${opsys}_${arch} \
"$last_kustomize_version"
install_dependency \
$GATORCLI_DOWNLOAD_BASE_URL \
gator \
gator-v*-${opsys}-${arch}.tar.gz \
browser_download.*${opsys}-${arch} \
"$last_gator_version"
install_dependency \
$KPT_DOWNLOAD_BASE_URL \
kpt \
kpt_${opsys}_${arch}*.tar.gz \
browser_download.*${opsys}_${arch} \
"$last_kpt_version"
printf "\\nDependencies installed/updated."
######################################################
######### STEP 3 - Update Configuration File #########
######################################################
# First, update system info if changed
if [[ $system_info != "${opsys}_${arch}" ]]; then
system_info="${opsys}_${arch}"
echo "Updated/Logged System Configuration"
fi
# Reconcile dependency_info text file
cat >dependency_info.txt <<EOL
LAST_UPDATED=$(date)
SYS_INFO=${system_info}
KPT_VERSION=${last_kpt_version}
KUSTOMIZE_VERSION=${last_kustomize_version}
GATOR_VERSION=${last_gator_version}
EOL
printf "\\nConfiguration updated."
printf "\\n-----\\n"
# Leave dependency folder
cd ..
#########################################################
##### STEP 4 - Make validate.sh a Pre-Commit Hook ######
#########################################################
# Warn user that this scrip will overwrite current pre-commit hook in .git/hooks
read -r -p "This script will overwrite your current ${bold}ACTIVE${normal} pre-commit hook. Are you sure you want to continue? [y/N] " response
if [[ ! "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
exit 0
fi
# Move validate.sh script to pre-commit hook folder
printf "\\nUpdating pre-commit hook..."
cp validate.sh .git/hooks/
cd .git/hooks/ || exit 1
mv validate.sh pre-commit
# Make pre-commit hook an executable
echo $'Making pre-commit hook executable...'
chmod +x pre-commit
# Return to project root directory
cd ../../ || exit 1
echo $'Done!'
printf "\\n-----\\n"
#########################################################
################# STEP 4 - Validation Prep ##############
#########################################################
# This section will allow a user to easily update their configuration without
# needing to run the main validation script which will be inaccessible in the
# .git/hooks folder. This configuration includes information on which directories
# to use for constraints, constraint templates, and kubernetes manifests.
# Warn user that this script will overwrite their current configuration.
read -r -p "This script will overwrite your current pre-validate configuration. Are you sure you want to continue? [y/N] " response
if [[ ! "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
exit 0
fi
printf "\\n-----\\n"
########################################################
################### Obtain Policies ###################
########################################################
# Gator, the application that runs the validation, works with public repositories and local files.
# In this step, the user can define a remote repo or local directory to use for constraints/templates.
# In the case that their constraints and templates don't live in the same place, this is
# Where they can update the location of their templates.
echo $'Gator works with both public repositories and local files. You can provide either in this configuration.'
# Formatting for locations
printf "\\nFormatting"
echo "* For ${bold}remote repositories${normal}, use URL format: https://github.com/[USER]/[REPO].git/[SUBDIRECTORY]/[CONSTRAINTS_SUBDIRECTORY]"
echo "* For ${bold}local directories${normal}, input ABSOLUTE directory path"
printf "* Ensure that the repositories/directories contain ONLY constraint and/or constraint template manifests.\\n"
printf "* Link DIRECTLY to folder where constraints and/or templates are located\\n"
# Obtain CONSTRAINT TEMPLATES location
printf "\\n"
echo "${bold}CONSTRAINT TEMPLATES${normal} location:"
echo "* If you are using the open-source constraint templates, ${bold}leave BLANK and press ENTER${normal}"
echo "* Open-source constraint templates are located in /constraints-and-templates/oss-constraint-templates-library."
echo "* They are pulled from https://github.com/open-policy-agent/gatekeeper-library/library/general."
read -r -p "> " templates_location
if [[ -z $templates_location ]]; then
templates_location='/constraints-and-templates/oss-constraint-templates-library' # Using OSS Templates
fi
# Obtain CONSTRAINT TEMPLATES location
printf "\\n"
read -r -p "${bold}CONSTRAINTS${normal} location:" constraints_location
# See if user is going to be using Kustomize or not
printf "\\n"
echo "${bold}USING KUSTOMIZE${normal}:"
read -r -p "Are you using Kustomize? If so, you will need to specify which environment you would like to build every time you commit changes. [y/N] " kustomize_yes_no
if [[ "$kustomize_yes_no" =~ ^([yY][eE][sS]|[yY])$ ]]; then
kustomize_yes_no_answer="YES"
fi
# Obtain KUBERNETES MANIFESTS location if user IS using Kustomize:
if [[ $kustomize_yes_no_answer == "YES" ]]; then
printf "\\n"
echo "${bold}KUBERNETES MANIFESTS${normal} location (should be a local directory):"
echo "* If you are running this script in that directory, please press ENTER."
read -r -p "> " kubernetes_filepath
if [[ -z $kubernetes_filepath ]]; then
kubernetes_filepath=$PWD
fi
printf " \\n-----\\n"
fi
########################################################
############# Prepare Variables for Hook ###############
########################################################
# Create or overwrite configuration directory
touch .oss_dependencies/user_config.txt
# Reconcile constraints into text file ---- TODO: STILL NECESSARY IF COULD EXPORT VARS?
cat >.oss_dependencies/user_config.txt <<EOL
TEMPLATES_LOCATION=$templates_location
CONSTRAINTS_LOCATION=$constraints_location
KUBERNETES_DIR=$kubernetes_filepath
KUSTOMIZED_FILES=$kustomize_yes_no_answer
EOL
printf "\\nConfiguration Updated"