Aller au contenu principal

Ordonnanceurs < Les incontournables < Autosys < Développement

Générer un script Graphviz à partir d’un JIL

Graphviz propose un langage simple pour générer des graphs orientés, le principe du script est de convertir les éléments du JIL (Job Interface Language) d’Autosys en script graphviz pour obtenir une image (gif, png, jpeg...) ou un dessin vectoriel (SVG) que l’on pourra éditer ensuite avec Inkscape ou Visio pour les plus riches.
E. Angenault
16 novembre 2008

 POPULARITE : 121 visites

Principe

Le JIL est convertit au format Graphviz, il peut ensuite être traité par l’exécutable de votre choix (dot, neato, twopi...) en fonction des besoins.

Pour utiliser ce script, il est nécessaire de disposer de perl (seulement l’interpréteur, les bibliothèques ne sont pas utiles) et graphviz que vous pourrez télécharger à l’adresse suivante : http://graphviz.org

Exemple

On prend comme exemple le JIL suivant qui représente une boite avec un job principal qui en cas de statut OK déclenche un JOB2 ou, en cas de problème (après 3 essais), déclenche le JOB3. Pour que la boite récupère son statut il est nécessaire de lui indiquer les condition de succès (box_success) et de failure (box_failure).

/* ----------------- ATSR-_ERIC_-B-BOX_FAILURE ----------------- */

insert_job: ATSR-_TEST_-B-BOX_FAILURE   job_type: b
owner: autosys
permission: gx,wx,mx,ge,we,me
box_failure: d(ATSR-_TEST_-CUX-JOB3)
box_success: s(ATSR-_TEST_-CUX-JOB2)
description: "Boite de test"
alarm_if_fail: 0

 /* ----------------- ATSR-_ERIC_-CUX-JOB1 ----------------- */

 insert_job: ATSR-_TEST_-CUX-JOB1   job_type: c
 box_name: ATSR-_TEST_-B-BOX_FAILURE
 command: exit 1
 machine: localhost
 owner: eric
 permission: gx,wx
 description: "Commande a executer"
 n_retrys: 3
 alarm_if_fail: 1

 /* ----------------- ATSR-_ERIC_-CUX-JOB2 ----------------- */

 insert_job: ATSR-_TEST_-CUX-JOB2   job_type: c
 box_name: ATSR-_TEST_-B-BOX_FAILURE
 command: echo test
 machine: localhost
 owner: eric
 permission: gx,wx
 description: "Si tout va bien"
 condition: s(ATSR-_TEST_-CUX-JOB1)
 alarm_if_fail: 1

 /* ----------------- ATSR-_ERIC_-CUX-JOB3 ----------------- */

 insert_job: ATSR-_TEST_-CUX-JOB3   job_type: c
 box_name: ATSR-_TEST_-B-BOX_FAILURE
 command: echo degrade
 description: "En cas de probleme"
 machine: localhost
 owner: eric
 permission: gx,wx
 condition: f(ATSR-_TEST_-CUX-JOB1)
 alarm_if_fail: 1

Appel

Le script utilise le JIL passé par l’entrée standard et génère le script qui peut être passé directement ) l’exécutable graphviz. Dans notre exemple, le JIL est dans le fichier test.jil et l’exécutable est dot, on génère des images de type PNG.

L’appel sans paramètre génère les noeuds et les liens entre ces noeuds avec l’affichage de la description :

perl jil2gvz.pl < test.jil | dot -Tpng > test1.png

PNG - 15.3 ko
jil2gvz simple
aucun paramètre n’est passé.

Pour disposer de plus d’informations, on peut ajouter des champs sur la boite, le job ou le filewatcher. Dans cet exemple, on ajoute la commande passée et la machine utilisée pour les jobs :

perl jil2gvz.pl job=description,command,machine < test.jil | dot -Tpng > test1.png

PNG - 17.5 ko
jil2gvz avec paramètres
Dans cet exemple, on ajoute la commande et la machine.

jil2gvz.pl PERL
Script de conversion JIL en Graphviz.
#!/usr/bin/perl
%Info = (
	'name'			=> 'Jil2Gvz',
	'desc'			=> 'This script converts a jil file to a graphviz file. Graphviz uses some executable as dot or neato to draw some diagrams.',
	'usage'			=> 'jil2Gvz.pl [BOX=(box fields,...)] [JOB=(job fields,...)] [FW=(job fields,...)] [HEAD=(y|n)] [FOOT=(y|n)] < jil_convert.jil > graphviz.gvz',
	'author'		=> 'E. Angenault',
	'license'		=> 'GNU GPL',
	'website'		=> 'http://ordonnancement.org',
	'input'			=> 'jil file',
	'parameters'=> 
		(	'box'=>	'autosys fields list for boxes. Default: description',
			'job'=>	'autosys fields list for job. Default: description',
			'fw' => 'autosys fields list for file watchers. Default: description',
			'head'=> 'indicates if a header file is added at the beginning. Default: y',
			'foot'=> 'indicates if a footer file is addes at the end. Default: y' ),
	'return'		=> 'gvz script' );
