sampledoc

Packages

New in version 1.0.0.

This page documents the Packages plugin. Packages is an alternative to Pkgmgr for specifying package entries for clients. Where Pkgmgr explicitly specifies package entry information, Packages delegates control of package version information to the underlying package manager, installing the latest version available through those channels.

“Magic Groups”

Packages is the only plugin that uses “magic groups”. Most plugins operate based on client group memberships, without any concern for the particular names chosen for groups by the user. The Packages plugin is the sole exception to this rule. Packages needs to “know” two different sorts of facts about clients. The first is the basic OS/distro of the client, enabling classes of sources. The second is the architecture of the client, enabling sources for a given architecture. In addition to these magic groups, each source may also specify a non-magic group to limit the source’s applicability to group member clients.

Source OS Group Architecture
APTSource debian i386
APTSource ubuntu amd64
APTSource nexenta  
YUMSource redhat i386
YUMSource centos x86_64
YUMSource fedora x86_64

Limiting sources to groups

Each source can also specify explicit group memberships. In the following example, the ubuntu-hardy group is also required. Finally, clients must be a member of the appropriate architecture group, in this case, either i386 or amd64. In total, in order for this source to be associated with a client is for the client to be in one of the sentinel groups (debian, ubuntu, or nexenta), the explicit group ubuntu-hardy, and any of the architecture groups (i386 or amd64).

Memberships in architecture groups is needed so that Packages can map software sources to clients. There is no other way to handle this than to impose membership in the appropriate architecture group.

When multiple sources are specified, clients are associated with each source to which they apply (based on group memberships, as described above). Packages and dependencies are resolved from all applicable sources.

Note

To recap, a client needs to be a member of the OS Group, Architecture group, and any other groups defined in your Packages/config.xml file in order for the client to be associated to the proper sources.

Setup

Three basic steps are required for Packages to work properly.

  1. Create Packages/config.xml. This file should look approximately like the example below, and describes both which software repositories should be used, and which clients are eligible to use each one.
  2. Ensure that clients are members of the proper groups. Each client should be a member of one of the sentinel groups listed above (debian/ubuntu/redhat/centos/nexenta), all of the groups listed in the source (like ubuntu-intrepid or centos-5.2 in the following examples), and one of the architecture groups listed in the source configuration (i386, amd64 or x86_64 in the following examples). ‘’‘Failure to do this will result in the source either not applying to the client, or only architecture independent packages being made available to the client.’‘’
  3. Add Package entries to bundles.
  4. Sit back and relax, as dependencies are resolved, and automatically added to client configurations.

Prerequisite Resolution

Packages provides a prerequisite resolution mechanism which has no analogue in Pkgmgr. During configuration generation, all structures are processed. After this phase, but before entry binding, a list of packages and the client metadata instance is passed into Packages’ resolver. This process determines a superset of packages that will fully satisfy dependencies of all package entries included in structures, and reports any prerequisites that cannot be satisfied. This facility should largely remove the need to use the Base plugin.

Disabling dependency resolution

New in version 1.1.0.

Dependency resolution can now be disabled by adding this to Sources in config.xml:

<Sources>
    <Config resolver="disabled" />
    ...
</Sources>

All metadata processing can be disabled as well:

<Sources>
    <Config metadata="disabled" />
    ...
</Sources>

Example usage

Create a config.xml file in the Packages directory that looks something like this:

<Sources>
  <APTSource>
    <Group>ubuntu-intrepid</Group>
    <URL>http://us.archive.ubuntu.com/ubuntu</URL>
    <Version>intrepid</Version>
    <Component>main</Component>
    <Component>universe</Component>
    <Arch>i386</Arch>
    <Arch>amd64</Arch>
  </APTSource>
</Sources>

Note

The default behavior of the Packages plugin is to not make any assumptions about which packages you want to have added automatically. For that reason, neither Recommended nor Suggested packages are added as dependencies by default. You will notice that the default behavior for apt is to add Recommended packages as dependencies. You can configure the Packages plugin to add recommended packages by adding the following line immediately following the URL:

New in version 1.1.0.

<Recommended>True</Recommended>

Yum sources can be similarly specified:

<Sources>
  <YUMSource>
    <Group>centos-5.2</Group>
    <URL>http://mirror.centos.org/centos/</URL>
    <Version>5.2</Version>
    <Component>os</Component>
    <Component>updates</Component>
    <Component>extras</Component>
    <Arch>i386</Arch>
    <Arch>x86_64</Arch>
  </YUMSource>
