Compare commits
8 commits
67bc8aa02b
...
977b530dab
Author | SHA1 | Date | |
---|---|---|---|
977b530dab | |||
1865ff9dce | |||
1af7e960fa | |||
3e77fbbb43 | |||
afa48b1028 | |||
c5929f397d | |||
d5b552ddb4 | |||
51d0b817fe |
12 changed files with 511 additions and 0 deletions
10
type/__single_binary_service/explorer/explorer-version
Executable file
10
type/__single_binary_service/explorer/explorer-version
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
BIN_PREFIX="/usr/local/bin"
|
||||
SERVICE_NAME="${__object_id}"
|
||||
|
||||
VERSION_FILE="${BIN_PREFIX}/.${SERVICE_NAME}.cdist.version"
|
||||
|
||||
if [ -f "${VERSION_FILE}" ]; then
|
||||
cat "${VERSION_FILE}"
|
||||
fi
|
190
type/__single_binary_service/man.rst
Normal file
190
type/__single_binary_service/man.rst
Normal file
|
@ -0,0 +1,190 @@
|
|||
cdist-type__single_binary_service(7)
|
||||
====================================
|
||||
|
||||
NAME
|
||||
----
|
||||
cdist-type__single_binary_service - Setup a single-binary service
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This type is designed to easily deploy and configure a single-binary service
|
||||
named `${__object_id}`.
|
||||
|
||||
A good example of this are Prometheus exporters.
|
||||
|
||||
This type makes certain assumptions that might not be correct on your system.
|
||||
If you need more flexibility, please get in touch and provide a use-case
|
||||
(and hopefully a backwards-compatible patch).
|
||||
|
||||
This type will place the downloaded binary and, if requested, other extra
|
||||
binaries in `/usr/local/bin`.
|
||||
|
||||
If a `--config-file-source` is provided, it will be placed under:
|
||||
`/etc/${__object_id}.conf`.
|
||||
|
||||
This type supports services managed by `__runit(7)` when `systemd` is not
|
||||
the init system being used.
|
||||
|
||||
|
||||
REQUIRED PARAMETERS
|
||||
-------------------
|
||||
checksum
|
||||
This will be passed verbatim to `__download(7)`.
|
||||
Use something like `sha256:...`.
|
||||
|
||||
url
|
||||
This will be passed verbatim to `__download(7)`.
|
||||
|
||||
version
|
||||
This type will use a thumbstone file with a "version" number to track
|
||||
whether or not a service must be updated.
|
||||
This thumbstone file is placed under
|
||||
`/usr/local/bin/.${__object_id}.cdist.version`.
|
||||
|
||||
|
||||
BOOLEAN PARAMETERS
|
||||
------------------
|
||||
unpack
|
||||
If present, the contents of `--url` will be treated as an archive to be
|
||||
unpacked with `__unpack(7)`.
|
||||
See also `--unpack-args` and `--extra-binary`.
|
||||
|
||||
do-not-manage-user
|
||||
Always considered present when `--user` is `root`.
|
||||
If present, the user in `--user` will not be managed by this type with
|
||||
`__user`, this means it *must* exist beforehand when installing the service
|
||||
and it will not be removed by this type.
|
||||
|
||||
|
||||
OPTIONAL PARAMETERS
|
||||
-------------------
|
||||
config-file-source
|
||||
If present, this file's contents will be placed under
|
||||
`/etc/${__object_id}.conf` with permissions `0440` and ownership assigned to
|
||||
`--user` and `--group`.
|
||||
If `-` is passed, this type's `stdin` will be used.
|
||||
|
||||
user
|
||||
The user under which the service will run. Defaults to `root`.
|
||||
If this user is not `root` and `--do-not-manage-user` is not present,
|
||||
this user will be created or removed as per the `--state` parameter.
|
||||
|
||||
user-home-dir
|
||||
Does not have an effect if `--do-not-manage-user` is used or `--user` is
|
||||
`root`.
|
||||
The home directory of the service user. It will be created.
|
||||
Defaults to `/nonexistent`, in this case the home directory will not be
|
||||
created.
|
||||
|
||||
group
|
||||
The group under which the service will run. Defaults to `--user`.
|
||||
|
||||
state
|
||||
Whether the service is to be `present` (default) or `absent`.
|
||||
When `absent`, this type will clean any binaries listed in `--extra-binary`
|
||||
and also the config file as described in `--config-file-source`.
|
||||
|
||||
binary
|
||||
This will be the binary name. Defaults to `${__object_id}`.
|
||||
If `--unpack` is used, a binary with this name must be unpacked.
|
||||
Otherwise, the contents of `--url` will be placed under this binary name.
|
||||
|
||||
service-args
|
||||
Any extra arguments to pass along with `--service-exec`. Beware that any
|
||||
service-args having the format `--config=/etc/foo.cfg` should be
|
||||
represented in the following way `--service-exec='--config=/etc/foo.cfg'`
|
||||
|
||||
service-exec
|
||||
The executable to use for this service.
|
||||
Defaults to `/usr/local/bin/BINARY_NAME` where `BINARY_NAME` is the
|
||||
resulting value of `--binary`.
|
||||
|
||||
service-definition
|
||||
The service definition to be used as an override.
|
||||
Note that this type decides dinammically between runit and systemd, and
|
||||
you can currently only define either a systemd unit or a runit script here.
|
||||
Use this parameter only for testing and get in touch to discuss how your
|
||||
particular use-case can be supported by the type.
|
||||
|
||||
service-description
|
||||
The service description to be used in, e.g. the systemd unit file.
|
||||
Defaults to `cdist-managed '${__object_id}' service`.
|
||||
|
||||
unpack-args
|
||||
Only has an effect if `--unpack` is used.
|
||||
These arguments will be passed verbatim to `__unpack(7)`.
|
||||
Very useful as this type assumes the archive does not have the binaries in
|
||||
subdirectories; that can be worked around with
|
||||
`--unpack-args '--tar-strip 1'`.
|
||||
|
||||
unpack-extension
|
||||
Only has an effect if `--unpack` is used.
|
||||
The file extension of the file to unpack, defaults to `.tar.gz`.
|
||||
|
||||
working-directory
|
||||
If set, the working directory with which the service will be started.
|
||||
|
||||
|
||||
OPTIONAL MULTIPLE PARAMETERS
|
||||
----------------------------
|
||||
extra-binary
|
||||
Only useful with `--unpack`.
|
||||
If passed, these binaries will also be installed when `--state` is `present`
|
||||
and removed when `--state` is `absent`.
|
||||
Handle with care :-).
|
||||
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# Install and enable the ipmi_exporter service
|
||||
# The variables are defined in the manifest previously
|
||||
__single_binary_service ipmi_exporter \
|
||||
--user "${USER}" \
|
||||
--service-args ' --config.file=/etc/ipmi_exporter.conf' \
|
||||
--version "${SHOULD_VERSION}" \
|
||||
--checksum "${CHECKSUM}" \
|
||||
--url "${DOWNLOAD_URL}" \
|
||||
--state "present" \
|
||||
--unpack \
|
||||
--unpack-args "--tar-strip 1" \
|
||||
--config-file-source '-' <<-EOF
|
||||
# Remotely managed, changes will be lost
|
||||
# [...] config contents goes here
|
||||
EOF
|
||||
|
||||
# Remove the ipmi_exporter service along with the user and its config
|
||||
__single_binary_service ipmi_exporter \
|
||||
--user "${USER}" \
|
||||
--version "${SHOULD_VERSION}" \
|
||||
--checksum "${CHECKSUM}" \
|
||||
--url "${DOWNLOAD_URL}" \
|
||||
--state "absent"
|
||||
|
||||
# Same, but the service was using my user! Let's not delete that!
|
||||
__single_binary_service ipmi_exporter \
|
||||
--user "evilham" \
|
||||
--do-not-manage-user \
|
||||
--version "${SHOULD_VERSION}" \
|
||||
--checksum "${CHECKSUM}" \
|
||||
--url "${DOWNLOAD_URL}" \
|
||||
--state "absent"
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
- `__download(7)`
|
||||
- `__unpack(7)`
|
||||
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
Evilham <contact@evilham.com>
|
||||
|
||||
|
||||
COPYING
|
||||
-------
|
||||
Copyright \(C) 2022 Evilham.
|
288
type/__single_binary_service/manifest
Executable file
288
type/__single_binary_service/manifest
Executable file
|
@ -0,0 +1,288 @@
|
|||
#!/bin/sh -e
|
||||
SERVICE_NAME="${__object_id}"
|
||||
|
||||
OS="$(cat "${__global}/explorer/os")"
|
||||
|
||||
case "${OS}" in
|
||||
debian|devuan)
|
||||
SUPER_USER_GROUP=root
|
||||
ETC_DIR="/etc"
|
||||
;;
|
||||
*bsd)
|
||||
SUPER_USER_GROUP=wheel
|
||||
ETC_DIR="/usr/local/etc"
|
||||
;;
|
||||
*)
|
||||
echo "Your OS '${OS}' is currently not supported." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
INIT="$(cat "${__global}/explorer/init")"
|
||||
|
||||
case "${INIT}" in
|
||||
systemd)
|
||||
service_definition_require="__systemd_unit/${SERVICE_NAME}.service"
|
||||
service_command="service ${SERVICE_NAME} %s"
|
||||
;;
|
||||
runit|sysvinit)
|
||||
# We will use runit to manage these services
|
||||
__runit
|
||||
export require="__runit"
|
||||
service_definition_require="__runit_service/${SERVICE_NAME}"
|
||||
service_command="sv %s ${SERVICE_NAME}"
|
||||
;;
|
||||
*)
|
||||
echo "Init system ${INIT}' is currently not supported." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
BIN_DIR="/usr/local/bin"
|
||||
|
||||
# Ensure the target bin dir exists
|
||||
# Care, we never want to remove it :-D
|
||||
__directory "${BIN_DIR}" \
|
||||
--state "exists" \
|
||||
--mode 0755
|
||||
export require="${require} __directory${BIN_DIR}"
|
||||
|
||||
STATE="$(cat "${__object}/parameter/state")"
|
||||
USER="$(cat "${__object}/parameter/user")"
|
||||
GROUP="$(cat "${__object}/parameter/group" 2>/dev/null || true)"
|
||||
if [ -z "${GROUP}" ]; then
|
||||
if [ "${USER}" != "root" ]; then
|
||||
GROUP="${USER}"
|
||||
else
|
||||
GROUP="${SUPER_USER_GROUP}"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
BINARY="$(cat "${__object}/parameter/binary" 2>/dev/null || true)"
|
||||
if [ -z "${BINARY}" ]; then
|
||||
BINARY="${SERVICE_NAME}"
|
||||
fi
|
||||
EXTRA_BINARIES="$(cat "${__object}/parameter/extra-binary" 2>/dev/null || true)"
|
||||
# This only makes sense for file archives
|
||||
if [ -n "${EXTRA_BINARIES}" ] && [ -f "${__object}/parameter/unpack" ]; then
|
||||
cat >&2 <<-EOF
|
||||
You cannot specify extra binaries without the --unpack argument.
|
||||
Make sure that the --url argument points to a file archive.
|
||||
EOF
|
||||
fi
|
||||
|
||||
SERVICE_EXEC="$(cat "${__object}/parameter/service-exec" 2>/dev/null || true)"
|
||||
if [ -z "${SERVICE_EXEC}" ]; then
|
||||
SERVICE_EXEC="${BIN_DIR}/${BINARY}"
|
||||
fi
|
||||
SERVICE_ARGS="$(cat "${__object}/parameter/service-args")"
|
||||
SERVICE_EXEC="${SERVICE_EXEC} ${SERVICE_ARGS}"
|
||||
|
||||
SERVICE_DESCRIPTION="$(cat "${__object}/parameter/service-description" \
|
||||
2>/dev/null || true)"
|
||||
if [ -z "${SERVICE_DESCRIPTION}" ]; then
|
||||
SERVICE_DESCRIPTION="cdist-managed '${SERVICE_NAME}' service"
|
||||
fi
|
||||
|
||||
SERVICE_DEFINITION="$(cat "${__object}/parameter/service-definition" 2>/dev/null || true)"
|
||||
|
||||
WORKING_DIRECTORY_PATH="$(cat "${__object}/parameter/working-directory" 2>/dev/null || true)"
|
||||
if [ -n "${WORKING_DIRECTORY_PATH}" ]; then
|
||||
WORKING_DIRECTORY_SYSTEMD="WorkingDirectory=${WORKING_DIRECTORY_PATH}"
|
||||
WORKING_DIRECTORY_RUNIT="cd '${WORKING_DIRECTORY_PATH}'"
|
||||
fi
|
||||
|
||||
DOWNLOAD_URL="$(cat "${__object}/parameter/url")"
|
||||
CHECKSUM="$(cat "${__object}/parameter/checksum")"
|
||||
SHOULD_VERSION="$(cat "${__object}/parameter/version")"
|
||||
|
||||
# Create a user for the service if it is not root
|
||||
USER_HOME_DIR="/root"
|
||||
if [ "${USER}" != "root" ] && \
|
||||
[ ! -f "${__object}/parameter/do-not-manage-user" ]; then
|
||||
if [ "${STATE}" = "absent" ]; then
|
||||
# When removing, ensure user is not being used
|
||||
user_require="${service_definition_require}"
|
||||
fi
|
||||
USER_HOME_DIR="$(cat "${__object}/parameter/user-home-dir")"
|
||||
if [ "${USER_HOME_DIR}" != "/nonexistent" ]; then
|
||||
USER_CREATE_HOME="--create-home"
|
||||
fi
|
||||
require="${require} ${user_require}" __user "${USER}" \
|
||||
--system \
|
||||
--state "${STATE}" \
|
||||
--home "${USER_HOME_DIR}" \
|
||||
--comment "cdist-managed ${SERVICE_NAME} user" \
|
||||
${USER_CREATE_HOME}
|
||||
# Track dependencies
|
||||
service_require="${service_require} __user/${USER}"
|
||||
fi
|
||||
|
||||
# Place config file if necessary
|
||||
CONFIG_FILE_DEST="${ETC_DIR}/${SERVICE_NAME}.conf"
|
||||
CONFIG_FILE_SOURCE="$(cat "${__object}/parameter/config-file-source" 2>/dev/null || true)"
|
||||
if [ "${CONFIG_FILE_SOURCE}" = "-" ]; then
|
||||
CONFIG_FILE_SOURCE="${__object}/stdin"
|
||||
fi
|
||||
if [ -n "${CONFIG_FILE_SOURCE}" ] && [ "${STATE}" = "present" ]; then
|
||||
require="${require} __user/${USER}" __file \
|
||||
"${CONFIG_FILE_DEST}" \
|
||||
--owner "${USER}" \
|
||||
--group "${GROUP}" \
|
||||
--mode "0440" \
|
||||
--source "${CONFIG_FILE_SOURCE}"
|
||||
service_require="${service_require} __file${CONFIG_FILE_DEST}"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# This should setup the object in $service_definition_require
|
||||
# See above.
|
||||
case "${INIT}" in
|
||||
systemd)
|
||||
if [ -z "${SERVICE_DEFINITION}" ]; then
|
||||
SERVICE_DEFINITION="$(cat <<EOF
|
||||
[Unit]
|
||||
Description=${SERVICE_DESCRIPTION}
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
|
||||
User=${USER}
|
||||
Group=${GROUP}
|
||||
ExecStart=${SERVICE_EXEC}
|
||||
Restart=always
|
||||
${WORKING_DIRECTORY_SYSTEMD}
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
)"
|
||||
fi
|
||||
__systemd_unit "${SERVICE_NAME}.service" \
|
||||
--source "-" \
|
||||
--state "${STATE}" \
|
||||
--enablement-state "enabled" <<EOF
|
||||
${SERVICE_DEFINITION}
|
||||
EOF
|
||||
;;
|
||||
runit|sysvinit)
|
||||
if [ -z "${SERVICE_DEFINITION}" ]; then
|
||||
SERVICE_DEFINITION="$(cat <<EOF
|
||||
#!/bin/sh -e
|
||||
${WORKING_DIRECTORY_RUNIT}
|
||||
export HOME="\$(getent passwd '${USER}' | cut -d: -f6)"
|
||||
export USER="${USER}"
|
||||
export GROUP="${GROUP}"
|
||||
exec chpst -u "${USER}:${GROUP}" ${SERVICE_EXEC}
|
||||
EOF
|
||||
)"
|
||||
fi
|
||||
__runit_service "${SERVICE_NAME}" \
|
||||
--state "${STATE}" \
|
||||
--log \
|
||||
--source - <<EOF
|
||||
${SERVICE_DEFINITION}
|
||||
EOF
|
||||
;;
|
||||
esac
|
||||
service_require="${service_require} ${service_definition_require}"
|
||||
|
||||
# Proceed after user and service description have been prepared
|
||||
export require="${require} ${service_require}"
|
||||
|
||||
VERSION_FILE="${BIN_DIR}/.${SERVICE_NAME}.cdist.version"
|
||||
IS_VERSION="$(cat "${__object}/explorer/explorer-version")"
|
||||
|
||||
|
||||
if [ "${STATE}" = "absent" ]; then
|
||||
# Perform cleanup of generated files
|
||||
for bin_file in ${BINARY} ${EXTRA_BINARIES}; do
|
||||
__file "${BIN_DIR}/${bin_file}" --state "absent"
|
||||
done
|
||||
__file "${VERSION_FILE}" --state "absent"
|
||||
__file "${CONFIG_FILE_DEST}" --state "absent"
|
||||
fi
|
||||
|
||||
if [ "${STATE}" != "present" ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
sv_cmd() {
|
||||
# This is intentional
|
||||
# shellcheck disable=SC2059
|
||||
printf "${service_command}" "$1"
|
||||
}
|
||||
|
||||
if [ "${SHOULD_VERSION}" != "${IS_VERSION}" ]; then
|
||||
# We are installing the service and there has been a version change
|
||||
# (or it is first-time install)
|
||||
TMP_PATH="/tmp/${SERVICE_NAME}-${SHOULD_VERSION}"
|
||||
|
||||
# This is what will stop the service, replace the binaries and
|
||||
# start the service again
|
||||
perform_service_upgrade="$(cat <<EOF
|
||||
$(sv_cmd stop) || true
|
||||
if [ -f '${TMP_PATH}' ]; then
|
||||
chown root:${SUPER_USER_GROUP} '${TMP_PATH}'
|
||||
chmod 0555 '${TMP_PATH}'
|
||||
cp -af '${TMP_PATH}' '${BIN_DIR}/${BINARY}'
|
||||
else
|
||||
for bin_file in ${BINARY} ${EXTRA_BINARIES}; do
|
||||
bin_path="${TMP_PATH}/\${bin_file}"
|
||||
chown root:${SUPER_USER_GROUP} "\${bin_path}"
|
||||
chmod 0555 "\${bin_path}"
|
||||
cp -af "\${bin_path}" "${BIN_DIR}/\${bin_file}"
|
||||
done
|
||||
fi
|
||||
$(sv_cmd start) || true
|
||||
EOF
|
||||
)"
|
||||
|
||||
if [ -f "${__object}/parameter/unpack" ]; then
|
||||
UNPACK_EXTENSION="$(cat "${__object}/parameter/unpack-extension")"
|
||||
UNPACK_ARGS="$(cat "${__object}/parameter/unpack-args" \
|
||||
2>/dev/null || true)"
|
||||
# Download packed file
|
||||
__download "${TMP_PATH}${UNPACK_EXTENSION}" \
|
||||
--url "${DOWNLOAD_URL}" \
|
||||
--download remote \
|
||||
--sum "${CHECKSUM}"
|
||||
|
||||
# Unpack file and also perform service upgrade
|
||||
# shellcheck disable=SC2086
|
||||
require="__download${TMP_PATH}${UNPACK_EXTENSION}" \
|
||||
__unpack "${TMP_PATH}${UNPACK_EXTENSION}" \
|
||||
${UNPACK_ARGS} \
|
||||
--destination "${TMP_PATH}"
|
||||
version_bump_require="__unpack${TMP_PATH}${UNPACK_EXTENSION}"
|
||||
else
|
||||
# Create temp directory
|
||||
__directory "${TMP_PATH}"
|
||||
# Download binary directoy to the temp directory with the
|
||||
# specified binary name
|
||||
require="__directory${TMP_PATH}" __download \
|
||||
"${TMP_PATH}/${BINARY}" \
|
||||
--url "${DOWNLOAD_URL}" \
|
||||
--download remote \
|
||||
--sum "${CHECKSUM}"
|
||||
version_bump_require="__download${TMP_PATH}/${BINARY}"
|
||||
fi
|
||||
|
||||
# Perform update of cdist-managed version file
|
||||
# And also perform service upgrade
|
||||
# This is a bug if service_upgrade fails >,<
|
||||
printf "%s" "${SHOULD_VERSION}" | \
|
||||
require="${version_bump_require}" __file \
|
||||
"${VERSION_FILE}" \
|
||||
--onchange "${perform_service_upgrade}" \
|
||||
--source "-"
|
||||
else
|
||||
# We only restart here if there was a config change
|
||||
# but there was not a version change
|
||||
require="${service_require}" __check_messages \
|
||||
"single_binary_service_${__object_id}" \
|
||||
--pattern "^__file${CONFIG_FILE_DEST}" \
|
||||
--execute "$(sv_cmd restart)"
|
||||
fi
|
2
type/__single_binary_service/parameter/boolean
Normal file
2
type/__single_binary_service/parameter/boolean
Normal file
|
@ -0,0 +1,2 @@
|
|||
do-not-manage-user
|
||||
unpack
|
1
type/__single_binary_service/parameter/default/state
Normal file
1
type/__single_binary_service/parameter/default/state
Normal file
|
@ -0,0 +1 @@
|
|||
present
|
|
@ -0,0 +1 @@
|
|||
.tar.gz
|
1
type/__single_binary_service/parameter/default/user
Normal file
1
type/__single_binary_service/parameter/default/user
Normal file
|
@ -0,0 +1 @@
|
|||
root
|
|
@ -0,0 +1 @@
|
|||
/nonexistent
|
13
type/__single_binary_service/parameter/optional
Normal file
13
type/__single_binary_service/parameter/optional
Normal file
|
@ -0,0 +1,13 @@
|
|||
config-file-source
|
||||
user
|
||||
group
|
||||
state
|
||||
binary
|
||||
service-args
|
||||
service-exec
|
||||
service-description
|
||||
service-definition
|
||||
unpack-extension
|
||||
unpack-args
|
||||
user-home-dir
|
||||
working-directory
|
1
type/__single_binary_service/parameter/optional_multiple
Normal file
1
type/__single_binary_service/parameter/optional_multiple
Normal file
|
@ -0,0 +1 @@
|
|||
extra-binary
|
3
type/__single_binary_service/parameter/required
Normal file
3
type/__single_binary_service/parameter/required
Normal file
|
@ -0,0 +1,3 @@
|
|||
url
|
||||
checksum
|
||||
version
|
Loading…
Reference in a new issue