source: ProjectBuilder/devel/pb-modules/lib/ProjectBuilder/VE.pm@ 1900

Last change on this file since 1900 was 1900, checked in by Bruno Cornec, 10 years ago
  • Add support for docker phase 1: newve working
  • Add separate pb_ve_snap function
  • Add separate pb_ve_docker functions to interact with the registry and the repository
  • Add a dockerregistry conf parameter
File size: 13.5 KB
Line 
1#!/usr/bin/perl -w
2#
3# Common functions for virtual environment
4#
5# Copyright B. Cornec 2007-2012
6# Eric Anderson's changes are (c) Copyright 2012 Hewlett Packard
7# Provided under the GPL v2
8#
9# $Id$
10#
11
12package ProjectBuilder::VE;
13
14use strict;
15use Data::Dumper;
16use Carp 'confess';
17use English;
18use ProjectBuilder::Version;
19use ProjectBuilder::Base;
20use ProjectBuilder::Conf;
21use ProjectBuilder::Distribution;
22
23# Global vars
24# Inherit from the "Exporter" module which handles exporting functions.
25
26use vars qw($VERSION $REVISION @ISA @EXPORT);
27use Exporter;
28
29# Export, by default, all the functions into the namespace of
30# any code which uses this module.
31
32our @ISA = qw(Exporter);
33our @EXPORT = qw(pb_ve_launch pb_ve_snap);
34
35($VERSION,$REVISION) = pb_version_init();
36
37=pod
38
39=head1 NAME
40
41ProjectBuilder::VE, part of the project-builder.org - module dealing with Virtual Environment
42
43=head1 DESCRIPTION
44
45This modules provides functions to deal with Virtual Environements (VE), aka chroot/containers.
46
47=head1 SYNOPSIS
48
49 use ProjectBuilder::VE;
50
51 #
52 # Return information on the running distro
53 #
54 my $pbos = pb_ve_launch();
55
56=head1 USAGE
57
58=over 4
59
60=item B<pb_ve_launch>
61
62This function launches a VE, creating it if necessary using multiple external potential tools.
63
64=cut
65
66sub pb_ve_launch {
67
68my $v = shift || undef;
69my $pbforce = shift || 0; # By default do not rebuild VE
70my $locsnap = shift || 0; # By default do not snap VE
71my $vetype = shift || undef; # By default no image
72my $pbimage = shift || undef; # By default no image
73
74my $dockerregistry = undef;
75my $docrepo = undef; # By default no repository for docker available
76
77# Get distro context
78my $pbos = pb_distro_get_context($v);
79
80# Get VE context
81if (not defined $vetype) {
82 my ($ptr) = pb_conf_get("vetype");
83 $vetype = $ptr->{$ENV{'PBPROJ'}};
84}
85confess "No vetype defined for $ENV{PBPROJ}" unless (defined $vetype);
86pb_log(1, "Using vetype $vetype for $ENV{PBPROJ}\n");
87my ($vepath) = pb_conf_get("vepath");
88
89if (($vetype eq "chroot") || ($vetype eq "schroot") || ($vetype eq "docker")) {
90
91 # We need to avoid umask propagation to the VE
92 umask 0022;
93
94 # We can probably only get those params now we have the distro context
95 my ($rbsb4pi,$rbspi,$vesnap,$oscodename,$osmindep,$verebuild,$rbsmirrorsrv) = pb_conf_get_if("rbsb4pi","rbspi","vesnap","oscodename","osmindep","verebuild","rbsmirrorsrv");
96 if ($vetype eq "docker") {
97 # Check acces to registry
98 ($dockerregistry) = pb_conf_get("dockerregistry");
99 if ((defined $dockerregistry) && (defined $dockerregistry->{$ENV{'PBPROJ'}})) {
100 pb_ve_docker_registry($dockerregistry->{$ENV{'PBPROJ'}});
101 } else {
102 die "When using docker you need to declare a dockerregistry parameter. Read the man page"
103 }
104 }
105
106 # Architecture consistency
107 my $arch = pb_get_arch();
108 if ($arch ne $pbos->{'arch'}) {
109 die "Unable to launch a VE of architecture $pbos->{'arch'} on a $arch platform" unless (($pbos->{'arch'} =~ /i?86/o) && ($arch eq "x86_64"));
110 }
111
112 # If we are already root (from pbmkbm e.g.) don't use sudo, just call the command
113 my $sudocmd="";
114 if ($EFFECTIVE_USER_ID != 0) {
115 $sudocmd ="sudo ";
116 foreach my $proxy (qw/http_proxy ftp_proxy/) {
117 if (defined $ENV{$proxy}) {
118 open(CMD,"sudo sh -c 'echo \$$proxy' |") or die "can't run sudo sh?: $!";
119 $_ = <CMD>;
120 chomp();
121 die "sudo not passing through env var $proxy; '$ENV{$proxy}' != '$_'\nAdd line Defaults:`whoami` env_keep += \"$proxy\" to sudoers file?" unless $_ eq $ENV{$proxy};
122 close(CMD);
123 }
124 }
125 }
126
127 # Handle cross arch on Intel based platforms
128 $sudocmd = "setarch i386 $sudocmd" if (($pbos->{'arch'} =~ /i[3456]86/) && ($arch eq 'x86_64'));
129
130 my $root = pb_path_expand($vepath->{$ENV{PBPROJ}});
131
132 if (((((defined $verebuild) && ($verebuild->{$ENV{'PBPROJ'}} =~ /true/i)) || ($pbforce == 1)) && ($vetype ne "docker"))
133 # For docker we may have a reference image that we'll use
134 || (((not defined $pbimage) || ($pbimage eq "")) && ($vetype eq "docker"))) {
135
136 my ($verpmtype,$vedebtype) = pb_conf_get("verpmtype","vedebtype");
137 my ($rbsopt1) = pb_conf_get_if("rbsopt");
138
139 # We have to rebuild the chroot
140 if ($pbos->{'type'} eq "rpm") {
141
142 # Which tool is used
143 my $verpmstyle = $verpmtype->{$ENV{'PBPROJ'}};
144 die "No verpmtype defined for $ENV{PBPROJ}" unless (defined $verpmstyle);
145
146 # Get potential rbs option
147 my $rbsopt = "";
148 if (defined $rbsopt1) {
149 if (defined $rbsopt1->{$verpmstyle}) {
150 $rbsopt = $rbsopt1->{$verpmstyle};
151 } elsif (defined $rbsopt1->{$ENV{'PBPROJ'}}) {
152 $rbsopt = $rbsopt1->{$ENV{'PBPROJ'}};
153 } else {
154 $rbsopt = "";
155 }
156 }
157
158 my $postinstall = pb_ve_get_postinstall($pbos,$rbspi,$verpmstyle);
159 if ($verpmstyle eq "rinse") {
160 # Need to reshape the mirrors generated with local before-post-install script
161 my $b4post = "--before-post-install ";
162 my $postparam = pb_distro_get_param($pbos,$rbsb4pi);
163 if ($postparam eq "") {
164 $b4post = "";
165 } else {
166 $b4post .= $postparam;
167 }
168
169 # Need to reshape the package list for pb
170 my $addpkgs;
171 $postparam = "";
172 $postparam .= pb_distro_get_param($pbos,$osmindep);
173 if ($postparam eq "") {
174 $addpkgs = "";
175 } else {
176 my $pkgfile = "$ENV{'PBTMP'}/addpkgs.lis";
177 open(PKG,"> $pkgfile") || die "Unable to create $pkgfile";
178 foreach my $p (split(/,/,$postparam)) {
179 print PKG "$p\n";
180 }
181 close(PKG);
182 $addpkgs = "--add-pkg-list $pkgfile";
183 }
184
185 my $rinseverb = "";
186 $rinseverb = "--verbose" if ($pbdebug gt 0);
187 my ($rbsconf) = pb_conf_get("rbsconf");
188
189 my $command = pb_check_req("rinse",0);
190 pb_system("$sudocmd $command --directory \"$root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}\" --arch \"$pbos->{'arch'}\" --distribution \"$pbos->{'name'}-$pbos->{'version'}\" --config \"$rbsconf->{$ENV{'PBPROJ'}}\" $b4post $postinstall $rbsopt $addpkgs $rinseverb","Creating the rinse VE for $pbos->{'name'}-$pbos->{'version'} ($pbos->{'arch'})", "verbose");
191 } elsif ($verpmstyle eq "rpmbootstrap") {
192 my $rbsverb = "";
193 foreach my $i (1..$pbdebug) {
194 $rbsverb .= " -v";
195 }
196 my $addpkgs = "";
197 my $postparam = "";
198 $postparam .= pb_distro_get_param($pbos,$osmindep);
199 if ($postparam eq "") {
200 $addpkgs = "";
201 } else {
202 $addpkgs = "-a $postparam";
203 }
204 my $command = pb_check_req("rpmbootstrap",0);
205 pb_system("$sudocmd $command $rbsopt $postinstall $addpkgs $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'} $rbsverb","Creating the rpmbootstrap VE for $pbos->{'name'}-$pbos->{'version'} ($pbos->{'arch'})", "verbose");
206 pb_system("$sudocmd /bin/umount $root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}/proc","Umounting stale /proc","mayfail") if (-f "$root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}/proc/cpuinfo");
207 } elsif ($verpmstyle eq "mock") {
208 my ($rbsconf) = pb_conf_get("rbsconf");
209 my $command = pb_check_req("mock",0);
210 pb_system("$sudocmd $command --init --resultdir=\"/tmp\" --configdir=\"$rbsconf->{$ENV{'PBPROJ'}}\" -r $v $rbsopt","Creating the mock VE for $pbos->{'name'}-$pbos->{'version'} ($pbos->{'arch'})");
211 # Once setup we need to install some packages, the pb account, ...
212 pb_system("$sudocmd $command --install --configdir=\"$rbsconf->{$ENV{'PBPROJ'}}\" -r $v su","Configuring the mock VE");
213 } else {
214 die "Unknown verpmtype type $verpmstyle. Report to dev team";
215 }
216 } elsif ($pbos->{'type'} eq "deb") {
217 my $vedebstyle = $vedebtype->{$ENV{'PBPROJ'}};
218
219 my $codename = pb_distro_get_param($pbos,$oscodename);
220 my $postparam = "";
221 my $addpkgs;
222 $postparam .= pb_distro_get_param($pbos,$osmindep);
223 if ($postparam eq "") {
224 $addpkgs = "";
225 } else {
226 $addpkgs = "--include $postparam";
227 }
228 my $debmir = "";
229 $debmir .= pb_distro_get_param($pbos,$rbsmirrorsrv);
230
231 # Get potential rbs option
232 my $rbsopt = "";
233 if (defined $rbsopt1) {
234 if (defined $rbsopt1->{$vedebstyle}) {
235 $rbsopt = $rbsopt1->{$vedebstyle};
236 } elsif (defined $rbsopt1->{$ENV{'PBPROJ'}}) {
237 $rbsopt = $rbsopt1->{$ENV{'PBPROJ'}};
238 } else {
239 $rbsopt = "";
240 }
241 }
242
243 # debootstrap works with amd64 not x86_64
244 my $debarch = $pbos->{'arch'};
245 $debarch = "amd64" if ($pbos->{'arch'} eq "x86_64");
246 if ($vedebstyle eq "debootstrap") {
247 my $dbsverb = "";
248 $dbsverb = "--verbose" if ($pbdebug gt 0);
249
250 # Some perl modules are in Universe on Ubuntu
251 $rbsopt .= " --components=main,universe" if ($pbos->{'name'} eq "ubuntu");
252
253 my $cmd1 = pb_check_req("mkdir",0);
254 my $cmd2 = pb_check_req("debootstrap",0);
255 pb_system("$sudocmd $cmd1 -p $root/$pbos->{name}/$pbos->{version}/$pbos->{arch} ; $sudocmd $cmd2 $dbsverb $rbsopt --arch=$debarch $addpkgs $codename \"$root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}\" $debmir","Creating the debootstrap VE for $pbos->{'name'}-$pbos->{'version'} ($pbos->{'arch'})", "verbose");
256 # debootstrap doesn't create an /etc/hosts file
257 if (! -f "$root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}/etc/hosts" ) {
258 my $cmd = pb_check_req("cp",0);
259 pb_system("$sudocmd $cmd /etc/hosts $root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}/etc/hosts");
260 }
261 } else {
262 die "Unknown vedebtype type $vedebstyle. Report to dev team";
263 }
264 } elsif ($pbos->{'type'} eq "ebuild") {
265 die "Please teach the dev team how to build gentoo chroot";
266 } else {
267 die "Unknown distribution type $pbos->{'type'}. Report to dev team";
268 }
269 }
270
271 # Test if an existing snapshot exists and use it if appropriate
272 # And also use it if no local extracted VE is present
273 if ((-f "$root/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}.tar.gz") &&
274 (((defined $vesnap->{$v}) && ($vesnap->{$v} =~ /true/i)) ||
275 ((defined $vesnap->{$ENV{'PBPROJ'}}) && ($vesnap->{$ENV{'PBPROJ'}} =~ /true/i))) &&
276 ($locsnap eq 1) &&
277 (! -d "$root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}")) {
278 my $cmd1 = pb_check_req("rm",0);
279 my $cmd2 = pb_check_req("mkdir",0);
280 my $cmd3 = pb_check_req("tar",0);
281 pb_system("$sudocmd $cmd1 -rf $root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'} ; $sudocmd $cmd2 -p $root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'} ; $sudocmd $cmd3 xz -C $root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'} -f $root/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}.tar.gz","Extracting snapshot of $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}.tar.gz under $root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}");
282 }
283
284 # Fix modes to allow access to the VE for pb user
285 my $command = pb_check_req("chmod",0);
286 pb_system("$sudocmd $command 755 $root/$pbos->{'name'} $root/$pbos->{'name'}/$pbos->{'version'} $root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}","Fixing permissions");
287
288 # If docker, create the image and remove the now temp dir except if we had one already
289 if ($vetype eq "docker") {
290 if ((not defined $pbimage) || ($pbimage eq "")) {
291 # Snaphot the VE to serve as an input for docker
292 pb_ve_snap($pbos,$root);
293 # Create the docker image from the previous bootstrap
294 my $cmd1 = pb_check_req("docker",0);
295 $docrepo = pb_ve_docker_repo($dockerregistry->{$ENV{'PBPROJ'}});
296 pb_system("$cmd1 import - $docrepo:$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'} < $root/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}.tar.gz");
297 pb_system("$cmd1 push $docrepo:$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}");
298 #} else {
299 }
300 }
301
302 # Nothing more to do for VE. No real launch
303} else {
304 die "VE of type $vetype not supported. Report to the dev team";
305}
306}
307
308#
309# Return the postinstall line if needed
310#
311
312sub pb_ve_get_postinstall {
313
314my $pbos = shift;
315my $rbspi = shift;
316my $vestyle = shift;
317my $post = "";
318
319# Do we have a local post-install script
320if ($vestyle eq "rinse") {
321 $post = "--post-install ";
322} elsif ($vestyle eq "rpmbootstrap") {
323 $post = "-s ";
324}
325
326my $postparam = pb_distro_get_param($pbos,$rbspi);
327if ($postparam eq "") {
328 $post = "";
329} else {
330 $post .= $postparam;
331}
332return($post);
333}
334
335# Snapshot the VE
336sub pb_ve_snap {
337
338my $pbos = shift;
339my $root = shift;
340my $tpdir = "$root/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}";
341pb_system("sudo tar cz -C $tpdir -f $root/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}.tar.gz .","Creating a snapshot of $tpdir");
342}
343
344# Returns the docker registry to interact with
345sub pb_ve_docker_registry {
346
347my $dockerreg = shift || undef;
348my $wget = pb_check_req("wget",0);
349my ($scheme, $account, $host, $port, $path) = pb_get_uri($dockerreg);
350my $docreg = $scheme."://";
351$docreg .= $account."@" if ((defined $account) && ($account ne ""));
352$docreg .= $host;
353$docreg .= ":$port" if ((defined $port) && ($port ne ""));
354open(FD,"$wget $docreg -q -O -|") || die "Unable to talk to the docker registry $docreg";
355my $found = undef;
356while (<FD>) {
357 $found = 1 if (/docker-registry/);
358}
359close(FD);
360die "No correct docker-registry answering at $docreg. Please check your configuration" if (not defined $found);
361#
362return($docreg);
363}
364
365# Returns the docker repository to interact with
366sub pb_ve_docker_repo {
367
368my $dockerreg = shift || undef;
369my $docrepo = "";
370my ($scheme, $account, $host, $port, $path) = pb_get_uri($dockerreg);
371$docrepo .= $host;
372$docrepo .= ":$port" if ((defined $port) && ($port ne ""));
373$docrepo .= "$path";
374return($docrepo);
375}
376
377=head1 WEB SITES
378
379The main Web site of the project is available at L<http://www.project-builder.org/>. Bug reports should be filled using the trac instance of the project at L<http://trac.project-builder.org/>.
380
381=head1 USER MAILING LIST
382
383None exists for the moment.
384
385=head1 AUTHORS
386
387The Project-Builder.org team L<http://trac.project-builder.org/> lead by Bruno Cornec L<mailto:bruno@project-builder.org>.
388
389=head1 COPYRIGHT
390
391Project-Builder.org is distributed under the GPL v2.0 license
392described in the file C<COPYING> included with the distribution.
393
394=cut
395
396
3971;
Note: See TracBrowser for help on using the repository browser.