</Sources>

Note

There is also a RawURL syntax for specifying APT or YUM sources that don’t follow the conventional layout:

<Sources>
  <!-- CentOS (5.4) sources -->
  <YUMSource>
    <Group>centos5.4</Group>
    <RawURL>http://mrepo.ices.utexas.edu/centos5-x86_64/RPMS.os</RawURL>
    <Arch>x86_64</Arch>
  </YUMSource>
  <YUMSource>
    <Group>centos5.4</Group>
    <RawURL>http://mrepo.ices.utexas.edu/centos5-x86_64/RPMS.updates</RawURL>
    <Arch>x86_64</Arch>
  </YUMSource>
  <YUMSource>
    <Group>centos5.4</Group>
    <RawURL>http://mrepo.ices.utexas.edu/centos5-x86_64/RPMS.extras</RawURL>
    <Arch>x86_64</Arch>
  </YUMSource>
</Sources>
<Sources>
  <APTSource>
    <Group>ubuntu-lucid</Group>
    <RawURL>http://hudson-ci.org/debian/binary</RawURL>
    <Arch>amd64</Arch>
  </APTSource>
  <APTSource>
    <Group>ubuntu-lucid</Group>
    <RawURL>http://hudson-ci.org/debian/binary</RawURL>
    <Arch>i386</Arch>
  </APTSource>
</Sources>

Configuration Updates

Packages will reload its configuration upon an explicit command via bcfg2-admin.:

[0:3711] bcfg2-admin xcmd Packages.Refresh
True

During this command (which will take some time depending on the quantity and size of the sources listed in the configuration file), the server will report information like:

Packages: Updating http://mirror.anl.gov/ubuntu//dists/jaunty/main/binary-i386/Packages.gz
Packages: Updating http://mirror.anl.gov/ubuntu//dists/jaunty/main/binary-amd64/Packages.gz
Packages: Updating http://mirror.anl.gov/ubuntu//dists/jaunty/universe/binary-i386/Packages.gz
Packages: Updating http://mirror.anl.gov/ubuntu//dists/jaunty/universe/binary-amd64/Packages.gz
...
Packages: Updating http://mirror.centos.org/centos/5/extras/x86_64/repodata/filelists.xml.gz
Packages: Updating http://mirror.centos.org/centos/5/extras/x86_64/repodata/primary.xml.gz

Once line per file download needed. Packages/config.xml will be reloaded at this time, so any source specification changes (new or modified sources in this file) will be reflected by the server at this point.

Soft reload

New in version 1.1.0.

A soft reload can be performed to reread the configuration file and download only missing sources.:

[0:3711] bcfg2-admin xcmd Packages.Reload
True

Availability

Support for clients using yum and apt is currently available. Support for other package managers (Portage, Zypper, IPS, etc) remain to be added.

Validation

A schema for Packages/config.xml is included; config.xml can be validated using bcfg2-repo-validate.

Note

The schema requires that elements be specified in the above order.

Limitations

Packages does not do traditional caching as other plugins do. Changes to the Packages config file require a server restart for the time being.

Package Verification

In order to do disable per-package verification Pkgmgr style, you will need to use BoundEntries like below

<BoundPackage name="mem-agent" priority="1" version="auto" type="yum" verify="false"/>

Generating Client APT/Yum Configurations

New in version 1.1.0.

Client repository information can be generated automatically from software sources using TGenshi or TCheetah. A list of source urls are exposed in the client’s metadata as metadata.Packages.sources.

An example TGenshi APT template:

# bcfg2 maintained apt

{% for s in metadata.Packages.sources %}\
deb ${s.url}${s.version} ${s.groups[0]} {% for comp in s.components %}$comp {% end %}

{% end %}\

An example TGenshi YUM template:

# bcfg2 maintained yum

% for s in metadata.Packages.sources %}\
[${s.groups[0]}_${s.component}]
name=${s.groups[0]}_${s.component}
baseurl=${s.url}

{% end %}\

Debugging unexpected behavior

Using bcfg2-info

The dependency resolver used in Packages can be run in debug mode:

