Skip to content

Commit 24f1b27

Browse files
authored
Namespace Functions, Constant Retry & Logging (#17)
Namespace Functions, Constant Retry & Logging
2 parents bc6459f + 8be41d3 commit 24f1b27

File tree

20 files changed

+453
-152
lines changed

20 files changed

+453
-152
lines changed

CHANGES.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Changelog
2+
3+
## V2
4+
* V2.0.0
5+
* Renamed all functions to include bl_ prefix
6+
* Added bl_retry_constant
7+
* Added bl_debug, bl_info, bl_warning, bl_error and bl_fatal logging functions
8+
9+
## V1
10+
* v1.0.0: Initial Release

README.md

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ files within it's directory.
113113
<td>Functions relating to file and path handling
114114
<td>
115115
<ol>
116-
<li> <b>abs_path</b>: Ensure a path is absolute</li>
116+
<li><b>bl_abs_path</b>: Ensure a path is absolute</li>
117117
</ol>
118118
</td>
119119
</tr>
@@ -122,24 +122,27 @@ files within it's directory.
122122
<td>Git helpers</td>
123123
<td>
124124
<ol>
125-
<li><b>repo_root</b>: Find the root of the current git repo.</li>
126-
<li><b>all_files_in_repo</b>: List files tracked by git.</li>
127-
<li><b>remote_latest_tag</b>: Returns the symbolic name of the latest tag from a remote.</li>
128-
<li><b>remote_latest_tagged_commit</b>: Returns the SHA of the most recently tagged commit in a remote repo (<code>tag^{}</code>).</li>
129-
<li><b>remote_sha_for_ref</b>: Returns the SHA for a given ref from a named remote.</li>
130-
<li><b>remote_tag_for_sha</b>: Returns the tag corresponding to a SHA from a named remote - if there is one.</li>
131-
<li><b>tracked_files_excluding_subtrees</b>: List files tracked by git, but excluding any files that are in paths listed in <code>.gittrees</code>.</li>
132-
<li><b>cat_gittrees</b>: Returns the contents of .gittrees from the top level of the repo, excluding any comments. Fails if .gittrees is not present.</li>
125+
<li><b>bl_repo_root</b>: Find the root of the current git repo.</li>
126+
<li><b>bl_all_files_in_repo</b>: List files tracked by git.</li>
127+
<li><b>bl_remote_latest_tag</b>: Returns the symbolic name of the latest tag from a remote.</li>
128+
<li><b>bl_remote_latest_tagged_commit</b>: Returns the SHA of the most recently tagged commit in a remote repo (<code>tag^{}</code>).</li>
129+
<li><b>bl_remote_sha_for_ref</b>: Returns the SHA for a given ref from a named remote.</li>
130+
<li><b>bl_remote_tag_for_sha</b>: Returns the tag corresponding to a SHA from a named remote - if there is one.</li>
131+
<li><b>bl_tracked_files_excluding_subtrees</b>: List files tracked by git, but excluding any files that are in paths listed in <code>.gittrees</code>.</li>
132+
<li><b>bl_cat_gittrees</b>: Returns the contents of .gittrees from the top level of the repo, excluding any comments. Fails if .gittrees is not present.</li>
133133
</ol>
134134
</td>
135135
</tr>
136136
<td><a href="helpers/lib">helpers</a></td>
137137
<td>Bash scripting helpers</td>
138138
<td>
139139
<ol>
140-
<li><b>die</b>: print message and exit 1</li>
141-
<li><b>spushd/spopd</b>: Safe verisons of pushd & popd that call die if the push/pop fails, they also drop stdout. </li>
142-
<li><b>retry</b>: Retry a command until it succeeds up to a user specified maximum number of attempts. Escalating delay between attempts.</li>
140+
<li><b>bl_die</b>: print message and exit 1</li>
141+
<li><b>bl_spushd/bl_spopd</b>: Safe verisons of pushd & popd that call die if the push/pop fails, they also drop stdout. </li>
142+
<li><b>bl_is_num</b>: Check if a value is a number via regex</li>
143+
<li><b>bl_retry</b>: Retry a command until it succeeds up to a user specified maximum number of attempts. Escalating delay between attempts.</li>
144+
<li><b>bl_retry_constant</b>: Retry a command until it succeeds with a
145+
constant delay between attempts</li>
143146
</ol>
144147
</td>
145148
</tr>
@@ -148,18 +151,26 @@ files within it's directory.
148151
<td>Utils for connecting to K8s</td>
149152
<td>
150153
<ol>
151-
<li><b>build_gke_image</b>: Build docker image for running kubectl commands against GKE.</li>
152-
<li><b>delete_gke_image</b>: Delete image from GKE.</li>
153-
<li><b>run_docker_gke_command</b>: Run command in gke-utils container, already authenticated to k8s cluster.</li>
154+
<li><b>bl_build_gke_image</b>: Build docker image for running kubectl commands against GKE.</li>
155+
<li><b>bl_delete_gke_image</b>: Delete image from GKE.</li>
156+
<li><b>bl_run_docker_gke_command</b>: Run command in gke-utils container, already authenticated to k8s cluster.</li>
154157
</ol>
155158
</td>
156159
</tr>
157160
<tr>
158161
<td><a href="logging/lib">logging</a></td>
159-
<td>Helpers related to login</td>
162+
<td>Helpers related to logging.</td>
160163
<td>
161164
<ol>
162-
<li><b>announce</b>: Echo message in ascii banner to distinguish it from other log messages.</li>
165+
<li><b>bl_announce</b>: Echo message in ascii banner to distinguish it from other log messages.</li>
166+
<li><b>bl_log</b>: Log a message at the specified level. Default log level is info, change level by setting environment variable BASH_LIB_LOG_LEVEL</li>
167+
<li><b>bl_check_log_level</b>: Check if a value is a valid bash lib
168+
log level</li>
169+
<li><b>bl_debug</b>: Log a message at debug level</li>
170+
<li><b>bl_info</b>: Log a message at info level</li>
171+
<li><b>bl_warning</b>: Log a message at warning level</li>
172+
<li><b>bl_error</b>: Log a message at error level</li>
173+
<li><b>bl_fatal</b>: Log a message at fatal level</li>
163174
</ol>
164175
</td>
165176
</tr>
@@ -168,9 +179,9 @@ files within it's directory.
168179
<td>Helpers for executing tests</td>
169180
<td>
170181
<ol>
171-
<li><b>shellcheck_script</b>: Execute shellcheck against a script, uses docker.</li>
172-
<li><b>find_scripts</b>: Find git tracked files with extension.</li>
173-
<li><b>tap2junit</b>: Convert a subset of <a href="http://testanything.org/">TAP</a> to JUnit XML. Retains logs for errors.</li>
182+
<li><b>bl_shellcheck_script</b>: Execute shellcheck against a script, uses docker.</li>
183+
<li><b>bl_find_scripts</b>: Find git tracked files with extension.</li>
184+
<li><b>bl_tap2junit</b>: Convert a subset of <a href="http://testanything.org/">TAP</a> to JUnit XML. Retains logs for errors.</li>
174185
</ol>
175186
</td>
176187
</tr>

filehandling/lib

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
: "${BASH_LIB_DIR:?BASH_LIB_DIR must be set. Please source bash-lib/init before other scripts from bash-lib.}"
44

55
#https://stackoverflow.com/a/23002317
6-
function abs_path() {
6+
function bl_abs_path() {
77
# generate absolute path from relative path
88
# path : relative filename
99
# return : absolute path
@@ -14,13 +14,13 @@ function abs_path() {
1414
fi
1515
if [ -d "${path}" ]; then
1616
# dir
17-
(spushd "${path}"; pwd)
17+
(bl_spushd "${path}"; pwd)
1818
elif [ -f "${path}" ]; then
1919
# file
2020
if [[ ${path} = /* ]]; then
2121
echo "${path}"
2222
elif [[ ${path} == */* ]]; then
23-
echo "$(spushd "${path%/*}"; pwd)/${path##*/}"
23+
echo "$(bl_spushd "${path%/*}"; pwd)/${path##*/}"
2424
else
2525
echo "$(pwd)/${path}"
2626
fi

git/lib

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
: "${BASH_LIB_DIR:?BASH_LIB_DIR must be set. Please source bash-lib/init before other scripts from bash-lib.}"
44

55
# Get the top level of a git repo
6-
function repo_root(){
6+
function bl_repo_root(){
77
git rev-parse --show-toplevel
88
}
99

1010
# List files tracked by git
11-
function all_files_in_repo(){
11+
function bl_all_files_in_repo(){
1212
git ls-tree -r HEAD --name-only
1313
}
1414

1515
# Find the latest tag available at a repo url
1616
# Returns tag name, not sha
17-
function remote_latest_tag(){
17+
function bl_remote_latest_tag(){
1818
local -r remote_url="${1}"
1919
# In ls-remote the ^{} suffix refers to a peeled/dereferenced object.
2020
# eg refs/tags/v0.0.1^{} shows the SHA of the commit that was tagged,
@@ -28,13 +28,13 @@ function remote_latest_tag(){
2828
}
2929

3030
# Find the SHA of the latests commit to be tagged in a remote repo
31-
function remote_latest_tagged_commit(){
31+
function bl_remote_latest_tagged_commit(){
3232
local -r remote="${1}"
33-
local -r tag="$(remote_latest_tag "${remote}")"
33+
local -r tag="$(bl_remote_latest_tag "${remote}")"
3434
git ls-remote "${remote}" | awk "/refs\/tags\/${tag}\^/{print \$1}"
3535
}
3636

37-
function remote_sha_for_ref(){
37+
function bl_remote_sha_for_ref(){
3838
local -r remote="${1}"
3939
local -r ref="${2}"
4040

@@ -54,7 +54,7 @@ function remote_sha_for_ref(){
5454
fi
5555
}
5656

57-
function remote_tag_for_sha(){
57+
function bl_remote_tag_for_sha(){
5858
local -r remote="${1}"
5959
local -r sha="${2}"
6060
git ls-remote "${remote}" \
@@ -64,15 +64,15 @@ function remote_tag_for_sha(){
6464

6565
## Minimal git subtree functionality required for tests to pass
6666
# full subtree functionality is not ready for merge.
67-
function cat_gittrees(){
68-
local -r git_trees="$(repo_root)/.gittrees"
67+
function bl_cat_gittrees(){
68+
local -r git_trees="$(bl_repo_root)/.gittrees"
6969
local -r subtrees_file_format=".gittrees should contain one subtree per line,\
7070
space seperated with three fields: subtree_path renmote_url remote_name"
71-
[[ -e "${git_trees}" ]] || die ".gittrees file ${git_trees} not found. ${subtrees_file_format}"
72-
grep -E -v '^\s*$|^\s*#' "$(repo_root)/.gittrees"
71+
[[ -e "${git_trees}" ]] || bl_die ".gittrees file ${git_trees} not found. ${subtrees_file_format}"
72+
grep -E -v '^\s*$|^\s*#' "$(bl_repo_root)/.gittrees"
7373
}
7474

75-
function tracked_files_excluding_subtrees(){
76-
subtrees="$(cat_gittrees | awk '{print $1}' | paste -sd '|' -)"
77-
all_files_in_repo | grep -E -v "${subtrees}"
75+
function bl_tracked_files_excluding_subtrees(){
76+
subtrees="$(bl_cat_gittrees | awk '{print $1}' | paste -sd '|' -)"
77+
bl_all_files_in_repo | grep -E -v "${subtrees}"
7878
}

helpers/lib

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,37 @@
22

33
: "${BASH_LIB_DIR:?BASH_LIB_DIR must be set. Please source bash-lib/init before other scripts from bash-lib.}"
44

5-
function die(){
5+
function bl_die(){
66
echo "${@}"
77
exit 1
88
}
99

1010
#safe pushd
11-
function spushd(){
11+
function bl_spushd(){
1212
if ! pushd "${1}" >/dev/null; then
1313
die "pushd ${1} failed :("
1414
fi
1515
}
1616

1717
#safe popd
18-
function spopd(){
19-
popd >/dev/null || die "popd failed :("
18+
function bl_spopd(){
19+
popd >/dev/null || bl_die "popd failed :("
20+
}
21+
22+
# Test if a variable contains a number
23+
function bl_is_num(){
24+
[[ ${1:-invalid} =~ ^-?[0-9\.]*$ ]]
2025
}
2126

2227
# Retry a command multiple times until it succeeds, with escalating
2328
# delay between attempts.
2429
# Delay is 2 * n + random up to 30s, then 30s + random after that.
2530
# For large numbers of retries the max delay is effectively the retry
26-
# in minutes.
31+
# count in minutes.
2732
# Based on:
2833
# https://gist.github.com/sj26/88e1c6584397bb7c13bd11108a579746
2934
# but now quite heavily modified.
30-
function retry {
35+
function bl_retry {
3136
# Maxiumum amount of fixed delay between attempts
3237
# a random value will still be added.
3338
local -r MAX_BACKOFF=30
@@ -40,7 +45,7 @@ function retry {
4045
local retries=$1
4146
shift
4247

43-
if ! [[ ${retries} =~ ^[0-9\.]*$ ]]; then
48+
if ! bl_is_num "${retries}"; then
4449
echo "Invalid number of retries: ${retries} for command '${*}'".
4550
exit 1
4651
fi
@@ -72,3 +77,42 @@ function retry {
7277
done
7378
return 0
7479
}
80+
81+
# retry function that waits a constant number of seconds between attempts.
82+
function bl_retry_constant {
83+
if [[ ${#} -lt 3 ]]; then
84+
echo "retry usage: retry <retries> <interval (seconds)> <command>"
85+
exit 1
86+
fi
87+
88+
local retries=$1; shift
89+
local interval=$1; shift
90+
91+
if ! bl_is_num "${retries}"; then
92+
echo "Invalid number of retries: ${retries} for command '${*}'".
93+
exit 1
94+
fi
95+
96+
if ! bl_is_num "${interval}"; then
97+
echo "Invalid interval in seconds: ${retries} for command '${*}'".
98+
exit 1
99+
fi
100+
101+
local count=0
102+
until eval "$@"; do
103+
# Command failed, otherwise until would have skipped the loop
104+
105+
# Store return code so it can be reported to the user
106+
exit=$?
107+
count=$((count + 1))
108+
if [ "${count}" -lt "${retries}" ]; then
109+
echo "'${*}' Retry $count/$retries exited $exit, retrying in $interval seconds..."
110+
sleep "${interval}"
111+
else
112+
# Out of retries :(
113+
echo "Retry $count/$retries exited $exit, no more retries left."
114+
return $exit
115+
fi
116+
done
117+
return 0
118+
}

init

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
#!/bin/bash
1+
#!/usr/bin/env bash
22

33
## Initialisation Functions for the
44
## Conjurinc Bash Library
55

6-
# Shell Options
6+
if (( BASH_VERSINFO[0] < 4 )); then
7+
echo "Bash Lib requires bash v4 or greater"
8+
echo "Current Bash Version: ${BASH_VERSION}"
9+
exit 1
10+
fi
11+
12+
# Shell Otions
713
set -euo pipefail
814

915
# This script should be sourced before any of
@@ -24,17 +30,17 @@ for lib in helpers logging filehandling git k8s test-utils; do
2430
. "${BASH_LIB_DIR_RELATIVE}/${lib}/lib"
2531
done
2632

27-
# Export functions to subshells
28-
eval "$(declare -F | sed -e 's/-f /-fx /')"
33+
# Filter functions and re export only bash-lib functions to subshells
34+
eval "$(declare -F | sed -e 's/-f /-fx /' | grep 'x bl_')"
2935

3036
# Export the absolute path
3137
# shellcheck disable=SC2086
32-
BASH_LIB_DIR="$(abs_path ${BASH_LIB_DIR_RELATIVE})"
38+
BASH_LIB_DIR="$(bl_abs_path ${BASH_LIB_DIR_RELATIVE})"
3339
export BASH_LIB_DIR
3440

3541
# Update Submodules
36-
spushd "${BASH_LIB_DIR}"
42+
bl_spushd "${BASH_LIB_DIR}"
3743
git submodule update --init --recursive
38-
spopd
44+
bl_spopd
3945

4046
export BATS_CMD="${BASH_LIB_DIR}/test-utils/bats/bin/bats"

k8s/lib

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,33 @@
44

55
# Sets additional required environment variables that aren't available in the
66
# secrets.yml file, and performs other preparatory steps
7-
function build_gke_image() {
7+
function bl_build_gke_image() {
88
local image="gke-utils:latest"
99
local rc=0
1010
docker rmi ${image} || true
11-
spushd "${BASH_LIB_DIR}/k8s"
11+
bl_spushd "${BASH_LIB_DIR}/k8s"
1212
# Prepare Docker images
1313
docker build --tag "${image}"\
1414
--build-arg KUBECTL_CLI_URL="${KUBECTL_CLI_URL}" \
1515
. 1>&2
1616
rc=${?}
17-
spopd
17+
bl_spopd
1818

1919
return ${rc}
2020
}
2121

2222
# Delete an image from GCR, unless it is has multiple tags pointing to it
2323
# This means another parallel build is using the image and we should
2424
# just untag it to be deleted by the later job
25-
function delete_gke_image() {
25+
function bl_delete_gke_image() {
2626
local image_and_tag="${1}"
2727

28-
run_docker_gke_command "
28+
bl_run_docker_gke_command "
2929
gcloud container images delete --force-delete-tags -q ${image_and_tag}
3030
"
3131
}
3232

33-
function run_docker_gke_command() {
33+
function bl_run_docker_gke_command() {
3434
docker run --rm \
3535
-i \
3636
-e DOCKER_REGISTRY_URL \

0 commit comments

Comments
 (0)