File Coverage

blib/lib/Rex/JobControl/Helper/Project/Job.pm
Criterion Covered Total %
statement 24 177 13.5
branch 0 40 0.0
condition 0 6 0.0
subroutine 8 27 29.6
pod 0 18 0.0
total 32 268 11.9


line stmt bran cond sub pod time code
1             #
2             # (c) Jan Gehring
3             #
4             # vim: set ts=2 sw=2 tw=0:
5             # vim: set expandtab:
6              
7             package Rex::JobControl::Helper::Project::Job;
8             $Rex::JobControl::Helper::Project::Job::VERSION = '0.18.0';
9 1     1   4 use strict;
  1         2  
  1         30  
10 1     1   3 use warnings;
  1         1  
  1         19  
11              
12 1     1   4 use File::Spec;
  1         1  
  1         17  
13 1     1   3 use File::Path;
  1         1  
  1         39  
14 1     1   4 use YAML;
  1         1  
  1         38  
15 1     1   337 use Rex::JobControl::Helper::Chdir;
  1         2  
  1         47  
16 1     1   4 use Digest::MD5 'md5_hex';
  1         2  
  1         33  
17 1     1   4 use Data::Dumper;
  1         1  
  1         1661  
18              
19             sub new {
20 0     0 0   my $that = shift;
21 0   0       my $proto = ref($that) || $that;
22 0           my $self = {@_};
23              
24 0           bless( $self, $proto );
25              
26 0           $self->load;
27              
28 0           return $self;
29             }
30              
31 0     0 0   sub name { (shift)->{job_configuration}->{name} }
32 0     0 0   sub description { (shift)->{job_configuration}->{description} }
33 0     0 0   sub environment { (shift)->{job_configuration}->{environment} }
34 0     0 0   sub project { (shift)->{project} }
35 0     0 0   sub directory { (shift)->{directory} }
36 0     0 0   sub fail_strategy { (shift)->{job_configuration}->{fail_strategy} }
37 0     0 0   sub execute_strategy { (shift)->{job_configuration}->{execute_strategy} }
38              
39             sub steps {
40 0     0 0   my ($self) = @_;
41 0           my $steps = $self->{job_configuration}->{steps};
42              
43 0           my @steps_a;
44              
45 0           for my $s ( @{$steps} ) {
  0            
46 0           my ( $rexfile_dir, $task ) = split( /\//, $s );
47 0           my $rexfile = $self->project->get_rexfile($rexfile_dir);
48 0           push @steps_a, $rexfile->name . "/$task";
49             }
50              
51 0           return \@steps_a;
52             }
53              
54             sub load {
55 0     0 0   my ($self) = @_;
56              
57 0 0         if ( -f $self->_config_file() ) {
58 0           $self->{job_configuration} = YAML::LoadFile( $self->_config_file );
59             }
60             }
61              
62             sub _config_file {
63 0     0     my ($self) = @_;
64 0           return File::Spec->catfile( $self->project->project_path(),
65             "jobs", $self->{directory}, "job.conf.yml" );
66             }
67              
68             sub get_output_log {
69 0     0 0   my ( $self, $job_id ) = @_;
70              
71 0           my $job_path = File::Spec->catdir( $self->project->project_path,
72             "jobs", $self->{directory} );
73 0           my $execute_path = "$job_path/execute/$job_id";
74              
75 0           my $logfile = "$execute_path/output.log";
76              
77 0 0         if ( !-f $logfile ) {
78 0           $self->project->app->log->error(
79             "This job doesn't have an output.log file.");
80 0           return "No output.log found.";
81             }
82              
83 0           my @loglines = eval { local ( @ARGV, $/ ) = ($logfile); <>; };
  0            
  0            
84              
85 0           return \@loglines;
86             }
87              
88             sub create {
89 0     0 0   my ( $self, %data ) = @_;
90              
91 0           my $job_path = File::Spec->catdir( $self->project->project_path,
92             "jobs", $self->{directory} );
93              
94 0           $self->project->app->log->debug(
95             "Creating new job $self->{directory} in $job_path.");
96              
97 0           File::Path::make_path($job_path);
98              
99 0           delete $data{directory};
100              
101 0           my $job_configuration = {%data};
102              
103 0           YAML::DumpFile( "$job_path/job.conf.yml", $job_configuration );
104             }
105              
106             sub update {
107 0     0 0   my ( $self, %data ) = @_;
108 0           $self->{job_configuration} = \%data;
109              
110 0           my $job_path = File::Spec->catdir( $self->project->project_path,
111             "jobs", $self->{directory} );
112              
113 0           YAML::DumpFile( "$job_path/job.conf.yml", \%data );
114             }
115              
116             sub remove {
117 0     0 0   my ($self) = @_;
118 0           my $job_path = File::Spec->catdir( $self->project->project_path,
119             "jobs", $self->{directory} );
120              
121 0           File::Path::remove_tree($job_path);
122             }
123              
124             sub execute {
125 0     0 0   my ( $self, $user, $cmdb, @server ) = @_;
126 0           $self->project->app->log->debug( "Executing job: " . $self->name );
127 0           my $job_path = File::Spec->catdir( $self->project->project_path,
128             "jobs", $self->{directory} );
129              
130 0 0         if ( scalar @server == 0 ) {
131 0           @server = ("");
132             }
133              
134 0           my $pid = time;
135 0           my $execute_path = "$job_path/execute/$pid";
136 0           my $cmdb_path = "$job_path/execute/$pid/cmdb";
137              
138 0           $ENV{JOBCONTROL_EXECUTION_PATH} = $execute_path;
139              
140 0           my @status;
141              
142 0           File::Path::make_path($execute_path);
143 0           File::Path::make_path($cmdb_path);
144              
145 0           $self->project->app->log->debug(
146             "Executing-Strategy: " . $self->execute_strategy );
147 0           $self->project->app->log->debug( "Fail-Strategy: " . $self->fail_strategy );
148              
149 0 0         if ($cmdb) {
150 0           $self->project->app->log->debug("Creating cmdb file");
151 0           YAML::DumpFile( "$cmdb_path/jobcontrol.yml", $cmdb );
152             }
153              
154             YAML::DumpFile(
155 0           "$execute_path/running.status.yml",
156             {
157             start_time => $pid,
158             user => $user,
159             }
160             );
161              
162 0 0         if ( $self->execute_strategy eq "step" ) {
163              
164             # execute strategy = step
165             # execute a step on all hosts, than continue with next step
166              
167 0           STEP: for my $s ( @{ $self->steps } ) {
  0            
168              
169 0           SERVER: for my $srv (@server) {
170              
171 0           my ( $rexfile_name, $task ) = split( /\//, $s );
172 0           $rexfile_name = md5_hex($rexfile_name);
173 0           my $rexfile = $self->project->get_rexfile($rexfile_name);
174              
175 0 0         my $ret = $rexfile->execute(
176             task => $task,
177             server => [$srv],
178             job => $self,
179             ( $cmdb ? ( cmdb => $cmdb_path ) : () )
180             );
181 0           push @status, $ret->[0];
182              
183 0 0         if ( exists $ret->[0]->{terminate_message} ) {
184 0           $self->project->app->log->debug("Terminating due to fail strategy.");
185 0           last STEP;
186             }
187              
188             }
189             }
190              
191             }
192             else {
193              
194             # execute strategt = node
195             # execute all steps on a server, than continue
196              
197 0           SERVER: for my $srv (@server) {
198              
199 0           STEP: for my $s ( @{ $self->steps } ) {
  0            
200              
201 0 0         if ( -f $self->project->project_path . "/next_server.txt" ) {
202 0           $srv = eval {
203 0           local ( @ARGV, $/ ) =
204             ( $self->project->project_path . "/next_server.txt" );
205 0           <>;
206             };
207 0           chomp $srv;
208 0           unlink $self->project->project_path . "/next_server.txt";
209             }
210              
211 0           my ( $rexfile_name, $task ) = split( /\//, $s );
212 0           $rexfile_name = md5_hex($rexfile_name);
213 0           my $rexfile = $self->project->get_rexfile($rexfile_name);
214              
215 0 0         my $ret = $rexfile->execute(
216             task => $task,
217             server => [$srv],
218             job => $self,
219             ( $cmdb ? ( cmdb => $cmdb_path ) : () )
220             );
221 0           push @status, $ret->[0];
222              
223 0 0         if ( exists $ret->[0]->{terminate_message} ) {
224 0           $self->project->app->log->debug("Terminating due to fail strategy.");
225 0           last SERVER;
226             }
227             }
228              
229             }
230              
231             }
232              
233 0           unlink "$execute_path/running.status.yml";
234              
235 0           YAML::DumpFile(
236             "$execute_path/run.status.yml",
237             {
238             start_time => $pid,
239             end_time => time,
240             user => $user,
241             status => \@status,
242             }
243             );
244              
245 0           YAML::DumpFile(
246             "$job_path/last.run.status.yml",
247             {
248             start_time => $pid,
249             end_time => time,
250             user => $user,
251             status => \@status,
252             }
253             );
254              
255 0           YAML::DumpFile(
256             $self->project->project_path . "/last.run.status.yml",
257             {
258             start_time => $pid,
259             end_time => time,
260             user => $user,
261             status => \@status,
262             }
263             );
264              
265              
266             }
267              
268             sub last_status {
269 0     0 0   my ($self) = @_;
270              
271 0           my $last_execution = $self->last_execution;
272              
273 0           my $job_path = File::Spec->catdir( $self->project->project_path,
274             "jobs", $self->{directory} );
275 0           my $execute_path = "$job_path/execute/$last_execution";
276              
277 0 0         if ( !-f "$execute_path/run.status.yml" ) {
278 0           return "not executed yet";
279             }
280              
281 0           my $ref = YAML::LoadFile("$execute_path/run.status.yml");
282              
283 0           my ($failed) = grep { $_->{status} eq "failed" } @{ $ref->{status} };
  0            
  0            
284              
285 0 0         if ($failed) {
286 0           return "failed";
287             }
288              
289 0           return "success";
290             }
291              
292             sub last_execution {
293 0     0 0   my ($self) = @_;
294 0           my $job_path = File::Spec->catdir( $self->project->project_path,
295             "jobs", $self->{directory} );
296 0           my $execute_path = "$job_path/execute";
297              
298 0 0         if ( -d $execute_path ) {
299 0           my @entries;
300 0 0         opendir( my $dh, $execute_path ) or die($!);
301 0           while ( my $entry = readdir($dh) ) {
302 0 0         next if ( !-f "$execute_path/$entry/run.status.yml" );
303 0           push @entries, $entry;
304             }
305 0           closedir($dh);
306              
307 0           my ($last) = sort { $b <=> $a } @entries;
  0            
308              
309 0           return $last;
310             }
311             else {
312 0           return 0;
313             }
314              
315             }
316              
317             sub get_logs {
318 0     0 0   my ($self) = @_;
319              
320 0           my $job_path = File::Spec->catdir( $self->project->project_path,
321             "jobs", $self->{directory} );
322              
323 0           my $execute_path = "$job_path/execute";
324              
325 0 0         if ( -d $execute_path ) {
326              
327 0           my @entries;
328 0 0         opendir( my $dh, $execute_path ) or die($!);
329 0           while ( my $entry = readdir($dh) ) {
330 0 0 0       next if ( $entry eq "." || $entry eq ".." );
331 0 0         if ( -f "$execute_path/$entry/running.status.yml" ) {
332 0           my $run_status =
333             YAML::LoadFile("$execute_path/$entry/running.status.yml");
334 0           $run_status->{id} = $entry;
335 0           $run_status->{finished} = 0;
336 0           push @entries, $run_status;
337             }
338              
339 0 0         if ( -f "$execute_path/$entry/run.status.yml" ) {
340 0           my $run_status = YAML::LoadFile("$execute_path/$entry/run.status.yml");
341 0           $run_status->{id} = $entry;
342 0           $run_status->{finished} = 1;
343 0           push @entries, $run_status;
344             }
345             }
346 0           closedir($dh);
347              
348 0           @entries = sort { $b->{start_time} <=> $a->{start_time} } @entries;
  0            
349              
350 0           return \@entries;
351              
352             }
353              
354             else {
355              
356 0           return [];
357              
358             }
359             }
360              
361             1;