File Coverage

blib/lib/App/MBUtiny/Storage.pm
Criterion Covered Total %
statement 64 134 47.7
branch 7 42 16.6
condition 5 18 27.7
subroutine 14 24 58.3
pod 15 15 100.0
total 105 233 45.0


line stmt bran cond sub pod time code
1             package App::MBUtiny::Storage; # $Id: Storage.pm 121 2019-07-01 19:51:50Z abalama $
2 2     2   65843 use strict;
  2         13  
  2         61  
3 2     2   576 use utf8;
  2         16  
  2         12  
4              
5             =encoding utf-8
6              
7             =head1 NAME
8              
9             App::MBUtiny::Storage - App::MBUtiny storage class
10              
11             =head1 VIRSION
12              
13             Version 1.00
14              
15             =head1 SYNOPSIS
16              
17             use App::MBUtiny::Storage;
18              
19             my $storage = new App::MBUtiny::Storage(
20             name => $name, # Backup name
21             host => $host, # Host config section
22             path => "/tmp/mbutiny/files", # Where is located backup archive
23             );
24              
25             print $storage->error unless $storage->status;
26              
27             =head1 DESCRIPTION
28              
29             App::MBUtiny storage class
30              
31             Storage - is a directory on disk, a remote FTP/SFTP/ HTTP server
32             or CLI process that simulates storage functional.
33              
34             =head2 new
35              
36             my $storage = new App::MBUtiny::Storage(
37             name => $name, # Backup name
38             host => $host, # Host config section
39             path => "/tmp/mbutiny/files", # Where is located backup archive
40             fixup => sub {
41             my $strg = shift; # Storage object
42             my $oper = shift // 'noop'; # Operation name
43             my @args = @_;
44              
45             return 1;
46             },
47             validate => sub {
48             my $strg = shift; # storage object
49             my $file = shift; # fetched file name
50              
51             return 1;
52             },
53             );
54              
55             Returns storage object
56              
57             =head2 cleanup
58              
59             $storage->cleanup();
60              
61             Flushes errors and the status property to defaults
62              
63             =head2 del
64              
65             my $status = $storage->del("foo-2019-06-25.tar.gz");
66              
67             Performs the "del" method in all storage subclasses
68              
69             Returns summary status. See L
70              
71             =head2 error
72              
73             print $storage->error("Foo"); # Foo
74             print $storage->error("Bar"); # Foo\nBar
75             print $storage->error; # Foo\nBar
76             print $storage->error(""); # <"">
77              
78             Sets and gets the error pool
79              
80             =head2 fixup
81              
82             Callback the "fixup" method. This method called automatically
83             when the put method performs
84              
85             =head2 get
86              
87             $st = $storage->get(
88             name => "foo-2019-06-25.tar.gz",
89             file => "/full/path/to/foo-2019-06-25.tar.gz",
90             );
91              
92             Fetching backup file to specified file path from each storage until first successful result
93              
94             Returns summary status. See L
95              
96             =head2 init
97              
98             Performs the "init" method in all storage subclasses and returns self object instance
99              
100             For internal use only
101              
102             =head2 list
103              
104             my @filelist = $storage->list;
105              
106             Returns summary list of backup files from all available storages
107              
108             =head2 put
109              
110             $st = $storage->put(
111             name => "foo-2019-06-25.tar.gz",
112             file => "/full/path/to/foo-2019-06-25.tar.gz",
113             size => 123456,
114             );
115              
116             Sending backup file to each available storage
117              
118             Returns summary status. See L
119              
120             =head2 status
121              
122             my $new_status = $storage->status(0);
123              
124             Sets new status value and returns it
125              
126             my $status = $storage->status;
127              
128             Returns status value. 0 - Error; 1 - Ok
129              
130             =head2 storage_status
131              
132             $storage->storage_status(HTTP => 0);
133             my $storage_status = $storage->storage_status("HTTP");
134              
135             Sets/gets storage status. For internal use only
136              
137             =head2 summary
138              
139             my $status = $storage->summary;
140              
141             Returns summary status.
142              
143             =over 4
144              
145             =item B<1> PASS status. Process successful
146              
147             =item B<0> FAIL status. Process failed
148              
149             =item B<-1> SKIP status. Process was skipped
150              
151             =back
152              
153             =head2 test
154              
155             my $test = $storage->test or die $storage->error;
156              
157             Performs testing each storage and returns summary status. See L
158              
159             =head2 test_report
160              
161             foreach my $tr ($storage->test_report) {
162             my ($st, $vl, $er) = @$tr;
163             print STDOUT $vl, "\n";
164             print STDOUT $st ? $st < 0 ? 'SKIP' : 'PASS' : 'FAIL', "\n";
165             print STDERR $er, "\n";
166             );
167             }
168              
169             Returns list of test result for each storage as:
170              
171             [
172             [STATUS, NAME, ERROR],
173             # ...
174             ]
175              
176             =head2 validate
177              
178             Callback the "validate" method. This method called automatically
179             when the get method performs
180              
181             This method can returns 0 or 1. 0 - validation failed; 1 - validation successful
182              
183             =head1 HISTORY
184              
185             See C file
186              
187             =head1 TO DO
188              
189             See C file
190              
191             =head1 BUGS
192              
193             * none noted
194              
195             =head1 SEE ALSO
196              
197             L
198              
199             =head1 AUTHOR
200              
201             Serż Minus (Sergey Lepenkov) L Eabalama@cpan.orgE
202              
203             =head1 COPYRIGHT
204              
205             Copyright (C) 1998-2019 D&D Corporation. All Rights Reserved
206              
207             =head1 LICENSE
208              
209             This program is free software; you can redistribute it and/or
210             modify it under the same terms as Perl itself.
211              
212             See C file and L
213              
214             =cut
215              
216 2     2   126 use vars qw/ $VERSION /;
  2         4  
  2         117  
