File Coverage

blib/lib/HealthCheck/Diagnostic/SFTP.pm
Criterion Covered Total %
statement 59 60 98.3
branch 19 20 95.0
condition 5 9 55.5
subroutine 10 10 100.0
pod 3 3 100.0
total 96 102 94.1


line stmt bran cond sub pod time code
1             package HealthCheck::Diagnostic::SFTP;
2 1     1   111412 use parent 'HealthCheck::Diagnostic';
  1         274  
  1         5  
3              
4             # ABSTRACT: Check for SFTP access and operations in a HealthCheck
5 1     1   6522 use version;
  1         3  
  1         6  
6             our $VERSION = 'v1.4.2'; # VERSION
7              
8 1     1   82 use strict;
  1         2  
  1         25  
9 1     1   4 use warnings;
  1         2  
  1         26  
10              
11 1     1   4 use Carp;
  1         2  
  1         65  
12 1     1   541 use Net::SFTP;
  1         74692  
  1         489  
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 2795 my ($class, @params) = @_;
20              
21             my %params = @params == 1 && ( ref $params[0] || '' ) eq 'HASH'
22 2 50 33     11 ? %{ $params[0] } : @params;
  0         0  
23              
24 2         14 return $class->SUPER::new(
25             id => 'sftp',
26             label => 'sftp',
27             %params,
28             );
29             }
30              
31             sub check {
32 20     20 1 17378 my ($self, %params) = @_;
33              
34             # Allow the diagnostic to be called as a class as well.
35 20 100       80 if ( ref $self ) {
36             $params{$_} = $self->{$_}
37 2         7 foreach grep { ! defined $params{$_} } keys %$self;
  6         18  
38             }
39              
40             # The host is the only required parameter.
41 20 100       247 croak "No host" unless $params{host};
42              
43 19         80 return $self->SUPER::check(%params);
44             }
45              
46             sub run {
47 19     19 1 350 my ($self, %params) = @_;
48 19         30 my $host = $params{host};
49 19         29 my $callback = $params{callback};
50 19   100     67 my $ssh_args = $params{ssh_args} // {};
51              
52             # Get our description of the connection.
53 19         30 my $port = $ssh_args->{port};
54 19         28 my $user = $params{user};
55 19         25 my $name = $params{name};
56 19   50     51 my $timeout = $params{timeout} // 3;
57 19 100       76 my $target = sprintf(
    100          
58             "%s%s%s",
59             $user ? $user . '@' : '',
60             $host,
61             $port ? ":$port" : '',
62             );
63              
64 19 100       48 my $description = $name ? "$name ($target) SFTP" : "$target SFTP";
65 19   50     56 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         24 my $sftp;
77 7         20 my %args = map { $_ => $params{$_} }
78 19         44 grep { exists $params{$_} }
  76         147  
79             qw( user password debug warn );
80 19         38 $args{ssh_args} = $ssh_args;
81              
82 19         26 local $@;
83 19     1   364 local $SIG{ALRM} = sub { die "timeout after $timeout seconds.\n" };
  1         3000234  
84 19         135 alarm $timeout;
85 19         46 eval {
86 19         61 local $SIG{__DIE__};
87 19         79 $sftp = Net::SFTP->new( $host, %args );
88             };
89 19         295 alarm 0;
90             return {
91 19 100       113 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       264 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         6 my $result;
104 3         6 eval {
105 3         9 local $SIG{__DIE__};
106 3         7 $result = $callback->( $sftp );
107             };
108             return {
109 3 100       40 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       40 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__