#-----------------------------------------------------------------#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#-----------------------------------------------------------------#

# get command line parameters
GetArgs();

# Display help screen if no args specified
Help(%Info);

# Information to add
$box='description'
	unless $box;
@InfosBox = split(',',$box);
$job='description'
	unless $job;
@InfosJob = split(',',$job);
$fw='description'
	unless $fw;
@InfosFW = split(',',$fw);

# HEADER and FOOTER
$head = 'y'
	unless $head;
$foot = 'y'
	unless $foot;
	
# Get JIL information
while (<STDIN>) {
	if (/(insert|update)_job: (.*?) *job_type: (\w)/) {
		 $job = $2;
		 $t = $3;
		 # No box by default.
		 $Box{$job}='.';
		 $Type{$job}= $t;
		 print STDERR "Job:\t".$job.' ('.$Type{$job}.")\n";
		 @Info = ();
	}
	if ((/box_name: (.*?)\n/)) {
		 $box = $1;
		 $Box{$job}=$box;
		 $SGraph{$box}.="\t".$job;
		 print STDERR "Box:\t".$Box{$job}."\n";
	}
	elsif (/condition: (.*?)\n/) {
		 $cond = $1;
		 $cond =~ s/ //g;
		 while ($cond =~ s/(\w)\((.*?)\)//) {
		 		 $t = $1;
		 		 $c = $2;
		 		 if ($cond =~ s/^([\>\<\=]\d*)//) {
		 		 		 $v = " $1";
		 		 }
		 		 else {
		 		 		 $v="";
		 		 }
		 		 $t =~ tr/A-Z/a-z/;
		 		 if ($t =~ /^g/) {
		 		 		 $Type{$c}='v';
		 		 }
		 		 $Dep{$job} .= "\t$t$v,$c";
		 		 print STDERR "Dep:\t\t$t$v,$c\n";
		 		 $i++;
		 }
	}
	elsif (/box_(success|failure): (.*?)[ \n]/) {
		 $type = $1;
		 $cond = $2;
		 $cond =~ s/ //g;
		 while ($cond =~ s/(\w)\((.*?)\)//) {
		 		 $t = $1;
		 		 $c = $2;
		 		 if ($cond =~ s/^([\>\<\=]\d*)//) {
		 		 		 $v = " $1";
		 		 }
		 		 else {
		 		 		 $v = "";
		 		 }
		 		 $t =~ tr/a-z/A-Z/;
		 		 $Dep{$job} .= "\t$t$v,$c";
		 		 print STDERR "Dep:\t".$Dep{$job}."\n";
		 		 $i++;
		 }
	}
	elsif (/n_retrys: (\d*)/) {
		 $n = $1;
		 print STDERR "Try:\t$n\n";
		 $Dep{$job} .= "\tr $n,$job";
	}
#	elsif (/box_terminator: 1/) {
#		 $Dep{$job} .= "\tb ".$Box{$job};
#	}
	elsif (s/\s*(.*?): (.*?)\n//) {
		 $var = $1;
		 $val = $2;
		 $val =~ s/\"//g;
		 $Info{$job.'_'.$var} = $val;
	}
}

# Add a default header
if ($head ne 'n') {
	# Generation du fichier
	print "digraph G {\n";
	print "fontname=arial\n";
	print "node [fontname=arial,fontsize=8]\n";
}

# V1.0: on traite les boites imbriquees

$clus=0;
foreach $f (sort keys %Box) {
	if ($Box{$f} eq '.') {
		GetSub($f);
	}
}
 
sub GetSub {
($job)=@_;


		 $sg = $SGraph{$job};
		 $sg =~ s/^\t//;
		 if ($sg ne '') {
		 		 $clus++;
		 		 $Cluster{$job} = "cluster".$clus;
		 		 print "subgraph ".$Cluster{$job}." {\n";
		 		 print "label=\"$job\";\n";
		 		 print "\"$job\";\n";
		 		 foreach $s (split("\t",$sg)) {
#		 		 		 $Cluster{$s} = $Cluster{$job}; 
		 		 		 GetSub($s);
		 		 }
		 		 print "}\n";
		 }
		 else {
		 		 print "\t\"$job\";\n";
		 }
}

