-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path__module__.pm
160 lines (123 loc) · 3.19 KB
/
__module__.pm
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
#
# (c) Jan Gehring <[email protected]>
#
# vim: set ts=2 sw=2 tw=0:
# vim: set expandtab:
package Fail;
use strict;
use warnings;
use Data::Dumper;
BEGIN {
use Rex -base;
use Cwd 'getcwd';
my $cwd = getcwd();
$cwd =~ s/\//_/g;
require IPC::Lite;
IPC::Lite->import(Key => "rex_ipc_lite_x_$cwd", qw($i_am_failed));
use Rex::CLI;
}
$Rex::TaskList::task_list = undef;
Rex::Config->set_distributor('Parallel_ForkManager');
require Exporter;
use base qw(Exporter);
use vars qw(@EXPORT);
@EXPORT = qw(fail max_fail_counter on_fail);
my $max_fail_counter = 0;
my $inside_fail = 0;
my @fail_code = ();
Rex::CLI->add_exit(
sub {
if ($i_am_failed) {
Rex::Logger::info("Exiting by order of fail module. ($i_am_failed)");
my $path = tied($i_am_failed)->path();
Rex::Logger::info("Cleaning up $path");
$i_am_failed = undef;
eval {
unlink $path;
Rex::Logger::info("Cleaning up done.");
1;
}
or do {
Rex::Logger::info( "Failed cleaning up: $@", "warn" );
};
CORE::exit 1;
}
my $path = tied($i_am_failed)->path();
Rex::Logger::info("Cleaning up $path");
$i_am_failed = undef;
eval {
unlink $path;
Rex::Logger::info("Cleaning up done.");
1;
}
or do {
Rex::Logger::info( "Failed cleaning up: $@", "warn" );
};
}
);
sub fail(&) {
my $code = shift;
$inside_fail = 1;
$i_am_failed = 0;
my $task_code = sub {
my @exit_codes = Rex::TaskList->create()->get_exit_codes();
my @failed_tasks = grep { $_ > 0 } @exit_codes;
if ( scalar @failed_tasks > $max_fail_counter ) {
for my $fail_c (@fail_code) {
$fail_c->( scalar(@failed_tasks) );
}
$i_am_failed = 1;
die(
"Failcounter reached. Too many tasks failed.\nFailcounter: "
. scalar(@failed_tasks)
. "\nMax fails: $max_fail_counter\n",
"error"
);
}
};
my @all_tasks = Rex::TaskList->create()->get_tasks;
for my $task (@all_tasks) {
my $task_o = Rex::TaskList->create()->get_task($task);
$task_o->modify( 'after_task_finished', $task_code, );
}
$code->();
$inside_fail = 0;
}
sub max_fail_counter {
if ( !$inside_fail ) {
die
"max_fail_counter can only be called inside fail{} block. Nested fail blocks are currently not supported.";
}
$max_fail_counter = shift;
}
sub on_fail(&) {
my $code = shift;
push @fail_code, $code;
}
1;
=pod
=head1 NAME
Fail - Fail execution if a defined number of tasks fail.
If you need to run one or more tasks on many servers and you want to stop the execution if a task fails on a specific number of systems, this module is for you.
=head1 SYNOPSIS
use Fail;
group servers => "frontend-[01..05]";
task "rollout", sub {
fail {
max_fail_counter 2; # fail the execution if the there are errors on 2 or more systems.
do_task [qw/
prepare
deploy_app
test_app
switch_instance
/];
};
};
task "prepare", group => "servers", sub {
};
task "deploy_app", group => "servers", sub {
};
task "test_app", group => "servers", sub {
};
task "switch_instance", group => "servers", sub {
};