File Coverage

blib/lib/Tapper/Installer/Precondition/Kernelbuild.pm
Criterion Covered Total %
statement 17 146 11.6
branch 0 66 0.0
condition 0 8 0.0
subroutine 5 11 45.4
pod 7 7 100.0
total 29 238 12.1


line stmt bran cond sub pod time code
1             our $AUTHORITY = 'cpan:TAPPER';
2             $Tapper::Installer::Precondition::Kernelbuild::VERSION = '5.0.1';
3              
4             use Moose;
5 4     4   125818 use IO::Handle; # needed to set pipe nonblocking
  4         403160  
  4         27  
6 4     4   23326 extends 'Tapper::Installer::Precondition';
  4         6098  
  4         223  
7              
8             use strict;
9 4     4   51 use warnings;
  4         31  
  4         80  
10 4     4   19  
  4         9  
  4         5821  
11              
12              
13             {
14             my ($self, $git_url) = @_;
15             $self->log->info("Git URL before rewrite: $git_url");
16 6     6 1 34 $git_url =~ s|^git://osrc((\.osrc)?\.amd\.com)?/|git://wotan.amd.com/|;
17 6         26 $self->log->info("Git URL after rewrite: $git_url");
18 6         620 return $git_url;
19 6         14 }
20 6         107  
21              
22             {
23             my ($self, $git_url, $git_rev)=@_;
24              
25             # git may generate more output than log_and_exec can handle, thus keep the system()
26 0     0 1   chdir $self->cfg->{paths}{base_dir};
27             $git_url = $self->fix_git_url($git_url);
28             system("git","clone","-q",$git_url,"linux") == 0
29 0           or return("unable to clone git repository $git_url");
30 0           chdir ("linux");
31 0 0         system("git","checkout",$git_rev) == 0
32             or return("unable to check out $git_rev from git repository $git_url");
33 0           return(0);
34 0 0         }
35              
36 0            
37             {
38             my ($self, $config_file) = @_;
39             $config_file ||= $self->cfg->{paths}{config_path}."/kernelconfigs/config_x86_64";
40             $self->log->debug("Getting config $config_file");
41              
42 0     0 1   return "Can not get config $config_file because the file does not exist"
43 0   0       if not -e $config_file;
44 0            
45             system("cp $config_file .config") == 0
46 0 0         or return "Can not get config $config_file";
47             return 0;
48             }
49 0 0          
50              
51 0           {
52             my ($self) = @_;
53             system("make","clean") == 0
54             or return("Making mrproper failed: $!");
55              
56             system('yes ""|make oldconfig') == 0
57 0     0 1   or return("Making oldconfig failed: $!");
58 0 0          
59             system('make','-j8') == 0
60             or return("Build the kernel failed: $!");
61 0 0          
62             system('make','install') == 0
63             or return("Installing the kernel failed: $!");
64 0 0          
65             system('make','modules_install') == 0
66             or return("Installing the kernel failed: $!");
67 0 0          
68             return 0;
69             }
70 0 0          
71              
72              
73 0            
74             {
75             my ($self) = @_;
76             my ($error, $kernelversion) = $self->log_and_exec("make","kernelversion");
77 0     0 1   my $kernel_file = "vmlinuz-$kernelversion";
78              
79             # double block, the outermost belongs to if, the innermost can be left with last;
80             # great stuff, isn't it?
81             if (not -e "/boot/$kernel_file") {{
82 0     0 1   if (-e "/boot/vmlinuz-${kernelversion}+"){
83 0           $kernelversion .='+';
84 0           $kernel_file = "vmlinuz-$kernelversion";
85             last;
86             }
87             if (-e "/boot/bzImage") {
88 0 0         $kernel_file = "bzImage";
89 0 0         last;
  0            
90 0           }
91 0           if (-e "/boot/bzImage-$kernelversion") {
92 0           $kernel_file = "bzImage-$kernelversion";
93             last;
94 0 0         }
95 0           if (-e "/boot/bzImage-$kernelversion+") {
96 0           $kernel_file = "bzImage-$kernelversion";
97             last;
98 0 0         }
99 0            
100 0           my @files = sort younger </boot/vmlinuz-*>;
101             if (@files) {
102 0 0         $kernel_file = $files[0];
103 0           $kernelversion = $1;
104 0           last;
105             }
106             my $filename;
107 0           $filename = "/tmp/bootdir-content";
108 0 0         system("ls -l /boot/ > $filename");
109 0           return "kernel install failed, can not find new kernel";
110 0           }}
111 0            
112             system("depmod $kernelversion") == 0
113 0           or return("Can not create initrd file, see log file");
114 0            
115 0           my $modules = "ixgbe forcedeth r8169 libata sata-sil scsi-mod atiixp ide-disk";
116 0           $modules .= " ide-core 3c59x tg3 mii amd8111e e1000e bnx2 bnx2x ixgb";
117             my $mkinitrd_command = "mkinitrd -k /boot/$kernel_file -i /boot/initrd-$kernelversion ";
118             $mkinitrd_command .= qq(-m "$modules");
119 0 0          
120             $self->log->debug($mkinitrd_command);
121             system($mkinitrd_command) == 0
122 0           or return("Can not create initrd file, see log file");
123 0            
124 0           # prepare_boot called at the end of the install process will generate
125 0           # a grub entry for vmlinuz/initrd with no version string attached
126             $error = $self->log_and_exec("ln -sf","/boot/$kernel_file", "/boot/vmlinuz");
127 0           return $error if $error;
128 0 0         $error = $self->log_and_exec("ln -sf","/boot/initrd-$kernelversion", "/boot/initrd");
129             return $error if $error;
130              
131             return 0;
132             }
133 0            
134 0 0          
135 0            
136 0 0          
137             {
138 0           my ($self, $build) = @_;
139             my $git_url = $build->{git_url} or return 'No git url given';
140             my $git_rev = $build->{git_changeset} || 'HEAD';
141             my $config_file = $build->{configfile_path};
142              
143             $self->log->debug("Installing kernel from $git_url $git_rev");
144              
145             my $git_path = qx(which git);
146 0     0 1   chomp $git_path;
147 0 0         return "Can not find git. Git_path is '$git_path'" if not -e $git_path;
148 0   0        
149 0           pipe (my $read, my $write);
150             return ("Can't open pipe:$!") if not (defined $read and defined $write);
151 0            
152              
153 0           # we need to fork for chroot
154 0           my $pid = fork();
155 0 0         return "fork failed: $!" if not defined $pid;
156              
157 0           # hello child
158 0 0 0       if ($pid == 0) {
159             close $read;
160             my ($error, $output);
161              
162 0           # TODO: handle error
163 0 0         ($error, $output) = $self->log_and_exec("mount -o bind /dev/ ".$self->cfg->{paths}{base_dir}."/dev");
164             ($error, $output) = $self->log_and_exec("mount -t sysfs sys ".$self->cfg->{paths}{base_dir}."/sys");
165             ($error, $output) = $self->log_and_exec("mount -t proc proc ".$self->cfg->{paths}{base_dir}."/proc");
166 0 0          
167 0           my $filename = $git_url.$git_rev;
168 0           $filename =~ s/[^A-Za-z_-]+/_/g;
169              
170             my $testrun_id = $self->cfg->{test_run};
171 0           my $output_dir = $self->cfg->{paths}{output_dir}."/$testrun_id/install/";
172 0           $self->makedir($output_dir);
173 0            
174              
175 0           my $output_file = $output_dir."/$filename";
176 0           # dup output to file before git_get and chroot but inside child
177             # so we don't need to care how to get rid of it at the end
178 0           open (STDOUT, ">>", "$output_file.stdout") or print($write "Can't open output file $output_file.stdout: $!\n"),exit 1;
179 0           open (STDERR, ">>", "$output_file.stderr") or print($write "Can't open output file $output_file.stderr: $!\n"),exit 1;
180 0            
181             $error = $self->git_get($git_url, $git_rev);
182             if ($error) {
183 0           print(write $error,"\n");
184             exit -1;
185             }
186 0 0          
187 0 0         $error = $self->get_config($config_file);
188             if ($error) {
189 0           print(write $error,"\n");
190 0 0         exit -1;
191 0           }
192 0            
193              
194             $ENV{TAPPER_TESTRUN} = $self->cfg->{test_run};
195 0           $ENV{TAPPER_SERVER} = $self->cfg->{mcp_host};
196 0 0         $ENV{TAPPER_REPORT_SERVER} = $self->cfg->{report_server};
197 0           $ENV{TAPPER_REPORT_API_PORT} = $self->cfg->{report_api_port};
198 0           $ENV{TAPPER_REPORT_PORT} = $self->cfg->{report_port};
199             $ENV{TAPPER_HOSTNAME} = $self->cfg->{hostname};
200             $ENV{TAPPER_OUTPUT_PATH} = $output_dir;
201              
202 0            
203 0           # chroot to execute script inside the future root file system
204 0           chroot $self->cfg->{paths}{base_dir};
205 0           chdir('linux');
206 0            
207 0           $error = $self->make_kernel();
208 0           if ($error) {
209             print( $write $error, "\n");
210             exit -1;
211             }
212 0            
213 0           $error = $self->make_initrd();
214             if ($error) {
215 0           print( $write $error, "\n");
216 0 0         exit -1;
217 0           }
218 0            
219             close $write;
220             exit 0;
221 0           } else {
222 0 0         close $write;
223 0           my $select = IO::Select->new( $read );
224 0           my ($error, $output);
225             MSG_FROM_CHILD:
226             while (my @ready = $select->can_read()){
227 0           my $tmpout = <$read>; # only $read can be in @ready, since no other FH is in $select
228 0           last MSG_FROM_CHILD if not $tmpout;
229             $output.=$tmpout;
230 0           }
231 0           # save logfile from within chroot
232 0           if (-e $self->cfg->{paths}{base_dir}."/tmp/bootdir-content" ) {
233             log_and_exec("cp",$self->cfg->{paths}{base_dir}."/tmp/bootdir-content",
234 0           $self->cfg->{paths}{output_dir}."/".$self->cfg->{test_run}."/install/");
235 0           }
236 0 0          
237 0           $self->log_and_exec("umount ".$self->cfg->{paths}{base_dir}."/sys");
238             $self->log_and_exec("umount ".$self->cfg->{paths}{base_dir}."/dev");
239             $self->log_and_exec("umount ".$self->cfg->{paths}{base_dir}."/proc");
240 0 0         waitpid($pid,0);
241             if ($?) {
242 0           return("Building kernel from $git_url $git_rev failed: $output");
243             }
244             return(0);
245 0           }
246 0           }
247 0           ;
248 0            
249 0 0          
250 0           1;
251              
252 0            
253             =pod
254              
255             =encoding UTF-8
256              
257             =head1 NAME
258              
259             Tapper::Installer::Precondition::Kernelbuild
260              
261             =head1 SYNOPSIS
262              
263             my $kernel_precondition = '
264             precondition_type: kernelbuild
265             git_url: git://osrc.amd.com/linux-2.6.git
266             changeset: HEAD
267             patchdir: /patches
268             ';
269              
270             use Tapper::Installer::Precondition::Kernelbuild;
271             $kernel = Tapper::Installer::Precondition::Kernelbuild->new($config);
272             $kernel->install(YAML::Load($kernel_precondition));
273              
274             =head1 NAME
275              
276             Tapper::Installer::Precondition::Kernelbuild - Build and install a kernel from git
277              
278             =head1 FUNCTIONS
279              
280             =head2 fix_git_url
281              
282             URL rewrite.
283              
284             @param string git_url
285              
286             @return string - fixed git url
287              
288             =head2 git_get
289              
290             This function encapsulates getting a kernel source directory out of a git
291             repository. It changes the current directory into the the repository.
292              
293             @param string - repository URL
294             @param string - revision in this repository
295              
296             @return success - 0
297             @return error - error string
298              
299             =head2 get_config
300              
301             Get the kernel config.
302              
303             @return success - 0
304             @return error - error string
305              
306             =head2 make_kernel
307              
308             Build and install a kernel and write all log messages to STDOUT/STDERR.
309              
310             @return success - 0
311             @return error - error string
312              
313             =head2 younger
314              
315             Sort function, sort files based on modification time.
316              
317             =head2 make_initrd
318              
319             Build and install an initrd and write all log messages to STDOUT/STDERR.
320              
321             @return success - 0
322             @return error - error string
323              
324             =head2 install
325              
326             Get the source if needed, prepare the config, build and install the
327             kernel and initrd file.
328              
329             @param hash reference - contains all information about the kernel
330              
331             @return success - 0
332             @return error - error string
333              
334             =head1 AUTHORS
335              
336             =over 4
337              
338             =item *
339              
340             AMD OSRC Tapper Team <tapper@amd64.org>
341              
342             =item *
343              
344             Tapper Team <tapper-ops@amazon.com>
345              
346             =back
347              
348             =head1 COPYRIGHT AND LICENSE
349              
350             This software is Copyright (c) 2022 by Advanced Micro Devices, Inc.
351              
352             This is free software, licensed under:
353              
354             The (two-clause) FreeBSD License
355              
356             =cut