Skip to content

Commit 29a0794

Browse files
evanfosterEvan Foster
and
Evan Foster
authored
Make setup script more robust and idempotent (#204)
* Make setup more robust and idempotent While doing some development work for a different feature, I kept running into issues with `make setup`. I'd run it after rebooting my laptop and it would fail, or I'd run it and receive a weird error that I wouldn't be able to reproduce. To address this, I've added more robust error handling and have taken the opportunity to make the script idempotent. You should be able to run `make setup` on a fully running system and have nothing happen except for the API server and client containers roll. * Use editorconfig instead of vim comment --------- Co-authored-by: Evan Foster <[email protected]>
1 parent e15f983 commit 29a0794

File tree

2 files changed

+176
-101
lines changed

2 files changed

+176
-101
lines changed

.editorconfig

+6
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,9 @@ insert_final_newline = true
3535
indent_style = space
3636
indent_size = 4
3737
trim_trailing_whitespace = true
38+
39+
# Formatting for shell scripts
40+
[*.{sh,bash}]
41+
indent_size = 4
42+
indent_style = space
43+
trim_trailing_whitespace = true

local/setup.sh

+170-101
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,45 @@
11
#!/usr/bin/env bash
2-
3-
set -o errexit
4-
set -o nounset
5-
set -o pipefail
2+
# shellcheck enable=check-unassigned-uppercase
3+
4+
echoerr() {
5+
echo "$@" 1>&2
6+
}
7+
8+
die() {
9+
message="$1"
10+
shift
11+
exit_code="${1:-1}"
12+
echoerr "$message"
13+
exit "$exit_code"
14+
}
15+
16+
container_exists() {
17+
local container_name container_id
18+
container_name="$1"
19+
[[ -z "$container_name" ]] && die 'container_exists was called without any args passed.'
20+
container_id="$(docker ps -a -q --filter name="$container_name")" || die "Failed to get ID for possibly extant container named $container_name"
21+
[[ -n "$container_id" ]]
22+
}
23+
24+
container_running() {
25+
local container_name container_id
26+
container_name="$1"
27+
[[ -z "$container_name" ]] && die 'container_running was called without any args passed.'
28+
container_id="$(docker ps -q --filter name="$container_name")" || die "Failed to get ID for possibly running container named $container_name"
29+
[[ -n "$container_id" ]]
30+
}
31+
32+
prerequisites=(aws docker kind)
33+
missing_prerequisite=false
34+
for prerequisite in "${prerequisites[@]}"; do
35+
if ! command -v "$prerequisite" > /dev/null; then
36+
echoerr "$prerequisite is not in your PATH. Is it installed?"
37+
missing_prerequisite=true
38+
fi
39+
done
40+
[[ "$missing_prerequisite" = true ]] && die 'Missing prerequisite commands. Cannot continue.'
41+
42+
docker info -f json > /dev/null || die 'Cannot talk to the docker daemon. Ensure docker is running and your user can access the socket.'
643

744
# by default run the apiserver and client
845
RUN_APISERVER="${1:-1}"
@@ -11,125 +48,157 @@ RUN_CLIENT="${2:-1}"
1148
ROOT_DIR="$(cd "$(dirname "$0")/.."; pwd)"
1249

1350
echo 'Loading local environment variables...'
14-
source ${ROOT_DIR}/local/.env.local
51+
# shellcheck source=./.env.local
52+
source "${ROOT_DIR}/local/.env.local" || die "Failed to source ${ROOT_DIR}/local/.env.local"
1553

16-
echo -e "Create docker network ${NETWORK} ..."
17-
if [[ $(docker network ls | grep ${NETWORK}) == "" ]]; then
18-
docker network create ${NETWORK}
19-
fi
54+
docker_network_id="$(docker network ls -q --filter name="${NETWORK}")"
2055

21-
echo 'Run a local dynamodb...'
22-
docker run -d \
23-
--name ${CONTAINER_DB} \
24-
-v dynamodb:/home/dynamodblocal/data \
25-
-p 8000:8000 \
26-
--network ${NETWORK} \
27-
${IMAGE_DB} -jar DynamoDBLocal.jar -inMemory -sharedDb
56+
if [[ -z "$docker_network_id" ]] > /dev/null 2>&1; then
57+
echo -e "Create docker network ${NETWORK} ..."
58+
docker network create "${NETWORK}" || die "Failed to create docker network ${NETWORK}"
59+
fi
2860

29-
echo 'Sleeping 3s in order to let dynamodb container to start up'
30-
sleep 3
61+
if ! container_exists "${CONTAINER_DB}" > /dev/null 2>&1; then
62+
echo 'Create a local dynamodb...'
63+
docker run -d \
64+
--name "${CONTAINER_DB}" \
65+
-v dynamodb:/home/dynamodblocal/data \
66+
-p 8000:8000 \
67+
--network "${NETWORK}" \
68+
"${IMAGE_DB}" -jar DynamoDBLocal.jar -inMemory -sharedDb || die "Failed to create $CONTAINER_DB container."
69+
until curl -s -o /dev/null http://localhost:8000; do
70+
echo "Waiting for dynamodb container to start up..."
71+
sleep 1
72+
done
73+
elif container_exists "${CONTAINER_DB}" && ! container_running "${CONTAINER_DB}"; then
74+
docker start "${CONTAINER_DB}" || die "Failed to start stopped $CONTAINER_DB container."
75+
until curl -s -o /dev/null http://localhost:8000; do
76+
echo "Waiting for dynamodb container to start up..."
77+
sleep 1
78+
done
79+
fi
3180

3281
echo 'Create dynamodb schema...'
33-
aws dynamodb delete-table --table-name ${DB_TABLE_NAME} --endpoint-url $DB_ENDPOINT > /dev/null 2>&1 || true
34-
aws dynamodb create-table --cli-input-json file://${ROOT_DIR}/local/database/schema.json --endpoint-url $DB_ENDPOINT > /dev/null
82+
aws dynamodb delete-table --region "${AWS_REGION}" --table-name "${DB_TABLE_NAME}" --endpoint-url "${DB_ENDPOINT}" > /dev/null 2>&1
83+
aws dynamodb create-table --region "${AWS_REGION}" --cli-input-json file://"${ROOT_DIR}"/local/database/schema.json --endpoint-url "${DB_ENDPOINT}" > /dev/null || die "Failed to create DB schema."
3584

3685
echo 'Populate database with dummy data..'
37-
go run ${ROOT_DIR}/local/database/import.go --input-file ${ROOT_DIR}/local/database/dummy-data.yaml
38-
39-
echo 'Run a local sqs...'
40-
docker run -d \
41-
--name ${CONTAINER_SQS} \
42-
-v ${ROOT_DIR}/local/sqs/sqs.conf:/opt/elasticmq.conf \
43-
-p 9324:9324 \
44-
-p 9325:9325 \
45-
--network ${NETWORK} \
46-
${IMAGE_SQS}
47-
48-
echo 'Run a local redis...'
49-
docker run -d \
50-
--name ${CONTAINER_REDIS} \
51-
-p 6379:6379 \
52-
--network ${NETWORK} \
53-
${IMAGE_REDIS}
54-
55-
echo 'Run mocking oidc instance'
56-
docker run -d \
57-
--name ${CONTAINER_OIDC} \
58-
-v ${ROOT_DIR}/local/oidc:/usr/share/nginx/html \
59-
-v ${ROOT_DIR}/local/oidc/default.conf:/etc/nginx/config.d/default.conf:ro \
60-
-p 80:80 \
61-
--network ${NETWORK} \
62-
${IMAGE_OIDC}
86+
go run "${ROOT_DIR}"/local/database/import.go --input-file "${ROOT_DIR}"/local/database/dummy-data.yaml || die "Failed to populate the database with dummy data."
87+
88+
if ! container_exists "${CONTAINER_SQS}"; then
89+
echo 'Run a local sqs...'
90+
docker run -d \
91+
--name "${CONTAINER_SQS}" \
92+
-v "${ROOT_DIR}"/local/sqs/sqs.conf:/opt/elasticmq.conf \
93+
-p 9324:9324 \
94+
-p 9325:9325 \
95+
--network "${NETWORK}" \
96+
"${IMAGE_SQS}" || die "Failed to create $CONTAINER_SQS container."
97+
elif container_exists "${CONTAINER_SQS}" && ! container_running "${CONTAINER_SQS}"; then
98+
docker start "${CONTAINER_SQS}" || die "Failed to start stopped $CONTAINER_SQS container."
99+
fi
100+
101+
if ! container_exists "${CONTAINER_REDIS}"; then
102+
echo 'Run a local redis...'
103+
docker run -d \
104+
--name ${CONTAINER_REDIS} \
105+
-p 6379:6379 \
106+
--network ${NETWORK} \
107+
"${IMAGE_REDIS}" || die "Failed to create $IMAGE_REDIS container."
108+
elif container_exists "${CONTAINER_REDIS}" && ! container_running "${CONTAINER_REDIS}"; then
109+
docker start "${CONTAINER_REDIS}" || die "Failed to start stopped $CONTAINER_REDIS container."
110+
fi
111+
112+
if ! container_exists "${CONTAINER_OIDC}"; then
113+
echo 'Run mocking oidc instance'
114+
docker run -d \
115+
--name "${CONTAINER_OIDC}" \
116+
-v "${ROOT_DIR}"/local/oidc:/usr/share/nginx/html \
117+
-v "${ROOT_DIR}"/local/oidc/default.conf:/etc/nginx/config.d/default.conf:ro \
118+
-p 80:80 \
119+
--network "${NETWORK}" \
120+
"${IMAGE_OIDC}" || die "Failed to create $CONTAINER_OIDC container."
121+
elif container_exists "${CONTAINER_OIDC}" && ! container_running "${CONTAINER_OIDC}"; then
122+
docker start "${CONTAINER_OIDC}" || die "Failed to start stopped $CONTAINER_OIDC container."
123+
fi
63124

64125
echo 'Creating a local k8s cluster...'
65-
kind delete cluster --name="${KIND_CLUSTERNAME}" > /dev/null 2>&1 || true
66-
kind create cluster --name="${KIND_CLUSTERNAME}" --kubeconfig=${ROOT_DIR}/kubeconfig \
67-
--image=kindest/node:"${KIND_NODE_VERSION}" --config="${ROOT_DIR}/local/kind/kind.yaml"
126+
kind delete cluster --name="${KIND_CLUSTERNAME}" > /dev/null 2>&1
127+
kind create cluster --name="${KIND_CLUSTERNAME}" --kubeconfig="${ROOT_DIR}"/kubeconfig \
128+
--image=kindest/node:"${KIND_NODE_VERSION}" --config="${ROOT_DIR}/local/kind/kind.yaml" || die "Failed to create $KIND_CLUSTERNAME kind cluster."
68129

69130
echo 'Testing local k8s cluster...'
70131
export KUBECONFIG=${ROOT_DIR}/kubeconfig
71-
docker network connect "${NETWORK}" "${KIND_CLUSTERNAME}-control-plane"
72-
cp "${ROOT_DIR}/kubeconfig" "${ROOT_DIR}/kubeconfig_client"
73-
chmod +r "${ROOT_DIR}/kubeconfig_client"
132+
docker network connect "${NETWORK}" "${KIND_CLUSTERNAME}-control-plane" || die "Failed to connect $NETWORK docker network to $KIND_CLUSTERNAME-control-plane network."
133+
cp "${ROOT_DIR}/kubeconfig" "${ROOT_DIR}/kubeconfig_client" || die "Failed to copy our client kubeconfig."
134+
chmod +r "${ROOT_DIR}/kubeconfig_client" || die "Failed to make ${ROOT_DIR}/kubeconfig_client readable."
74135

75-
perl -pi.bak -e "s/0.0.0.0/${KIND_CLUSTERNAME}-control-plane/g" "${ROOT_DIR}/kubeconfig_client"
76-
kubectl cluster-info --context kind-k8s-cluster-registry
77-
kubectl create ns cluster-registry
136+
perl -pi.bak -e "s/0.0.0.0/${KIND_CLUSTERNAME}-control-plane/g" "${ROOT_DIR}/kubeconfig_client" || die "Failed to modify the kubeconfig server address."
137+
kubectl cluster-info --context kind-k8s-cluster-registry || die "Can't get cluster info. There may be an issue with the kind cluster or your kubeconfig."
138+
kubectl create ns cluster-registry || die "Failed to create cluster-registry namespace."
78139

79140
echo 'Installing cluster-registry-client prerequisites...'
80-
make manifests
81-
kubectl --kubeconfig="${ROOT_DIR}/kubeconfig" apply -f ${ROOT_DIR}/config/crd/bases/
141+
make manifests || die "Failed to run the manifests make target."
142+
kubectl --kubeconfig="${ROOT_DIR}/kubeconfig" apply -f "${ROOT_DIR}"/config/crd/bases/ || die "Failed to apply k8s manifests at ${ROOT_DIR}/config/crd/bases/"
82143

83144
echo 'Building docker images'
84-
make --always-make image TAG="${TAG}"
145+
make --always-make image TAG="${TAG}" || die "Failed to build images."
85146

86147
if [[ "${RUN_APISERVER}" == 1 ]]; then
87-
echo 'Running cluster-registry api'
88-
docker run -d \
89-
--name ${CONTAINER_API} \
90-
-p 8080:8080 \
91-
-e AWS_REGION \
92-
-e AWS_ACCESS_KEY_ID \
93-
-e AWS_SECRET_ACCESS_KEY \
94-
-e DB_AWS_REGION \
95-
-e DB_ENDPOINT=http://${CONTAINER_DB}:8000 \
96-
-e DB_TABLE_NAME=${DB_TABLE_NAME} \
97-
-e DB_INDEX_NAME=${DB_INDEX_NAME} \
98-
-e OIDC_ISSUER_URL=http://${CONTAINER_OIDC} \
99-
-e OIDC_CLIENT_ID \
100-
-e SQS_AWS_REGION \
101-
-e SQS_ENDPOINT=http://${CONTAINER_SQS}:9324 \
102-
-e SQS_QUEUE_NAME=${SQS_QUEUE_NAME} \
103-
-e SQS_BATCH_SIZE \
104-
-e SQS_WAIT_SECONDS \
105-
-e SQS_RUN_INTERVAL \
106-
-e API_RATE_LIMITER=${API_RATE_LIMITER} \
107-
-e LOG_LEVEL=${LOG_LEVEL} \
108-
-e API_HOST=${API_HOST} \
109-
-e K8S_RESOURCE_ID=${K8S_RESOURCE_ID} \
110-
-e API_TENANT_ID=${API_TENANT_ID} \
111-
-e API_CLIENT_ID=${API_CLIENT_ID} \
112-
-e API_CLIENT_SECRET=${API_CLIENT_SECRET} \
113-
-e API_AUTHORIZED_GROUP_ID=${API_AUTHORIZED_GROUP_ID} \
114-
-e API_CACHE_TTL \
115-
-e API_CACHE_REDIS_HOST=${CONTAINER_REDIS}:6379 \
116-
--network ${NETWORK} \
117-
${IMAGE_APISERVER}:${TAG}
148+
echo 'Running cluster-registry api'
149+
if container_exists "${CONTAINER_API}"; then
150+
container_running "${CONTAINER_API}" && { docker stop "$CONTAINER_API" || die "Failed to stop cluster-registry api container $CONTAINER_API"; }
151+
docker rm "${CONTAINER_API}" || die "Failed to remove cluster-registry api container $CONTAINER_API"
152+
fi
153+
docker run -d \
154+
--name "${CONTAINER_API}" \
155+
-p 8080:8080 \
156+
-e AWS_REGION \
157+
-e AWS_ACCESS_KEY_ID \
158+
-e AWS_SECRET_ACCESS_KEY \
159+
-e DB_AWS_REGION \
160+
-e DB_ENDPOINT=http://"${CONTAINER_DB}":8000 \
161+
-e DB_TABLE_NAME="${DB_TABLE_NAME}" \
162+
-e DB_INDEX_NAME="${DB_INDEX_NAME}" \
163+
-e OIDC_ISSUER_URL=http://"${CONTAINER_OIDC}" \
164+
-e OIDC_CLIENT_ID \
165+
-e SQS_AWS_REGION \
166+
-e SQS_ENDPOINT=http://"${CONTAINER_SQS}":9324 \
167+
-e SQS_QUEUE_NAME="${SQS_QUEUE_NAME}" \
168+
-e SQS_BATCH_SIZE \
169+
-e SQS_WAIT_SECONDS \
170+
-e SQS_RUN_INTERVAL \
171+
-e API_RATE_LIMITER="${API_RATE_LIMITER}" \
172+
-e LOG_LEVEL="${LOG_LEVEL}" \
173+
-e API_HOST="${API_HOST}" \
174+
-e K8S_RESOURCE_ID="${K8S_RESOURCE_ID}" \
175+
-e API_TENANT_ID="${API_TENANT_ID}" \
176+
-e API_CLIENT_ID="${API_CLIENT_ID}" \
177+
-e API_CLIENT_SECRET="${API_CLIENT_SECRET}" \
178+
-e API_AUTHORIZED_GROUP_ID="${API_AUTHORIZED_GROUP_ID}" \
179+
-e API_CACHE_TTL \
180+
-e API_CACHE_REDIS_HOST=${CONTAINER_REDIS}:6379 \
181+
--network "${NETWORK}" \
182+
"${IMAGE_APISERVER}":"${TAG}" || die "Failed to create $CONTAINER_API container."
118183
fi
119184

120185
if [[ "${RUN_CLIENT}" == 1 ]]; then
121-
echo 'Running cluster-registry-client'
122-
docker run -d \
123-
--name ${CONTAINER_CLIENT} \
124-
-v "${ROOT_DIR}/kubeconfig_client":/kubeconfig \
125-
-e AWS_ACCESS_KEY_ID \
126-
-e AWS_SECRET_ACCESS_KEY \
127-
-e KUBECONFIG=/kubeconfig \
128-
-e SQS_AWS_REGION \
129-
-e SQS_ENDPOINT=http://${CONTAINER_SQS}:9324 \
130-
-e SQS_QUEUE_NAME=${SQS_QUEUE_NAME} \
131-
--network ${NETWORK} \
132-
${IMAGE_CLIENT}:${TAG}
186+
echo 'Running cluster-registry-client'
187+
if container_exists "${CONTAINER_CLIENT}"; then
188+
container_running "${CONTAINER_CLIENT}" && { docker stop "$CONTAINER_CLIENT" || die "Failed to stop cluster-registry-client container $CONTAINER_CLIENT"; }
189+
docker rm "${CONTAINER_CLIENT}" || die "Failed to remove cluster-registry-client container $CONTAINER_CLIENT"
190+
fi
191+
docker run -d \
192+
--name "${CONTAINER_CLIENT}" \
193+
-v "${ROOT_DIR}/kubeconfig_client":/kubeconfig \
194+
-e AWS_ACCESS_KEY_ID \
195+
-e AWS_SECRET_ACCESS_KEY \
196+
-e KUBECONFIG=/kubeconfig \
197+
-e SQS_AWS_REGION \
198+
-e SQS_ENDPOINT=http://"${CONTAINER_SQS}":9324 \
199+
-e SQS_QUEUE_NAME="${SQS_QUEUE_NAME}" \
200+
--network "${NETWORK}" \
201+
"${IMAGE_CLIENT}":"${TAG}" || die "Failed to create $CONTAINER_CLIENT container."
133202
fi
134203

135204
echo 'Local stack was set up successfully.'

0 commit comments

Comments
 (0)