]> git.proxmox.com Git - dab.git/blame - dab
bump version to 3.3-1
[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
DM
29sub print_usage {
30 my ($msg) = @_;
31
32 if ($msg) {
300bd06d 33 print STDERR "\nERROR: $msg\n\n";
8ab34b87 34 }
300bd06d 35 print STDERR "USAGE: dab <command> [parameters]\n\n";
8ab34b87 36
300bd06d
TL
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}
8ab34b87
DM
45
46if (scalar (@ARGV) == 0) {
300bd06d 47 print_usage("no command specified");
8ab34b87
DM
48 exit (-1);
49}
50
51my $cmdline = join (' ', @ARGV);
8ab34b87
DM
52my $cmd = shift @ARGV;
53
54if (!$cmd) {
55 print_usage("no command specified");
56 exit (-1);
300bd06d
TL
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);
8ab34b87
DM
63}
64
300bd06d
TL
65my $dab;
66sub dab() {
67 $dab = PVE::DAB->new() if !$dab;
68 return $dab;
69}
8ab34b87 70
300bd06d 71dab->writelog ("dab: $cmdline\n");
8ab34b87
DM
72
73$SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = sub {
74 die "interrupted by signal\n";
75};
76
77eval {
8ab34b87 78 if ($cmd eq 'init') {
8ab34b87
DM
79 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
80
300bd06d 81 dab->initialize();
8ab34b87
DM
82
83 } elsif ($cmd eq 'bootstrap') {
8ab34b87 84 my $opts = {};
8ab34b87 85 if (!GetOptions ($opts, 'exim', 'minimal')) {
300bd06d 86 print_usage();
8ab34b87
DM
87 exit (-1);
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')) {
300bd06d 97 print_usage();
8ab34b87
DM
98 exit (-1);
99 }
8ab34b87
DM
100 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
101
102 $dab->finalize($opts);
103
104 } elsif ($cmd eq 'veid') {
8ab34b87
DM
105 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
106
107 print $dab->{veid} . "\n";
108
109 } elsif ($cmd eq 'basedir') {
8ab34b87
DM
110 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
111
f0134ed2 112 print $dab->{rootfs} . "\n";
8ab34b87
DM
113
114 } elsif ($cmd eq 'packagefile') {
8ab34b87
DM
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') {
8ab34b87 120 my $verbose;
8ab34b87 121 if (!GetOptions ('verbose' =>\$verbose)) {
300bd06d 122 print_usage();
8ab34b87
DM
123 exit (-1);
124 }
8ab34b87
DM
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') {
8ab34b87 139 my $task = shift @ARGV;
8ab34b87 140 if (!$task) {
300bd06d 141 print_usage("no task specified");
8ab34b87
DM
142 exit (-1);
143 }
144
145 my $opts = {};
8ab34b87 146 if ($task eq 'mysql') {
8ab34b87 147 if (!GetOptions ($opts, 'password=s', 'start')) {
300bd06d 148 print_usage();
8ab34b87
DM
149 exit (-1);
150 }
8ab34b87
DM
151 die "task '$task' expects no arguments.\n" if scalar (@ARGV) != 0;
152
153 $dab->task_mysql ($opts);
8ab34b87 154
300bd06d 155 } elsif ($task eq 'postgres') {
8ab34b87 156 if (!GetOptions ($opts, 'version=s', 'start')) {
300bd06d 157 print_usage();
8ab34b87
DM
158 exit (-1);
159 }
8ab34b87
DM
160 die "task '$task' expects no arguments.\n" if scalar (@ARGV) != 0;
161
162 $dab->task_postgres ($opts);
163
164 } elsif ($task eq 'php') {
8ab34b87 165 if (!GetOptions ($opts, 'memlimit=i')) {
300bd06d 166 print_usage();
8ab34b87
DM
167 exit (-1);
168 }
8ab34b87
DM
169 die "task '$task' expects no arguments.\n" if scalar (@ARGV) != 0;
170
171 $dab->task_php ($opts);
300bd06d 172
8ab34b87 173 } else {
300bd06d 174 print_usage("unknown task '$task'");
8ab34b87
DM
175 exit (-1);
176
177 }
178
179 } elsif ($cmd eq 'install' || $cmd eq 'unpack') {
8ab34b87
DM
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') {
8ab34b87
DM
209 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
210
211 $dab->enter();
212
213 } elsif ($cmd eq 'clean') {
8ab34b87
DM
214 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
215
300bd06d 216 $dab->cleanup(0);
8ab34b87
DM
217
218 } elsif ($cmd eq 'dist-clean') {
8ab34b87
DM
219 die "command '$cmd' expects no arguments.\n" if scalar (@ARGV) != 0;
220
300bd06d 221 $dab->cleanup(1);
8ab34b87
DM
222
223 } else {
300bd06d 224 print_usage("invalid command '$cmd'");
8ab34b87
DM
225 exit (-1);
226 }
227
228};
8ab34b87
DM
229if (my $err = $@) {
230 $dab->logmsg ($@);
231 die ($@);
232}
233
234exit 0;
235
236__END__
237
238=head1 NAME
300bd06d 239
f0134ed2 240dab - Debian LXC Appliance Builder
8ab34b87
DM
241
242=head1 SYNOPSIS
243
244=over
245
246=item B<dab> I<command> I<[OPTIONS]>
247
248=item B<dab init>
249
300bd06d
TL
250Downloads the package descriptions form the repository. Also truncates the
251C<logfile>.
8ab34b87
DM
252
253=item B<dab bootstrap>
254
300bd06d
TL
255Bootstrap a debian system and allocate a temporary container (we use IDs 90000
256and above).
8ab34b87
DM
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
300bd06d
TL
285C<xyz.pkglist> which contains a list of packages. All dependencies are
286automatically installed.
8ab34b87
DM
287
288=item B<dab unpack I<pkg ...>>
289
290Unpack one or more packages. I<pkg> can also refer to a file named
300bd06d
TL
291C<xyz.pkglist> which contains a list of packages. All dependencies are
292automatically unpacked.
8ab34b87
DM
293
294=item B<dab exec I<CMD> I<ARGS>>
295
296Executes command CMD inside the container.
297
298=item B<dab enter>
299
f0134ed2 300Calls C<lxc-attach> - this is for debugging only.
8ab34b87
DM
301
302=item B<dab task mysql>
303
300bd06d
TL
304Install a mysql database server. During appliance generation we use C<admin> as
305mysql root password (also stored in /root/.my.cnf).
8ab34b87
DM
306
307=over
308
309=item I<--password=XXX>
310
300bd06d
TL
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)
8ab34b87
DM
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
300bd06d
TL
330Select Postgres version. Posible values are C<7.4>, C<8.1> and C<8.3> (depends
331on the selected suite).
8ab34b87
DM
332
333=item I<--start>
334
300bd06d
TL
335Start the postgres server (if you want to execute sql commands during appliance
336generation).
8ab34b87
DM
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
300bd06d
TL
354Cleanup everything inside the container and generate the final appliance
355package.
8ab34b87
DM
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.
300bd06d 368
8ab34b87
DM
369=over
370
371=item I<--verbose>
372
373Also print package versions.
374
375=back
376
377=item B<dab clean>
378
f0134ed2 379Remove all temporary files and destroy the container.
8ab34b87
DM
380
381=item B<dab dist-clean>
382
300bd06d
TL
383Like clean, but also removes the package cache (except when you specified your
384own cache directory in the config file)
8ab34b87
DM
385
386=back
387
8ab34b87
DM
388=head1 DESCRIPTION
389
300bd06d
TL
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.
8ab34b87 395
300bd06d
TL
396Furthermore some common tasks are fully automated, like setting up a database
397server (mysql or postgres).
8ab34b87 398
300bd06d
TL
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).
8ab34b87
DM
402
403See http://pve.proxmox.com/wiki/Debian_Appliance_Builder for examples.
404
300bd06d
TL
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.
8ab34b87 408
300bd06d
TL
409All generated templates includes an appliance description file. Those can be
410used to build appliance repositories.
8ab34b87
DM
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
3a9c8648 419=item B<Suite:> I<squeeze|wheezy|jessie|trusty|vivid>
8ab34b87
DM
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
300bd06d
TL
432There are also reasonable defaults for Ubuntu. If you do not specify any source
433the defaults are used.
8ab34b87
DM
434
435=item B<Depends:> I<dependencies>
436
300bd06d
TL
437Debian like package dependencies. This can be used to make sure that speific
438package versions are available.
8ab34b87
DM
439
440=item B<CacheDir>: I<path>
441
300bd06d 442Allows you to specify the directory where downloaded packages are cached.
8ab34b87
DM
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
300bd06d 459The name of the appliance.
8ab34b87 460
300bd06d
TL
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.
8ab34b87
DM
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
300bd06d
TL
475This field specifies an application area into which the appliance has been
476classified. Currently we use the following section names: system, mail
8ab34b87
DM
477
478=item B<Maintainer:> I<name <email>>
479
300bd06d
TL
480The appliance maintainer's name and email address. The name should come first,
481then the email address inside angle brackets <> (in RFC822 format).
8ab34b87
DM
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
300bd06d 489extended description over several lines (indended by space) may follow.
8ab34b87
DM
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
300bd06d
TL
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.
8ab34b87
DM
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
300bd06d
TL
513appliance. The disk space is represented in megabytes as a simple decimal
514number.
8ab34b87
DM
515
516=item B<Type:> I<type>
517
f0134ed2 518This is always C<lxc>.
8ab34b87
DM
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
300bd06d 549
8ab34b87
DM
550=head1 AUTHOR
551
552Dietmar Maurer <dietmar@proxmox.com>
553
300bd06d
TL
554Many thanks to Proxmox Server Solutions (www.proxmox.com) for sponsoring this
555work.
8ab34b87
DM
556
557=head1 COPYRIGHT AND DISCLAIMER
558
300bd06d 559Copyright (C) 2007-2020 Proxmox Server Solutions GmbH
8ab34b87
DM
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.