Skip to content

Commit

Permalink
New attribute to control pot stop (#275)
Browse files Browse the repository at this point in the history
By setting exec_stop and stop_timeout (which correspond to
jail(8) attributes exec.stop and stop.timeout), the user
has better control over shutting down a pot.

For "fat" pots this could mean setting

    pot set-attr -A exec_stop -V "/bin/sh /etc/rc.shutdown jail"

for light jails (like nomad controlled using tinirc), this could
point to a simple script that make sure the wrapped process is
stopped gracefully and, in case multiple processes are running
inseide of the pot, make sure they're terminated in the correct
order.

Also:
- Fix a typo that made the nullfs attribute not work.
- Make pot start use _save_params, which makes wrapping
  attributes safer and therefore allows to remove
  a shellcheck exemption.
  • Loading branch information
grembo authored Nov 18, 2023
1 parent 46f13fe commit 9a102e9
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 31 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- set-attr/stop: Add attributes exec_stop and stop_timeout (#275)

### Fixed
- start: Fix setting of nullfs attribute

## [0.15.6] 2023-09-29
### Added
- start: Add custom pf rule configuration hook, POT_EXPORT_PORTS_PF_RULES_HOOK (#273)
Expand Down
26 changes: 22 additions & 4 deletions share/pot/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ _POT_RO_ATTRIBUTES="to-be-pruned"
_POT_NETWORK_TYPES="inherit alias public-bridge private-bridge"

# not devfs handles separately
_POT_JAIL_RW_ATTRIBUTES='enforce_statfs mount fdescfs linprocfs nullfs procfs tmpfs zfs raw_sockets sysvshm sysvsem sysvmsg children mlock devfs_ruleset'
_POT_JAIL_RW_ATTRIBUTES='enforce_statfs mount fdescfs linprocfs nullfs procfs tmpfs zfs raw_sockets sysvshm sysvsem sysvmsg children mlock devfs_ruleset exec_stop stop_timeout'

# N: arg name jail command, T: type of data, D: deafult value
# devfs is always mounted
Expand All @@ -23,9 +23,9 @@ _POT_DEFAULT_fdescfs_D='NO'
_POT_DEFAULT_linprocfs_N='allow.mount.linprocfs'
_POT_DEFAULT_linprocfs_T='bool'
_POT_DEFAULT_linprocfs_D='NO'
_POT_DEFAULT_nullcfs_N='allow.mount.nullfs'
_POT_DEFAULT_nullcfs_T='bool'
_POT_DEFAULT_nullcfs_D='NO'
_POT_DEFAULT_nullfs_N='allow.mount.nullfs'
_POT_DEFAULT_nullfs_T='bool'
_POT_DEFAULT_nullfs_D='NO'
_POT_DEFAULT_procfs_N='mount.procfs'
_POT_DEFAULT_procfs_T='bool'
_POT_DEFAULT_procfs_D='NO'
Expand Down Expand Up @@ -56,6 +56,12 @@ _POT_DEFAULT_devfs_ruleset_D='4'
_POT_DEFAULT_mlock_N='allow.mlock'
_POT_DEFAULT_mlock_T='bool'
_POT_DEFAULT_mlock_D='NO'
_POT_DEFAULT_exec_stop_N='exec.stop'
_POT_DEFAULT_exec_stop_T='string'
_POT_DEFAULT_exec_stop_D=''
_POT_DEFAULT_stop_timeout_N='stop.timeout'
_POT_DEFAULT_stop_timeout_T='uint'
_POT_DEFAULT_stop_timeout_D='10'
# 0:everything, 1:chroot+below(poudriere), 2:just chroot(normal jail)
_POT_DEFAULT_enforce_statfs_N='enforce_statfs'
_POT_DEFAULT_enforce_statfs_T='uint'
Expand Down Expand Up @@ -511,6 +517,18 @@ _get_conf_var()
echo "$_value"
}

# $1 pot name
# $2 var name
_get_conf_var_string()
{
local _pname _cdir _var _value
_pname="$1"
_cdir="${POT_FS_ROOT}/jails/$_pname/conf"
_var="$2"
_value="$( grep "^$_var=" "$_cdir/pot.conf" | cut -f2 -d'=' )"
echo "$_value"
}

# $1 pot name
# $2 var name
_get_ip_var()
Expand Down
18 changes: 18 additions & 0 deletions share/pot/set-attribute.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ _set_uint_attribute()
echo "pot.attr.$_attr=$_value" >> "$_cdir/pot.conf"
}

# $1 pot name
# $2 attribute name
# $3 value
_set_string_attribute()
{
local _pname _value _cdir
_pname=$1
_attr=$2
_value=$3

_cdir="$POT_FS_ROOT/jails/$_pname/conf"
${SED} -i '' -e "/^pot.attr.$_attr=.*/d" "$_cdir/pot.conf"
echo "pot.attr.$_attr=$_value" >> "$_cdir/pot.conf"
}

# $1 pot name
# $2 attribute name
# $3 value
Expand Down Expand Up @@ -194,6 +209,9 @@ pot-set-attribute()
(uint)
_cmd=_set_uint_attribute
;;
(string)
_cmd=_set_string_attribute
;;
(sysvopt)
_cmd=_set_sysvopt_attribute
;;
Expand Down
63 changes: 37 additions & 26 deletions share/pot/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,8 @@ _js_start()
local _default
_pname="$1"
_confdir="${POT_FS_ROOT}/jails/$_pname/conf"
_param="allow.set_hostname=false allow.raw_sockets allow.socket_af"
_param="$_param allow.chflags exec.clean mount.devfs"
_param=$(_save_params "allow.set_hostname=false" "allow.raw_sockets" \
"allow.socket_af" "allow.chflags" "exec.clean" "mount.devfs")

for _attr in ${_POT_JAIL_RW_ATTRIBUTES} ; do
# shellcheck disable=SC1083,2086
Expand All @@ -472,25 +472,33 @@ _js_start()
eval _type=\"\${_POT_DEFAULT_${_attr}_T}\"
# shellcheck disable=SC1083,2086
eval _default=\"\${_POT_DEFAULT_${_attr}_D}\"
_value="$(_get_conf_var "$_pname" "pot.attr.${_attr}")"
if [ "${_value}" = "YES" ]; then
_param="$_param ${_name}"
elif [ "${_type}" != "bool" ] && [ -n "${_value}" ]; then
_param="$_param ${_name}=${_value}"
elif [ "${_type}" = "sysvopt" ] && [ -z "${_value}" ]; then
_param="$_param ${_name}=${_default}"
if [ "$_type" = "string" ]; then
_value="$(_get_conf_var_string "$_pname" "pot.attr.${_attr}")"
else
_value="$(_get_conf_var "$_pname" "pot.attr.${_attr}")"
fi

if [ "$_type" = "bool" ] && [ "$_value" = "YES" ]; then
_param="$_param"$(_save_params "$_name")
elif [ "$_type" != "bool" ] && [ -n "$_value" ]; then
_param="$_param"$(_save_params "$_name=$_value")
elif [ "$_type" = "sysvopt" ] && [ -z "$_value" ]; then
_param="$_param"$(_save_params "$_name=$_default")
fi
done

_hostname="$( _get_conf_var "$_pname" host.hostname )"
_osrelease="$( _get_os_release "$_pname" )"
_param="$_param name=$_pname host.hostname=$_hostname osrelease=$_osrelease"
_param="$_param path=${POT_FS_ROOT}/jails/$_pname/m"
_param="$_param"$(_save_params "name=$_pname" \
"host.hostname=$_hostname" \
"osrelease=$_osrelease" \
"path=${POT_FS_ROOT}/jails/$_pname/m")

_persist="$(_get_conf_var "$_pname" "pot.attr.persistent")"
if [ "$_persist" != "NO" ]; then
_param="$_param persist"
_param="$_param"$(_save_params "persist")
else
_param="$_param nopersist"
_param="$_param"$(_save_params "nopersist")
fi
if [ "$(_get_conf_var "$_pname" "pot.attr.no-rc-script")" = "YES" ]; then
if [ "$( _get_pot_network_stack "$_pname" )" = "ipv4" ]; then
Expand Down Expand Up @@ -519,13 +527,14 @@ _js_start()
"inherit")
case "$( _get_pot_network_stack "$_pname" )" in
"dual")
_param="$_param ip4=inherit ip6=inherit"
_param="$_param"$(_save_params \
"ip4=inherit" "ip6=inherit")
;;
"ipv4")
_param="$_param ip4=inherit"
_param="$_param"$(_save_params "ip4=inherit")
;;
"ipv6")
_param="$_param ip6=inherit"
_param="$_param"$(_save_params "ip6=inherit")
;;
esac
;;
Expand All @@ -537,16 +546,16 @@ _js_start()
_ip4addr="$( _get_alias_ipv4 "$_pname" "$_ip" )"
_ip6addr="$( _get_alias_ipv6 "$_pname" "$_ip" )"
if [ -n "$_ip4addr" ]; then
_param="$_param ip4.addr=$_ip4addr"
_param="$_param"$(_save_params "ip4.addr=$_ip4addr")
fi
if [ -n "$_ip6addr" ]; then
_param="$_param ip6.addr=$_ip6addr"
_param="$_param"$(_save_params "ip6.addr=$_ip6addr")
fi
;;
"ipv4")
_ip4addr="$( _get_alias_ipv4 "$_pname" "$_ip" )"
if [ -n "$_ip4addr" ]; then
_param="$_param ip4.addr=$_ip4addr"
_param="$_param"$(_save_params "ip4.addr=$_ip4addr")
else
_error "No ipv4 address found for $_pname"
start-cleanup "$_pname"
Expand All @@ -556,7 +565,7 @@ _js_start()
"ipv6")
_ip6addr="$( _get_alias_ipv6 "$_pname" "$_ip" )"
if [ -n "$_ip6addr" ]; then
_param="$_param ip6.addr=$_ip6addr"
_param="$_param"$(_save_params "ip6.addr=$_ip6addr")
else
_error "No ipv6 address found for $_pname"
start-cleanup "$_pname"
Expand All @@ -566,7 +575,7 @@ _js_start()
esac
;;
"public-bridge")
_param="$_param vnet"
_param="$_param"$(_save_params "vnet")
_stack="$( _get_pot_network_stack "$_pname" )"
if [ "$_stack" = "dual" ] || [ "$_stack" = "ipv4" ]; then
_tmp="$( _js_create_epair "$_pname" '4' )" || return 1
Expand All @@ -576,7 +585,7 @@ _js_start()
_epaira=$1
_epairb=$2
_js_vnet "$_pname" "$_epaira" "$_epairb"
_param="$_param vnet.interface=${_epairb}"
_param="$_param"$(_save_params "vnet.interface=$_epairb")
_js_export_ports "$_pname"
fi
if [ "$_stack" = "dual" ] || [ "$_stack" = "ipv6" ]; then
Expand All @@ -588,7 +597,7 @@ _js_start()
_ipv6_epairb=$2
_js_vnet_ipv6 "$_pname" "$_ipv6_epaira" \
"$_ipv6_epairb" "$_stack"
_param="$_param vnet.interface=${_ipv6_epairb}"
_param="$_param"$(_save_params "vnet.interface=$_ipv6_epairb")
fi
;;
"private-bridge")
Expand All @@ -599,7 +608,7 @@ _js_start()
_epaira=$1
_epairb=$2
_js_private_vnet "$_pname" "$_epaira" "$_epairb"
_param="$_param vnet vnet.interface=${_epairb}"
_param="$_param"$(_save_params "vnet" "vnet.interface=$_epairb")
_js_export_ports "$_pname"
;;
esac
Expand All @@ -624,8 +633,10 @@ _js_start()
rm -f "${POT_TMP:-/tmp}/pot_main_pid_${_pname}"

