File Coverage

blib/lib/Tapper/Installer/Precondition/Kernelbuild.pm
Criterion Covered Total %
statement 13 147 8.8
branch 0 66 0.0
condition 0 8 0.0
subroutine 5 12 41.6
pod n/a
total 18 233 7.7


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