.. -*- mode: rst -*-

.. _server-plugins-generators-pkgmgr:

======
Pkgmgr
======

The Pkgmgr plugin resolves the Abstract Configuration Entity "Package"
to a package specification that the client can use to detect, verify
and install the specified package.

For a package specification to be included in the Literal configuration
the name attribute from an Abstract Package Tag (from Base or Bundler)
must match the name attribute of a Package tag in Pkgmgr, along with
the appropriate group associations of course.

Each file in the Pkgmgr directory has a priority. This allows the
same package to be served by multiple files. The priorities can be
used to break ties in the case that multiple files serve data for the
same package.

Usage of Groups in Pkgmgr
=========================

Groups are used by the Pkgmgr plugin, along with host metadata,
for selecting the package entries to include in the clients literal
configuration. They can be thought of as::

    if client is a member of group1 then
        assign to literal config

Nested groups are conjunctive (logical and).::

    if client is a member of group1 and group2 then
        assign to literal config

Group membership may be negated.

Tag Attributes in Pkgmgr
========================

.. xml:schema:: pkglist.xsd
   :linktotype:
   :noautodep: PackageType

Pkgmgr Directory
================

The Pkgmgr/ directory keeps the XML files that define what packages
are available for a host or image and where to find those packages.
All the files in the directory are processed.

The names of the XML files have no special meaning to Bcfg2; they
are simply named so it's easy for the administrator to know what the
contents hold. All Packages could be kept in a single file if so desired.
Bcfg2 simply uses the Groups in the files and priorities to determine
how to assign Packages to a host's literal configuration.

Listed detailed below is one possible structure for the Pkgmgr directory.

The files are structured to contain particular portions of distribution
repositories.

The files  in the directory are::

    $ ls Pkgmgr/
    centos-4-noarch-updates.xml
    centos-4-x86_64-updates.xml
    centos-4-x86_64.xml
    backup.example.com.xml
    fedora-core-4-noarch-updates.xml
    fedora-core-4-x86-updates.xml
    fedora-core-4-x86.xml
    rhel-as-4-noarch-updates.xml
    rhel-as-4-x86-updates.xml
    rhel-as-4-x86.xml
    rhel-es-4-noarch-updates.xml
    rhel-es-4-x86-updates.xml
    rhel-es-4-x86.xml
    rhel-ws-4-noarch-udpates.xml
    rhel-ws-4-x86_64-updates.xml
    rhel-ws-4-x86_64.xml
    rhel-ws-4-x86-updates.xml
    rhel-ws-4-x86.xml

As can be seen the file names have been selected to indicate what the
contents are and have been split by Vendor, product and repository area.

A partial listing of the centos-4-x86_64.xml is below

.. code-block:: xml

    $ cat centos-4-x86_64.xml
    <PackageList uri='http://www.example.com/yam/Centos44-x86_64/RPMS.os/' type='yum' priority='0'>
        <Group name='Centos4.4-Standard'>
            <Group name='x86_64'>
                <Package name='audit-libs' version='1.0.13-1.EL4' type='yum'/>
                <Package name='audit' version='1.0.13-1.EL4' type='yum'/>
                <Package name='basesystem' version='8.0-2' type='yum'/>
                <Package name='bash' version='3.0-18.1' type='yum'/>
                <Package name='bcfg2' version='0.9.1-0.1' type='yum'/>
                <Package name='beecrypt' version='3.1.0-3' type='yum'/>
                ...
                <Package name='VMwareTools' version='6530-29996' type='yum'/>
                <Package name='yum' version='2.4.2-1' type='yum'/>
                <Package name='zlib' version='1.2.1.2-1.2' type='yum'/>
            </Group>
      </Group>
    </PackageList>

.. code-block:: xml

    $ cat centos-4-x86_64-updates.xml
    <PackageList uri='http://www.example.com/yam/Centos44-x86_64/RPMS.updates/' type='yum' priority='5'>
        <Group name='Centos4.4-Standard'>
            <Group name='x86_64'>
                <Package name='audit-libs' version='1.0.14-1.EL4' type='yum'/>
                <Package name='audit' version='1.0.14-1.EL4' type='yum'/>
                <Package name='basesystem' version='8.0-4' type='yum'/>
                <Package name='bash' version='3.0-19.3' type='yum'/>
                <Package name='bcfg2' version='0.9.2-0.1' type='yum'/>
                <Package name='beecrypt' version='3.1.0-6' type='yum'/>
                ...
                <Package name='VMwareTools' version='6530-29996' type='yum'/>
                <Package name='yum' version='2.4.3-1' type='yum'/>
                <Package name='zlib' version='1.2.1.2-1.2' type='yum'/>
            </Group>
      </Group>
    </PackageList>

Here it can be seen that the data is encapsulated in a !PackageList Tag
which describes the URI of the files described, the type of package,
and the priority of the files in this list.

The priority is used to decide which specific file to use when there are
multiple files that could be used for a particular host. The highest
priority file is the one that is used.