_info "Starting the pot $_pname"
# shellcheck disable=SC2086
jail -c $_param exec.start="sh -c 'sleep 1234&'"
# execute command
eval "set -- $_param"
_debug "Pot $_pname jail params are: $*"
jail -c "$@" exec.start="sh -c 'sleep 1234&'"

if [ -e "$_confdir/pot.conf" ] && _is_pot_prunable "$_pname" ; then
# set-attr cannot be used for read-only attributes
Expand Down
18 changes: 17 additions & 1 deletion share/pot/stop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ _js_cpu_rebalance()
_js_stop()
{
local _pname _pdir _epaira _epaira_ifs _ip _aname _from_start
local _exec_stop _stop_timeout
_pname="$1"
_from_start="$2"
_epaira_ifs="$3"
Expand All @@ -51,7 +52,22 @@ _js_stop()
)
fi
_debug "Stop the pot $_pname"
jail -q -r "$_pname"

_exec_stop="$(_get_conf_var_string "$_pname" "pot.attr.exec_stop")"
_stop_timeout="$(_get_conf_var "$_pname" "pot.attr.stop_timeout")"
(
echo "$_pname {"
if [ -n "$_exec_stop" ]; then
printf " %s=%s;\n" "exec.stop" \
"$(echo "$_exec_stop" | sed 's/["\]/\\&/g; s/.*/"&"/')"

# balance quotes for cheap syntax highlighting editors'
fi
if [ -n "$_stop_timeout" ]; then
printf " %s=%s;\n" "stop.timeout" "$_stop_timeout"
fi
echo "}"
) | jail -f- -q -r "$_pname"
fi
# those are clean up operations for a pot already stopped
if [ -n "$_epaira_ifs" ]; then
Expand Down

0 comments on commit 9a102e9

Please sign in to comment.