$ bcfg2-info
...
Handled 20 events in 0.004s
> debug
dropping to python interpreter; press ^D to resume
...
(debug_shell)
>>> m = self.build_metadata('ubik3')
>>> self.plugins['Packages'].complete(m, ['ssh'], debug=True)
Package ssh: adding new deps ['openssh-client', 'openssh-server']
Package openssh-server: adding new deps ['libc6', 'libcomerr2', 'libkrb53', 'libpam0g', 'libselinux1', 'libssl0.9.8
', 'libwrap0', 'zlib1g', 'debconf', 'libpam-runtime', 'libpam-modules', 'adduser', 'dpkg', 'lsb-base']
Package debconf: adding new deps ['debconf-i18n']
Package libpam-modules: adding new deps ['libdb4.7']
Package openssh-client: adding new deps ['libedit2', 'libncurses5', 'passwd']
Package lsb-base: adding new deps ['sed', 'ncurses-bin']
Package adduser: adding new deps ['perl-base']
Package debconf-i18n: adding new deps ['liblocale-gettext-perl', 'libtext-iconv-perl', 'libtext-wrapi18n-perl', 'libtext-charwidth-perl']
Package passwd: adding new deps ['debianutils']
Package libtext-charwidth-perl: adding new deps ['perlapi-5.10.0']
VPackage perlapi-5.10.0: got provides ['perl-base']
Package libkrb53: adding new deps ['libkeyutils1']
Package libtext-iconv-perl: adding new deps ['perlapi-5.10.0']
Package libc6: adding new deps ['libgcc1', 'findutils']
Package libgcc1: adding new deps ['gcc-4.3-base']
(set(['debconf', 'libgcc1', 'lsb-base', 'libtext-wrapi18n-perl', 'libtext-iconv-perl', 'sed', 'passwd', 'findutils', 'libpam0g', 'openssh-client', 'debconf-i18n', 'libselinux1', 'zlib1g', 'adduser', 'libwrap0', 'ncurses-bin', 'libssl0.9.8', 'liblocale-gettext-perl', 'libkeyutils1', 'libpam-runtime', 'libpam-modules', 'openssh-server', 'libkrb53', 'ssh', 'libncurses5', 'libc6', 'libedit2', 'libcomerr2', 'dpkg', 'perl-base', 'libdb4.7', 'libtext-charwidth-perl', 'gcc-4.3-base', 'debianutils']), set([]), 'deb')

This will show why the resolver is acting as it is. Replace “ubik3” and [‘ssh’] with a client name and list of packages, respectively. Also, a more polished interface to this functionality is coming as well.

Each line starting with Package: <name> describes a set of new prerequisites pulled in by a package. Lines starting with VPackage <vname> describe provides entries and their mappings to required names. The last line describes the overall results of the resolver, with three fields: a list of packages that should be installed, a list of unresolved requirements, and a type for these packages.

Using bcfg2-server

Once the server is started, enable debugging via bcfg2-admin:

$ bcfg2-admin xcmd Packages.toggle_debug

TODO list

  • Zypper support
  • Portage support
  • Explicit version pinning (a la Pkgmgr)

Developing for Packages

In order to support a given client package tool driver, that driver must support use of the auto value for the version attribute in Package entries. In this case, the tool driver views the current state of available packages, and uses the underlying package manager’s choice of correct package version in lieu of an explicit, centrally-specified, version. This support enables Packages to provide a list of Package entries with version=’auto’. Currently, the APT and YUMng drivers support this feature. Note that package management systems without any network support cannot operate in this fashion, so RPMng and SYSV will never be able to use Packages. Emerge, Zypper, IPS, and Blastwave all have the needed features to be supported by Packages, but support has not yet been written.

Packages fills two major functions in configuration generation. The first is to provide entry level binding support for Package entries included in client configurations. This function is quite easy to implement; Packages determines (based on client group membership) if the package is available for the client system, and which type it has. Because version=’auto’ is used, no version determination needs to be done.

The second major function is more complex. Packages ensures that client configurations include all package-level prerequisites for package entries explicitly included in the configuration. In order to support this, Packages needs to directly process network data for package management systems (the network sources for apt or yum, for examples), process these files, and build data structures describing prerequisites and the providers of those functions/paths. To simplify implementations of this, there is a generic base class (Bcfg2.Server.Plugins.Packages.Source) that provides a framework for fetching network data via HTTP, processing those sources (with subclass defined methods for processing the specific format provided by the tool), a generic dependency resolution method, and a caching mechanism that greatly speeds up server/bcfg2-info startup.

Each source type must define:

  • a get_urls attribute (and associated urls property) that describes the URLS where to get data from.
  • a read_files method that reads and processes the downloaded files

Sources may define a get_provides method, if provides are complex. For example, provides in rpm can be either rpm names or file paths, so multiple data sources need to be multiplexed.

The APT source in src/lib/Server/Plugins/Packages.py provides a relatively simple implementation of a source.