File Coverage

blib/lib/HealthCheck/Diagnostic/SFTP.pm
Criterion Covered Total %
statement 59 60 98.3
branch 19 20 95.0
condition 6 9 66.6
subroutine 10 10 100.0
pod 3 3 100.0
total 97 102 95.1


line stmt bran cond sub pod time code
1             package HealthCheck::Diagnostic::SFTP;
2 1     1   130312 use parent 'HealthCheck::Diagnostic';
  1         305  
  1         6  
3              
4             # ABSTRACT: Check for SFTP access and operations in a HealthCheck
5 1     1   4829 use version;
  1         2  
  1         4  
6             our $VERSION = 'v1.5.0'; # VERSION
7              
8 1     1   90 use strict;
  1         3  
  1         19  
9 1     1   5 use warnings;
  1         2  
  1         23  
10              
11 1     1   5 use Carp;
  1         2  
  1         49  
12 1     1   523 use Net::SFTP;
  1         84415  
  1         591  
13              
14             # For some reason, without this in the cpanfile
15             # Net::SFTP wouldn't install, so leave this note.
16             require Net::SSH::Perl::Buffer;
17              
18             sub new {
19 2     2 1 3128 my ($class, @params) = @_;
20              
21             my %params = @params == 1 && ( ref $params[0] || '' ) eq 'HASH'
22 2 50 33     13 ? %{ $params[0] } : @params;
  0         0  
23              
24 2         15 return $class->SUPER::new(
25             id => 'sftp',
26             label => 'sftp',
27             %params,
28             );
29             }
30              
31             sub check {
32 20     20 1 19477 my ($self, %params) = @_;
33              
34             # Allow the diagnostic to be called as a class as well.
35 20 100       64 if ( ref $self ) {
36             $params{$_} = $self->{$_}
37 2         9 foreach grep { ! defined $params{$_} } keys %$self;
  6         21  
38             }
39              
40             # The host is the only required parameter.
41 20 100       252 croak "No host" unless $params{host};
42              
43 19         81 return $self->SUPER::check(%params);
44             }
45              
46             sub run {
47 19     19 1 450 my ($self, %params) = @_;
48 19         34 my $host = $params{host};
49 19         35 my $callback = $params{callback};
50 19   100     78 my $ssh_args = $params{ssh_args} // {};
51              
52             # Get our description of the connection.
53 19         36 my $port = $ssh_args->{port};
54 19         32 my $user = $params{user};
55 19         32 my $name = $params{name};
56 19   100     58 my $timeout = $params{timeout} // 10;
57 19 100       139 my $target = sprintf(
    100          
58             "%s%s%s",
59             $user ? $user . '@' : '',
60             $host,
61             $port ? ":$port" : '',
62             );
63              
64 19 100       53 my $description = $name ? "$name ($target) SFTP" : "$target SFTP";
65 19   50     67 my $options = $ssh_args->{options} // [];
66              
67             # Once the SSH ConnectTimeout option is supported, we can re-enable this:
68             # https://rt.cpan.org/Public/Bug/Display.html?id=66433
69             #
70             # unless ( grep { $_ =~ /^ConnectTimeout / } @$options ) {
71             # push @$options, "ConnectTimeout $timeout";
72             # $ssh_args->{options} = $options;
73             # }
74              
75             # Try to connect to the host.
76 19         29 my $sftp;
77 7         22 my %args = map { $_ => $params{$_} }
78 19         50 grep { exists $params{$_} }
  76         169  
79             qw( user password debug warn );
80 19         37 $args{ssh_args} = $ssh_args;
81              
82 19         28 local $@;
83 19     1   368 local $SIG{ALRM} = sub { die "timeout after $timeout seconds.\n" };
  1         2000214  
84 19         138 alarm $timeout;
85 19         53 eval {
86 19         72 local $SIG{__DIE__};
87 19         97 $sftp = Net::SFTP->new( $host, %args );
88             };
89 19         333 alarm 0;
90             return {
91 19 100       126 status => 'CRITICAL',
92             info => "Error for $description: $@",
93             } if $@;
94              
95             # No errors were returned so it must be a successful result,
96             # unless we want to run a callback.
97             return {
98 17 100       372 status => 'OK',
99             info => "Successful connection for $description",
100             } unless $callback;
101              
102             # Try to run a callback on the instance if one is provided.
103 3         5 my $result;
104 3         7 eval {
105 3         9 local $SIG{__DIE__};
106 3         12 $result = $callback->( $sftp );
107             };
108             return {
109 3 100       50 status => 'CRITICAL',
110             info => "Error in running callback for $description: $@",
111             } if $@;
112              
113             # Return the callback result hash, or a generic success message.
114 2 100       42 return ref $result eq 'HASH' ? $result : {
115             status => 'OK',
116             info => "Successful connection and callback for $description",
117             };
118             }
119              
120             1;
121              
122             __END__