This file contains important information about how pkgsync works --
please at least skim it, or you will probably break your system quite
thoroughly. :-)

1. Introduction

pkgsync is an automated tool to keep multiple Debian machines more or
less in sync with regard to what packages are installed, primarily based
on aptitude functionality. Every night (run from cron.daily), it scans
the system for packages, making sure packages that are supposed to be
installed are installed, and packages that shouldn't be installed are
removed. In addition, it does a full dist-upgrade; in other words, one
could think of it as an `extended cron-apt'.

2. General mode of operation

pkgsync doesn't need any command-line options, and one usually won't need them
except for testing. See section 2.1 for a complete list of options.

pkgsync bases itself on three lists in the directory /etc/pkgsync. These are
not included, and you must create them yourself; the usual way of distributing
these files would be via rdist or cfengine (or any other method you choose, or
course) from a central location. If they do not exist, pkgsync will exit with
an error (see below).

The lists, in plain text format, are:

- `musthave' -- packages that are to be available on all machines. Your
  favourite window manager (if you're running X), editor and other
  critical tools (sl, perhaps?) go here. Packages that are in `musthave'
  but not on the system will be installed when pkgsync runs.
- `mayhave' -- packages that won't be removed, but not automatically
  installed either. A typical example would be when you have only one
  machine with a sound card and want it to have xmms, but you don't need
  it on the others. Other prime candidates are kernel images (one
  machine might need -k7 kernels, another might want -686 kernels, etc.)
  and things that aren't in the standard Debian repositories. This list
  could probably be empty if you're using e.g. cfengine's class system,
  which is a lot more powerful than using such a list.
- `maynothave' -- packages that aren't to be on any machines (like ppp
  or pcmcia-cs if you don't use those packages; they are installed by
  default on most Debian machines). Packages that are in `maynothave'
  but are present on the system will be explicitly removed.

See /usr/share/doc/pkgsync/ for bare-bones example files.

Blank lines and comments (lines starting with #) are ignored; simple glob
patterns (as matched by dpkg-query -- ie. [], * and ?, but not {}) are
supported, and could probably be useful in the `mayhave' list. Note that
if a package is in multiple lists, the results are somewhat undefined --
you can safely have a package in both musthave and mayhave, though.

See sections 2.1 and 2.2 for information on special pattern types.

pkgsync works by translating the package lists into a series of requests
to aptitude; one should keep in mind that (from pkgsync 1.9 onwards) everything
is done in a single aptitude operation, so if the lists are inconsistent,
aptitude's dependency resolver might pick suboptimal states for your system.

Besides setting the system in the state dictated by the package list, pkgsync
also attempts to remove cruft (unless the --keep-unused flag is given; see
section 2.1 below). Everything that is not in `musthave' or `mayhave' or in at
least one such package's dependency chain (as determined by aptitude) will be
automatically removed (see Caveats below), but not purged. It is recommended
that you run pkgsync manually at least once when you install it on a new
machine, so you avoid nasty surprises.

Last but not least, pkgsync also does a full dist-upgrade in the process.

If any step along the way returns an error, pkgsync aborts and prints
out its entire log to stdout. This will usually make cron send an error
mail. Note that there are several conditions which are not regarded as
"errors" by aptitude (such as non-existant packages).

2.1. Command-line options

pkgsync supports the current command line options:

  -h or --help: Print a short help text and exit.
  
  -s or --simulate: Do everything as usual, but put aptitude in simulation
  mode, causing it to never do any changes (except update and autoclean, which
  should both be harmless) to your system. This is especially useful on a new
  system to make sure pkgsync behaves as expected.

  Note that aptitude prints out its intended actions _before_ running the
  conflict resolver. If there's a conflict somewhere, chances are that the
  results on your system will be different from what aptitude prints out.

  -k or --keep-unused: Instruct aptitude to not remove cruft (ie. unused
  packages); this is morally equivalent to having an "*" entry in mayhave.

2.2. debtags patterns

Starting with pkgsync 1.4, pkgsync supports the debtags system by Enrico
Zini and others. Instead of writing a package name, you can write 
"debtags:pattern" where "pattern" is a pattern that is expanded by
"debtags grep". This can be useful both with the standard set of tags
(to do "debtags:( protocol::irc && use::chatting )" in maynothave to
forcibly remove all IRC clients from the system, if you think that's
useful), or with personal tags, so you can add something like
"debtags:sesse::must-have" in musthave on all your systems to make sure
your personal pet packages are everywhere.

2.3. Meta-patterns

Similar to the debtags patterns above, pkgsync support special patterns
starting with "meta:". Currently, only one is recognized, namely
"meta:current-kernel". This tries to match any kernel packages for the
currently running kernel, and is usually a good idea to have in mayhave
even if you already have a specific kernel in musthave (the kernel
packages are not very fond of being removed while the kernel is still
running).

The syntax for meta-patterns is not fixed yet -- it's not unlikely that
pkgsync will move to a different model in the future.

3. Caveats

Note that there are a lot of packages aptitude will happily remove if
you don't add them to `musthave' or `mayhave', but that your system (or
at least pkgsync) probably can't live without. Non-obvious examples are
lilo/grub, aptitude, pkgsync itself (and debtags and/or cfengine if you use
those), sysklogd, console-tools and kernel images.

You may want to think of the security implications by doing unattended
upgrades. Please do not run pkgsync on critical infrastructure; it is
mainly intended to keep workstations etc. in OK shape.

Depending on your setup, pkgsync may or may not work with the signing
procedures in apt 0.6 and above. (Signed repositories will definitely
reduce the risk of a man-in-the-middle attack, though; however, remember
that if you're using debtags, the public debtags repository is writable by
everyone.) The most common problem seems to be that apt insists on asking
manually whenever you want to install an untrusted package, causing
infinite loops and full disks since pkgsync has to provide an endless
stream of "n" responses to dpkg's standard conffile handling. There is
currently no provision in apt for marking some repositories as implicitly
trusted; you can trust unsigned repositories, or you can make sure you
only use signed, trusted repositories. The choice is yours.

pkgsync configures all packages in noninteractive mode. You may probably
want to setup some kind of central debconf system (LDAP, for instance)
if you want more control of the package configuration. Also, it answers
"n" to all conffile override questions, which will probably also break
packages that don't use debconf for input (see above)... A better way of
doing this would of course be welcome, but fortunately such packages are
becoming increasingly rare.

4. cfengine2 example setup

We use the following cfengine setup to distribute and assemble pkgsync
files based on their respective classes; it might prove useful to others
as well:

copy:
	pkgsync::
		$(master_cfinput)/etc/pkgsync   dest=/etc/pkgsync/fragments
		                                r=inf
						server=$(distsource)
						define=pkgsync_remake
						purge=true

shellcommands:
	pkgsync_remake::
		"/bin/sh -c 'for FILE in musthave mayhave maynothave; do
			echo > /etc/pkgsync/$FILE;
			for CLASS in `cat $(workdir)/state/allclasses`; do
			if [ -r /etc/pkgsync/fragments/$FILE.$CLASS ]; then
				cat /etc/pkgsync/fragments/$FILE.$CLASS >> /etc/pkgsync/$FILE
			fi
		done
	done'"

Then, simply make /etc/pkgsync/musthave.any, /etc/pkgsync/musthave.multimedia,
/etc/pkgsync/maynothave.embedded, etc. etc. etc.. (All machines in cfengine are
in the class "any", plus several system-dependent classes; other classes can be
defined as needed.)

You might also want to distribute sources.list, /etc/apt/preferences and
/etc/apt/trust{ed,db}.gpg (for secure apt).

Note that adding or removing a machine from a class will _not_ reassemble
the pkgsync file. Remember to touch at least one pkgsync fragment (to force
reassembly) if you change what machines are in which class.

5. Feedback

I'd be most grateful for any feedback, bug reports etc.. Please submit
bug reports to the Bug Tracking System as usual; feedback can be sent to
sesse@debian.org.