Using this system, it is possible to have a file that contains all the
Packages from the original installation, centos-4-x86_64.xml in this case,
and then create a new file that contains updates that are made available
afterwards, centos-4-x86_64-updates.xml and centos-4-noarch-updates.xml
in this case. The priority of the update PackageLists just needs to be
higher so that they will be selected instead of the original installation
Packages.

The backup.example.com.xml contains a packalist for a specific host which
is qualified by the Client tag. Its Packages have a higher priority
than the update Packages. This is because this particular host requires
special Packages that are older than the ones available in the updates.

.. code-block:: xml

    <PackageList uri='http://www.example.com/yam/Centos44-x86_64/RPMS.os/' type='yum' priority='1000'>
        <Client name='server86.example.com'>
            <Package name='audit-libs' version='1.0.13-1.EL4' type='yum'/>
            <Package name='audit' version='1.0.13-1.EL4' type='yum'/>
            <Package name='basesystem' version='8.0-2' type='yum'/>
            <Package name='bash' version='3.0-18.1' type='yum'/>
            <Package name='bcfg2' version='0.9.1-0.1' type='yum'/>
            <Package name='beecrypt' version='3.1.0-3' type='yum'/>
            ...
            <Package name='VMwareTools' version='6530-29996' type='yum'/>
            <Package name='yum' version='2.4.2-1' type='yum'/>
            <Package name='zlib' version='1.2.1.2-1.2' type='yum'/>
        </Client>
    </PackageList>

Simplifying Multi-Architecture Environments with :ref:`Altsrc <server-plugins-structures-altsrc>`
=================================================================================================

Frequently multi-architecture environments (typically x86_64) will run
into problems needing to specify different architectures on different
groups for clients. For example, desktop machines may install 32-bit
compatibility packages in addition to 64-bit ones, while servers
may install only 64-bit packages. Specifying this in the Pkgmgr was
onerous, because different package targets (64bit, 32+64, etc) needed
to be specified on a package by group basis. Two features have been
implemented that should ease this situation considerably.

* The :ref:`Altsrc <server-plugins-structures-altsrc>` feature adds the ability to add a "bind as" directive
  to entries. For example, the following entry, in a bundle:

.. code-block:: xml

    <Package name='foo' altsrc='bar'/>

  would bind as if it were named bar, while the entry would still appear named "foo" in the client configuration specification.

* Pkgmgr now builds virtual package targets for any package with Instance
  client elements. This means that if a client attempts to bind:

.. code-block:: xml

    <Package name='libfoo:x86_64,i686'/>
  It will only include the instances listed in the package.
  By using these features together, a bundle can include:

.. code-block:: xml

    <Package name='libfoo' altsrc='libfoo:i386,i686'/>

  This in conjunction with a Pkgmgr entry that looks like:

.. code-block:: xml

    <Package name='libfoo'>
      <Instance arch='i386' version='1.0.4-12'/>
      <Instance arch='i586' version='1.0.4-12'/>
      <Instance arch='i686' version='1.0.4-12'/>
      <Instance arch='x86_64' version='1.0.4-12'/>
    </Package>

  Will result in a bound entry that looks like:

.. code-block:: xml

    <Package name='libfoo'>
      <Instance arch='i386' version='1.0.4-12'/>
      <Instance arch='i686' version='1.0.4-12'/>
    </Package>

Altogether, this should move policy decisions about package architectures
to bundles/base.

Automated Generation of Pkgmgr Configuration Files
==================================================

The two utilities detailed below are provided in the tools directory of
the source tarball.

Also see the general :ref:`Pkgmgr <server-plugins-generators-pkgmgr>`
and :ref:`server-plugins-structures-altsrc` pages.

pkgmgr_gen.py
^^^^^^^^^^^^^

pkgmgr_gen will generate a Pkgmgr file from a list of directories
containing RPMs or from a list of YUM repositories.::

    [root@bcfg2 Pkgmgr]# pkgmgr_gen.py --help usage: pkgmgr_gen.py
    [options]

    options:
      -h, --help            show this help message and exit
      -aARCHS, --archs=ARCHS
                            Comma separated list of subarchitectures to include.
                            The highest subarichitecture required in an
                            architecture group should specified.   Lower
                            subarchitecture packages will be loaded if that
                            is all that is available. e.g. The higher of i386,
                            i486 and i586 packages will be loaded if -a i586
                            is specified. (Default: all).
      -dRPMDIRS, --rpmdirs=RPMDIRS
                            Comma separated list of directories to scan for RPMS.
                            Wilcards are permitted.
      -eENDDATE, --enddate=ENDDATE
                            End date for RPM file selection.
      -fFORMAT, --format=FORMAT
                            Format of the Output. Choices are yum or rpm.
                            (Default: yum)
      -gGROUPS, --groups=GROUPS
                            List of comma separated groups to nest Package
                            entities in.
      -iINDENT, --indent=INDENT
                            Number of leading spaces to indent nested entries in
                            the                                             output.
                            (Default:4)
      -oOUTFILE, --outfile=OUTFILE
                            Output file name.
      -P, --pkgmgrhdr       Include PackageList header in output.
      -pPRIORITY, --priority=PRIORITY
                            Value to set priority attribute in the PackageList Tag.
                            (Default: 0)
      -rRELEASE, --release=RELEASE
                            Which releases to include in the output. Choices are
                            all or latest.  (Default: latest).
      -sSTARTDATE, --startdate=STARTDATE
                            Start date for RPM file selection.
      -uURI, --uri=URI      URI for PackageList header required for RPM format
                            ouput.
      -v, --verbose         Enable verbose output.
      -yYUMREPOS, --yumrepos=YUMREPOS
                            Comma separated list of YUM repository URLs to load.
                            NOTE: Each URL must end in a '/' character.

