From 9a102e9a82accf97501cfea9487e3728ebb6eff1 Mon Sep 17 00:00:00 2001 From: grembo Date: Sat, 18 Nov 2023 12:26:25 +0100 Subject: [PATCH] New attribute to control pot stop (#275) 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. --- CHANGELOG.md | 7 +++++ share/pot/common.sh | 26 +++++++++++++--- share/pot/set-attribute.sh | 18 +++++++++++ share/pot/start.sh | 63 ++++++++++++++++++++++---------------- share/pot/stop.sh | 18 ++++++++++- 5 files changed, 101 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6c1ff8..94d8513 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/share/pot/common.sh b/share/pot/common.sh index 33239c6..607c846 100644 --- a/share/pot/common.sh +++ b/share/pot/common.sh @@ -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 @@ -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' @@ -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' @@ -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() diff --git a/share/pot/set-attribute.sh b/share/pot/set-attribute.sh index 6ba159d..65973fc 100644 --- a/share/pot/set-attribute.sh +++ b/share/pot/set-attribute.sh @@ -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 @@ -194,6 +209,9 @@ pot-set-attribute() (uint) _cmd=_set_uint_attribute ;; + (string) + _cmd=_set_string_attribute + ;; (sysvopt) _cmd=_set_sysvopt_attribute ;; diff --git a/share/pot/start.sh b/share/pot/start.sh index 8b35e0e..153193a 100644 --- a/share/pot/start.sh +++ b/share/pot/start.sh @@ -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 @@ -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 @@ -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 ;; @@ -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" @@ -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" @@ -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 @@ -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 @@ -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") @@ -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 @@ -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 diff --git a/share/pot/stop.sh b/share/pot/stop.sh index 7c4e0f4..489159a 100644 --- a/share/pot/stop.sh +++ b/share/pot/stop.sh @@ -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" @@ -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