217             $VERSION = '1.00';
218              
219 2     2   438 use Class::C3::Adopt::NEXT;
  2         7948  
  2         16  
220 2     2   68 use List::Util qw/uniq/;
  2         4  
  2         183  
221 2     2   431 use CTK::ConfGenUtil;
  2         1089  
  2         157  
222 2     2   427 use CTK::TFVals qw/ :ALL /;
  2         2006  
  2         498  
223              
224 2         910 use base qw/
225             App::MBUtiny::Storage::Local
226             App::MBUtiny::Storage::FTP
227             App::MBUtiny::Storage::SFTP
228             App::MBUtiny::Storage::HTTP
229             App::MBUtiny::Storage::Command
230 2     2   15 /;
  2         4  
231              
232             use constant {
233 2         2745 STORAGE_SIGN=> "core",
234             NAME => "virtual",
235             SKIP => -1,
236             FAIL => 0,
237             PASS => 1,
238 2     2   17 };
  2         6  
239              
240             sub new {
241 1     1 1 676 my $class = shift;
242 1         3 my %args = @_;
243 1   50     8 my $name = $args{name} || NAME;
244 1   50     5 my $host = $args{host} || {};
245 1   50     7 my $path = $args{path} || '.';
246              
247             my $self = bless {
248             errors => [],
249             status => 1, # 1 - Ok; 0 - Error
250             name => $name,
251             host => $host,
252             path => $path,
253             fixup => $args{fixup},
254             validate=> $args{validate},
255 1         11 storages=> {},
256             test => {},
257             list => {},
258             }, $class;
259              
260 1         5 return $self->init();
261             }
262             sub error {
263 0     0 1 0 my $cnt = @_;
264 0         0 my $self = shift;
265 0         0 my $s = shift;
266 0   0     0 my $errors = $self->{errors} || [];
267 0 0       0 if ($cnt >= 2) {
268 0 0       0 if ($s) {
269 0         0 push @$errors, $s;
270             } else {
271 0         0 $errors = [];
272             }
273 0         0 $self->{errors} = $errors;
274             }
275 0         0 return join("\n", @$errors);
276             }
277             sub status {
278 1     1 1 3 my $self = shift;
279 1         2 my $s = shift;
280 1 50       4 $self->{status} = $s if defined $s;
281 1         2 return $self->{status};
282             }
283             sub storage_status {
284 5     5 1 10 my $self = shift;
285 5   50     14 my $sign = shift || STORAGE_SIGN;
286 5         6 my $v = shift;
287 5         13 my $h = $self->{storages};
288 5 50       17 $h->{"$sign"} = $v if defined $v;
289 5         11 return $h->{"$sign"};
290             }
291             sub summary {
292 0     0 1 0 my $self = shift;
293 0         0 my $list = $self->{storages};
294 0         0 my $ret = SKIP;
295 0         0 foreach my $k (keys %$list) {
296 0         0 my $v = $list->{$k};
297 0 0       0 return $self->status(FAIL) unless $v;
298 0 0       0 $ret = PASS if $v > 0;
299             }
300 0         0 return $self->status($ret);
301             }
302             sub test_report {
303 0     0 1 0 my $self = shift;
304 0         0 my $list = $self->{storages};
305 0         0 my @storages;
306             #foreach my $sign (grep { $list->{$_} >=0 } keys %$list) { # Not SKIPped only!
307 0         0 foreach my $sign (keys %$list) {
308 0         0 my $test = $self->{test}->{$sign};
309 0 0       0 push @storages, @$test if $test;
310             }
311 0         0 return @storages;
312             }
313             sub cleanup {
314 0     0 1 0 my $self = shift;
315 0         0 $self->error("");
316 0         0 $self->status(1);
317             }
318             sub init {
319 1     1 1 3 my $self = shift;
320 1         5 $self->maybe::next::method();
321 1         4 return $self;
322             }
323             sub test {
324 1     1 1 5 my $self = shift;
325 1         4 my %params = @_;
326 1 50       4 $self->maybe::next::method(%params) unless $params{dummy};
327 1   50     5 my $reqired_all = $params{reqired_all} || 0; # Must be passed all tests! Default: any
328              
329             # Get storages list
330 1         3 my $storages = $self->{storages};
331 1         4 my @ok = grep {$storages->{$_}} keys %$storages;
  5         11  
332 1 50       3 unless (@ok) { # If all failed!
333 0 0       0 $self->error("All tests failed") if $self->status;
334 0         0 return $self->status(FAIL);
335             }
336              
337             # Check each test
338 1         3 my $ret = SKIP; # Default!
339 1         3 my @fails = ();
340 1         3 foreach my $k (keys %$storages) {
341 5         6 my $v = $storages->{$k};
342 5 50       11 push @fails, $k unless $v; # Test failed!
343 5 50       11 $ret = PASS if $v > 0; # Any is PASS - change default value to PASS
344             }
345 1 50       3 unless ($reqired_all) {
346 1         5 $self->status(PASS);
347 1         4 return $ret;
348             }
349 0 0         if (@fails == 1) { # One fail catched!
    0          
350 0 0         $self->error(sprintf("Test %s failed", $fails[0])) if $self->status;
351 0           $ret = FAIL;
352             } elsif (@fails > 1) { # Fails catched!
353 0 0         $self->error(sprintf("Tests %s failed", join(", ", @fails))) if $self->status;
354 0           $ret = FAIL;
355             }
356 0 0         $self->status($ret ? PASS : FAIL);
357 0           return $ret;
358             }
359             sub put {
360 0     0 1   my $self = shift;
361 0           $self->cleanup;
362 0           $self->maybe::next::method(@_);
363 0           return $self->summary;
364             }
365             sub get {
366 0     0 1   my $self = shift;
367 0           $self->cleanup;
368 0           $self->maybe::next::method(@_);
369 0           return $self->summary;
370             }
371             sub del {
372 0     0 1   my $self = shift;
373 0           $self->cleanup;
374 0           $self->maybe::next::method(@_);
375 0           return $self->summary;
376             }
377             sub list {
378 0     0 1   my $self = shift;
379 0           $self->cleanup;
380 0           $self->maybe::next::method(@_);
381              
382 0           my @files = ();
383 0           my $storages = $self->{storages};
384 0           foreach my $sign (grep { $storages->{$_} >=0 } keys %$storages) { # Not SKIPped only!
  0            
385 0           my $list = $self->{list}->{$sign};
386 0 0         push @files, @$list if $list;
387             }
388 0           return (sort {$a cmp $b} uniq(@files));
  0            
389             }
390             sub fixup {
391 0     0 1   my $self = shift;
392 0           my @ar = @_;
393 0           my $fixup = $self->{fixup};
394 0 0 0       return SKIP unless $fixup && ref($fixup) eq 'CODE';
395 0           return $self->$fixup(@ar);
396             }
397             sub validate {
398 0     0 1   my $self = shift;
399 0           my @ar = @_;
400 0           my $validate = $self->{validate};
401 0 0 0       return SKIP unless $validate && ref($validate) eq 'CODE';
402 0           return $self->$validate(@ar);
403             }
404              
405             1;
406              
407             __END__