@cryptotaxi247 / netdata-1 / commits / 56e22c16e

Cleanly reimplement system/edit-config.in. (#13702)

* Cleanly reimplement system/edit-config.in - Added support for pulling config files from Docker containers. - Added auto-detection for Docker containers. - Use directory the script is in for target directory for config files instead of templating it in at build time. - Prefix error messages with `ERROR:`. - Robustly check for a valid editor _before_ invoking it. - Add support for actual command-line options, including a proper `--help` option. - Use prefix matching of absolute paths to determine file validity instead of blindly excluding certain path types. - If editing a non-existing file we do not provide a stock copy of, create an empty file instead of throwing an error. - Make the whole script properly modular. * Improve robustness of container autodetection. Instead of relying on the lack of certain directories on a host system, use some relatively standard checks to determine if we appear to be running in a container. * Auto-detect stock config paths at runtinme instead of hard-coding them at build time. THis will simplify testing of the script, as well as making it a bit more resilient to users moving things around. * Add an option to list known config files. * Fix container environment check to not require root. * Fix help output. * Fix path prefix check. * Fix file path handling. * Use correct variable when editing files. * Use correct path for `env`. * Source profile before running `set -e`. To prevent questionablly written profiles from causing the script to exit. * Produce columnar output when listing valid files. * Fix copy check. * Fix build issues. * fix build issues * formatting Co-authored-by: ilyam8 <ilya@netdata.cloud>

Austin S. Hemmelgarn committed Dec 6, 2022 at 10:53 UTC 56e22c16e8de8ae63f58bca359351e6f10c15af5
5 files changed +315 -86
.gitignore
-1
@@ -126,7 +126,6 @@ system/netdata-updater.service
126 !system/netdata.service.*.in
127 system/netdata.plist
128 system/netdata-freebsd
129 -system/edit-config
129 system/netdata.crontab
130 system/install-service.sh
131
packaging/docker/run.sh
+6
@@ -49,6 +49,12 @@ if mountpoint -q /etc/netdata && [ -z "$(ls -A /etc/netdata)" ]; then
49 cp -a /etc/netdata.stock/. /etc/netdata
50 fi
51
52 +if mountpoint -q /etc/netdata; then
53 + hostname > /etc/netdata/.container-hostname
54 +else
55 + rm -f /etc/netdata/.container-hostname
56 +fi
57 +
58 if [ -n "${NETDATA_CLAIM_URL}" ] && [ -n "${NETDATA_CLAIM_TOKEN}" ] && [ ! -f /var/lib/netdata/cloud.d/claimed_id ]; then
59 # shellcheck disable=SC2086
60 /usr/sbin/netdata-claim.sh -token="${NETDATA_CLAIM_TOKEN}" \
system/Makefile.am
-2
@@ -3,7 +3,6 @@
3
4 MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
5 CLEANFILES = \
6 - edit-config \
6 netdata-openrc \
7 netdata.logrotate \
8 netdata.service \
@@ -55,7 +54,6 @@ dist_libsys_DATA = \
54 $(NULL)
55
56 dist_noinst_DATA = \
58 - edit-config.in \
57 install-service.sh.in \
58 netdata-openrc.in \
59 netdata.logrotate.in \
system/edit-config new
+309
@@ -0,0 +1,309 @@
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 "${@}"
system/edit-config.in deleted
-83
@@ -1,83 +0,0 @@
1 -#!/usr/bin/env sh
2 -
3 -[ -f /etc/profile ] && . /etc/profile
4 -
5 -file="${1}"
6 -
7 -if [ "$(command -v editor)" ]; then
8 - EDITOR="${EDITOR-editor}"
9 -else
10 - EDITOR="${EDITOR-vi}"
11 -fi
12 -
13 -[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="@configdir_POST@"
14 -[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="@libconfigdir_POST@"
15 -
16 -if [ -z "${file}" ]; then
17 - cat << EOF
18 -
19 -USAGE:
20 - ${0} FILENAME
21 -
22 - Copy and edit the stock config file named: FILENAME
23 - if FILENAME is already copied, it will be edited as-is.
24 -
25 - The EDITOR shell variable is used to define the editor to be used.
26 -
27 - Stock config files at: '${NETDATA_STOCK_CONFIG_DIR}'
28 - User config files at: '${NETDATA_USER_CONFIG_DIR}'
29 -
30 - Available files in '${NETDATA_STOCK_CONFIG_DIR}' to copy and edit:
31 -
32 -EOF
33 -
34 - cd "${NETDATA_STOCK_CONFIG_DIR}" || exit 1
35 - ls >&2 -R ./*.conf ./*/*.conf
36 - exit 1
37 -
38 -fi
39 -
40 -edit() {
41 - echo >&2 "Editing '${1}' ..."
42 -
43 - # check we can edit
44 - if [ ! -w "${1}" ]; then
45 - echo >&2 "Cannot write to ${1}! Aborting ..."
46 - exit 1
47 - fi
48 -
49 - "${EDITOR}" "${1}"
50 - exit $?
51 -}
52 -
53 -copy_and_edit() {
54 - # check we can copy
55 - if [ ! -w "${NETDATA_USER_CONFIG_DIR}" ]; then
56 - echo >&2 "Cannot write to ${NETDATA_USER_CONFIG_DIR}! Aborting ..."
57 - exit 1
58 - fi
59 -
60 - if [ ! -f "${NETDATA_USER_CONFIG_DIR}/${1}" ]; then
61 - echo >&2 "Copying '${NETDATA_STOCK_CONFIG_DIR}/${1}' to '${NETDATA_USER_CONFIG_DIR}/${1}' ... "
62 - cp -p "${NETDATA_STOCK_CONFIG_DIR}/${1}" "${NETDATA_USER_CONFIG_DIR}/${1}" || exit 1
63 - fi
64 -
65 - edit "${NETDATA_USER_CONFIG_DIR}/${1}"
66 -}
67 -
68 -# make sure it is not absolute filename
69 -c1="$(echo "${file}" | cut -b 1)"
70 -if [ "${c1}" = "/" ] || [ "${c1}" = "." ]; then
71 - echo >&2 "Please don't use filenames starting with '/' or '.'"
72 - exit 1
73 -fi
74 -
75 -# already exists
76 -[ -f "${NETDATA_USER_CONFIG_DIR}/${file}" ] && edit "${NETDATA_USER_CONFIG_DIR}/${file}"
77 -
78 -# stock config is valid, copy and edit
79 -[ -f "${NETDATA_STOCK_CONFIG_DIR}/${file}" ] && copy_and_edit "${file}"
80 -
81 -# no such config found
82 -echo >&2 "File '${file}' is not found in '${NETDATA_STOCK_CONFIG_DIR}'"
83 -exit 1