[CFT] multiple instance support in rc.d script

2014-10-16 Thread Hiroki Sato
[Please reply to freebsd-rc@]

Hi,

 I would like your feedback and testers of the attached patch.  This
 implements multiple instance support in rc.d scripts.  You can try it
 by replacing /etc/rc.subr with the attached one.

 More details are as follow.  Typically, an rc.d/foo script has the
 following structure and rc.conf variables:

   /etc/rc.d/foo:
   
   name=foo
   rcvar=foo_enable
   ...
   load_rc_command $name
   run_rc_command $*
   

   /etc/rc.conf:
   
   foo_enable=YES
   foo_flags=-f -l -a -g
   

 The above supports one instance for one script.  After replacing
 rc.subr, you can specify additional instances in rc.conf:

   /etc/rc.conf:
   
   foo_instances=one two

   foo_one_enable=YES
   foo_one_flags=-f -l -a -g

   foo_two_enable=YES
   foo_two_flags=-F -L -A -G
   

 $foo_instances defines instances by space-separated list of instance
 names, and rc.conf variables for them are something like
 ${name}_${instname}_enable.  The following command

  # service foo start

 starts foo_one and foo_two with the specified flags.  Instances can
 be specified in the following form:

  # service foo start:one

 or multiple instances in a particular order:

  # service foo start:two,one

 Basically, no change is required for the rc.d/foo script itself.
 However, there is a problem that default values of the instantiated
 variables are not defined.

 For example, if an rc.d/script uses $foo_mode, you need to define
 $foo_one_mode.  The default value of $foo_mode is usually defined in
 etc/defaults/rc.conf for rc.d scripts in the base system and :
 ${foo_mode:=value} idiom in scripts from Ports Collection.  So all
 of the variables should be defined for each instance, too.  As you
 noticed, this is not easy without editing the script itself.

 To alleviate this, set_rcvar() can be used:

   /etc/rc.d/foo:
   
   name=foo
   rcvar=foo_enable

   set_rcvar foo_enable YES Enable $name
   set_rcvar foo_program/tmp/test Command for $name
   ...
   load_rc_command $name
   run_rc_command $*
   

 The three arguments are varname, default value, and description.  If
 a variable is defined by set_rcvar(), default values instantiated
 variables will be set automatically---foo_one_program is set by
 foo_program if it is not defined.

 This approach still has another problem.  set_rcvar() is not
 supported in all branches, so a script using it does not work in old
 supported branches.  One solution which can be used for scripts in
 Ports Collection is adding both definitions before and after
 load_rc_command() until EoL of old branches like this:

   /etc/rc.d/foo:
   
   name=foo
   rcvar=foo_enable

   if type set_rcvar /dev/null 21; then
set_rcvar foo_enableYES Enable $name
set_rcvar foo_program   /tmp/test Command for $name
   fi
   ...
   load_rc_command $name

   # will be removed after all supported branches have set_rcvar().
   if ! type set_rcvar /dev/null 21; then
: ${foo_enable:=YES}
: ${foo_program:=/tmp/test}
for _i in $foo_instances; do
for _j in enable program; do
eval : \${foo_${_i}_enable:=\$foo_$_j}
done
done
   fi

   run_rc_command $*
   

 This is a bit ugly but should work fine.

 I am using this patch to invoke multiple named (caching
 server/contents server) and syslogd (local only/listens INET/INET6
 socket only) daemons.  While $foo_instances is designed as a
 user-defined knob, this can be applied to software which need to
 invoke multiple/different daemons which depend on each other in a
 script, too.

 I am feeling this patch still needs more careful review from others.
 Any comments are welcome.  Thank you.

-- Hiroki
Index: etc/rc.subr
===
--- etc/rc.subr	(revision 272976)
+++ etc/rc.subr	(working copy)
@@ -698,7 +698,10 @@
 #		start stop restart rcvar status poll ${extra_commands}
 #	If there's a match, run ${argument}_cmd or the default method
 #	(see below).
+#	_run_rc_command0() is the main routine and run_rc_command() is
+#	a wrapper to handle multiple instances.
 #
+#
 #	If argument has a given prefix, then change the operation as follows:
 #		Prefix	Operation
 #		--	-
@@ -755,6 +758,9 @@
 #
 #	${name}_nice	n	Nice level to run ${command} at.
 #
+#	${name}_pidfile	n	This to be used in /etc/rc.conf to override
+#${pidfile}.
+#
 #	${name}_user	n	User to run ${command} as, using su(1) if not
 #using ${name}_chroot.
 #Requires /usr to be mounted.
