1
+#!/usr/bin/env sh
2
+
3
+# shellcheck disable=SC1091
4
+[ -f /etc/profile ] && . /etc/profile
5
+
6
+set -e
7
+
8
+script_dir="$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd -P)"
9
+
10
+usage() {
11
+ check_directories
12
+ cat <<EOF
13
+USAGE:
14
+ ${0} [options] FILENAME
15
+
16
+ Copy and edit the stock config file named: FILENAME
17
+ if FILENAME is already copied, it will be edited as-is.
18
+
19
+ Stock config files at: '${NETDATA_STOCK_CONFIG_DIR}'
20
+ User config files at: '${NETDATA_USER_CONFIG_DIR}'
21
+
22
+ The editor to use can be specified either by setting the EDITOR
23
+ environment variable, or by using the --editor option.
24
+
25
+ The file to edit can also be specified using the --file option.
26
+
27
+ For a list of known config files, run '${0} --list'
28
+EOF
29
+ exit 0
30
+}
31
+
32
+error() {
33
+ echo >&2 "ERROR: ${1}"
34
+}
35
+
36
+abspath() {
37
+ if [ -d "${1}" ]; then
38
+ echo "$(cd "${1}" && /usr/bin/env PWD= pwd -P)/"
39
+ else
40
+ echo "$(cd "$(dirname "${1}")" && /usr/bin/env PWD= pwd -P)/$(basename "${1}")"
41
+ fi
42
+}
43
+
44
+is_prefix() {
45
+ echo "${2}" | grep -qE "^${1}"
46
+ return $?
47
+}
48
+
49
+check_directories() {
50
+ if [ -e "${script_dir}/.environment" ]; then
51
+ OLDPATH="${PATH}"
52
+ # shellcheck disable=SC1091
53
+ . "${script_dir}/.environment"
54
+ PATH="${OLDPATH}"
55
+ fi
56
+
57
+ if [ -n "${NETDATA_PREFIX}" ] && [ -d "${NETDATA_PREFIX}/usr/lib/netdata/conf.d" ]; then
58
+ stock_dir="${NETDATA_PREFIX}/usr/lib/netdata/conf.d"
59
+ elif [ -n "${NETDATA_PREFIX}" ] && [ -d "${NETDATA_PREFIX}/lib/netdata/conf.d" ]; then
60
+ stock_dir="${NETDATA_PREFIX}/lib/netdata/conf.d"
61
+ elif [ -d "${script_dir}/../../usr/lib/netdata/conf.d" ]; then
62
+ stock_dir="${script_dir}/../../usr/lib/netdata/conf.d"
63
+ elif [ -d "${script_dir}/../../lib/netdata/conf.d" ]; then
64
+ stock_dir="${script_dir}/../../lib/netdata/conf.d"
65
+ elif [ -d "/usr/lib/netdata/conf.d" ]; then
66
+ stock_dir="/usr/lib/netdata/conf.d"
67
+ fi
68
+
69
+ [ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="${script_dir}"
70
+ [ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="${stock_dir}"
71
+
72
+ if [ -z "${NETDATA_STOCK_CONFIG_DIR}" ]; then
73
+ error "Unable to find stock config directory."
74
+ exit 1
75
+ fi
76
+}
77
+
78
+check_editor() {
79
+ if [ -z "${editor}" ]; then
80
+ if [ -n "${EDITOR}" ] && command -v "${EDITOR}" >/dev/null 2>&1; then
81
+ editor="${EDITOR}"
82
+ elif command -v editor >/dev/null 2>&1; then
83
+ editor="editor"
84
+ elif command -v vi >/dev/null 2>&1; then
85
+ editor="vi"
86
+ else
87
+ error "Unable to find a usable editor, tried \${EDITOR} (${EDITOR}), editor, and vi."
88
+ exit 1
89
+ fi
90
+ elif ! command -v "${editor}" >/dev/null 2>&1; then
91
+ error "Unable to locate user specified editor ${editor}, is it in your PATH?"
92
+ exit 1
93
+ fi
94
+}
95
+
96
+running_in_container() {
97
+ [ -e /.dockerenv ] && return 0
98
+ [ -e /.dockerinit ] && return 0
99
+ [ -r /proc/1/environ ] && tr '\000' '\n' </proc/1/environ | grep -Eiq '^container=podman' && return 0
100
+ grep -qF -e /docker/ -e /libpod- /proc/self/cgroup 2>/dev/null && return 0
101
+}
102
+
103
+get_docker_command() {
104
+ if [ -x "${docker}" ]; then
105
+ return 0
106
+ elif command -v docker >/dev/null 2>&1; then
107
+ docker="$(command -v docker)"
108
+ elif command -v podman >/dev/null 2>&1; then
109
+ docker="$(command -v podman)"
110
+ else
111
+ error "Unable to find a usable container tool stack. I support Docker and Podman."
112
+ exit 1
113
+ fi
114
+}
115
+
116
+run_in_container() {
117
+ ${docker} exec "${1}" /bin/sh -c "${2}" || return 1
118
+ return 0
119
+}
120
+
121
+check_for_container() {
122
+ get_docker_command
123
+ ${docker} container inspect "${1}" >/dev/null 2>&1 || return 1
124
+ run_in_container "${1}" "[ -d \"${NETDATA_STOCK_CONFIG_DIR}\" ]" >/dev/null 2>&1 || return 1
125
+ return 0
126
+}
127
+
128
+handle_container() {
129
+ if running_in_container; then
130
+ return 0
131
+ elif [ -z "${container}" ] && [ -f "${script_dir}/.container-hostname" ]; then
132
+ echo >&2 "Autodetected containerized Netdata instance. Attempting to autodetect container ID."
133
+ possible_container="$(cat "${script_dir}/.container-hostname")"
134
+ if check_for_container "${possible_container}"; then
135
+ container="${possible_container}"
136
+ elif check_for_container netdata; then
137
+ container="netdata"
138
+ else
139
+ error "Could not autodetect container ID. It must be supplied on the command line with the --container option."
140
+ exit 1
141
+ fi
142
+
143
+ echo >&2 "Found Netdata container with ID or name ${container}"
144
+ elif [ -n "${container}" ]; then
145
+ if ! check_for_container "${container}"; then
146
+ error "No container with ID or name ${container} exists."
147
+ exit 1
148
+ fi
149
+ fi
150
+}
151
+
152
+list_files() {
153
+ check_directories
154
+ handle_container
155
+
156
+ if test -t; then
157
+ width="$(tput cols)"
158
+ fi
159
+
160
+ if [ -z "${container}" ]; then
161
+ if [ "$(uname -s)" = "Linux" ]; then
162
+ # shellcheck disable=SC2046,SC2086
163
+ files="$(cd "${NETDATA_STOCK_CONFIG_DIR}" && ls ${width:+-C} ${width:+-w ${width}} $(find . -type f | cut -d '/' -f 2-))"
164
+ elif [ "$(uname -s)" = "FreeBSD" ]; then
165
+ if [ -n "${width}" ]; then
166
+ export COLUMNS="${width}"
167
+ fi
168
+
169
+ # shellcheck disable=SC2046
170
+ files="$(cd "${NETDATA_STOCK_CONFIG_DIR}" && ls ${width:+-C} $(find . -type f | cut -d '/' -f 2-))"
171
+ else
172
+ # shellcheck disable=SC2046
173
+ files="$(cd "${NETDATA_STOCK_CONFIG_DIR}" && ls $(find . -type f | cut -d '/' -f 2-))"
174
+ fi
175
+ else
176
+ files="$(run_in_container "${container}" "cd /usr/lib/netdata/conf.d && ls ${width:+-C} ${width:+-w ${width}} \$(find . -type f | cut -d '/' -f 2-)")"
177
+ fi
178
+
179
+ if [ -z "${files}" ]; then
180
+ error "Failed to find any configuration files."
181
+ exit 1
182
+ fi
183
+
184
+ cat <<EOF
185
+The following configuration files are known to this script:
186
+
187
+${files}
188
+EOF
189
+ exit 0
190
+}
191
+
192
+parse_args() {
193
+ while [ -n "${1}" ]; do
194
+ case "${1}" in
195
+ "--help") usage ;;
196
+ "--list") list_files ;;
197
+ "--file")
198
+ if [ -n "${2}" ]; then
199
+ file="${2}"
200
+ shift 1
201
+ else
202
+ error "No file specified to edit."
203
+ exit 1
204
+ fi
205
+ ;;
206
+ "--container")
207
+ if [ -n "${2}" ]; then
208
+ container="${2}"
209
+ shift 1
210
+ else
211
+ error "No container ID or name specified with the --container option."
212
+ exit 1
213
+ fi
214
+ ;;
215
+ "--editor")
216
+ if [ -n "${2}" ]; then
217
+ editor="${2}"
218
+ shift 1
219
+ else
220
+ error "No editor specified with the --editor option."
221
+ exit 1
222
+ fi
223
+ ;;
224
+ *)
225
+ if [ -z "${2}" ]; then
226
+ file="${1}"
227
+ else
228
+ error "Unrecognized option ${1}."
229
+ exit 1
230
+ fi
231
+ ;;
232
+ esac
233
+ shift 1
234
+ done
235
+
236
+ [ -z "${file}" ] && usage
237
+
238
+ absfile="$(abspath "${file}")"
239
+ if ! is_prefix "${script_dir}" "${absfile}"; then
240
+ error "${file} is not located under ${script_dir}"
241
+ exit 1
242
+ fi
243
+
244
+ file="${absfile##"${script_dir}"}"
245
+}
246
+
247
+copy_native() {
248
+ if [ ! -w "${NETDATA_USER_CONFIG_DIR}" ]; then
249
+ error "Cannot write to ${NETDATA_USER_CONFIG_DIR}!"
250
+ exit 1
251
+ fi
252
+
253
+ if [ -f "${NETDATA_STOCK_CONFIG_DIR}/${1}" ]; then
254
+ echo >&2 "Copying '${NETDATA_STOCK_CONFIG_DIR}/${1}' to '${NETDATA_USER_CONFIG_DIR}/${1}' ... "
255
+ cp -p "${NETDATA_STOCK_CONFIG_DIR}/${1}" "${NETDATA_USER_CONFIG_DIR}/${1}" || exit 1
256
+ else
257
+ echo >&2 "Creating empty '${NETDATA_USER_CONFIG_DIR}/${1}' ... "
258
+ touch "${NETDATA_USER_CONFIG_DIR}/${1}" || exit 1
259
+ fi
260
+}
261
+
262
+copy_container() {
263
+ if [ ! -w "${NETDATA_USER_CONFIG_DIR}" ]; then
264
+ error "Cannot write to ${NETDATA_USER_CONFIG_DIR}!"
265
+ exit 1
266
+ fi
267
+
268
+ if run_in_container "${container}" "[ -f \"${NETDATA_STOCK_CONFIG_DIR}/${1}\" ]"; then
269
+ echo >&2 "Copying '${NETDATA_STOCK_CONFIG_DIR}/${1}' to '${NETDATA_USER_CONFIG_DIR}/${1}' ... "
270
+ ${docker} cp -a "${container}:${NETDATA_STOCK_CONFIG_DIR}/${1}" "${NETDATA_USER_CONFIG_DIR}/${1}" || exit 1
271
+ else
272
+ echo >&2 "Creating empty '${NETDATA_USER_CONFIG_DIR}/${1}' ... "
273
+ touch "${NETDATA_USER_CONFIG_DIR}/${1}" || exit 1
274
+ fi
275
+}
276
+
277
+copy() {
278
+ if [ -f "${NETDATA_USER_CONFIG_DIR}/${1}" ]; then
279
+ return 0
280
+ elif [ -n "${container}" ]; then
281
+ copy_container "${1}"
282
+ else
283
+ copy_native "${1}"
284
+ fi
285
+}
286
+
287
+edit() {
288
+ echo >&2 "Editing '${1}' ..."
289
+
290
+ # check we can edit
291
+ if [ ! -w "${1}" ]; then
292
+ error "Cannot write to ${1}!"
293
+ exit 1
294
+ fi
295
+
296
+ "${editor}" "${1}"
297
+ exit $?
298
+}
299
+
300
+main() {
301
+ parse_args "${@}"
302
+ check_directories
303
+ check_editor
304
+ handle_container
305
+ copy "${file}"
306
+ edit "${absfile}"
307
+}
308
+
309
+main "${@}"