File Coverage

blib/lib/Tapper/Installer/Precondition.pm
Criterion Covered Total %
statement 103 128 80.4
branch 51 92 55.4
condition 4 9 44.4
subroutine 17 18 94.4
pod 6 6 100.0
total 181 253 71.5


line stmt bran cond sub pod time code
1             our $AUTHORITY = 'cpan:TAPPER';
2             $Tapper::Installer::Precondition::VERSION = '5.0.1';
3             use strict;
4 9     9   113184 use warnings;
  9         29  
  9         254  
5 9     9   42 use 5.010;
  9         21  
  9         228  
6 9     9   190  
  9         28  
7             use Hash::Merge::Simple 'merge';
8 9     9   2845 use File::Type;
  9         3156  
  9         513  
9 9     9   4818 use File::Basename;
  9         75883  
  9         437  
10 9     9   87 use Moose;
  9         24  
  9         706  
11 9     9   489 use Socket;
  9         378874  
  9         85  
12 9     9   57988 use Sys::Hostname;
  9         23349  
  9         3560  
13 9     9   1128 use YAML;
  9         2327  
  9         416  
14 9     9   2216 use File::Temp qw/tempdir/;
  9         30832  
  9         507  
15 9     9   1477  
  9         17527  
  9         11718  
16             extends 'Tapper::Installer';
17              
18              
19              
20              
21             {
22             my ($self, $file) = @_;
23             my @file_split=split(/\./,$file);
24 10     10 1 44 my $type=$file_split[-1];
25 10         46 if ($type eq "iso") {
26 10         28 return (0,"iso");
27 10 100 100     113 } elsif ($type eq "gz" or $type eq "tgz") {
    100 33        
    100          
    50          
    50          
    100          
28 1         5 return (0,"gzip");
29             } elsif ($type eq "tar") {
30 4         35 return (0,"tar");
31             } elsif ($type eq "bz" or $type eq "bz2") {
32 1         5 return (0,"bz2");
33             } elsif ($type eq "rpm") {
34 0         0 return(0,"rpm");
35             } elsif ($type eq "deb") {
36 0         0 return(0,"deb");
37             }
38 1         7  
39             if (not -e $file) {
40             return (0,"$file does not exist. Can't check file type");
41 3 50       91 }
42 0         0 my $ft = File::Type->new();
43             $type = $ft->mime_type("$file");
44 3         24 if ($type eq "application/octet-stream") {
45 3         29 my ($error, $output)=$self->log_and_exec("file $file");
46 3 50       2686 return (0, "Getting file type of $file failed: $output") if $error;
    50          
    100          
    100          
    50          
47 0         0 return (0,"iso") if $output =~m/ISO 9660/i;
48 0 0       0 return (0,"rpm") if $output =~m/$file: RPM/i;
49 0 0       0 return (0,"deb") if $output =~m/$file: Debian/i;
50 0 0       0 } elsif ($type eq "application/x-dpkg") {
51 0 0       0 return (0,"deb");
52             } elsif ($type eq "application/x-gzip") {
53 0         0 return (0,"gzip");
54             } elsif ($type eq "application/x-gtar") {
55 1         18 return (0,"tar");
56             } elsif ($type eq "application/x-bzip2") {
57 1         6 return (0,"bz2");
58             } else {
59 1         7 return(1, "$file is of unrecognised file type \"$type\"");
60             }
61 0         0 }
62              
63              
64              
65              
66              
67             {
68             my ($self) = @_;
69             my $hostname = Sys::Hostname::hostname();
70             if ($hostname =~ m/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
71 1     1 1 909 ($hostname) = gethostbyaddr(inet_aton($hostname), AF_INET) or ( print("Can't get hostname: $!") and exit 1);
72 1         4 $hostname =~ s/^(\w+?)\..+$/$1/;
73 1 50       5 system("hostname", "$hostname");
74 0 0 0     0 }
75 0         0 return $hostname;
76 0         0 }
77              
78 1         4  
79             {
80             my ($self) = @_;
81             foreach my $order (@{$self->cfg->{cleanup} || []}) {
82             $order->{call}->(@{$order->{options} || []});
83             }
84 6     6 1 10 return 0;
85 6 100       8 }
  6         236  
