]> git.proxmox.com Git - dab.git/blob - dab
add help and output all available commands
[dab.git] / dab
1 #!/usr/bin/perl -w
2
3 use strict;
4 use warnings;
5
6 use Getopt::Long;
7
8 use PVE::DAB;
9
10 $ENV{'LC_ALL'} = 'C';
11
12 my $commands = {
13 'init' => '',
14 'bootstrap' => '[--exim] [--minimal]',
15 'finalize' => '[--keepmycnf]',
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
29 sub 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
46 if (scalar (@ARGV) == 0) {
47 print_usage("no command specified");
48 exit (-1);
49 }
50
51 my $cmdline = join (' ', @ARGV);
52 my $cmd = shift @ARGV;
53
54 if (!$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
65 my $dab;
66 sub dab() {
67 $dab = PVE::DAB->new() if !$dab;
68 return $dab;
69 }
70
71 dab->writelog ("dab: $cmdline\n");
72
73 $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = sub {
74 die "interrupted by signal\n";
75 };
76
77 eval {
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')) {
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 };
229 if (my $err = $@) {
230 $dab->logmsg ($@);
231 die ($@);
232 }
233
234 exit 0;
235
236 __END__
237
238 =head1 NAME
239
240 dab - 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
250 Downloads the package descriptions form the repository. Also truncates the
251 C<logfile>.
252
253 =item B<dab bootstrap>
254
255 Bootstrap a debian system and allocate a temporary container (we use IDs 90000
256 and above).
257
258 =over
259
260 =item I<--exim>
261
262 Use exim as MTA (we use postfix by default)
263
264 =item I<--minimal>
265
266 Do not install standard packages.
267
268 =back
269
270 =item B<dab veid>
271
272 Print used container ID.
273
274 =item B<dab basedir>
275
276 Print container private directory.
277
278 =item B<dab packagefile>
279
280 Print the appliance file name.
281
282 =item B<dab install I<pkg ...>>
283
284 Install 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 are
286 automatically installed.
287
288 =item B<dab unpack I<pkg ...>>
289
290 Unpack one or more packages. I<pkg> can also refer to a file named
291 C<xyz.pkglist> which contains a list of packages. All dependencies are
292 automatically unpacked.
293
294 =item B<dab exec I<CMD> I<ARGS>>
295
296 Executes command CMD inside the container.
297
298 =item B<dab enter>
299
300 Calls C<lxc-attach> - this is for debugging only.
301
302 =item B<dab task mysql>
303
304 Install a mysql database server. During appliance generation we use C<admin> as
305 mysql root password (also stored in /root/.my.cnf).
306
307 =over
308
309 =item I<--password=XXX>
310
311 Specify the mysql root password. The special value C<random> can be use to
312 generate a random root password when the appliance is started first time
313 (stored in /root/.my.cnf)
314
315 =item I<--start>
316
317 Start the mysql server (if you want to execute sql commands during
318 appliance generation).
319
320 =back
321
322 =item B<dab task postgres>
323
324 Install a postgres database server.
325
326 =over
327
328 =item I<--version=XXX>
329
330 Select Postgres version. Posible values are C<7.4>, C<8.1> and C<8.3> (depends
331 on the selected suite).
332
333 =item I<--start>
334
335 Start the postgres server (if you want to execute sql commands during appliance
336 generation).
337
338 =back
339
340 =item B<dab task php>
341
342 Install php5.
343
344 =over
345
346 =item I<--memlimit=i>
347
348 Set the php I<memory_limit>.
349
350 =back
351
352 =item B<dab finalize>
353
354 Cleanup everything inside the container and generate the final appliance
355 package.
356
357 =over
358
359 =item I<--keepmycnf>
360
361 Do not delete file C</root/.my.cfg> (mysql).
362
363 =back
364
365 =item B<dab list>
366
367 List installed packages.
368
369 =over
370
371 =item I<--verbose>
372
373 Also print package versions.
374
375 =back
376
377 =item B<dab clean>
378
379 Remove all temporary files and destroy the container.
380
381 =item B<dab dist-clean>
382
383 Like clean, but also removes the package cache (except when you specified your
384 own cache directory in the config file)
385
386 =back
387
388 =head1 DESCRIPTION
389
390 dab is a script to automate the creation of LXC appliances. It is basically a
391 rewrite of debootstrap in perl, but uses LXC instead of chroot and generates
392 LXC templates. Another difference is that it supports multi-stage building of
393 templates. That way you can execute arbitrary scripts between to accomplish
394 what you want.
395
396 Furthermore some common tasks are fully automated, like setting up a database
397 server (mysql or postgres).
398
399 To accomplish minimal template creation time, packages are cached to a local
400 directory, so you do not need a local debian mirror (although this would speed
401 up the first run).
402
403 See http://pve.proxmox.com/wiki/Debian_Appliance_Builder for examples.
404
405 This script need to be run as root, so it is not recommended to start it on a
406 production machine with running containers. So many people run Proxmox VE
407 inside a KVM or VMWare 64bit virtual machine to build appliances.
408
409 All generated templates includes an appliance description file. Those can be
410 used to build appliance repositories.
411
412 =head1 CONFIGURATION
413
414 Configuration is read from the file C<dab.conf> inside the current working
415 directory. 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
421 The Debian or Ubuntu suite.
422
423 =item B<Source:> I<URL [components]>
424
425 Defines 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
430 Note: SUITE is a variable and will be substituted.
431
432 There are also reasonable defaults for Ubuntu. If you do not specify any source
433 the defaults are used.
434
435 =item B<Depends:> I<dependencies>
436
437 Debian like package dependencies. This can be used to make sure that speific
438 package versions are available.
439
440 =item B<CacheDir>: I<path>
441
442 Allows you to specify the directory where downloaded packages are cached.
443
444 =item B<Mirror:> I<SRCURL> => I<DSTURL>
445
446 Define a mirror location. for example:
447
448 Mirror: http://ftp.debian.org/debian => ftp://mirror/debian
449
450 =back
451
452 All other settings in this files are also included into the appliance
453 description file.
454
455 =over 2
456
457 =item B<Name:> I<name>
458
459 The name of the appliance.
460
461 Appliance names must consist only of lower case letters (a-z), digits (0-9),
462 plus (+) and minus (-) signs, and periods (.). They must be at least two
463 characters long and must start with an alphanumeric character.
464
465 =item B<Architecture:> I<i386|amd64>
466
467 Target architecture.
468
469 =item B<Version:> I<upstream_version[-build_revision]>
470
471 The version number of an appliance.
472
473 =item: B<Section:> I<section>
474
475 This field specifies an application area into which the appliance has been
476 classified. Currently we use the following section names: system, mail
477
478 =item B<Maintainer:> I<name <email>>
479
480 The appliance maintainer's name and email address. The name should come first,
481 then the email address inside angle brackets <> (in RFC822 format).
482
483 =item B<Infopage:> I<URL>
484
485 Link to web page containing more informations about this appliance.
486
487 =item B<Description:> I<single line synopsis>
488
489 extended description over several lines (indended by space) may follow.
490
491 =back
492
493 =head1 Appliance description file
494
495 All generated templates includes an appliance description file called
496
497 /etc/appliance.info
498
499 this is the first file inside the tar archive. That way it can be easily
500 exctracted without scanning the whole archive. The file itself contains
501 informations like a debian C<control> file. It can be used to build appliance
502 repositories.
503
504 Most fields are directly copied from the configuration file C<dab.conf>.
505
506 Additionally there are some auto-generated files:
507
508 =over
509
510 =item B<Installed-Size:> I<bytes>
511
512 It gives the total amount of disk space required to install the named
513 appliance. The disk space is represented in megabytes as a simple decimal
514 number.
515
516 =item B<Type:> I<type>
517
518 This is always C<lxc>.
519
520 =item B<OS:> I<[debian-4.0|debian-5.0|ubuntu-8.0]>
521
522 Operation system.
523
524 =back
525
526 Appliance repositories usually add additional fields:
527
528 =over
529
530 =item B<md5sum:> I<md5sum>
531
532 MD5 checksum
533
534 =back
535
536 =head1 FILES
537
538 The 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
552 Dietmar Maurer <dietmar@proxmox.com>
553
554 Many thanks to Proxmox Server Solutions (www.proxmox.com) for sponsoring this
555 work.
556
557 =head1 COPYRIGHT AND DISCLAIMER
558
559 Copyright (C) 2007-2020 Proxmox Server Solutions GmbH
560
561 Copyright: dab is under GNU GPL, the GNU General Public License.
562
563 This program is free software; you can redistribute it and/or modify
564 it under the terms of the GNU General Public License as published by
565 the Free Software Foundation; version 2 dated June, 1991.
566
567 This program is distributed in the hope that it will be useful,
568 but WITHOUT ANY WARRANTY; without even the implied warranty of
569 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
570 GNU General Public License for more details.
571
572 You should have received a copy of the GNU General Public License
573 along with this program; if not, write to the
574 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
575 MA 02110-1301, USA.