## Format des liens
foreach $t (keys %Type) {
	if ($Type{$t} eq "b") {
		 print "\t\"$t\" ";
		 print '[shape=record,label="'.$t;
		 foreach $i (@InfosBox) {
				PrintStr($Info{$t.'_'.$i}); 
		 }
		 print '"]'.";\n";
	}
	elsif ($Type{$t} eq "c") {
		 print "\t\"$t\" ";
		 print '[shape=Mrecord,label="'.$t;
		 foreach $i (@InfosJob) {
	 		PrintStr($Info{$t.'_'.$i})
		 }
		 print '"]'.";\n";
	}
	elsif ($Type{$t} eq "f") {
		 print "\t\"$t\" ";
		 print '[color=blue,shape=Mrecord,label="'.$t;
		 foreach $i (@InfosFW) {
	 		PrintStr($Info{$t.'_'.$i})
		 }
		 print '"]'.";\n";
	}
	elsif ($Type{$t} eq "g") {
		 print "\t\"$t\" ";
		 print '[shape=invtrapezium]';
	}
	elsif ($Type{$t} eq "v") {
		 print "\t\"$t\" ";
		 print '[shape=invtriangle]';
		 print ";\n";
	}
	else{
		 print "\t\"$t\" ";
		 print '[color=red]';
		 print ";\n";
	}
}

 # 		 
 foreach $j (keys %Dep) {
 		 @D = split("\t",$Dep{$j});
 		 @opttail = ();

 		 if ($Type{$j} eq 'b') {
 		 		 push(@opttail,'lhead="'.$Cluster{$j}.'"');
 		 		 push(@opttail,'arrowsize=2.0');
 		 }

 		 $dummy = shift(@D);
 		 foreach $d (@D) {
 		 		 ($t,$c) = split(/,/,$d);

 		 		 @opt = @opttail;		 		 		 		 

 		 		 if ($Type{$c} eq 'b') {
 		 		 		 push(@opt,'ltail="'.$Cluster{$c}.'"');
 		 		 		push(@opt,'arrowsize=2.0');
 		 		 }

 		 		 print "\"$c\" -> \"$j\" ";

 		 		 if ($t =~ /^s/i) {
 		 		 		 push(@opt,"color=green");
 		 		 }
 		 		 elsif ($t =~ /^f/i) {
 		 		 		 push(@opt,"color=red");
 		 		 }
 		 		 elsif ($t =~ /^n/i) {
 		 		 		 push(@opt,"color=orange");
 		 		 }		 		 		 
 		 		 elsif ($t =~ /^d/i) {
 		 		 		 push(@opt,"color=blue");
 		 		 }
 		 		 elsif ($t =~ /^[gve] /i) {
 		 		 		 push(@opt,"color=purple");
 		 		 		 push(@opt,"label=\"$t\"");
 		 		 }		 		 		 
 		 		 elsif ($t =~ s/^t//i) {
 		 		 }		 		 		 
 		 		 else {
 		 		 		 push(@opt,"label=\"$t\"");
 		 		 }
 		 		 if ($t =~ /^[SF]/) {
 		 		 		 push(@opt,"style=dotted");
 		 		 }
 		 		 print "[".join(",",@opt)."];\n";
 		 }
 }
 print "}\n"
 	unless $foot eq 'n';

# Write a string
sub PrintStr {
local($t) = @_;

	if ($t eq '') { return; }

	$str = '';	
	$n=0;
	$t =~ s/\\/\\\\/g;
	$t =~ s/\>/\>/;
	 foreach $c (split("",$t)) {
		if (($c eq ' ') && ($n>20)) { 
	 		$str .= '\n';
	 		$n=0;
		} 
		else {
	 		$str .= $c;
	 		$n++;
	 	}
	 }
	print '|'.$str;
}



sub GetArgs {
local(%Default) = @_;

	# Parametres en arguments
	foreach (@ARGV) {
		($var,@Val) = split('=');
		$val = join('=',@Val);
		if ($val eq 'STDIN') {
			while (<STDIN>) {
				chop;
				if (@Head) {
					@Infos{@Head} = split(/\t/);
					foreach $k (keys %Infos) {
						push(@{$k},$Infos{$k});
					}
				}
				else {
					@Head = split(/\t/);
				}
			}
		}
		else {
			${$var} = $val
				if ($var !~ s/^\!//);
		}
	}
	# parametres en ligne de commande
	
	# parametres par defaut
	foreach $d (keys %Default) {
		${$d} = $Default{$d}
			unless ${$d};
	}
}

sub Help {
%Info=@_;
	if ($HELP) {
		print $Info{'name'}."\n\n";
		print $Info{'desc'}."\n";
		exit;
	}
}
Télécharger PERL (7434 octets)

Doc
Scripts
Ces scripts sont destinés aux utilisateurs d’ordonnanceurs, qu’ils soient simple utilisateurs ou administrateurs.
Voir aussi...
A la une, autotrad, Communiqué de Presse, Documentation, FAQ, Fiche technique, graphique, news, PRIVE, Procédure d’installation

Le document issu de http://Ordonnancement.org est mis à disposition sous les termes de la licence Creative Commons, vous pouvez l'utilisez dans vos documents à condition de citer l'auteur E. Angenault, vous êtes aussi libre de le modifier. Par contre, vous devez le redistribuer dans les mêmes conditions et la commercialisation ne peut se faire qu'avec l'accord de l'auteur.