-
Notifications
You must be signed in to change notification settings - Fork 127
/
Copy pathentrypoint.sh
executable file
·314 lines (269 loc) · 11.1 KB
/
entrypoint.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
#!/usr/bin/env bash
# Entrypoint for running Zebra in Docker.
#
# The main script logic is at the bottom.
#
# ## Notes
#
# - `$ZEBRA_CONF_PATH` must point to a Zebra conf file.
set -eo pipefail
# Exit early if `ZEBRA_CONF_PATH` does not point to a file.
if [[ ! -f "${ZEBRA_CONF_PATH}" ]]; then
echo "ERROR: No Zebra config file found at ZEBRA_CONF_PATH (${ZEBRA_CONF_PATH})."
echo "Please ensure the file exists or mount your custom config file and set ZEBRA_CONF_PATH accordingly."
exit 1
fi
# Define function to execute commands as the specified user
exec_as_user() {
if [[ "$(id -u)" = '0' ]]; then
exec gosu "${USER}" "$@"
else
exec "$@"
fi
}
# Modifies the existing Zebra config file at ZEBRA_CONF_PATH using environment variables.
#
# The config options this function supports are also listed in the "docker/.env" file.
#
# This function modifies the existing file in-place and prints its location.
prepare_conf_file() {
# Set a custom network.
if [[ -n "${NETWORK}" ]]; then
sed -i '/network = ".*"/s/".*"/"'"${NETWORK//\"/}"'"/' "${ZEBRA_CONF_PATH}"
fi
# Enable the RPC server by setting its port.
if [[ -n "${ZEBRA_RPC_PORT}" ]]; then
sed -i '/# listen_addr = "0.0.0.0:18232" # Testnet/d' "${ZEBRA_CONF_PATH}"
sed -i 's/ *# Mainnet$//' "${ZEBRA_CONF_PATH}"
sed -i '/# listen_addr = "0.0.0.0:8232"/s/^# //; s/8232/'"${ZEBRA_RPC_PORT//\"/}"'/' "${ZEBRA_CONF_PATH}"
fi
# Disable or enable cookie authentication.
if [[ -n "${ENABLE_COOKIE_AUTH}" ]]; then
sed -i '/# enable_cookie_auth = true/s/^# //; s/true/'"${ENABLE_COOKIE_AUTH//\"/}"'/' "${ZEBRA_CONF_PATH}"
fi
# Set a custom state, network and cookie cache dirs.
#
# We're pointing all three cache dirs at the same location, so users will find
# all cached data in that single location. We can introduce more env vars and
# use them to set the cache dirs separately if needed.
if [[ -n "${ZEBRA_CACHE_DIR}" ]]; then
mkdir -p "${ZEBRA_CACHE_DIR//\"/}"
sed -i 's|_dir = ".*"|_dir = "'"${ZEBRA_CACHE_DIR//\"/}"'"|' "${ZEBRA_CONF_PATH}"
# Fix permissions right after creating/configuring the directory
if [[ "$(id -u)" = '0' ]]; then
# "Setting permissions for the cache directory
chown -R "${USER}:${USER}" "${ZEBRA_CACHE_DIR//\"/}"
fi
fi
# Enable the Prometheus metrics endpoint.
if [[ "${FEATURES}" == *"prometheus"* ]]; then
sed -i '/# endpoint_addr = "0.0.0.0:9999" # Prometheus/s/^# //' "${ZEBRA_CONF_PATH}"
fi
# Enable logging to a file by setting a custom log file path.
if [[ -n "${LOG_FILE}" ]]; then
mkdir -p "$(dirname "${LOG_FILE//\"/}")"
sed -i 's|# log_file = ".*"|log_file = "'"${LOG_FILE//\"/}"'"|' "${ZEBRA_CONF_PATH}"
# Fix permissions right after creating/configuring the log directory
if [[ "$(id -u)" = '0' ]]; then
# "Setting permissions for the log directory
chown -R "${USER}:${USER}" "$(dirname "${LOG_FILE//\"/}")"
fi
fi
# Enable or disable colored logs.
if [[ -n "${LOG_COLOR}" ]]; then
sed -i '/# force_use_color = true/s/^# //' "${ZEBRA_CONF_PATH}"
sed -i '/use_color = true/s/true/'"${LOG_COLOR//\"/}"'/' "${ZEBRA_CONF_PATH}"
fi
# Enable or disable logging to systemd-journald.
if [[ -n "${USE_JOURNALD}" ]]; then
sed -i '/# use_journald = true/s/^# //; s/true/'"${USE_JOURNALD//\"/}"'/' "${ZEBRA_CONF_PATH}"
fi
# Set a mining address.
if [[ -n "${MINER_ADDRESS}" ]]; then
sed -i '/# miner_address = ".*"/{s/^# //; s/".*"/"'"${MINER_ADDRESS//\"/}"'"/}' "${ZEBRA_CONF_PATH}"
fi
# Trim all comments and empty lines.
sed -i '/^#/d; /^$/d' "${ZEBRA_CONF_PATH}"
echo "${ZEBRA_CONF_PATH}"
}
# Checks if a directory contains subdirectories
#
# Exits with 0 if it does, and 1 otherwise.
check_directory_files() {
local dir="$1"
# Check if the directory exists
if [[ -d "${dir}" ]]; then
# Check if there are any subdirectories
if find "${dir}" -mindepth 1 -type d | read -r; then
:
else
echo "No subdirectories found in ${dir}."
exit 1
fi
else
echo "Directory ${dir} does not exist."
exit 1
fi
}
# Runs cargo test with an arbitrary number of arguments.
#
# ## Positional Parameters
#
# - '$1' must contain
# - either cargo FEATURES as described here:
# https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options,
# - or be empty.
# - The remaining params will be appended to a command starting with
# `exec_as_user cargo test ... -- ...`
run_cargo_test() {
# Start constructing the command, ensuring that $1 is enclosed in single
# quotes as it's a feature list
local cmd="exec_as_user cargo test --locked --release --features '$1' --package zebrad --test acceptance -- --nocapture --include-ignored"
# Shift the first argument, as it's already included in the cmd
shift
# Loop through the remaining arguments
for arg in "$@"; do
if [[ -n ${arg} ]]; then
# If the argument is non-empty, add it to the command
cmd+=" ${arg}"
fi
done
# Run the command using eval. This will replace the current process with the
# cargo command.
echo "Running:"
echo "${cmd}"
eval "${cmd}" || {
echo "Cargo test failed"
exit 1
}
}
# Runs tests depending on the env vars.
#
# Positional Parameters
#
# - $@: Arbitrary command that will be executed if no test env var is set.
run_tests() {
if [[ "${RUN_ALL_TESTS}" -eq "1" ]]; then
# Run unit, basic acceptance tests, and ignored tests, only showing command
# output if the test fails. If the lightwalletd environment variables are
# set, we will also run those tests.
exec_as_user cargo test --locked --release --workspace --features "${FEATURES}" \
-- --nocapture --include-ignored --skip check_no_git_refs_in_cargo_lock
elif [[ "${RUN_CHECK_NO_GIT_REFS}" -eq "1" ]]; then
# Run the check_no_git_refs_in_cargo_lock test.
exec_as_user cargo test --locked --release --workspace --features "${FEATURES}" \
-- --nocapture --include-ignored check_no_git_refs_in_cargo_lock
elif [[ "${TEST_FAKE_ACTIVATION_HEIGHTS}" -eq "1" ]]; then
# Run state tests with fake activation heights.
exec_as_user cargo test --locked --release --lib --features "zebra-test" \
--package zebra-state \
-- --nocapture --include-ignored with_fake_activation_heights
elif [[ "${TEST_SCANNER}" -eq "1" ]]; then
# Test the scanner.
exec_as_user cargo test --locked --release --package zebra-scan \
-- --nocapture --include-ignored scan_task_commands scan_start_where_left
elif [[ "${TEST_ZEBRA_EMPTY_SYNC}" -eq "1" ]]; then
# Test that Zebra syncs and checkpoints a few thousand blocks from an empty
# state.
run_cargo_test "${FEATURES}" "sync_large_checkpoints_"
elif [[ -n "${FULL_SYNC_MAINNET_TIMEOUT_MINUTES}" ]]; then
# Run a Zebra full sync test on mainnet.
run_cargo_test "${FEATURES}" "full_sync_mainnet"
elif [[ -n "${FULL_SYNC_TESTNET_TIMEOUT_MINUTES}" ]]; then
# Run a Zebra full sync test on testnet.
run_cargo_test "${FEATURES}" "full_sync_testnet"
elif [[ "${TEST_DISK_REBUILD}" -eq "1" ]]; then
# Run a Zebra sync up to the mandatory checkpoint.
run_cargo_test "${FEATURES} test_sync_to_mandatory_checkpoint_${NETWORK,,}" \
"sync_to_mandatory_checkpoint_${NETWORK,,}"
echo "ran test_disk_rebuild"
elif [[ "${TEST_UPDATE_SYNC}" -eq "1" ]]; then
# Run a Zebra sync starting at the cached tip, and syncing to the latest
# tip.
run_cargo_test "${FEATURES}" "zebrad_update_sync"
elif [[ "${TEST_CHECKPOINT_SYNC}" -eq "1" ]]; then
# Run a Zebra sync starting at the cached mandatory checkpoint, and syncing
# past it.
run_cargo_test "${FEATURES} test_sync_past_mandatory_checkpoint_${NETWORK,,}" \
"sync_past_mandatory_checkpoint_${NETWORK,,}"
elif [[ "${GENERATE_CHECKPOINTS_MAINNET}" -eq "1" ]]; then
# Generate checkpoints after syncing Zebra from a cached state on mainnet.
#
# TODO: disable or filter out logs like:
# test generate_checkpoints_mainnet has been running for over 60 seconds
run_cargo_test "${FEATURES}" "generate_checkpoints_mainnet"
elif [[ "${GENERATE_CHECKPOINTS_TESTNET}" -eq "1" ]]; then
# Generate checkpoints after syncing Zebra on testnet.
#
# This test might fail if testnet is unstable.
run_cargo_test "${FEATURES}" "generate_checkpoints_testnet"
elif [[ "${TEST_LWD_RPC_CALL}" -eq "1" ]]; then
# Starting at a cached Zebra tip, test a JSON-RPC call to Zebra.
# Run both the fully synced RPC test and the subtree snapshot test, one test
# at a time. Since these tests use the same cached state, a state problem in
# the first test can fail the second test.
run_cargo_test "${FEATURES}" "--test-threads" "1" "fully_synced_rpc_"
elif [[ "${TEST_LWD_INTEGRATION}" -eq "1" ]]; then
# Test launching lightwalletd with an empty lightwalletd and Zebra state.
run_cargo_test "${FEATURES}" "lightwalletd_integration"
elif [[ "${TEST_LWD_FULL_SYNC}" -eq "1" ]]; then
# Starting at a cached Zebra tip, run a lightwalletd sync to tip.
run_cargo_test "${FEATURES}" "lightwalletd_full_sync"
elif [[ "${TEST_LWD_UPDATE_SYNC}" -eq "1" ]]; then
# Starting with a cached Zebra and lightwalletd tip, run a quick update sync.
run_cargo_test "${FEATURES}" "lightwalletd_update_sync"
# These tests actually use gRPC.
elif [[ "${TEST_LWD_GRPC}" -eq "1" ]]; then
# Starting with a cached Zebra and lightwalletd tip, test all gRPC calls to
# lightwalletd, which calls Zebra.
run_cargo_test "${FEATURES}" "lightwalletd_wallet_grpc_tests"
elif [[ "${TEST_LWD_TRANSACTIONS}" -eq "1" ]]; then
# Starting with a cached Zebra and lightwalletd tip, test sending
# transactions gRPC call to lightwalletd, which calls Zebra.
run_cargo_test "${FEATURES}" "sending_transactions_using_lightwalletd"
# These tests use mining code, but don't use gRPC.
elif [[ "${TEST_GET_BLOCK_TEMPLATE}" -eq "1" ]]; then
# Starting with a cached Zebra tip, test getting a block template from
# Zebra's RPC server.
run_cargo_test "${FEATURES}" "get_block_template"
elif [[ "${TEST_SUBMIT_BLOCK}" -eq "1" ]]; then
# Starting with a cached Zebra tip, test sending a block to Zebra's RPC
# port.
run_cargo_test "${FEATURES}" "submit_block"
else
exec_as_user "$@"
fi
}
# Main Script Logic
prepare_conf_file "${ZEBRA_CONF_PATH}"
echo "Prepared the following Zebra config:"
cat "${ZEBRA_CONF_PATH}"
# - If "$1" is "--", "-", or "zebrad", run `zebrad` with the remaining params.
# - If "$1" is "tests":
# - and "$2" is "zebrad", run `zebrad` with the remaining params,
# - else run tests with the remaining params.
# - TODO: If "$1" is "monitoring", start a monitoring node.
# - If "$1" doesn't match any of the above, run "$@" directly.
case "$1" in
--* | -* | zebrad)
shift
exec_as_user zebrad --config "${ZEBRA_CONF_PATH}" "$@"
;;
test)
shift
if [[ "$1" == "zebrad" ]]; then
shift
exec_as_user zebrad --config "${ZEBRA_CONF_PATH}" "$@"
else
chown -R "${USER}:${USER}" "/home/zebra/.cache/zebra"
run_tests "$@"
fi
;;
monitoring)
# TODO: Impl logic for starting a monitoring node.
:
;;
*)
exec_as_user "$@"
;;
esac