86 1 50       11  
  1         15  
87              
88 6         17  
89             {
90             my ($self, $precondition) = @_;
91              
92             if ( $precondition->{source_url} =~ m{^nfs://(.+/)([^/]+)(/?)$} ) {
93             my $nfs_dir = tempdir (CLEANUP => 1); # allow to have multiple nfs mount
94             $self->log_and_exec("mount","-t nfs","$1", $nfs_dir);
95 1     1 1 11 $precondition->{name} = $precondition->{filename} = "$nfs_dir/$2";
96             push @{$self->cfg->{cleanup}}, {call => sub {$self->log_and_exec(@_)},
97 1 50       20 options => ['umount',$nfs_dir]};
98 1         22 }
99 1         530 return $precondition;
100 1         16 }
101 1     1   37  
  1         5  
102 1         9  
103              
104 1         11 {
105             my ($self, $precondition) = @_;
106              
107             $precondition = $self->handle_source_url($precondition) if $precondition->{source_url};
108              
109             my $retval;
110             my ($error, $loop);
111 6     6 1 7651 $self->makedir($self->cfg->{paths}{guest_mount_dir}) if not -d $self->cfg->{paths}{guest_mount_dir};
112              
113 6 100       30 my $image;
114             my $partition = $precondition->{mountpartition};
115 6         13 my $new_base_dir = $self->cfg->{paths}{base_dir};
116 6         8  
117 6 50       175 if ($precondition->{mountfile}) {
118             $image = $self->cfg->{paths}{base_dir}.$precondition->{mountfile};
119 6         18 $new_base_dir = $self->cfg->{paths}{guest_mount_dir};
120 6         13 if ( $precondition->{mountpartition} ) {
121 6         154 # make sure loop device is free
122             # don't use losetup -f, until it is available on installer NFS root
123 6 100       23 $self->log_and_exec("losetup -d /dev/loop0"); # ignore error since most of the time device won't be already bound
    100          
    100          
124 2         42 return $retval if $retval = $self->log_and_exec("losetup /dev/loop0 $image");
125 2         42 return $retval if $retval = $self->log_and_exec("kpartx -a /dev/loop0");
126 2 100       5 return $retval if $retval = $self->log_and_exec("mount /dev/mapper/loop0$partition ".$new_base_dir);
127             } else {
128             return $retval if $retval = $self->log_and_exec("mount -o loop $image ".$new_base_dir);
129 1         4 }
130 1 50       9 }
131 1 50       7 elsif ($precondition->{mountpartition}) {
132 1 50       8 $new_base_dir = $self->cfg->{paths}{guest_mount_dir};
133             return $retval if $retval = $self->log_and_exec("mount $partition ".$new_base_dir);
134 1 50       10 }
135             elsif ($precondition->{mountdir}) {
136             $new_base_dir .= $precondition->{mountdir};
137             }
138 1         23  
139 1 50       6 # call
140             my $old_basedir = $self->cfg->{paths}{base_dir};
141             $self->cfg->{paths}{base_dir} = $new_base_dir;
142 1         4 return $retval if $retval=$self->install($precondition);
143              
144              
145             if ($precondition->{mountfile}) {
146 6         144 if ( $precondition->{mountpartition} ) {
147 6         119 return $retval if $retval = $self->log_and_exec("umount /dev/mapper/loop0$partition");
148 6 50       29 return $retval if $retval = $self->log_and_exec("kpartx -d /dev/loop0");
149             if ($retval = $self->log_and_exec("losetup -d /dev/loop0")) {
150             sleep (2);
151 6 100       22 return $retval if $retval = $self->log_and_exec("kpartx -d /dev/loop0");
    100          
152 2 100       6 return $retval if $retval = $self->log_and_exec("losetup -d /dev/loop0");
153 1 50       4 }
154 1 50       8 } else {
155 1 50       7 $retval = $self->log_and_exec("umount $new_base_dir");
156 0         0 $self->log->error("Can not unmount $new_base_dir: $retval") if $retval;
157 0 0       0  
158 0 0       0 # seems like mount -o loop uses a loop device that is not freed at umount
159             $self->log_and_exec("kpartx -d /dev/loop0");
160             $self->log_and_exec("losetup -d /dev/loop0");
161 1         3 }
162 1 50       14 }
163             elsif ($precondition->{mountpartition}) {
164             $retval = $self->log_and_exec("umount $new_base_dir");
165 1         4 $self->log->error("Can not unmount $new_base_dir: $retval") if $retval;
166 1         6 }
167             $self->cleanup();
168             $self->cfg->{paths}{base_dir} = $old_basedir;
169             return 0;
170 1         3  
171 1 50       8 }
172              
173 6         39  
174 6         131  
175 6         28 {
176             my ($self, $output, $filename) = @_;
177             my $testrun_id = $self->cfg->{test_run};
178             my $destdir = $self->cfg->{paths}{output_dir}."/$testrun_id/install/";
179             my $destfile = $destdir."/$filename";
180             if (not -d $destdir) {
181             system("mkdir","-p",$destdir) == 0 or return ("Can't create $destdir:$!");
182             }
183 0     0 1   open(my $FH,">",$destfile)
184 0           or return ("Can't open $destfile:$!");
185 0           print $FH $output;
186 0           close $FH;
187 0 0         }
188 0 0          
189              
190 0 0          
191             1;
192 0            
193 0            
194             =pod
195              
196             =encoding UTF-8
197              
198             =head1 NAME
199              
200             Tapper::Installer::Precondition
201              
202             =head1 SYNOPSIS
203              
204             use Tapper::Installer::Precondition;
205              
206             =head1 NAME
207              
208             Tapper::Installer::Precondition - Base class with common functions
209             for Tapper::Installer::Precondition modules
210              
211             =head1 FUNCTIONS
212              
213             =head2 get_file_type
214              
215             Return the file type of a given file. "rpm, "deb", "tar", "gzip", "bz2" and
216             "iso" 9660 cd images are recognised at the moment. If file does not exists at
217             the given file name, only suffix analysis will be available. To enforce any of
218             the above mentioned types, just set the suffix of the file accordingly.
219              
220             @param string - file name
221              
222             @returnlist success - (0, rpm|deb|iso|tar|gzip|bzip2)
223             @returnlist error - (1, error string)
224              
225             =head2 gethostname
226              
227             This function returns the host name of the machine. When NFS root is
228             used together with DHCP the hostname set in the kernel usually equals
229             the IP address received from DHCP as a string. In this case the kernel
230             hostname is set to the DNS hostname associated to this IP address.
231              
232             @return hostname of the machine as set in the kernel
233              
234             =head2 cleanup
235              
236             Clean up all remaining preparations (given in config).
237              
238             @return success - 0
239             @return error - error string
240              
241             =head2 handle_source_url
242              
243             A preconditions source may need some preparation, e.g. if it's located
244             on an NFS share we need to mount this share. This function handles these
245             preparations.
246              
247             @param hash ref - precondition
248              
249             @return success - hash ref with updated precondition
250             @return error - error string
251              
252             =head2 precondition_install
253              
254             Install a precondition with preparations up front. This could be
255             mounting an NFS share or installing inside a virtualisation guest or
256             even no preparation at all.
257              
258             A guest can be given as image, partition or directory. This function
259             makes the necessary preparations, calls the right precondition install
260             function and cleans up afterwards. An image can be given as file name
261             and partition or file name only. The later is supposed to be an image
262             file containing just one partition.
263              
264             @param hash ref - precondition
265              
266             @return success - 0
267             @return error - error string
268              
269             =head2 file_save
270              
271             Save output as file for MCP to find it and upload it to reports receiver.
272              
273             @param string - output to be written to file
274             @param string - basename of the file to write output to
275              
276             @return success - 0
277             @return errorr - error string
278              
279             =head1 AUTHORS
280              
281             =over 4
282              
283             =item *
284              
285             AMD OSRC Tapper Team <tapper@amd64.org>
286              
287             =item *
288              
289             Tapper Team <tapper-ops@amazon.com>
290              
291             =back
292              
293             =head1 COPYRIGHT AND LICENSE
294              
295             This software is Copyright (c) 2022 by Advanced Micro Devices, Inc.
296              
297             This is free software, licensed under:
298              
299             The (two-clause) FreeBSD License
300              
301             =cut