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