Skip to content

Commit

Permalink
Add support for template args
Browse files Browse the repository at this point in the history
Closes 211.
  • Loading branch information
chriswells0 committed Sep 10, 2020
1 parent a4fcf01 commit baf36e8
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 19 deletions.
43 changes: 31 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -652,17 +652,18 @@ echo "usr" > /usr/local/bastille/templates/username/base-template/OVERLAY
Template hooks are executed in specific order and require specific syntax to
work as expected. This table outlines that order and those requirements:
| SUPPORTED | format | example |
|-----------|---------------------|------------------------------------------------|
| LIMITS | resource value | memoryuse 1G |
| INCLUDE | template path/URL | http?://TEMPLATE_URL or username/base-template |
| PRE | /bin/sh command | mkdir -p /usr/local/path |
| FSTAB | fstab syntax | /host/path container/path nullfs ro 0 0 |
| PKG | port/pkg name(s) | vim-console zsh git-lite tree htop |
| OVERLAY | paths (one/line) | etc usr |
| SYSRC | sysrc command(s) | nginx_enable=YES |
| SERVICE | service command(s) | nginx restart |
| CMD | /bin/sh command | /usr/bin/chsh -s /usr/local/bin/zsh |
| SUPPORTED | format | example |
|-----------|-----------------------|------------------------------------------------|
| ARG | name=value (one/line) | domain=example.com (omit value for no default) |
| LIMITS | resource value | memoryuse 1G |
| INCLUDE | template path/URL | http?://TEMPLATE_URL or username/base-template |
| PRE | /bin/sh command | mkdir -p /usr/local/path |
| FSTAB | fstab syntax | /host/path container/path nullfs ro 0 0 |
| PKG | port/pkg name(s) | vim-console zsh git-lite tree htop |
| OVERLAY | paths (one/line) | etc usr |
| SYSRC | sysrc command(s) | nginx_enable=YES |
| SERVICE | service command(s) | nginx restart |
| CMD | /bin/sh command | /usr/bin/chsh -s /usr/local/bin/zsh |
| PLANNED | format | example |
|---------|------------------|----------------------------------------------------------------|
Expand All @@ -671,6 +672,11 @@ work as expected. This table outlines that order and those requirements:
Note: SYSRC requires NO quotes or that quotes (`"`) be escaped. ie; `\"`)
Any name provided in the ARG file can be used as a variable in the other hooks.
For example, `domain` in the ARG file will cause instances of `${domain}` to be
replaced. Values can be specified either through the command line when applying
the template or as a default in the ARG file.
In addition to supporting template hooks, Bastille supports overlaying files
into the container. This is done by placing the files in their full path, using the
template directory as "/".
Expand Down Expand Up @@ -702,6 +708,10 @@ create a `Bastillefile` inside the base template directory. Each line in
the file should begin with an uppercase reference to a Bastille command
followed by its arguments (omitting the target, which is deduced from the
`template` arguments). Lines beginning with `#` are treated as comments.
Variables can also be defined using `ARG` with one `name=value` pair per
line. Subsequent references to `${name}` would be replaced by `value`.
Note that argument values are not available for use until after the point
at which they are defined in the file.
Bastillefile example:
Expand All @@ -716,6 +726,11 @@ SERVICE nginx restart
# Copy files to nginx.
CP www/ usr/local/www/nginx-dist/
# This value can be overridden when the template is applied.
ARG domain=example.com
# Create a file on the server containing the domain.
CMD echo "${domain}" > /usr/local/www/nginx-dist/domain.txt
# Create a file on the server containing the jail's hostname.
CMD hostname > /usr/local/www/nginx-dist/hostname.txt
Expand All @@ -732,8 +747,12 @@ Bastille includes a `template` sub-command. This sub-command requires a target
and a template name. As covered in the previous section, template names
correspond to directory names in the `bastille/templates` directory.
To provide values for arguments defined by `ARG` in the template, pass the
optional `--arg` parameter as many times as needed. Alternatively, use
`--arg-file <fileName>` with one `name=value` pair per line.
```shell
ishmael ~ # bastille template folsom username/base
ishmael ~ # bastille template folsom username/base --arg domain=example.com
[folsom]:
Copying files...
Copy complete.
Expand Down
101 changes: 94 additions & 7 deletions usr/local/share/bastille/template.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,50 @@ bastille_usage() {
exit 1
}

get_arg_value() {
_arg_name="${1}"
_default_value="${2}"
shift 2

# Remaining arguments in $@ are the script arguments, which take precedence. -- cwells
for _script_arg in "$@"; do
case ${_script_arg} in
--arg)
# Parse whatever is next. -- cwells
_next_arg='true' ;;
*)
if [ "${_next_arg}" = 'true' ]; then # This is the parameter after --arg. -- cwells
_next_arg=''
if [ "$(echo "${_script_arg}" | sed -E 's/=.*//')" = "${_arg_name}" ]; then
echo "${_script_arg}" | sed -E 's/[^=]+=?//'
return
fi
fi
;;
esac
done

# Check the ARG_FILE if one was provided. --cwells
if [ -n "${ARG_FILE}" ]; then
# To prevent a false empty value, only parse the value if this argument exists in the file. -- cwells
if grep "^${_arg_name}=" "${ARG_FILE}" > /dev/null 2>&1; then
grep "^${_arg_name}=" "${ARG_FILE}" | sed -E 's/[^=]+=?//'
return
fi
fi

# Return the provided default if no matching arg was found. -- cwells
echo "${_default_value}"
}

# Handle special-case commands first.
case "$1" in
help|-h|--help)
bastille_usage
;;
esac

if [ $# -gt 2 ] || [ $# -lt 2 ]; then
if [ $# -lt 2 ]; then
bastille_usage
fi

Expand Down Expand Up @@ -92,6 +128,27 @@ if [ -z "${HOOKS}" ]; then
HOOKS='LIMITS INCLUDE PRE FSTAB PF PKG OVERLAY CONFIG SYSRC SERVICE CMD'
fi

# Check for an --arg-file parameter. -- cwells
for _script_arg in "$@"; do
case ${_script_arg} in
--arg-file)
# Parse whatever is next. -- cwells
_next_arg='true' ;;
*)
if [ "${_next_arg}" = 'true' ]; then # This is the parameter after --arg-file. -- cwells
_next_arg=''
ARG_FILE="${_script_arg}"
break
fi
;;
esac
done

if [ -n "${ARG_FILE}" ] && [ ! -f "${ARG_FILE}" ]; then
echo -e "${COLOR_RED}File not found: ${ARG_FILE}${COLOR_RESET}"
exit 1
fi

## global variables
bastille_template=${bastille_templatesdir}/${TEMPLATE}
for _jail in ${JAILS}; do
Expand All @@ -115,6 +172,23 @@ for _jail in ${JAILS}; do
fi
fi

# This is parsed outside the HOOKS loop so an ARG file can be used with a Bastillefile. -- cwells
ARG_NAMES=''
ARG_VALUES=''
if [ -s "${bastille_template}/ARG" ]; then
while read _line; do
if [ -z "${_line}" ]; then
continue
fi
_arg_name=$(echo "${_line}" | sed -E 's/=.*//')
_arg_value=$(get_arg_value "${_arg_name}" "$(echo "${_line}" | sed -E 's/[^=]+=?//')" "$@")
# Build a list of names like this: ${username},${domain}
ARG_NAMES="${ARG_NAMES},\${${_arg_name}}"
# Build a list of name=value pairs like this: username=root domain=example.com
ARG_VALUES="${ARG_VALUES} ${_arg_name}=${_arg_value}"
done < "${bastille_template}/ARG"
fi

if [ -s "${bastille_template}/Bastillefile" ]; then
# Ignore blank lines and comments. -- cwells
SCRIPT=$(grep -v '^\s*$' "${bastille_template}/Bastillefile" | grep -v '^\s*#')
Expand All @@ -123,11 +197,22 @@ for _jail in ${JAILS}; do
'
set -f
for _line in ${SCRIPT}; do
# First word converted to lowercase is the Bastille command. -- cwells
_cmd=$(echo "${_line}" | awk '{print tolower($1);}')
_args=$(echo "${_line}" | awk '{$1=""; sub(/^ */, ""); print;}')
# Rest of the line with "arg" variables replaced will be the arguments. -- cwells
_args=$(echo "${_line}" | awk '{$1=""; sub(/^ */, ""); print;}' | eval "${ARG_VALUES}" envsubst '${ARG_NAMES}')

# Apply overrides for commands/aliases and arguments. -- cwells
case $_cmd in
arg) # This is a template argument definition. -- cwells
_arg_name=$(echo "${_args}" | sed -E 's/=.*//')
_arg_value=$(get_arg_value "${_arg_name}" "$(echo "${_args}" | sed -E 's/[^=]+=?//')" "$@")
# Build a list of names like this: ${username},${domain}
ARG_NAMES="${ARG_NAMES},\${${_arg_name}}"
# Build a list of name=value pairs like this: username=root domain=example.com
ARG_VALUES="${ARG_VALUES} ${_arg_name}=${_arg_value}"
continue
;;
cmd)
# Allow redirection within the jail. -- cwells
_args="sh -c '${_args}'"
Expand Down Expand Up @@ -164,8 +249,8 @@ for _jail in ${JAILS}; do

for _hook in ${HOOKS}; do
if [ -s "${bastille_template}/${_hook}" ]; then
# Default command is the lowercase hook name and default args are the line from the file. -- cwells
_cmd=$(echo "${_hook}" | awk '{print tolower($1);}')
# Default command is the lowercase hook name and default args are the line from the file. -- cwells
_cmd=$(echo "${_hook}" | awk '{print tolower($1);}')
_args_template='${_line}'

# Override default command/args for some hooks. -- cwells
Expand Down Expand Up @@ -196,9 +281,11 @@ for _jail in ${JAILS}; do
bastille pkg "${_jail}" audit -F
else
while read _line; do
if [ -z "${_line}" ]; then
continue
fi
if [ -z "${_line}" ]; then
continue
fi
# Replace "arg" variables in this line with the provided values. -- cwells
_line=$(echo "${_line}" | eval "${ARG_VALUES}" envsubst '${ARG_NAMES}')
eval "_args=\"${_args_template}\""
bastille "${_cmd}" "${_jail}" ${_args} || exit 1
done < "${bastille_template}/${_hook}"
Expand Down

0 comments on commit baf36e8

Please sign in to comment.