| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Net::Hadoop::YARN::ApplicationMaster; |
|
2
|
|
|
|
|
|
|
$Net::Hadoop::YARN::ApplicationMaster::VERSION = '0.203'; |
|
3
|
1
|
|
|
1
|
|
86384
|
use strict; |
|
|
1
|
|
|
|
|
10
|
|
|
|
1
|
|
|
|
|
25
|
|
|
4
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
23
|
|
|
5
|
1
|
|
|
1
|
|
9
|
use 5.10.0; |
|
|
1
|
|
|
|
|
3
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
use constant { |
|
8
|
1
|
|
|
|
|
68
|
RE_ARCHIVED_ERROR => qr{ |
|
9
|
|
|
|
|
|
|
Application .+? |
|
10
|
|
|
|
|
|
|
\Qcould not be found, please try the history server\E |
|
11
|
|
|
|
|
|
|
}xms, |
|
12
|
1
|
|
|
1
|
|
5
|
}; |
|
|
1
|
|
|
|
|
2
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
1
|
|
|
1
|
|
367
|
use Constant::FromGlobal DEBUG => { int => 1, default => 0, env => 1 }; |
|
|
1
|
|
|
|
|
7575
|
|
|
|
1
|
|
|
|
|
6
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
1
|
|
|
1
|
|
183
|
use Carp (); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
11
|
|
|
17
|
1
|
|
|
1
|
|
331
|
use Clone (); |
|
|
1
|
|
|
|
|
1915
|
|
|
|
1
|
|
|
|
|
22
|
|
|
18
|
1
|
|
|
1
|
|
396
|
use HTML::PullParser; |
|
|
1
|
|
|
|
|
5561
|
|
|
|
1
|
|
|
|
|
29
|
|
|
19
|
1
|
|
|
1
|
|
441
|
use Moo; |
|
|
1
|
|
|
|
|
9023
|
|
|
|
1
|
|
|
|
|
4
|
|
|
20
|
1
|
|
|
1
|
|
1575
|
use Ref::Util (); |
|
|
1
|
|
|
|
|
1217
|
|
|
|
1
|
|
|
|
|
20
|
|
|
21
|
1
|
|
|
1
|
|
6
|
use Scalar::Util (); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
24
|
|
|
22
|
|
|
|
|
|
|
|
|
23
|
1
|
|
|
1
|
|
374
|
use Net::Hadoop::YARN::HistoryServer; |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
239
|
|
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
with 'Net::Hadoop::YARN::Roles::AppMasterHistoryServer'; |
|
26
|
|
|
|
|
|
|
with 'Net::Hadoop::YARN::Roles::Common'; |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
has '+servers' => ( |
|
29
|
|
|
|
|
|
|
default => sub {["localhost:8088"]}, |
|
30
|
|
|
|
|
|
|
); |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
has history_object => ( |
|
33
|
|
|
|
|
|
|
is => 'rw', |
|
34
|
|
|
|
|
|
|
isa => sub { |
|
35
|
|
|
|
|
|
|
my $o = shift || return; # this is optional |
|
36
|
|
|
|
|
|
|
if ( ! Scalar::Util::blessed $o |
|
37
|
|
|
|
|
|
|
|| ! $o->isa('Net::Hadoop::YARN::HistoryServer') |
|
38
|
|
|
|
|
|
|
) { |
|
39
|
|
|
|
|
|
|
Carp::confess "$o is not a Net::Hadoop::YARN::HistoryServer"; |
|
40
|
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
}, |
|
42
|
|
|
|
|
|
|
lazy => 1, |
|
43
|
|
|
|
|
|
|
default => sub { }, |
|
44
|
|
|
|
|
|
|
); |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
my $PREFIX = '_' x 4; |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
#<<< |
|
49
|
|
|
|
|
|
|
my $methods_urls = { |
|
50
|
|
|
|
|
|
|
jobs => ['/proxy/{appid}/ws/v1/mapreduce/jobs', 'job' ], |
|
51
|
|
|
|
|
|
|
job => ['/proxy/{appid}/ws/v1/mapreduce/jobs/{jobid}', '' ], |
|
52
|
|
|
|
|
|
|
jobconf => ['/proxy/{appid}/ws/v1/mapreduce/jobs/{jobid}/conf', '' ], |
|
53
|
|
|
|
|
|
|
jobcounters => ['/proxy/{appid}/ws/v1/mapreduce/jobs/{jobid}/counters', 'counterGroup' ], |
|
54
|
|
|
|
|
|
|
jobattempts => ['/proxy/{appid}/ws/v1/mapreduce/jobs/{jobid}/jobattempts', 'jobAttempt' ], |
|
55
|
|
|
|
|
|
|
_get_tasks => ['/proxy/{appid}/ws/v1/mapreduce/jobs/{jobid}/tasks', 'task' ], |
|
56
|
|
|
|
|
|
|
task => ['/proxy/{appid}/ws/v1/mapreduce/jobs/{jobid}/tasks/{taskid}', '' ], |
|
57
|
|
|
|
|
|
|
taskcounters => ['/proxy/{appid}/ws/v1/mapreduce/jobs/{jobid}/tasks/{taskid}/counters', 'taskCounterGroup' ], |
|
58
|
|
|
|
|
|
|
taskattempts => ['/proxy/{appid}/ws/v1/mapreduce/jobs/{jobid}/tasks/{taskid}/attempts', 'taskAttempt' ], |
|
59
|
|
|
|
|
|
|
taskattempt => ['/proxy/{appid}/ws/v1/mapreduce/jobs/{jobid}/tasks/{taskid}/attempts/{attemptid}', '' ], |
|
60
|
|
|
|
|
|
|
taskattemptcounters => ['/proxy/{appid}/ws/v1/mapreduce/jobs/{jobid}/tasks/{taskid}/attempts/{attemptid}/counters', 'taskAttemptCounterGroup' ], |
|
61
|
|
|
|
|
|
|
}; |
|
62
|
|
|
|
|
|
|
#>>> |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# For each of the keys, at startup: |
|
65
|
|
|
|
|
|
|
# - make a method, adding the path |
|
66
|
|
|
|
|
|
|
# - pass the path and variables to a validation and substitution engine |
|
67
|
|
|
|
|
|
|
# - execute the request |
|
68
|
|
|
|
|
|
|
# - return the proper fragment of the JSON tree |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
_mk_subs($methods_urls, { prefix => $PREFIX } ); |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
my %app_to_hist = ( |
|
73
|
|
|
|
|
|
|
jobs => [ job => qr{ \A job_[0-9]+ }xms ], |
|
74
|
|
|
|
|
|
|
); |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
foreach my $name ( keys %{ $methods_urls } ) { |
|
77
|
|
|
|
|
|
|
my $base = $PREFIX . $name; |
|
78
|
1
|
|
|
1
|
|
9
|
no strict qw( refs ); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
711
|
|
|
79
|
|
|
|
|
|
|
*{ $name } = sub { |
|
80
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
81
|
0
|
|
|
|
|
|
my $args = Clone::clone( \@_ ); |
|
82
|
0
|
|
|
|
|
|
my @rv; |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
eval { |
|
85
|
0
|
|
|
|
|
|
@rv = $self->$base( @_ ); |
|
86
|
0
|
|
|
|
|
|
1; |
|
87
|
0
|
0
|
|
|
|
|
} or do { |
|
88
|
0
|
|
0
|
|
|
|
my $eval_error = $@ || 'Zombie error'; |
|
89
|
0
|
0
|
0
|
|
|
|
if ( $eval_error =~ RE_ARCHIVED_ERROR && $self->history_object ) { |
|
90
|
0
|
|
|
|
|
|
@rv = $self->_collect_from_history( |
|
91
|
|
|
|
|
|
|
$args, |
|
92
|
|
|
|
|
|
|
$name, |
|
93
|
|
|
|
|
|
|
$eval_error, |
|
94
|
|
|
|
|
|
|
); |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
else { |
|
97
|
0
|
|
|
|
|
|
Carp::confess $eval_error; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
}; |
|
100
|
|
|
|
|
|
|
|
|
101
|
0
|
0
|
|
|
|
|
return wantarray ? @rv : $rv[0]; |
|
102
|
|
|
|
|
|
|
}; |
|
103
|
|
|
|
|
|
|
} |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub _collect_from_history { |
|
106
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
107
|
0
|
|
|
|
|
|
my $args = shift; |
|
108
|
0
|
|
|
|
|
|
my $name = shift; |
|
109
|
0
|
|
0
|
|
|
|
my $error = shift || Carp::confess "No error message specified!"; |
|
110
|
|
|
|
|
|
|
|
|
111
|
0
|
|
0
|
|
|
|
my $hist_method = $app_to_hist{ $name } || [ $name ]; |
|
112
|
0
|
|
|
|
|
|
my($hmethod, $hregex) = @{ $hist_method }; |
|
|
0
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
|
|
114
|
0
|
|
|
|
|
|
if ( DEBUG ) { |
|
115
|
|
|
|
|
|
|
print STDERR "Received HTML from the API. ", |
|
116
|
|
|
|
|
|
|
"I will now attempt to collect the information from the history server\n"; |
|
117
|
|
|
|
|
|
|
printf STDERR "The error was: %s\n", $error |
|
118
|
|
|
|
|
|
|
if DEBUG > 1; |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
0
|
|
|
|
|
|
my @hist_param; |
|
122
|
0
|
0
|
0
|
|
|
|
if ( $error =~ RE_ARCHIVED_ERROR && ( $name eq 'jobs' || $name eq 'job' ) ) { |
|
|
|
|
0
|
|
|
|
|
|
123
|
0
|
|
|
|
|
|
print STDERR "Job was archived\n" if DEBUG; |
|
124
|
|
|
|
|
|
|
@hist_param = ( |
|
125
|
|
|
|
|
|
|
map { |
|
126
|
0
|
|
|
|
|
|
(my $c = $_) =~ s{ \bapplication_ }{job_}xms; |
|
127
|
0
|
|
|
|
|
|
$c; |
|
128
|
0
|
|
|
|
|
|
} @{ $args } |
|
|
0
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
); |
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
else { |
|
132
|
0
|
|
|
|
|
|
print STDERR "Job was not available from he RM\n" if DEBUG; |
|
133
|
|
|
|
|
|
|
@hist_param = ( |
|
134
|
|
|
|
|
|
|
$hregex |
|
135
|
0
|
0
|
|
|
|
|
? grep { $_ =~ $hregex } |
|
|
0
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
$self->_extract_ids_from_error_html( $error ) |
|
137
|
|
|
|
|
|
|
: () |
|
138
|
|
|
|
|
|
|
); |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
|
|
141
|
0
|
|
|
|
|
|
my @rv; |
|
142
|
|
|
|
|
|
|
eval { |
|
143
|
0
|
|
|
|
|
|
@rv = $self->history_object->$hmethod( @hist_param ); |
|
144
|
0
|
|
|
|
|
|
1; |
|
145
|
0
|
0
|
|
|
|
|
} or do { |
|
146
|
0
|
|
0
|
|
|
|
my $eval_error_hist = $@ || 'Zombie error'; |
|
147
|
0
|
|
|
|
|
|
Carp::confess "Received HTML from the API and attempting to map that to a historical job failed: $error\n$eval_error_hist\n"; |
|
148
|
|
|
|
|
|
|
}; |
|
149
|
|
|
|
|
|
|
|
|
150
|
0
|
|
|
|
|
|
foreach my $thing ( @rv ) { |
|
151
|
0
|
0
|
|
|
|
|
next if ! Ref::Util::is_hashref $thing; |
|
152
|
0
|
|
|
|
|
|
$thing->{__from_history} = 1; |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
0
|
|
|
|
|
|
return @rv; |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
sub _extract_ids_from_error_html { |
|
159
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
160
|
0
|
|
0
|
|
|
|
my $error = shift || Carp::confess "No error message specified!"; |
|
161
|
0
|
|
|
|
|
|
my(undef, $html) = split m{\Q
|
|
162
|
0
|
|
|
|
|
|
$html = '
|
|
163
|
0
|
|
0
|
|
|
|
my $parser = HTML::PullParser->new( |
|
164
|
|
|
|
|
|
|
doc => \$html, |
|
165
|
|
|
|
|
|
|
start => 'event, tagname, @attr', |
|
166
|
|
|
|
|
|
|
report_tags => [qw( a )], |
|
167
|
|
|
|
|
|
|
) || Carp::confess "Can't parse HTML received from the API: $!"; |
|
168
|
0
|
|
|
|
|
|
my %link; |
|
169
|
0
|
|
|
|
|
|
while ( my $token = $parser->get_token ) { |
|
170
|
0
|
0
|
|
|
|
|
next if $token->[0] ne 'start'; |
|
171
|
0
|
|
|
|
|
|
my($type, $tag, %attr) = @{ $token }; |
|
|
0
|
|
|
|
|
|
|
|
172
|
0
|
|
0
|
|
|
|
my $link = $attr{href} || next; |
|
173
|
0
|
|
|
|
|
|
$link{ $link }++; |
|
174
|
|
|
|
|
|
|
} |
|
175
|
0
|
|
|
|
|
|
my %id; |
|
176
|
0
|
|
|
|
|
|
for my $link ( keys %link ) { |
|
177
|
0
|
|
|
|
|
|
$id{ $_ }++ for $self->_extract_valid_params( $link ); |
|
178
|
|
|
|
|
|
|
} |
|
179
|
0
|
|
|
|
|
|
return keys %id; |
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub info { |
|
183
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
184
|
0
|
|
|
|
|
|
$self->mapreduce(@_); |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub mapreduce { |
|
188
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
189
|
0
|
|
|
|
|
|
my $app_id = shift; |
|
190
|
0
|
|
|
|
|
|
my $res = $self->_get("{appid}/ws/v1/mapreduce/info"); |
|
191
|
0
|
|
|
|
|
|
return $res->{info}; |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub tasks { |
|
195
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
196
|
0
|
|
|
|
|
|
$self->_get_tasks(@_); |
|
197
|
|
|
|
|
|
|
} |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
1; |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
__END__ |