mirror of
https://github.com/netdata/netdata.git
synced 2025-04-06 06:25:32 +00:00
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>
This commit is contained in:
parent
6f2f84936b
commit
56e22c16e8
5 changed files with 315 additions and 86 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -126,7 +126,6 @@ system/netdata-updater.service
|
|||
!system/netdata.service.*.in
|
||||
system/netdata.plist
|
||||
system/netdata-freebsd
|
||||
system/edit-config
|
||||
system/netdata.crontab
|
||||
system/install-service.sh
|
||||
|
||||
|
|
|
@ -49,6 +49,12 @@ if mountpoint -q /etc/netdata && [ -z "$(ls -A /etc/netdata)" ]; then
|
|||
cp -a /etc/netdata.stock/. /etc/netdata
|
||||
fi
|
||||
|
||||
if mountpoint -q /etc/netdata; then
|
||||
hostname > /etc/netdata/.container-hostname
|
||||
else
|
||||
rm -f /etc/netdata/.container-hostname
|
||||
fi
|
||||
|
||||
if [ -n "${NETDATA_CLAIM_URL}" ] && [ -n "${NETDATA_CLAIM_TOKEN}" ] && [ ! -f /var/lib/netdata/cloud.d/claimed_id ]; then
|
||||
# shellcheck disable=SC2086
|
||||
/usr/sbin/netdata-claim.sh -token="${NETDATA_CLAIM_TOKEN}" \
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
CLEANFILES = \
|
||||
edit-config \
|
||||
netdata-openrc \
|
||||
netdata.logrotate \
|
||||
netdata.service \
|
||||
|
@ -55,7 +54,6 @@ dist_libsys_DATA = \
|
|||
$(NULL)
|
||||
|
||||
dist_noinst_DATA = \
|
||||
edit-config.in \
|
||||
install-service.sh.in \
|
||||
netdata-openrc.in \
|
||||
netdata.logrotate.in \
|
||||
|
|
309
system/edit-config
Executable file
309
system/edit-config
Executable file
|
@ -0,0 +1,309 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
[ -f /etc/profile ] && . /etc/profile
|
||||
|
||||
set -e
|
||||
|
||||
script_dir="$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd -P)"
|
||||
|
||||
usage() {
|
||||
check_directories
|
||||
cat <<EOF
|
||||
USAGE:
|
||||
${0} [options] FILENAME
|
||||
|
||||
Copy and edit the stock config file named: FILENAME
|
||||
if FILENAME is already copied, it will be edited as-is.
|
||||
|
||||
Stock config files at: '${NETDATA_STOCK_CONFIG_DIR}'
|
||||
User config files at: '${NETDATA_USER_CONFIG_DIR}'
|
||||
|
||||
The editor to use can be specified either by setting the EDITOR
|
||||
environment variable, or by using the --editor option.
|
||||
|
||||
The file to edit can also be specified using the --file option.
|
||||
|
||||
For a list of known config files, run '${0} --list'
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
error() {
|
||||
echo >&2 "ERROR: ${1}"
|
||||
}
|
||||
|
||||
abspath() {
|
||||
if [ -d "${1}" ]; then
|
||||
echo "$(cd "${1}" && /usr/bin/env PWD= pwd -P)/"
|
||||
else
|
||||
echo "$(cd "$(dirname "${1}")" && /usr/bin/env PWD= pwd -P)/$(basename "${1}")"
|
||||
fi
|
||||
}
|
||||
|
||||
is_prefix() {
|
||||
echo "${2}" | grep -qE "^${1}"
|
||||
return $?
|
||||
}
|
||||
|
||||
check_directories() {
|
||||
if [ -e "${script_dir}/.environment" ]; then
|
||||
OLDPATH="${PATH}"
|
||||
# shellcheck disable=SC1091
|
||||
. "${script_dir}/.environment"
|
||||
PATH="${OLDPATH}"
|
||||
fi
|
||||
|
||||
if [ -n "${NETDATA_PREFIX}" ] && [ -d "${NETDATA_PREFIX}/usr/lib/netdata/conf.d" ]; then
|
||||
stock_dir="${NETDATA_PREFIX}/usr/lib/netdata/conf.d"
|
||||
elif [ -n "${NETDATA_PREFIX}" ] && [ -d "${NETDATA_PREFIX}/lib/netdata/conf.d" ]; then
|
||||
stock_dir="${NETDATA_PREFIX}/lib/netdata/conf.d"
|
||||
elif [ -d "${script_dir}/../../usr/lib/netdata/conf.d" ]; then
|
||||
stock_dir="${script_dir}/../../usr/lib/netdata/conf.d"
|
||||
elif [ -d "${script_dir}/../../lib/netdata/conf.d" ]; then
|
||||
stock_dir="${script_dir}/../../lib/netdata/conf.d"
|
||||
elif [ -d "/usr/lib/netdata/conf.d" ]; then
|
||||
stock_dir="/usr/lib/netdata/conf.d"
|
||||
fi
|
||||
|
||||
[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="${script_dir}"
|
||||
[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="${stock_dir}"
|
||||
|
||||
if [ -z "${NETDATA_STOCK_CONFIG_DIR}" ]; then
|
||||
error "Unable to find stock config directory."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_editor() {
|
||||
if [ -z "${editor}" ]; then
|
||||
if [ -n "${EDITOR}" ] && command -v "${EDITOR}" >/dev/null 2>&1; then
|
||||
editor="${EDITOR}"
|
||||
elif command -v editor >/dev/null 2>&1; then
|
||||
editor="editor"
|
||||
elif command -v vi >/dev/null 2>&1; then
|
||||
editor="vi"
|
||||
else
|
||||
error "Unable to find a usable editor, tried \${EDITOR} (${EDITOR}), editor, and vi."
|
||||
exit 1
|
||||
fi
|
||||
elif ! command -v "${editor}" >/dev/null 2>&1; then
|
||||
error "Unable to locate user specified editor ${editor}, is it in your PATH?"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
running_in_container() {
|
||||
[ -e /.dockerenv ] && return 0
|
||||
[ -e /.dockerinit ] && return 0
|
||||
[ -r /proc/1/environ ] && tr '\000' '\n' </proc/1/environ | grep -Eiq '^container=podman' && return 0
|
||||
grep -qF -e /docker/ -e /libpod- /proc/self/cgroup 2>/dev/null && return 0
|
||||
}
|
||||
|
||||
get_docker_command() {
|
||||
if [ -x "${docker}" ]; then
|
||||
return 0
|
||||
elif command -v docker >/dev/null 2>&1; then
|
||||
docker="$(command -v docker)"
|
||||
elif command -v podman >/dev/null 2>&1; then
|
||||
docker="$(command -v podman)"
|
||||
else
|
||||
error "Unable to find a usable container tool stack. I support Docker and Podman."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_in_container() {
|
||||
${docker} exec "${1}" /bin/sh -c "${2}" || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
check_for_container() {
|
||||
get_docker_command
|
||||
${docker} container inspect "${1}" >/dev/null 2>&1 || return 1
|
||||
run_in_container "${1}" "[ -d \"${NETDATA_STOCK_CONFIG_DIR}\" ]" >/dev/null 2>&1 || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
handle_container() {
|
||||
if running_in_container; then
|
||||
return 0
|
||||
elif [ -z "${container}" ] && [ -f "${script_dir}/.container-hostname" ]; then
|
||||
echo >&2 "Autodetected containerized Netdata instance. Attempting to autodetect container ID."
|
||||
possible_container="$(cat "${script_dir}/.container-hostname")"
|
||||
if check_for_container "${possible_container}"; then
|
||||
container="${possible_container}"
|
||||
elif check_for_container netdata; then
|
||||
container="netdata"
|
||||
else
|
||||
error "Could not autodetect container ID. It must be supplied on the command line with the --container option."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo >&2 "Found Netdata container with ID or name ${container}"
|
||||
elif [ -n "${container}" ]; then
|
||||
if ! check_for_container "${container}"; then
|
||||
error "No container with ID or name ${container} exists."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
list_files() {
|
||||
check_directories
|
||||
handle_container
|
||||
|
||||
if test -t; then
|
||||
width="$(tput cols)"
|
||||
fi
|
||||
|
||||
if [ -z "${container}" ]; then
|
||||
if [ "$(uname -s)" = "Linux" ]; then
|
||||
# shellcheck disable=SC2046,SC2086
|
||||
files="$(cd "${NETDATA_STOCK_CONFIG_DIR}" && ls ${width:+-C} ${width:+-w ${width}} $(find . -type f | cut -d '/' -f 2-))"
|
||||
elif [ "$(uname -s)" = "FreeBSD" ]; then
|
||||
if [ -n "${width}" ]; then
|
||||
export COLUMNS="${width}"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2046
|
||||
files="$(cd "${NETDATA_STOCK_CONFIG_DIR}" && ls ${width:+-C} $(find . -type f | cut -d '/' -f 2-))"
|
||||
else
|
||||
# shellcheck disable=SC2046
|
||||
files="$(cd "${NETDATA_STOCK_CONFIG_DIR}" && ls $(find . -type f | cut -d '/' -f 2-))"
|
||||
fi
|
||||
else
|
||||
files="$(run_in_container "${container}" "cd /usr/lib/netdata/conf.d && ls ${width:+-C} ${width:+-w ${width}} \$(find . -type f | cut -d '/' -f 2-)")"
|
||||
fi
|
||||
|
||||
if [ -z "${files}" ]; then
|
||||
error "Failed to find any configuration files."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
The following configuration files are known to this script:
|
||||
|
||||
${files}
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
while [ -n "${1}" ]; do
|
||||
case "${1}" in
|
||||
"--help") usage ;;
|
||||
"--list") list_files ;;
|
||||
"--file")
|
||||
if [ -n "${2}" ]; then
|
||||
file="${2}"
|
||||
shift 1
|
||||
else
|
||||
error "No file specified to edit."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
"--container")
|
||||
if [ -n "${2}" ]; then
|
||||
container="${2}"
|
||||
shift 1
|
||||
else
|
||||
error "No container ID or name specified with the --container option."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
"--editor")
|
||||
if [ -n "${2}" ]; then
|
||||
editor="${2}"
|
||||
shift 1
|
||||
else
|
||||
error "No editor specified with the --editor option."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if [ -z "${2}" ]; then
|
||||
file="${1}"
|
||||
else
|
||||
error "Unrecognized option ${1}."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
shift 1
|
||||
done
|
||||
|
||||
[ -z "${file}" ] && usage
|
||||
|
||||
absfile="$(abspath "${file}")"
|
||||
if ! is_prefix "${script_dir}" "${absfile}"; then
|
||||
error "${file} is not located under ${script_dir}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
file="${absfile##"${script_dir}"}"
|
||||
}
|
||||
|
||||
copy_native() {
|
||||
if [ ! -w "${NETDATA_USER_CONFIG_DIR}" ]; then
|
||||
error "Cannot write to ${NETDATA_USER_CONFIG_DIR}!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f "${NETDATA_STOCK_CONFIG_DIR}/${1}" ]; then
|
||||
echo >&2 "Copying '${NETDATA_STOCK_CONFIG_DIR}/${1}' to '${NETDATA_USER_CONFIG_DIR}/${1}' ... "
|
||||
cp -p "${NETDATA_STOCK_CONFIG_DIR}/${1}" "${NETDATA_USER_CONFIG_DIR}/${1}" || exit 1
|
||||
else
|
||||
echo >&2 "Creating empty '${NETDATA_USER_CONFIG_DIR}/${1}' ... "
|
||||
touch "${NETDATA_USER_CONFIG_DIR}/${1}" || exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
copy_container() {
|
||||
if [ ! -w "${NETDATA_USER_CONFIG_DIR}" ]; then
|
||||
error "Cannot write to ${NETDATA_USER_CONFIG_DIR}!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if run_in_container "${container}" "[ -f \"${NETDATA_STOCK_CONFIG_DIR}/${1}\" ]"; then
|
||||
echo >&2 "Copying '${NETDATA_STOCK_CONFIG_DIR}/${1}' to '${NETDATA_USER_CONFIG_DIR}/${1}' ... "
|
||||
${docker} cp -a "${container}:${NETDATA_STOCK_CONFIG_DIR}/${1}" "${NETDATA_USER_CONFIG_DIR}/${1}" || exit 1
|
||||
else
|
||||
echo >&2 "Creating empty '${NETDATA_USER_CONFIG_DIR}/${1}' ... "
|
||||
touch "${NETDATA_USER_CONFIG_DIR}/${1}" || exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
copy() {
|
||||
if [ -f "${NETDATA_USER_CONFIG_DIR}/${1}" ]; then
|
||||
return 0
|
||||
elif [ -n "${container}" ]; then
|
||||
copy_container "${1}"
|
||||
else
|
||||
copy_native "${1}"
|
||||
fi
|
||||
}
|
||||
|
||||
edit() {
|
||||
echo >&2 "Editing '${1}' ..."
|
||||
|
||||
# check we can edit
|
||||
if [ ! -w "${1}" ]; then
|
||||
error "Cannot write to ${1}!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"${editor}" "${1}"
|
||||
exit $?
|
||||
}
|
||||
|
||||
main() {
|
||||
parse_args "${@}"
|
||||
check_directories
|
||||
check_editor
|
||||
handle_container
|
||||
copy "${file}"
|
||||
edit "${absfile}"
|
||||
}
|
||||
|
||||
main "${@}"
|
|
@ -1,83 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
[ -f /etc/profile ] && . /etc/profile
|
||||
|
||||
file="${1}"
|
||||
|
||||
if [ "$(command -v editor)" ]; then
|
||||
EDITOR="${EDITOR-editor}"
|
||||
else
|
||||
EDITOR="${EDITOR-vi}"
|
||||
fi
|
||||
|
||||
[ -z "${NETDATA_USER_CONFIG_DIR}" ] && NETDATA_USER_CONFIG_DIR="@configdir_POST@"
|
||||
[ -z "${NETDATA_STOCK_CONFIG_DIR}" ] && NETDATA_STOCK_CONFIG_DIR="@libconfigdir_POST@"
|
||||
|
||||
if [ -z "${file}" ]; then
|
||||
cat << EOF
|
||||
|
||||
USAGE:
|
||||
${0} FILENAME
|
||||
|
||||
Copy and edit the stock config file named: FILENAME
|
||||
if FILENAME is already copied, it will be edited as-is.
|
||||
|
||||
The EDITOR shell variable is used to define the editor to be used.
|
||||
|
||||
Stock config files at: '${NETDATA_STOCK_CONFIG_DIR}'
|
||||
User config files at: '${NETDATA_USER_CONFIG_DIR}'
|
||||
|
||||
Available files in '${NETDATA_STOCK_CONFIG_DIR}' to copy and edit:
|
||||
|
||||
EOF
|
||||
|
||||
cd "${NETDATA_STOCK_CONFIG_DIR}" || exit 1
|
||||
ls >&2 -R ./*.conf ./*/*.conf
|
||||
exit 1
|
||||
|
||||
fi
|
||||
|
||||
edit() {
|
||||
echo >&2 "Editing '${1}' ..."
|
||||
|
||||
# check we can edit
|
||||
if [ ! -w "${1}" ]; then
|
||||
echo >&2 "Cannot write to ${1}! Aborting ..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"${EDITOR}" "${1}"
|
||||
exit $?
|
||||
}
|
||||
|
||||
copy_and_edit() {
|
||||
# check we can copy
|
||||
if [ ! -w "${NETDATA_USER_CONFIG_DIR}" ]; then
|
||||
echo >&2 "Cannot write to ${NETDATA_USER_CONFIG_DIR}! Aborting ..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${NETDATA_USER_CONFIG_DIR}/${1}" ]; then
|
||||
echo >&2 "Copying '${NETDATA_STOCK_CONFIG_DIR}/${1}' to '${NETDATA_USER_CONFIG_DIR}/${1}' ... "
|
||||
cp -p "${NETDATA_STOCK_CONFIG_DIR}/${1}" "${NETDATA_USER_CONFIG_DIR}/${1}" || exit 1
|
||||
fi
|
||||
|
||||
edit "${NETDATA_USER_CONFIG_DIR}/${1}"
|
||||
}
|
||||
|
||||
# make sure it is not absolute filename
|
||||
c1="$(echo "${file}" | cut -b 1)"
|
||||
if [ "${c1}" = "/" ] || [ "${c1}" = "." ]; then
|
||||
echo >&2 "Please don't use filenames starting with '/' or '.'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# already exists
|
||||
[ -f "${NETDATA_USER_CONFIG_DIR}/${file}" ] && edit "${NETDATA_USER_CONFIG_DIR}/${file}"
|
||||
|
||||
# stock config is valid, copy and edit
|
||||
[ -f "${NETDATA_STOCK_CONFIG_DIR}/${file}" ] && copy_and_edit "${file}"
|
||||
|
||||
# no such config found
|
||||
echo >&2 "File '${file}' is not found in '${NETDATA_STOCK_CONFIG_DIR}'"
|
||||
exit 1
|
Loading…
Add table
Reference in a new issue