File Coverage

blib/lib/FusionInventory/Agent/Task/Deploy/File.pm
Criterion Covered Total %
statement 47 110 42.7
branch 6 46 13.0
condition 1 2 50.0
subroutine 11 16 68.7
pod 0 5 0.0
total 65 179 36.3


line stmt bran cond sub pod time code
1             package FusionInventory::Agent::Task::Deploy::File;
2              
3 4     4   33136063 use strict;
  4         5  
  4         107  
4 4     4   16 use warnings;
  4         4  
  4         111  
5              
6 4     4   978 use Digest::SHA;
  4         5397  
  4         147  
7 4     4   15 use English qw(-no_match_vars);
  4         4  
  4         29  
8 4     4   1311 use File::Basename;
  4         6  
  4         261  
9 4     4   13 use File::Path qw(mkpath);
  4         7  
  4         160  
10 4     4   16 use File::Glob;
  4         5  
  4         145  
11 4     4   851 use HTTP::Request;
  4         25239  
  4         35  
12              
13             sub new {
14 1     1 0 1229 my ($class, %params) = @_;
15              
16 1 50       3 die "no datastore parameter" unless $params{datastore};
17 1 50       4 die "no sha512 parameter" unless $params{sha512};
18              
19             my $self = {
20             p2p => $params{data}->{p2p},
21             retention_duration => $params{data}->{'p2p-retention-duration'} || 60 * 24 * 3,
22             uncompress => $params{data}->{uncompress},
23             mirrors => $params{data}->{mirrors},
24             multiparts => $params{data}->{multiparts},
25             name => $params{data}->{name},
26             sha512 => $params{sha512},
27             datastore => $params{datastore},
28             client => $params{client},
29             logger => $params{logger}
30 1   50     13 };
31              
32 1         2 bless $self, $class;
33              
34 1         2 return $self;
35             }
36              
37             sub getPartFilePath {
38 4     4 0 395 my ($self, $sha512) = @_;
39              
40 4 50       17 return unless $sha512 =~ /^(.)(.)(.{6})/;
41 4         12 my $subFilePath = $1.'/'.$2.'/'.$3;
42              
43             my @storageDirs =
44             File::Glob::glob($self->{datastore}->{path}.'/fileparts/shared/*'),
45 4         217 File::Glob::glob($self->{datastore}->{path}.'/fileparts/private/*');
46              
47 4         12 foreach my $dir (@storageDirs) {
48 0 0       0 if (-f $dir.'/'.$subFilePath) {
49 0         0 return $dir.'/'.$subFilePath;
50             }
51             }
52              
53 4         12 my $filePath = $self->{datastore}->{path}.'/fileparts/';
54             # filepart not found
55 4 50       10 if ($self->{p2p}) {
56 0         0 $filePath .= 'shared/';
57             } else {
58 4         8 $filePath .= 'private/';
59             }
60              
61             # Compute a directory name that will be used to know
62             # if the file must be purge. We don't want a new directory
63             # everytime, so we use a 10h frame
64 4         19 $filePath .= int(time/10000)*10000 + ($self->{retention_duration} * 60);
65 4         7 $filePath .= '/'.$subFilePath;
66              
67 4         20 return $filePath;
68             }
69              
70             sub download {
71 0     0 0 0 my ($self) = @_;
72              
73 0 0       0 die unless $self->{mirrors};
74              
75 0         0 my @peers;
76 0 0       0 if ($self->{p2p}) {
77 0         0 FusionInventory::Agent::Task::Deploy::P2P->require();
78 0 0       0 if ($EVAL_ERROR) {
79 0         0 $self->{logger}->debug("can't enable P2P: $EVAL_ERROR")
80             } else {
81             my $p2p = FusionInventory::Agent::Task::Deploy::P2P->new(
82             logger => $self->{logger}
83 0         0 );
84 0         0 eval {
85 0         0 @peers = $p2p->findPeers(62354);
86             };
87 0 0       0 $self->{logger}->debug("failed to enable P2P: $EVAL_ERROR")
88             if $EVAL_ERROR;
89             }
90             };
91              
92 0         0 my $lastPeer;
93 0         0 PART: foreach my $sha512 (@{$self->{multiparts}}) {
  0         0  
94 0         0 my $path = $self->getPartFilePath($sha512);
95 0 0       0 if (-f $path) {
96 0 0       0 next PART if $self->_getSha512ByFile($path) eq $sha512;
97             }
98 0         0 File::Path::mkpath(dirname($path));
99              
100             # try to download from the same peer as last part, if defined
101 0 0       0 if ($lastPeer) {
102 0         0 my $success = $self->_download($lastPeer, $sha512, $path);
103 0 0       0 next PART if $success;
104             }
105              
106             # try to download from peers
107 0         0 foreach my $peer (@peers) {
108 0         0 my $success = $self->_downloadPeer($peer, $sha512, $path);
109 0 0       0 if ($success) {
110 0         0 $lastPeer = $peer;
111 0         0 next PART;
112             }
113             }
114              
115             # try to download from mirrors
116 0         0 foreach my $mirror (@{$self->{mirrors}}) {
  0         0  
117 0         0 my $success = $self->_download($mirror, $sha512, $path);
118 0 0       0 next PART if $success;
119             }
120             }
121             }
122              
123             sub _downloadPeer {
124 0     0   0 my ($self, $peer, $sha512, $path) = @_;
125              
126 0         0 my $source = 'http://'.$peer.':62354/deploy/getFile/';
127              
128 0         0 return $self->_download($source, $sha512, $path);
129             }
130              
131             sub _download {
132 0     0   0 my ($self, $source, $sha512, $path) = @_;
133              
134 0 0       0 return unless $sha512 =~ /^(.)(.)/;
135 0         0 my $sha512dir = $1.'/'.$1.$2.'/';
136              
137 0         0 my $url = $source.$sha512dir.$sha512;
138 0         0 $self->{logger}->debug($url);
139              
140 0         0 my $request = HTTP::Request->new(GET => $url);
141 0         0 my $response = $self->{client}->request($request, $path);
142              
143 0 0       0 return if $response->code != 200;
144 0 0       0 return if ! -f $path;
145              
146 0 0       0 if ($self->_getSha512ByFile($path) ne $sha512) {
147 0         0 $self->{logger}->debug("sha512 failure: $sha512");
148 0         0 unlink($path);
149 0         0 return;
150             }
151              
152 0         0 return 1;
153             }
154              
155             sub filePartsExists {
156 2     2 0 571 my ($self) = @_;
157              
158 2         3 foreach my $sha512 (@{$self->{multiparts}}) {
  2         5  
159              
160 2         3 my $filePath = $self->getPartFilePath($sha512);
161 2 100       24 return 0 unless -f $filePath;
162              
163             }
164 1         4 return 1;
165             }
166              
167             sub _getSha512ByFile {
168 0     0     my ($self, $filePath) = @_;
169              
170 0           my $sha = Digest::SHA->new('512');
171              
172 0           my $sha512;
173 0           eval {
174 0           $sha->addfile($filePath, 'b');
175 0           $sha512 = $sha->hexdigest;
176             };
177 0 0         $self->{logger}->debug("SHA512 failure: $@") if $@;
178              
179 0           return $sha512;
180             }
181              
182             sub validateFileByPath {
183 0     0 0   my ($self, $filePath) = @_;
184              
185              
186 0 0         if (-f $filePath) {
187 0 0         if ($self->_getSha512ByFile($filePath) eq $self->{sha512}) {
188 0           return 1;
189             }
190             }
191              
192 0           return 0;
193             }
194              
195              
196             1;