-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathentrypoint.sh
326 lines (277 loc) · 12 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
315
316
317
318
319
320
321
322
323
324
325
326
#!/bin/bash
set -eo pipefail
# Do our best to match the logging requested by the user running the container.
declare -rA LOG_LEVELS=([error]=0 [warn]=1 [info]=2 [debug]=3)
declare LOG_LEVEL=error
# Mimic the structured logging used by InfluxDB.
# Usage: log <level> <msg> [<key> <val>]...
function log () {
local -r level=$1 msg=$2
shift 2
if [ "${LOG_LEVELS[${level}]}" -gt "${LOG_LEVELS[${LOG_LEVEL}]}" ]; then
return
fi
local attrs='"system": "docker"'
while [ "$#" -gt 1 ]; do
attrs="${attrs}, \"$1\": \"$2\""
shift 2
done
local -r logtime="$(date --utc +'%FT%T.%NZ')"
1>&2 echo -e "${logtime}\t${level}\t${msg}\t{${attrs}}"
}
# Set the global log-level for the entry-point to match the config passed to influxd.
function set_global_log_level () {
local level="$(influxd print-config --key-name log-level "${@}")"
if [ -z "${level}" ] || [ -z "${LOG_LEVELS[${level}]}" ]; then
return 1
fi
LOG_LEVEL=${level}
}
# Look for standard config names in the volume configured in our Dockerfile.
declare -r CONFIG_VOLUME=/etc/influxdb2
declare -ra CONFIG_NAMES=(config.json config.toml config.yaml config.yml)
# Search for a V2 config file, and export its path into the env for influxd to use.
function set_config_path () {
local config_path=/etc/defaults/influxdb2/config.yml
if [ -n "$INFLUXD_CONFIG_PATH" ]; then
config_path="${INFLUXD_CONFIG_PATH}"
else
for name in "${CONFIG_NAMES[@]}"; do
if [ -f "${CONFIG_VOLUME}/${name}" ]; then
config_path="${CONFIG_VOLUME}/${name}"
break
fi
done
fi
export INFLUXD_CONFIG_PATH="${config_path}"
}
function set_data_paths () {
BOLT_PATH="$(influxd print-config --key-name bolt-path "${@}")"
ENGINE_PATH="$(influxd print-config --key-name engine-path "${@}")"
export BOLT_PATH ENGINE_PATH
}
# Ensure all the data directories needed by influxd exist with the right permissions.
function create_directories () {
local -r bolt_dir="$(dirname "${BOLT_PATH}")"
local user=$(id -u)
mkdir -p "${bolt_dir}" "${ENGINE_PATH}"
chmod 700 "${bolt_dir}" "${ENGINE_PATH}" || :
mkdir -p "${CONFIG_VOLUME}" || :
chmod 775 "${CONFIG_VOLUME}" || :
if [ ${user} = 0 ]; then
find "${bolt_dir}" \! -user influxdb -exec chown influxdb '{}' +
find "${ENGINE_PATH}" \! -user influxdb -exec chown influxdb '{}' +
find "${CONFIG_VOLUME}" \! -user influxdb -exec chown influxdb '{}' +
fi
}
# List of env vars required to auto-run setup or upgrade processes.
declare -ra REQUIRED_INIT_VARS=(DOCKER_INFLUXDB_INIT_USERNAME DOCKER_INFLUXDB_INIT_PASSWORD DOCKER_INFLUXDB_INIT_ORG DOCKER_INFLUXDB_INIT_BUCKET)
# Ensure all env vars required to run influx setup or influxd upgrade are set in the env.
function ensure_init_vars_set () {
local missing_some=0
for var in "${REQUIRED_INIT_VARS[@]}"; do
if [ -z "${!var}" ]; then
log error "missing parameter, cannot init InfluxDB" parameter ${var}
missing_some=1
fi
done
if [ ${missing_some} = 1 ]; then
exit 1
fi
}
# If exiting on error, delete all bolt and engine files.
# If we didn't do this, the container would see the boltdb file on reboot and assume
# the DB is already full set up.
function cleanup_influxd () {
log warn "cleaning bolt and engine files to prevent conflicts on retry" bolt_path "${BOLT_PATH}" engine_path "${ENGINE_PATH}"
rm -rf "${BOLT_PATH}" "${ENGINE_PATH}"
}
# Upgrade V1 data into the V2 format using influxd upgrade.
# The process will use either a V1 config file or a V1 data dir to drive
# the upgrade, with precedence order:
# 1. Config file pointed to by DOCKER_INFLUXDB_INIT_UPGRADE_V1_CONFIG env var
# 2. Data dir pointed to by DOCKER_INFLUXDB_INIT_UPGRADE_V1_DIR env var
# 3. Config file at /etc/influxdb/influxdb.conf
# 4. Data dir at /var/lib/influxdb
function upgrade_influxd () {
local -a upgrade_args=(
--force
--username "${DOCKER_INFLUXDB_INIT_USERNAME}"
--password "${DOCKER_INFLUXDB_INIT_PASSWORD}"
--org "${DOCKER_INFLUXDB_INIT_ORG}"
--bucket "${DOCKER_INFLUXDB_INIT_BUCKET}"
--v2-config-path "${CONFIG_VOLUME}/config.toml"
--influx-configs-path "${INFLUX_CONFIGS_PATH}"
--continuous-query-export-path "${CONFIG_VOLUME}/v1-cq-export.txt"
--log-path "${CONFIG_VOLUME}/upgrade.log"
--log-level "${LOG_LEVEL}"
--bolt-path "${BOLT_PATH}"
--engine-path "${ENGINE_PATH}"
--overwrite-existing-v2
)
if [ -n "${DOCKER_INFLUXDB_INIT_RETENTION}" ]; then
upgrade_args=("${upgrade_args[@]}" --retention "${DOCKER_INFLUXDB_INIT_RETENTION}")
fi
if [ -n "${DOCKER_INFLUXDB_INIT_ADMIN_TOKEN}" ]; then
upgrade_args=("${upgrade_args[@]}" --token "${DOCKER_INFLUXDB_INIT_ADMIN_TOKEN}")
fi
if [[ -n "${DOCKER_INFLUXDB_INIT_UPGRADE_V1_CONFIG}" && -f "${DOCKER_INFLUXDB_INIT_UPGRADE_V1_CONFIG}" ]]; then
upgrade_args=("${upgrade_args[@]}" --config-file "${DOCKER_INFLUXDB_INIT_UPGRADE_V1_CONFIG}")
elif [[ -n "${DOCKER_INFLUXDB_INIT_UPGRADE_V1_DIR}" && -d "${DOCKER_INFLUXDB_INIT_UPGRADE_V1_DIR}" ]]; then
upgrade_args=("${upgrade_args[@]}" --v1-dir "${DOCKER_INFLUXDB_INIT_UPGRADE_V1_DIR}")
elif [ -f /etc/influxdb/influxdb.conf ]; then
upgrade_args=("${upgrade_args[@]}" --config-file /etc/influxdb/influxdb.conf)
elif [ -d /var/lib/influxdb ]; then
upgrade_args=("${upgrade_args[@]}" --v1-dir /var/lib/influxdb)
else
log error "failed to autodetect usable V1 config or data dir, aborting upgrade"
exit 1
fi
influxd upgrade "${upgrade_args[@]}"
# Reset global influxd config to pick up new file written by the upgrade process.
set_config_path
}
# Wait up to a minute for the DB to boot
declare -r STARTUP_PING_WAIT_SECONDS=2
declare -r STARTUP_PING_ATTEMPTS=30
# Ping influxd until it responds.
# Used to block execution until the server is ready to process setup requests.
function wait_for_influxd () {
local ping_count=0
while [ ${ping_count} -lt ${STARTUP_PING_ATTEMPTS} ]; do
sleep ${STARTUP_PING_WAIT_SECONDS}
log info "pinging influxd..."
if influx ping &> /dev/null; then
log info "got response from influxd, proceeding"
return
fi
ping_count=$((ping_count+1))
done
log error "failed to detect influxd startup" ping_attempts ${ping_count}
exit 1
}
# Create an initial user/org/bucket in the DB using the influx CLI.
function setup_influxd () {
local -a setup_args=(
--force
--username "${DOCKER_INFLUXDB_INIT_USERNAME}"
--password "${DOCKER_INFLUXDB_INIT_PASSWORD}"
--org "${DOCKER_INFLUXDB_INIT_ORG}"
--bucket "${DOCKER_INFLUXDB_INIT_BUCKET}"
)
if [ -n "${DOCKER_INFLUXDB_INIT_RETENTION}" ]; then
setup_args=("${setup_args[@]}" --retention "${DOCKER_INFLUXDB_INIT_RETENTION}")
fi
if [ -n "${DOCKER_INFLUXDB_INIT_ADMIN_TOKEN}" ]; then
setup_args=("${setup_args[@]}" --token "${DOCKER_INFLUXDB_INIT_ADMIN_TOKEN}")
fi
influx setup "${setup_args[@]}"
}
# Get the IDs of the initial user/org/bucket created during setup, and export them into the env.
# We do this to help with arbitrary user scripts, since many influx CLI commands only take IDs.
function set_init_resource_ids () {
DOCKER_INFLUXDB_INIT_USER_ID="$(influx user list -n "${DOCKER_INFLUXDB_INIT_USER}" --hide-headers | cut -f 1)"
DOCKER_INFLUXDB_INIT_ORG_ID="$(influx org list -n "${DOCKER_INFLUXDB_INIT_ORG}" --hide-headers | cut -f 1)"
DOCKER_INFLUXDB_INIT_BUCKET_ID="$(influx bucket list -n "${DOCKER_INFLUXDB_INIT_BUCKET}" --hide-headers | cut -f 1)"
export DOCKER_INFLUXDB_INIT_USER_ID DOCKER_INFLUXDB_INIT_ORG_ID DOCKER_INFLUXDB_INIT_BUCKET_ID
}
# Allow users to mount arbitrary startup scripts into the container,
# for execution after initial setup/upgrade.
declare -r USER_SCRIPT_DIR=/docker-entrypoint-initdb.d
# Execute all shell files mounted into the expected path for user-defined startup scripts.
function run_user_scripts () {
if [ -d ${USER_SCRIPT_DIR} ]; then
log info "Executing user-provided scripts" script_dir ${USER_SCRIPT_DIR}
run-parts --regex ".*sh$" --report --exit-on-error ${USER_SCRIPT_DIR}
fi
}
# Helper used to propagate signals received during initialization to the influxd
# process running in the background.
function handle_signal () {
kill -${1} ${2}
wait ${2}
}
# Perform initial setup on the InfluxDB instance, either by setting up fresh metadata
# or by upgrading existing V1 data.
function init_influxd () {
if [[ "${DOCKER_INFLUXDB_INIT_MODE}" != setup && "${DOCKER_INFLUXDB_INIT_MODE}" != upgrade ]]; then
log error "found invalid DOCKER_INFLUXDB_INIT_MODE, valid values are 'setup' and 'upgrade'" DOCKER_INFLUXDB_INIT_MODE "${DOCKER_INFLUXDB_INIT_MODE}"
exit 1
fi
ensure_init_vars_set
trap "cleanup_influxd" EXIT
# The upgrade process needs to run before we boot the server, otherwise the
# boltdb file will be generated and cause conflicts.
if [ "${DOCKER_INFLUXDB_INIT_MODE}" = upgrade ]; then
upgrade_influxd
fi
# Capture final bind address, and check it is distinct from init addr
local -r final_bind_addr="$(influxd print-config --key-name http-bind-address "${@}")"
local -r init_bind_addr=":${INFLUXD_INIT_PORT}"
if [ "${init_bind_addr}" = "${final_bind_addr}" ]; then
log warn "influxd setup binding to same addr as final config, server will be exposed before ready" addr "${init_bind_addr}"
fi
# Start influxd in the background.
log info "booting influxd server in the background"
INFLUXD_HTTP_BIND_ADDRESS="${init_bind_addr}" influxd "${@}" &
local -r influxd_init_pid="$!"
trap "handle_signal TERM ${influxd_init_pid}" TERM
trap "handle_signal INT ${influxd_init_pid}" INT
export INFLUX_HOST="http://localhost:${INFLUXD_INIT_PORT}"
wait_for_influxd
# Use the influx CLI to create an initial user/org/bucket.
if [ "${DOCKER_INFLUXDB_INIT_MODE}" = setup ]; then
setup_influxd
fi
set_init_resource_ids
run_user_scripts
log info "initialization complete, shutting down background influxd"
kill -TERM "${influxd_init_pid}"
wait "${influxd_init_pid}" || true
trap - EXIT INT TERM
# Rewrite the ClI configs to point at the server's final HTTP address.
local -r final_port="$(echo "${final_bind_addr}" | sed -E 's#[^:]*:(.*)#\1#')"
sed -i "s#http://localhost:${INFLUXD_INIT_PORT}#http://localhost:${final_port}#g" "${INFLUX_CONFIGS_PATH}"
}
# Run influxd, with optional setup logic.
function influxd_main () {
if [ -f "${BOLT_PATH}" ]; then
log info "found existing boltdb file, skipping setup wrapper" bolt_path "${BOLT_PATH}"
elif [ -z "${DOCKER_INFLUXDB_INIT_MODE}" ]; then
log warn "boltdb not found at configured path, but DOCKER_INFLUXDB_INIT_MODE not specified, skipping setup wrapper" bolt_path "${bolt_path}"
else
init_influxd "${@}"
fi
exec influxd "${@}"
}
function main () {
# Ensure INFLUXD_CONFIG_PATH is set.
# We do this even if we're not running the main influxd server so subcommands
# (i.e. print-config) still find the right config values.
set_config_path
local run_influxd=false
if [[ $# = 0 || "$1" = run || "${1:0:1}" = '-' ]]; then
run_influxd=true
elif [[ "$1" = influxd && ($# = 1 || "$2" = run || "${2:0:1}" = '-') ]]; then
run_influxd=true
shift 1
fi
if ! ${run_influxd}; then
exec "${@}"
fi
if [ "$1" = run ]; then
shift 1
fi
# Configure logging for our wrapper.
set_global_log_level "${@}"
# Configure data paths used across functions.
set_data_paths "${@}"
# Ensure volume directories exist w/ correct permissions.
create_directories
if [ "$(id -u)" = 0 ]; then
exec gosu influxdb "$BASH_SOURCE" "${@}"
return
fi
influxd_main "${@}"
}
main "${@}"