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