.. note:: The startdate and enddate options are not yet implemented.

pkgmgr_update.py
^^^^^^^^^^^^^^^^

pkgmgr_update will update the release (meaning the epoch, version
and release) information in an existing Pkgrmgr file from a list of
directories containing RPMs or from a list of YUM repositories.  All Tags
and other attributes in the existing file will remain unchanged.::

    [root@bcfg2 Pkgmgr]# pkgmgr_update.py --help
    usage: pkgmgr_update.py [options]

    options:
      -h, --help            show this help message and exit
      -cCONFIGFILE, --configfile=CONFIGFILE
                            Existing Pkgmgr configuration  file name.
      -dRPMDIRS, --rpmdirs=RPMDIRS
                            Comma separated list of directories to scan for RPMS.
                            Wilcards are permitted.
      -oOUTFILE, --outfile=OUTFILE
                            Output file name or new Pkgrmgr file.
      -v, --verbose         Enable verbose output.
      -yYUMREPOS, --yumrepos=YUMREPOS
                            Comma separated list of YUM repository URLs to load.
                            NOTE: Each URL must end in a '/' character.

Pkgmgr Configuration Examples
=============================

verify_flags
^^^^^^^^^^^^

This entry was used for the Centos test client used during RPM
development.

.. code-block:: xml

    <Package name='bcfg2' type='rpm'>
        <Instance simplefile='bcfg2-0.9.3-0.0pre5.noarch.rpm' version='0.9.3' release='0.0pre5' arch='noarch' verify_flags='nomd5,nosize,nomtime'/>
    </Package>

Multiple Instances
^^^^^^^^^^^^^^^^^^

.. code-block:: xml

    <Package name='beecrypt' type='rpm'>
        <Instance simplefile='beecrypt-3.1.0-6.x86_64.rpm' version='3.1.0' release='6' arch='x86_64'/>
        <Instance simplefile='beecrypt-3.1.0-6.i386.rpm' version='3.1.0' release='6' arch='i386'/>
    </Package>

Kernel
^^^^^^

.. note:: Multiple instances with the same architecture must be in the installOnlyPkgs list.

.. code-block:: xml

    <Package name='kernel' type='rpm'>
        <Instance simplefile='kernel-2.6.9-42.0.8.EL.x86_64.rpm' version='2.6.9' release='42.0.8.EL' arch='x86_64'/>
        <Instance simplefile='kernel-2.6.9-42.0.10.EL.x86_64.rpm' version='2.6.9' release='42.0.10.EL' arch='x86_64'/>
    </Package>

Per Instance Ignore
^^^^^^^^^^^^^^^^^^^

.. note::

    In this case a per instance ignore is actually a bad idea as the
    verify failure is because of multiarch issues where  the last package
    installed wins.  So this would be better as a Package level ignore.

Ignore tag entries only work with the RPM driver. They do not appear
to be supported in YUM as of 1.0pre5.

.. code-block:: xml

    <Package name='glibc' type='rpm'>
        <Instance simplefile='glibc-2.3.4-2.25.x86_64.rpm' version='2.3.4' release='2.25' arch='x86_64'>
            <Ignore name='/etc/rpc'/>
        </Instance>
        <Instance simplefile='glibc-2.3.4-2.25.i686.rpm' version='2.3.4' release='2.25' arch='i686'/>
    </Package>

pkg_checks
^^^^^^^^^^

If pkg_checks = false the version information is not required. If
pkg_checks = true the full information is needed as normal.

For YUM a minimal entry is

.. code-block:: xml

    <Package name="bcfg2" type="yum" pkg_checks="False"/>

In fact for YUM, with pkg_checks = false, any combination of the nevra
attributes that will build a valid yum package name (see the Misc heading
on the yum man page) is valid.

.. code-block:: xml

    <Package name="bcfg2" type="yum" pkg_checks="False" arch="x86_64"/>

For RPM a minimal entry is

.. code-block:: xml

    <Package name="bcfg2" type="rpm" pkg_checks="False" simplefile="bcfg2-0.9.4-0.0pre1.noarch.rpm"/>

verify_fail_action
^^^^^^^^^^^^^^^^^^

The way I have Bcfg2 configured for my development systems. This way
it reports bad, but doesn't do anything about it.

.. code-block:: xml

    <Package name='bcfg2' type='rpm'>
        <Instance simplefile='bcfg2-0.9.3-0.0pre5.noarch.rpm' version='0.9.3' release='0.0pre5' arch='noarch' verify_fail_action='none'/>
    </Package>
