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