]> git.proxmox.com Git - dab.git/blob - dab
add support for ubuntu 18.04 (bionic beaver)
[dab.git] / dab
1 #!/usr/bin/perl -w
2
3 use strict;
4 use Getopt::Long;
5 use PVE::DAB;
6
7 $ENV{'LC_ALL'} = 'C';
8
9 sub print_usage {
10 my ($msg) = @_;
11
12 if ($msg) {
13 print STDERR "ERROR: $msg\n";
14 }
15 print STDERR "dab <command> [parameters]\n";
16 }
17
18
19 if (scalar (@ARGV) == 0) {
20 print_usage ();
21 exit (-1);
22 }
23
24 my $cmdline = join (' ', @ARGV);
25
26 my $cmd = shift @ARGV;
27
28 if (!$cmd) {
29 print_usage("no command specified");
30 exit (-1);
31 }
32
33 my $dab = PVE::DAB->new();
34
35 $dab->writelog ("dab: $cmdline\n");
36
37 $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = sub {
38 die "interrupted by signal\n";
39 };
40
41 eval {
42
43 if ($cmd eq 'init') {
44
45 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
46
47 $dab->initialize();
48
49 } elsif ($cmd eq 'bootstrap') {
50
51 my $opts = {};
52
53 if (!GetOptions ($opts, 'exim', 'minimal')) {
54 print_usage ();
55 exit (-1);
56 }
57
58 die "command 'bootstrap' expects no arguments.\n" if scalar (@ARGV) != 0;
59
60 $dab->ve_init();
61
62 $dab->bootstrap ($opts);
63
64 } elsif ($cmd eq 'finalize') {
65
66 my $opts = {};
67
68 if (!GetOptions ($opts, 'keepmycnf')) {
69 print_usage ();
70 exit (-1);
71 }
72
73 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
74
75 $dab->finalize($opts);
76
77 } elsif ($cmd eq 'veid') {
78
79 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
80
81 print $dab->{veid} . "\n";
82
83 } elsif ($cmd eq 'basedir') {
84
85 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
86
87 print $dab->{rootfs} . "\n";
88
89 } elsif ($cmd eq 'packagefile') {
90
91 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
92
93 print "$dab->{targetname}.tar.gz\n";
94
95 } elsif ($cmd eq 'list') {
96
97 my $verbose;
98
99 if (!GetOptions ('verbose' =>\$verbose)) {
100 print_usage ();
101 exit (-1);
102 }
103
104 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
105
106 my $instpkgs = $dab->read_installed ();
107
108 foreach my $pkg (sort keys %$instpkgs) {
109 if ($verbose) {
110 my $version = $instpkgs->{$pkg}->{version};
111 print "$pkg $version\n";
112 } else {
113 print "$pkg\n";
114 }
115 }
116
117 } elsif ($cmd eq 'task') {
118
119 my $task = shift @ARGV;
120
121 if (!$task) {
122 print_usage ("no task specified");
123 exit (-1);
124 }
125
126 my $opts = {};
127
128 if ($task eq 'mysql') {
129
130 if (!GetOptions ($opts, 'password=s', 'start')) {
131 print_usage ();
132 exit (-1);
133 }
134
135 die "task '$task' expects no arguments.\n" if scalar (@ARGV) != 0;
136
137 $dab->task_mysql ($opts);
138
139 } elsif ($task eq 'postgres') {
140
141 if (!GetOptions ($opts, 'version=s', 'start')) {
142 print_usage ();
143 exit (-1);
144 }
145
146 die "task '$task' expects no arguments.\n" if scalar (@ARGV) != 0;
147
148 $dab->task_postgres ($opts);
149
150 } elsif ($task eq 'php') {
151
152 if (!GetOptions ($opts, 'memlimit=i')) {
153 print_usage ();
154 exit (-1);
155 }
156
157 die "task '$task' expects no arguments.\n" if scalar (@ARGV) != 0;
158
159 $dab->task_php ($opts);
160
161 } else {
162
163 print_usage ("unknown task '$task'");
164 exit (-1);
165
166 }
167
168 } elsif ($cmd eq 'install' || $cmd eq 'unpack') {
169
170 my $required;
171 foreach my $arg (@ARGV) {
172 if ($arg =~ m/\.pkglist$/) {
173 open (TMP, $arg) ||
174 die "cant open package list '$arg' - $!";
175 while (defined (my $line = <TMP>)) {
176 chomp $line;
177 next if $line =~ m/^\s*$/;
178 next if $line =~ m/\#/;
179 if ($line =~ m/^\s*(\S+)\s*$/) {
180 push @$required, $1;
181 } else {
182 die "invalid package name in '$arg' - $line\n";
183 }
184 }
185 } else {
186 push @$required, $arg;
187 }
188
189 close (TMP);
190 }
191
192 $dab->install ($required, $cmd eq 'unpack');
193
194 } elsif ($cmd eq 'exec') {
195
196 $dab->ve_exec (@ARGV);
197
198 } elsif ($cmd eq 'enter') {
199
200 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
201
202 $dab->enter();
203
204 } elsif ($cmd eq 'clean') {
205
206 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
207
208 $dab->cleanup (0);
209
210 } elsif ($cmd eq 'dist-clean') {
211
212 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
213
214 $dab->cleanup (1);
215
216 } else {
217 print_usage ("invalid command '$cmd'");
218 exit (-1);
219 }
220
221 };
222
223 if (my $err = $@) {
224 $dab->logmsg ($@);
225 die ($@);
226 }
227
228 exit 0;
229
230 __END__
231
232 =head1 NAME
233
234 dab - Debian LXC Appliance Builder
235
236 =head1 SYNOPSIS
237
238 =over
239
240 =item B<dab> I<command> I<[OPTIONS]>
241
242 =item B<dab init>
243
244 Downloads the package descriptions form the
245 repository. Also truncates the C<logfile>.
246
247 =item B<dab bootstrap>
248
249 Bootstrap a debian system and allocate a
250 temporary container (we use IDs 90000 and above).
251
252 =over
253
254 =item I<--exim>
255
256 Use exim as MTA (we use postfix by default)
257
258 =item I<--minimal>
259
260 Do not install standard packages.
261
262 =back
263
264 =item B<dab veid>
265
266 Print used container ID.
267
268 =item B<dab basedir>
269
270 Print container private directory.
271
272 =item B<dab packagefile>
273
274 Print the appliance file name.
275
276 =item B<dab install I<pkg ...>>
277
278 Install one or more packages. I<pkg> can also refer to a file named
279 C<xyz.pkglist> which contains a list of packages. All dependencies
280 are automatically installed.
281
282 =item B<dab unpack I<pkg ...>>
283
284 Unpack one or more packages. I<pkg> can also refer to a file named
285 C<xyz.pkglist> which contains a list of packages. All dependencies
286 are automatically unpacked.
287
288 =item B<dab exec I<CMD> I<ARGS>>
289
290 Executes command CMD inside the container.
291
292 =item B<dab enter>
293
294 Calls C<lxc-attach> - this is for debugging only.
295
296 =item B<dab task mysql>
297
298 Install a mysql database server. During appliance generation we use
299 C<admin> as mysql root password (also stored in /root/.my.cnf).
300
301 =over
302
303 =item I<--password=XXX>
304
305 Specify the mysql root password. The special value C<random> can be
306 use to generate a random root password when the appliance is started
307 first time (stored in /root/.my.cnf)
308
309 =item I<--start>
310
311 Start the mysql server (if you want to execute sql commands during
312 appliance generation).
313
314 =back
315
316 =item B<dab task postgres>
317
318 Install a postgres database server.
319
320 =over
321
322 =item I<--version=XXX>
323
324 Select Postgres version. Posible values are C<7.4>, C<8.1> and C<8.3>
325 (depends on the selected suite).
326
327 =item I<--start>
328
329 Start the postgres server (if you want to execute sql commands during
330 appliance generation).
331
332 =back
333
334 =item B<dab task php>
335
336 Install php5.
337
338 =over
339
340 =item I<--memlimit=i>
341
342 Set the php I<memory_limit>.
343
344 =back
345
346 =item B<dab finalize>
347
348 Cleanup everything inside the container and generate the final
349 appliance package.
350
351 =over
352
353 =item I<--keepmycnf>
354
355 Do not delete file C</root/.my.cfg> (mysql).
356
357 =back
358
359 =item B<dab list>
360
361 List installed packages.
362
363 =over
364
365 =item I<--verbose>
366
367 Also print package versions.
368
369 =back
370
371 =item B<dab clean>
372
373 Remove all temporary files and destroy the container.
374
375 =item B<dab dist-clean>
376
377 Like clean, but also removes the package cache (except when you
378 specified your own cache directory in the config file)
379
380 =back
381
382 =head1 DESCRIPTION
383
384 dab is a script to automate the creation of LXC appliances. It is
385 basically a rewrite of debootstrap in perl, but uses LXC instead of
386 chroot and generates LXC templates. Another difference is that it
387 supports multi-stage building of templates. That way you can execute
388 arbitrary scripts between to accomplish what you want.
389
390 Furthermore some common tasks are fully automated, like setting up a
391 database server (mysql or postgres).
392
393 To accomplish minimal template creation time, packages are cached to a
394 local directory, so you do not need a local debian mirror (although
395 this would speed up the first run).
396
397 See http://pve.proxmox.com/wiki/Debian_Appliance_Builder for examples.
398
399 This script need to be run as root, so it is not recommended to start
400 it on a production machine with running containers. So many people run
401 Proxmox VE inside a KVM or VMWare 64bit virtual machine to build
402 appliances.
403
404 All generated templates includes an appliance description file. Those
405 can be used to build appliance repositories.
406
407 =head1 CONFIGURATION
408
409 Configuration is read from the file C<dab.conf> inside the current working
410 directory. The files contains key value pairs, separated by colon.
411
412 =over 2
413
414 =item B<Suite:> I<squeeze|wheezy|jessie|trusty|vivid>
415
416 The Debian or Ubuntu suite.
417
418 =item B<Source:> I<URL [components]>
419
420 Defines a source location. By default we use the following for debian:
421
422 Source: http://ftp.debian.org/debian SUITE main contrib
423 Source: http://security.debian.org SUITE/updates main contrib
424
425 Note: SUITE is a variable and will be substituted.
426
427 There are also reasonable defaults for Ubuntu. If you do not specify
428 any source the defaults are used.
429
430 =item B<Depends:> I<dependencies>
431
432 Debian like package dependencies. This can be used to make sure that
433 speific package versions are available.
434
435 =item B<CacheDir>: I<path>
436
437 Allows you to specify the directory where downloaded packages are
438 cached.
439
440 =item B<Mirror:> I<SRCURL> => I<DSTURL>
441
442 Define a mirror location. for example:
443
444 Mirror: http://ftp.debian.org/debian => ftp://mirror/debian
445
446 =back
447
448 All other settings in this files are also included into the appliance
449 description file.
450
451 =over 2
452
453 =item B<Name:> I<name>
454
455 The name of the appliance.
456
457 Appliance names must consist only of lower case letters (a-z), digits
458 (0-9), plus (+) and minus (-) signs, and periods (.). They must be at
459 least two characters long and must start with an alphanumeric
460 character.
461
462 =item B<Architecture:> I<i386|amd64>
463
464 Target architecture.
465
466 =item B<Version:> I<upstream_version[-build_revision]>
467
468 The version number of an appliance.
469
470 =item: B<Section:> I<section>
471
472 This field specifies an application area into which the appliance has
473 been classified. Currently we use the following section names: system,
474 admin, www
475
476 =item B<Maintainer:> I<name <email>>
477
478 The appliance maintainer's name and email address. The name should
479 come first, then the email address inside angle brackets <> (in RFC822
480 format).
481
482 =item B<Infopage:> I<URL>
483
484 Link to web page containing more informations about this appliance.
485
486 =item B<Description:> I<single line synopsis>
487
488 extended description over several lines (indended by space) may follow.
489
490 =back
491
492 =head1 Appliance description file
493
494 All generated templates includes an appliance description file called
495
496 /etc/appliance.info
497
498 this is the first file inside the tar archive. That way it can be
499 easily exctracted without scanning the whole archive. The file itself
500 contains informations like a debian C<control> file. It can be used to
501 build appliance repositories.
502
503 Most fields are directly copied from the configuration file C<dab.conf>.
504
505 Additionally there are some auto-generated files:
506
507 =over
508
509 =item B<Installed-Size:> I<bytes>
510
511 It gives the total amount of disk space required to install the named
512 appliance. The disk space is represented in megabytes as a simple
513 decimal number.
514
515 =item B<Type:> I<type>
516
517 This is always C<lxc>.
518
519 =item B<OS:> I<[debian-4.0|debian-5.0|ubuntu-8.0]>
520
521 Operation system.
522
523 =back
524
525 Appliance repositories usually add additional fields:
526
527 =over
528
529 =item B<md5sum:> I<md5sum>
530
531 MD5 checksum
532
533 =back
534
535 =head1 FILES
536
537 The following files are created inside your working directory:
538
539 dab.conf appliance configuration file
540
541 logfile contains installation logs
542
543 .veid stores the used container ID
544
545 cache/* default package cache directory
546
547 info/* package information cache
548
549 =head1 AUTHOR
550
551 Dietmar Maurer <dietmar@proxmox.com>
552
553 Many thanks to Proxmox Server Solutions (www.proxmox.com) for sponsoring
554 this work.
555
556 =head1 COPYRIGHT AND DISCLAIMER
557
558 Copyright (C) 2007-2012 Proxmox Server Solutions GmbH
559
560 Copyright: dab is under GNU GPL, the GNU General Public License.
561
562 This program is free software; you can redistribute it and/or modify
563 it under the terms of the GNU General Public License as published by
564 the Free Software Foundation; version 2 dated June, 1991.
565
566 This program is distributed in the hope that it will be useful,
567 but WITHOUT ANY WARRANTY; without even the implied warranty of
568 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
569 GNU General Public License for more details.
570
571 You should have received a copy of the GNU General Public License
572 along with this program; if not, write to the
573 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
574 MA 02110-1301, USA.