/usr/bin/fai-deps is in fai-client 4.0.8~deb7u1.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | #!/usr/bin/perl
=head1 NAME
fai-deps - class dependencies for FAI
=head1 SYNOPSIS
fai-deps [-h] [--man] [-d]
=head1 ABSTRACT
implements dependencies between fai classes.
=head1 DESCRIPTION
fai-deps uses files $FAI/class/*.deps to sort the classes in $LOGDIR/FAI_CLASSES and define additional ones. While doing so, it retains the original order as much as possible.
*.deps files may contain class names, seperated by whitespace. Comments ( after # or ; ) are ignored
e.g. you have a class WORDPRESS that depends on the classes VHOST and POSTGRES . VHOST again may depend on WEBSERVER.
So if you want to install the blogging software wordpress, you add a file
$FAI/class/WORDPRESS.deps
that contains the words
VHOST
POSTGRES
and a file
$FAI/class/VHOST.deps
that contains the word
WEBSERVER
The order often is important, so this script is taking care of it. The order of the example above would be:
WEBSERVER VHOST POSTGRES WORDPRESS
That way, in $FAI/scripts/ first the webserver would be configured, then the vhosts, ...
It removes double entries from FAI_CLASSES and handles circular dependencies[1].
I do not recommend using circular dependencies, but if you accidentally define them, they will not break your neck. But you'll get a warning ...
=head1 ENVIROMENT
One non-standard perl module is required:
Graph::Directed;
On debian install libgraph-perl
The following enviroment variables are used:
$LOGDIR : path to fai temporary files
$FAI : path to fai config space
=cut
INIT
{
unless ( $ENV{FAI} and $ENV{LOGDIR} ) {
print STDERR '$ENV{FAI} and $ENV{LOGDIR} are not defined', $/;
print STDERR 'This script should be called from within fai', $/;
exit 1;
}
}
use strict;
use warnings;
use Getopt::Long;
use Pod::Usage;
use Graph::Directed;
#use Text::Glob qw(match_glob);
#use Data::Dumper;
#use GraphViz;
my %opts;
GetOptions( \%opts, 'help|h', 'man', 'debug|d' ) or pod2usage(1);
pod2usage(1) if $opts{help};
pod2usage(-verbose => 2) if $opts{man};
my $debug = $opts{debug};
my $fai_classes_file = "$ENV{LOGDIR}/FAI_CLASSES";
my $class_dir = "$ENV{FAI}/class";
# main
{
# read classes and dependencies into $digraph
# retain order of first appearance in @uniq_classes
my $digraph = Graph::Directed->new;
my ( @uniq_classes ) =
read_fai_classes( $digraph, $fai_classes_file );
push @uniq_classes,
read_dependencies( $digraph, $class_dir, @uniq_classes );
exit if not $digraph->has_edges;
# debug output
if ( $debug ) {
print STDERR 'graph:', $/;
print STDERR $digraph->stringify(), $/;
print STDERR 'is strongly connected', $/
if $digraph->is_strongly_connected;
# create_graphviz_output($digraph->edges);
print STDERR 'unique list of classes, orderd by appearence', $/;
print STDERR join('-', @uniq_classes), $/;
print STDERR $/;
}
# warn if graph has cycles
if ( $digraph->has_a_cycle ) {
print STDERR 'Warning: cyclic class dependencies found:', $/;
my $copy = $digraph->copy;
while ( my @cycle = $copy->find_a_cycle ) {
print STDERR join('-', @cycle), $/;
$copy->delete_cycle(@cycle);
}
print STDERR 'I`ll try my best to retain your class order', $/;
}
# sort classes: retain order where possible, respect dependencies where necessary
my @sorted_classes = sort_classes( $digraph, @uniq_classes );
# debug output
if ( $debug ) {
print STDERR "list of all classes after resolving dependencies:", $/;
print STDERR "@sorted_classes", $/;
print STDERR 'in debug mode, this script has no effect at all!', $/x5;
print STDERR 'Goodbye, and thank you for the fish', $/;
exit;
}
# rewrite $fai_classes_file
open FAI_CLASSES, ">$fai_classes_file"
or die "$!: $fai_classes_file";
print FAI_CLASSES join($/, @sorted_classes), $/;
close FAI_CLASSES;
}
exit; # end main
# sort_classes:
# topological sort classes, retaining order as much as possible
my %class_finished_for;
my @order;
sub sort_classes {
my ( $digraph, @uniq_classes ) = @_;
@order = @uniq_classes if not @order;
my @sorted_classes;
for my $class ( @uniq_classes ) {
next if exists $class_finished_for{$class};
my %unfinished_successor_for =
map { $_, 1 }
grep { not exists $class_finished_for{$_} }
successors($digraph, $class);
# retain order for successors
my @unfinished_successors =
grep { $unfinished_successor_for{$_} }
@order;
push @sorted_classes, sort_classes( $digraph, @unfinished_successors );
push @sorted_classes, $class;
$class_finished_for{$class}++;
}
return @sorted_classes;
}
# successors: find successors for a given class
# handle circular dependencies:
# * do not return circular connected successors
# * _do_ return all successors of circular connected successors
sub successors {
my ( $digraph, $class ) = @_;
my $component = $digraph->strongly_connected_component_by_vertex($class);
# strongly connected components to all successors, except own component
my %successor_components =
map { $_, undef } # turn list into hash for uniqueness
grep { $_ ne $component }
map { $digraph->strongly_connected_component_by_vertex($_) }
$digraph->successors($class);
# classes for these components
my %successors =
map { $_, undef } # turn list into hash for uniqueness
map { $digraph->strongly_connected_component_by_index($_) }
keys %successor_components;
return keys %successors;
}
# read_fai_classes: reads fai classes from $fai_classes_file
# usually $LOGDIR/FAI_CLASSES
sub read_fai_classes {
my ( $digraph, $fai_classes_file) = @_;
my @uniq_classes;
# read plain classes from $LOGDIR/FAI_CLASSES
open FAI_CLASSES, $fai_classes_file
or die "$!: $fai_classes_file";
while ( <FAI_CLASSES> ) {
chomp;
# skip double classes
next if $digraph->has_vertex( $_ );
push @uniq_classes, $_;
$digraph->add_vertex( $_ );
}
close FAI_CLASSES;
return @uniq_classes;
}
# read_dependencies: reads dependencies and its classes from $class_dir/*.deps
my %deps_file_seen_for;
sub read_dependencies {
my ( $digraph, $class_dir, @uniq_classes) = @_;
my @new_classes;
# read class dependencies from $class_dir/*.deps
my $prefix = quotemeta($class_dir);
my @deps_files = grep {
-f "$class_dir/$_.deps"
and not -x "$class_dir/$_.deps"
} @uniq_classes;
for my $class ( @deps_files ) {
next if $deps_file_seen_for{$class}++;
open DEPSFILE, "$class_dir/$class.deps"
or die "$!: $class";
while ( <DEPSFILE> ) {
chomp;
# remove comments, leading and trailing whitespace
s/(#|;).*// ;
s/ ^\s+ //x;
s/ \s+$ //x;
# allow multiple classes per line
my @deps = split m/\s+/;
for my $dep ( @deps ) {
push @new_classes, $dep
if not $digraph->has_vertex( $dep );
$digraph->add_edge($class, $dep);
}
}
close DEPSFILE;
push @new_classes, read_dependencies( $digraph, $class_dir, @new_classes );
}
return @new_classes;
}
#sub create_graphviz_output {
# my @edges = @_;
# my $g = GraphViz->new();
# for ( @edges ) {
# $g->add_edge( @$_ );
# }
# return $g->as_png('graph-test.png');
#}
=head1 SEE ALSO
http://fai-project.org
=head1 AUTHOR
Copyright 2008 by Ingo Wichmann <iw@linuxhotel.de>
This software ist free software; you can redistribute it and/or modify
it unter the same terms as Perl itself.
=cut
|