@@ -863,6 +869,57 @@
 #
 run_rc_command()
 {
+	local _act _instances _name _desc _rcvar
+
+	_act=$1
+	shift
+	eval _instances=\$${name}_instances
+
+	# Check if instance is specified, e.g. start:instance,
+	case ${_act%:*} in
+	$_act)	;;			# no instance specified
+	*)
+		_instances=$(echo ${_act#*:} | tr ,  )
+		_act=${_act%:*}
+	;;
+	esac
+
+	# Use 

Re: [CFT] multiple instance support in rc.d script

2014-10-16 Thread Allan Jude
On 2014-10-16 21:22, Hiroki Sato wrote:
 [Please reply to freebsd-rc@]
 
 Hi,
 
  I would like your feedback and testers of the attached patch.  This
  implements multiple instance support in rc.d scripts.  You can try it
  by replacing /etc/rc.subr with the attached one.
 
  More details are as follow.  Typically, an rc.d/foo script has the
  following structure and rc.conf variables:
 
/etc/rc.d/foo:

name=foo
rcvar=foo_enable
...
load_rc_command $name
run_rc_command $*

 
/etc/rc.conf:

foo_enable=YES
foo_flags=-f -l -a -g

 
  The above supports one instance for one script.  After replacing
  rc.subr, you can specify additional instances in rc.conf:
 
/etc/rc.conf:

foo_instances=one two
 
foo_one_enable=YES
foo_one_flags=-f -l -a -g
 
foo_two_enable=YES
foo_two_flags=-F -L -A -G

 
  $foo_instances defines instances by space-separated list of instance
  names, and rc.conf variables for them are something like
  ${name}_${instname}_enable.  The following command
 
   # service foo start
 
  starts foo_one and foo_two with the specified flags.  Instances can
  be specified in the following form:
 
   # service foo start:one
 
  or multiple instances in a particular order:
 
   # service foo start:two,one
 
  Basically, no change is required for the rc.d/foo script itself.
  However, there is a problem that default values of the instantiated
  variables are not defined.
 
  For example, if an rc.d/script uses $foo_mode, you need to define
  $foo_one_mode.  The default value of $foo_mode is usually defined in
  etc/defaults/rc.conf for rc.d scripts in the base system and :
  ${foo_mode:=value} idiom in scripts from Ports Collection.  So all
  of the variables should be defined for each instance, too.  As you
  noticed, this is not easy without editing the script itself.
 
  To alleviate this, set_rcvar() can be used:
 
/etc/rc.d/foo:

name=foo
rcvar=foo_enable
 
set_rcvar foo_enable   YES Enable $name
set_rcvar foo_program  /tmp/test Command for $name
...
load_rc_command $name
run_rc_command $*

 
  The three arguments are varname, default value, and description.  If
  a variable is defined by set_rcvar(), default values instantiated
  variables will be set automatically---foo_one_program is set by
  foo_program if it is not defined.
 
  This approach still has another problem.  set_rcvar() is not
  supported in all branches, so a script using it does not work in old
  supported branches.  One solution which can be used for scripts in
  Ports Collection is adding both definitions before and after
  load_rc_command() until EoL of old branches like this:
 
/etc/rc.d/foo:

name=foo
rcvar=foo_enable
 
if type set_rcvar /dev/null 21; then
   set_rcvar foo_enableYES Enable $name
   set_rcvar foo_program   /tmp/test Command for $name
fi
...
load_rc_command $name
 
# will be removed after all supported branches have set_rcvar().
if ! type set_rcvar /dev/null 21; then
   : ${foo_enable:=YES}
   : ${foo_program:=/tmp/test}
   for _i in $foo_instances; do
   for _j in enable program; do
   eval : \${foo_${_i}_enable:=\$foo_$_j}
   done
   done
fi
 
run_rc_command $*

 
  This is a bit ugly but should work fine.
 
  I am using this patch to invoke multiple named (caching
  server/contents server) and syslogd (local only/listens INET/INET6
  socket only) daemons.  While $foo_instances is designed as a
  user-defined knob, this can be applied to software which need to
  invoke multiple/different daemons which depend on each other in a
  script, too.
 
  I am feeling this patch still needs more careful review from others.
  Any comments are welcome.  Thank you.
 
 -- Hiroki
 

This feature is quite useful. I've used the built in version that the
rc.d script in memcached and it is very helpful to be able to run
multiple named instances.

I wonder if sysrc could be improved to support an 'append', so you can have:

foo_instances=one two

and do:
sysrc --append foo_instances=three

to get:
foo_instances=one two three

instead of having to do:

sysrc foo_instances=`sysrc -n foo_instances` three

or something more convoluted

-- 
Allan Jude



signature.asc
Description: OpenPGP digital signature