summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoretienne2005-07-08 14:40:35 +0000
committeretienne2005-07-08 14:40:35 +0000
commit086b3f50ac7b14bc22cbafa02a7187bc7de6cb78 (patch)
treecdc7d6d29cb0bec4142674a06d7d2e95b72c9dcc
parente0b86459e97aa90419e129e67229397783ac3f80 (diff)
downloadivylaunch-086b3f50ac7b14bc22cbafa02a7187bc7de6cb78.zip
ivylaunch-086b3f50ac7b14bc22cbafa02a7187bc7de6cb78.tar.gz
ivylaunch-086b3f50ac7b14bc22cbafa02a7187bc7de6cb78.tar.bz2
ivylaunch-086b3f50ac7b14bc22cbafa02a7187bc7de6cb78.tar.xz
Correction :
Sur réception d'un message Die, tous les processus fils sont tués. Le comportement est le meme que celui induit par un Ctrl-C. Cela remplace le contournement qui consistait à envoyer un message Die aux agents. Le dysfontionnement a été introduit quand on a formaté avec awk la sortie standard des agents et commandes.
-rw-r--r--FugueConfig.pm123
-rw-r--r--debian/changelog8
-rwxr-xr-xivylaunch132
3 files changed, 155 insertions, 108 deletions
diff --git a/FugueConfig.pm b/FugueConfig.pm
index b0e9b72..ef69e9d 100644
--- a/FugueConfig.pm
+++ b/FugueConfig.pm
@@ -1,6 +1,7 @@
package FugueConfig;
use Sys::Hostname;
+use IO::Handle;
use strict;
my $rsh = $ENV{"RSH"};
@@ -48,32 +49,34 @@ sub parse {
# empty lines
if (/^\s*$/) {
next;
+
# comments
} elsif (/^\s*\#.*$/) {
push(@data, ['comment', $_]);
+
} else {
- my ($type, $host, $name, $command, @param) =
+ my ($type, $host, $name, $command, $param) =
m/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)\#*.*$/ ;
- #print "t=$type h=$host n=$name c=$command p=".join(' ', @param)."\n";
+ #print "### t=$type h=$host n=$name c=$command p=$param\n";
+
if (not defined $type) {
- warn ("*** FugueConfig::parse WARNING : ".
- "syntax error at line $line : \n\t=> $_\n");
+ warn ("[FugueConfig][WARNING][line $line] syntax error : ".
+ "\n\t=> $_\n");
next;
}
unless ($type eq 'global' or $type eq 'local' or
$type eq 'begin' or $type eq 'end') {
- warn ("*** FugueConfig::parse WARNING : ".
- "unknown command type '$type' at line $line. Ignored.\n");
+ warn ("[FugueConfig][WARNING][line $line] unknown command type ".
+ "'$type'\n");
next;
}
if ($appname{$name}) {
- warn ("*** FugueConfig::parse WARNING : ".
- "at line $line at least 2 agents have the same name '$name'; ".
- "skipping all but the first\n");
+ warn ("[FugueConfig][WARNING][line $line] at least 2 agents have ".
+ "the same name '$name'; skipping all but the first\n");
next;
}
$appname{$name} = 1 if $type eq 'global' or $type eq 'local';
- push(@data, [$type, $host, $name, $command, [@param]]);
+ push(@data, [$type, $host, $name, $command, $param]);
}
}
@@ -88,64 +91,76 @@ sub parse {
sub launchAgent {
my ($appname, $host, $command, $options, $bus) = @_;
- my @options = @$options if ref($options) eq 'ARRAY';
- push(@options, -b => $bus) if $bus;
- my $command_opt = $command.' '.join(' ', @options);
- my $pid = fork;
- warn ("*** FugueConfig::launchAgent WARNING: Could not fork!\n"), return
- unless defined $pid;
-
- if ($pid) {
- # parent
- print "*** FugueConfig::launchAgent INFO: $host: launching $appname agent ".
- "with \'$command_opt\' (pid=$pid)\n";
- return ($pid);
- } else {
- # child
- my $awk_command = "awk -W interactive '{print \"$appname  \", \$0;}'";
- if ($host eq 'localhost' or $host eq hostname() ) {
- exec "$command_opt 2>&1 | $awk_command" or
- warn "*** FugueConfig::launchAgent WARNING: Error executing $command\n";
- } else {
- exec "$rsh -n $host '$command_opt' 2>&1 | $awk_command "
- or warn "*** FugueConfig::launchAgent WARNING: Error executing ".
- "$command on $host\n";
- }
- }
-
+ $options .= " -b $bus" if $bus;
+ my $command_opt = $command;
+ $command_opt .= ' '.$options unless $options =~ /^\s*$/;
+ &_launch($appname, $host, $command_opt, 'agent');
+
} # end launchAgent
+
# launch a given command (not an ivy agent) on a given host
sub launchCommand {
my ($type, $host, $command, $options) = @_;
- my @options = @$options if ref($options) eq 'ARRAY';
- my $command_opt = $command.' '.join(' ', @options);
+ my $command_opt = $command;
+ $command_opt .= ' '.$options unless $options =~ /^\s*$/;
+ &_launch($type, $host, $command_opt, 'command');
+
+} # end launchCommand
+
+
+
+sub _launch {
+
+ my ($label, $host, $command_opt, $type) = @_;
my $pid = fork;
- warn ("*** FugueConfig::launchCommand WARNING: Could not fork!\n"), return
+ warn ("[FugueConfig][WARNING] Could not fork $type \'$command_opt\'!\n"), return
unless defined $pid;
-
+
+ # parent P1
if ($pid) {
- # parent
- print "*** FugueConfig::launchCommand INFO: $host: launching command ".
- "\'$command_opt\' (pid=$pid)\n";
+ print "[FugueConfig][INFO] launch on $host $label $type \'$command_opt\' ".
+ "(pid=$pid)\n";
return ($pid);
+
+ # child P2
} else {
- # child
- my $awk_command = "awk -W interactive '{print \"$type  \", \$0;}'";
- if ($host eq 'localhost' or $host eq hostname() ) {
- exec "$command_opt 2>&1 | $awk_command" or
- warn "*** FugueConfig::launchCommand WARNING: Error executing ".
- "$command\n";
+
+ # overload parent trap
+ $SIG{INT} = 'DEFAULT';
+
+ # remote command
+ $command_opt = "$rsh -n $host '$command_opt'"
+ unless $host eq 'localhost' or $host eq hostname();
+
+ pipe(READER, WRITER);
+ WRITER->autoflush(1);
+ my $pid2 = fork;
+ warn ("[FugueConfig][WARNING] Could not fork $type \'$command_opt\'!\n"),
+ return
+ unless defined $pid2;
+ # parent P2
+ if ($pid2) {
+ close READER;
+ CORE::open(STDOUT, ">&=WRITER") or
+ die "[FugueConfig][WARNING] Couldn't redirect STDOUT";
+ exec "$command_opt" or
+ die "[FugueConfig][WARNING] Couldn't launch $command_opt";
+ # child P3
} else {
- exec "$rsh -n $host '$command_opt' 2>&1 | $awk_command "
- or warn "*** FugueConfig::launchCommand WARNING: Error executing ".
- "$command on $host\n";
+ close WRITER;
+ while(<READER>) {
+ chomp();
+ print "$label $_\n";
+ }
+ close READER;
+ exit;
}
- }
-
-} # end launchCommand
+ }
+
+} # end _launch
1;
diff --git a/debian/changelog b/debian/changelog
index e98dce3..49631e2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+ivylaunch (1.4) unstable; urgency=low
+
+ * Correction : sur réception d'un message Die, tous les processus fils
+ sont tués; cette modification remplace le contournement introduit
+ dans la version 1.2.
+
+ -- Daniel Etienne <etienne@cena.fr> Fri, 8 Jul 2005 16:32:31 +0200
+
ivylaunch (1.3) unstable; urgency=low
* Possibilité de passer des options à cpp
diff --git a/ivylaunch b/ivylaunch
index c51abdc..59e4887 100755
--- a/ivylaunch
+++ b/ivylaunch
@@ -29,15 +29,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# All applications that should be launched should be specified in the <project file>.
-# @Global is the list of applications that are independent of projet instances. If one
-# of these applications is not present, it is launched. @Local are the applications
-# needed for one instance of the project program. @Begin is the list of command that I
-# should execute before launching the projet applications. @End is the list of command
-# that I should execute when leaving.
+our $VERSION = 1.4;
-# signal handlers
BEGIN {
if (-d "/usr/lib/ivylaunch") {
@@ -47,7 +40,8 @@ BEGIN {
}
}
-$SIG{INT} = $SIG{KILL} = 'Quit';
+$SIG{INT} = 'RunEndCmd';
+
use Ivy;
use strict;
@@ -73,9 +67,10 @@ my $bus = defined $ENV{"IVYBUS"} ? $ENV{"IVYBUS"} : '127.255.255.255:2010';
$bus = $opt{'b'} if defined $opt{'b'};
my $file = pop @ARGV;
+&usage unless defined($file);
+
my @cppopts = @ARGV;
-&usage unless defined($file);
my (%child);
@@ -86,17 +81,17 @@ $| = 1;
print "$HEADER Reading configuration file $file...\n";
-my ($type, @param, %ready);
+my ($type, %ready);
for (FugueConfig::parse($file, @cppopts)) {
- my ($type, $host, $name, $command, $paramslist) = @$_;
+ my ($type, $host, $name, $command, $params) = @$_;
next if $type eq 'comment';
if ($type eq 'begin' or $type eq 'end') {
- push @{$cmd{$type}}, [$host, $command, $paramslist];
+ push @{$cmd{$type}}, [$host, $command, $params];
} else {
# add filename to ivycontrolpanel command (not destructive)
- push(@$paramslist, $file) if ($name eq 'ivycontrolpanel');
- push @{$agent{$type}}, [$name, $host, $command, $paramslist, $bus];
+ $params .= " $file" if ($name eq 'ivycontrolpanel');
+ push @{$agent{$type}}, [$name, $host, $command, $params, $bus];
push (@apps, $name);
}
}
@@ -105,7 +100,7 @@ print "$HEADER needs ", join (",", @apps), "\n";
Ivy->init(-loopMode => 'LOCAL',
- -onDieFunc => [\&Terminate],
+ -onDieFunc => [\&Quit],
-appName => $appliname,
-ivyBus => $bus);
@@ -120,6 +115,7 @@ print "$HEADER $appliname is being launched using bus $bus (pid=$$)...\n";
foreach my $app (@{$cmd{'begin'}}) {
my $pid = FugueConfig::launchCommand ('begin', @$app);
$child{$pid} = $app->[1];
+ $child{$pid} .= " ".$app->[2] if $app->[2] !~ /^\s*$/;
}
foreach my $app (@{$agent{'local'}}) {
my $pid = FugueConfig::launchAgent(@$app);
@@ -127,17 +123,20 @@ foreach my $app (@{$agent{'local'}}) {
}
# if after 5 seconds the "global" agents are not detected, launch them.
-print "$HEADER Wait 5 seconds before global apps checking...\n";
-Ivy::after (5000, [\&Global]) if @{$agent{'global'}};
+if (@{$agent{'global'}}) {
+ print "$HEADER Wait 5 seconds before global apps checking...\n";
+ Ivy::after (5000, [\&Global]);
+}
my $host = hostname;
+
$SIG{CHLD} = 'Child';
$ivy->start;
+
$ivy->mainLoop;
-######################################################
sub Global {
@@ -158,8 +157,8 @@ sub Global {
-######################################################
+# function called when a child exits
sub Child {
$SIG{CHLD} = 'Child';
@@ -174,40 +173,35 @@ sub Child {
}
}
-######################################################
-
-sub Terminate {
- print "$HEADER Die message received\n";
- foreach (values %child) {
- print "$HEADER sendDieTo $_ ...\n";
- $ivy->sendDieTo($_);
- }
- foreach my $app (@{$cmd{'end'}}) {
- FugueConfig::launchCommand('end',@$app);
+# function called on a die message
+sub Quit {
+
+ print "$HEADER Quit (on Die message)\n";
+ # kill begin commands (if running) and agents
+ foreach (keys %child) {
+ print "$HEADER Stopping '$child{$_}' (pid=$_)...\n";
+ kill INT => $_;
}
- print "$HEADER Terminated\n";
+ &RunEndCmd;
}
-######################################################
-sub Quit {
- print "$HEADER Quit\n";
- foreach (keys %child) {
- print "$HEADER Stopping $child{$_} (pid=$_)...\n";
- kill 15, $_;
- }
+sub RunEndCmd {
+
+
+ # execute end commands
foreach my $app (@{$cmd{'end'}}) {
- FugueConfig::launchCommand('end',@$app);
+ FugueConfig::launchCommand('end',@$app);
}
$ivy->stop();
exit;
-}
-######################################################
+}
sub Status {
+
my ($ref_array_present, $ref_array_absent, $ref_hash_present,
$agent, $status, $host) = @_;
@@ -225,6 +219,8 @@ sub Status {
}
sub usage {
+
+ print "Version : $VERSION\n";
print "Usage: $appliname [-b bus] [-override] [cpp options] <config_file>\n";
exit;
}
@@ -233,15 +229,15 @@ __END__
=head1 NAME
-ivylaunch - a script which launches ivy agents, according to a Fugue configuration file.
+ivylaunch - a script which launches ivy agents and commands, according to a configuration file.
=head1 SYNOPSIS
-ivylaunch [-help] [-b bus] [-override] fugueconfigfile
+ivylaunch [-help] [-b bus] [-override] [cpp options] configfile
=head1 DESCRIPTION
-ivylaunch forks ivy agents described in a Fugue configuration file. ivylaunch is also an ivy agent : it reports agents connection and disconnection, and can be killed by an Ivy die message which is transmitted to its forked agents. It can be also killed by sending an interrupt signal (SIGINT) or kill signal (SIGKILL); in this case, ivylaunch sends a termination signal to its forked children before exiting.
+ivylaunch forks ivy agents and commands described in configuration file. ivylaunch is also an ivy agent : it reports agents connection and disconnection, and can be killed by an Ivy die message.
=back
@@ -260,16 +256,35 @@ Infer ivylaunch behavior when a B<global> agent is detected on the bus. See belo
=back
-=head1 FUGUE CONFIGURATION FILE FORMAT
+=head1 CONFIGURATION FILE FORMAT
-Each line of a fugue configuration file should contain at least 4 mandatory fields separated by space or tabulation : the first three fields are B<type>, B<host> and B<name>. The next ones are dedicated to the B<command> and its options.
+Each line of configuration file should contain at least 4 mandatory fields separated by space or tabulation : B<type>, B<host>, B<name> and B<command> and its options.
=over
=item B<type>
-the type of command should take one of the following values : begin, end, global or local. B<begin> links up with commands which are executed before launching ivy agents, B<end> with commands which are executed after agents have been killed, just before exiting. B<global> and B<local> relate to ivy agents. The B<global> tag assures the unicity of an agent : before launching a global agent, ivylaunch checks for it on the bus; if this agent is already connected, ivylaunch preserves it if the B<-override> option is false (the default value), or kills it (by sending an ivy die message) and forks a new one if -override is true. B<local> agents are launched without checking before global ones.
+the type of forked commands should take one of the following values : begin, local, global, end.
+
+=over
+
+=item B<begin>
+
+links up with simple commands (not ivy agents) which are executed at first,
+
+=item B<local>
+
+links up with ivy agents which can have one or more instances on the bus.
+
+=item B<global>
+links up with ivy agents which must be single. Before launching a global agent, ivylaunch checks for it on the bus; if this agent is not present, ivylaunch launches it. If it's already connected, ivylaunch preserves it if the B<-override> option is false (the default value), or kills it (by sending an ivy die message) and forks a new one if -override is true. global agents are launched after local ones.
+
+=item B<end>
+
+links up with simple commands which are executed after agents have been killed, just before exiting. These commands are kept alive when ivylaunch exits.
+
+=back
=item B<host>
@@ -277,7 +292,7 @@ the host where the command will be executed.
=item B<name>
-the application name. This indicative field is used to detect double agents. Insure that this name corresponds to the real ivy name detected on the bus. This field make sense only for ivy agent; usage is to set 'none' to other commands.
+This indicative field is used to detect double agents. Insure that this name corresponds to the real ivy name detected on the bus. This field make sense only for ivy agent; usage is to set 'none' to other commands.
=item B<command>
@@ -285,10 +300,15 @@ the command to execute and its options.
=back
-Before being analysed, the configuration file is parsed by the preprocessor B<cpp>, which provides some facilities like macro expansion.
+Before being analysed, the configuration file is parsed by the preprocessor B<cpp>, which provides some facilities like macro expansion. cpp options can be passed on command line.
-=head1 EXAMPLE OF CONFIGURATION FILE
+=head1 EXAMPLE
+
+ % ivylaunch -b 127:3456 -D ACC=reims -D WP=WP0 configfile
+where configfile contains :
+
+
#ifndef ACC
#define ACC paris
#endif
@@ -299,13 +319,17 @@ Before being analysed, the configuration file is parsed by the preprocessor B<cp
#define POSITION --acc ACC --wp WP
#endif
-global anglo Rejeu rejeu -s 9:10 STR_ATH_01_06_26.rej
+ begin lasra none xset fp+ tcp/10.192.36.68:7100
+
+ global anglo Rejeu rejeu -s 9:10 STR_ATH_01_06_26.rej
+
+ global tibot ivycontrolpanel ivycontrolpanel -nocursor
-global tibot ivycontrolpanel ivycontrolpanel -nocursor
+ local lasra twinkle:ACC:WP:TC twinkle POSITION --role TC
-local lasra twinkle:ACC:WP:TC twinkle POSITION --role TC -norender
+ local astik IvyMon ivymon
-local astik IvyMon ivymon
+ end lasra none xset fp- tcp/10.192.36.68:7100
=head1 SEE ALSO