summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2012-09-26 09:48:07 -0400
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2012-09-26 10:05:22 -0400
commit34e5287c4b18ba5bfdbb74b729ceebb2a1f1637e (patch)
treebb36dd2684745ca5723c7c4909c912971f050d25
parentcd47ea485e6be6327c3b67323dc55c0533d4f256 (diff)
downloadbcfg2-34e5287c4b18ba5bfdbb74b729ceebb2a1f1637e.tar.gz
bcfg2-34e5287c4b18ba5bfdbb74b729ceebb2a1f1637e.tar.bz2
bcfg2-34e5287c4b18ba5bfdbb74b729ceebb2a1f1637e.zip
deprecated YUM24 tool, renamed YUMng to YUM, RPMng to RPM
-rw-r--r--doc/client/tools.txt33
-rw-r--r--doc/client/tools/yum.txt346
-rw-r--r--doc/client/tools/yumng.txt803
-rw-r--r--doc/server/plugins/generators/pkgmgr.txt309
-rw-r--r--src/lib/Bcfg2/Client/Frame.py15
-rw-r--r--src/lib/Bcfg2/Client/Tools/RPM.py988
-rw-r--r--src/lib/Bcfg2/Client/Tools/RPMng.py989
-rw-r--r--src/lib/Bcfg2/Client/Tools/YUM.py951
-rw-r--r--src/lib/Bcfg2/Client/Tools/YUM24.py35
-rw-r--r--src/lib/Bcfg2/Client/Tools/YUMng.py955
-rw-r--r--src/lib/Bcfg2/Client/Tools/__init__.py3
-rw-r--r--src/lib/Bcfg2/Options.py130
12 files changed, 2641 insertions, 2916 deletions
diff --git a/doc/client/tools.txt b/doc/client/tools.txt
index bff2e97ed..1dbb33b1a 100644
--- a/doc/client/tools.txt
+++ b/doc/client/tools.txt
@@ -130,16 +130,10 @@ as Gentoo.
RPM
---
-.. warning:: Deprecated in favor of :ref:`RPMng <client-tools-yumng>`
+Executes RPM to manage packages on Redhat-based and similar systems.
+Consider using the :ref:`YUM <client-tools-yum>` tool instead if possible.
-Executes rpm to manage packages most often on redhat based systems.
-
-RPMng
------
-
-Next-generation RPM tool. Handles RPM sublties like epoch and
-prelinking and 64-bit platforms better than the RPM client
-tool. :ref:`client-tools-yumng`
+Formerly called ``RPMng``, but was renamed for the 1.3 release.
SMF
---
@@ -157,12 +151,6 @@ Systemd
Systemd service support.
-Example:
-
-.. code-block:: xml
-
- <Service name='udev' status='on' type='systemd'/>
-
SYSV
----
@@ -175,15 +163,16 @@ Upstart service support. Uses `Upstart`_ to configure services.
.. _Upstart: http://upstart.ubuntu.com/
-Yum
+YUM
---
-.. warning:: Deprecated in favor of :ref:`YUMng <client-tools-yumng>`
-
-Handles RPMs using the YUM package manager.
+Handles RPMs using the YUM package manager. Renamed from ``YUMng`` for
+the 1.3 release. See :ref:`client-tools-yum` for more details.
-YUMng
+YUM24
-----
-Handles RPMs using the YUM package manager. Handles sublties better than
-the Yum client tool. :ref:`client-tools-yumng`
+.. warning:: Deprecated in favor of :ref:`YUM <client-tools-yum>`
+
+Handles RPMs using older versions of the YUM package manager.
+
diff --git a/doc/client/tools/yum.txt b/doc/client/tools/yum.txt
new file mode 100644
index 000000000..10c3cf725
--- /dev/null
+++ b/doc/client/tools/yum.txt
@@ -0,0 +1,346 @@
+.. -*- mode: rst -*-
+
+.. _client-tools-yum:
+
+============================
+Bcfg2 RPM/YUM Client Drivers
+============================
+
+The RPM and YUM client drivers provide client support for RPMs
+(installed directly from URLs) and Yum repositories. These drivers
+were formerly called ``RPMng`` and ``YUMng``, respectively, but were
+renamed for Bcfg2 1.3.0.
+
+Features
+========
+
+* Full RPM package identification using epoch, version, release and
+ arch.
+* Support for multiple instances of packages with the Instance tag.
+* Better control of the RPM verification using the pkg_checks,
+ pkg_verify and verify_flags attributes.
+* Support for install only packages such as the kernel packages.
+* Support for per instance ignoring of individual files for the RPM
+ verification with the Ignore tag.
+* Multiple package Instances with full version information listed in
+ interactive mode.
+* Support for installation and removal of gpg-pubkey packages.
+* Support for controlling what action is taken on package verification
+ failure with the install_action, version_fail_action and
+ verify_fail_action attributes.
+
+Installation
+============
+
+isprelink
+---------
+
+``isprelink`` is a Python module that can greatly improve the
+performance of the ``RPM`` driver. It should be installed on any
+system that has prelink installed and will be using the ``RPM`` driver.
+
+Source can be found at ftp://ftp.mcs.anl.gov/pub/bcfg/isprelink-0.1.2.tar.gz
+
+To compile and install prelink, execute::
+
+ python setup.py install
+
+in the rpmtools directory. The elfutils-libelf-devel package is required
+for the compilation.
+
+There may also be RPMs available in the repositories for your distro.
+
+Configuration and Usage
+=======================
+
+Loading of RPM
+--------------
+
+The RPM driver can be loaded by command line options, client
+configuration file options or as the default driver for RPM packages.
+
+From the command line::
+
+ bcfg2 -n -v -d -D Action,POSIX,Chkconfig,RPM
+
+This produces quite a bit of output so you may want to redirect the
+output to a file for review.
+
+In the ``bcfg2.conf`` file::
+
+ [client]
+ drivers = Action,Chkconfig,POSIX,RPM
+
+Configuration File Options
+--------------------------
+
+A number of paramters can be set in the client configuration for both
+the RPM and YUM drivers. Each driver has its own section (``[RPM]`` or
+``[YUM]``), and most of the same options are accepted by each driver.
+An example config might look like this::
+
+ [RPM]
+ pkg_checks = true
+ pkg_verify = true
+ erase_flags = allmatches
+ installonlypackages = kernel, kernel-bigmem, kernel-enterprise, kernel-smp, kernel-modules, kernel-debug, kernel-unsupported, kernel-source, kernel-devel, kernel-default, kernel-largesmp-devel, kernel-largesmp, kernel-xen, gpg-pubkey
+ install_action = install
+ version_fail_action = upgrade
+ verify_fail_action = reinstall
+
+installonlypackages
+^^^^^^^^^^^^^^^^^^^
+
+Install-only packages are packages that should only ever be installed
+or deleted, not upgraded.
+
+It is best practice to only ever install/delete kernel packages, the
+wisdom being that the package for the currently running kernel should
+always be installed. Doing an upgrade would delete the running kernel
+package.
+
+``gpg-pubkey`` will be automatically added to the list of install-only
+packages.
+
+Example::
+
+ [RPM]
+ installonlypackages = kernel, kernel-bigmem, kernel-enterprise, kernel-smp, kernel-modules, kernel-debug, kernel-unsupported, kernel-source, kernel-devel, kernel-default, kernel-largesmp-devel, kernel-largesmp, kernel-xen, gpg-pubkey
+
+This option is not honored by the ``YUM`` driver.
+
+erase_flags
+^^^^^^^^^^^
+
+erase_flags are rpm options used by 'rpm -erase' in the client ``Remove()``
+method. The RPM erase is written using rpm-python and does not use
+the rpm command.
+
+The erase flags are specified in the client configuration file as a
+comma separated list and apply to all RPM erase operations. The
+following rpm erase options are supported. See the rpm man page for
+details::
+
+ noscripts
+ notriggers
+ repackage
+ allmatches
+ nodeps
+
+This option is not honored by the ``YUM`` driver.
+
+pkg_checks
+^^^^^^^^^^
+
+The RPM/YUM drivers do the following three checks/status:
+
+#. Installed
+#. Version
+#. rpm verify
+
+Setting pkg_checks = true (the default) in the client configuration file
+means that all three checks will be done for all packages.
+
+Setting pkg_checks = false in the client configuration file means that
+only the Installed check will be done for all packages.
+
+The true/false value can be any combination of upper and lower case.
+
+.. note::
+ #. pkg_checks must evaluate true for both the client (this option)
+ and the package (see the Package Tag pkg_checks attribute
+ below) for the action to take place.
+ #. If pkg_checks = false then the Pkgmgr entries do not need the
+ version information. See the examples towards the bottom of
+ the page.
+
+pkg_verify
+^^^^^^^^^^
+
+The RPM/YUM drivers do the following three checks/status:
+
+#. Installed
+#. Version
+#. rpm verify
+
+Setting pkg_verify = true (the default) in the client configuration
+file means that all three checks will be done for all packages as long
+as pkg_checks = true.
+
+Setting pkg_verify = false in the client configuration file means that
+the rpm verify wil not be done for all packages on the client.
+
+The true/false value can be any combination of upper and lower case.
+
+.. note::
+ #. pkg_verify must evaluate true for both the client (this option)
+ and the package instance (see the Instance Tag pkg_verify
+ attribute below) for the action to take place.
+
+install_action
+^^^^^^^^^^^^^^
+
+``install_action`` controls whether or not a package instance will be
+installed if the package instance isn't installed.
+
+If install_action = install then the package instance is installed.
+If install_action = none then the package instance is not installed.
+
+.. note::
+ #. install_action must evaluate true for both the client (this
+ option) and the package instance (see the Instance Tag
+ install_action attribute below) for the action to take place.
+
+version_fail_action
+^^^^^^^^^^^^^^^^^^^
+
+``version_fail_action`` controls whether or not a package instance
+will be updated if the installed package instance isn't the same
+version as specified in the configuration.
+
+If version_fail_action = upgrade then the package instance is upgraded
+(or downgraded).
+
+If version_fail_action = none then the package instance is not upgraded
+(or downgraded).
+
+.. note::
+ #. verion_fail_action must evaluate true for both the client (this
+ option) and the package instance (see the Instance Tag
+ version_fail_action attribute below) for the action to take
+ place.
+
+verify_fail_action
+^^^^^^^^^^^^^^^^^^
+
+``verify_fail_action`` controls whether or not a package instance will
+be reinstalled if the installed package instance fails the Yum or RPM
+verify.
+
+If verify_fail_action = reinstall then the package instance is reinstalled.
+If verify_fail_action = none then the package instance is not reinstalled.
+
+.. note::
+ #. verify_fail_action must evaluate true for both the client (this
+ option) and the package instance (see the Instance Tag
+ verify_fail_action attribute below) for the action to take
+ place.
+ #. The driver will not attempt to reinstall a package instance if
+ the only failure is a configuration file.
+
+Interactive Mode
+----------------
+
+Running the client in interactive mode (-I) prompts for the actions to
+be taken as before. Prompts are per package and may apply to multiple
+instances of that package. Each per package prompt will contain a list
+of actions per instance.
+
+In the RPM driver, actions are encoded as:
+
+* D - Delete
+* I - Install
+* R - Reinstall
+* U - Upgrade/Downgrade
+
+An example follows::
+
+ Install/Upgrade/delete Package aaa_base instance(s) - R(*:10.2-38.*) (y/N)
+ Install/Upgrade/delete Package evms instance(s) - R(*:2.5.5-67.*) (y/N)
+ Install/Upgrade/delete Package gpg-pubkey instance(s) - D(*:9c800aca-40d8063e.*) D(*:0dfb3188-41ed929b.*) D(*:7e2e3b05-44748aba.*) D(*:a1912208-446a0899.*) D(*:9c777da4-4515b5fd.*) D(*:307e3d54-44201d5d.*) (y/N)
+ Install/Upgrade/delete Package module-init-tools instance(s) - R(*:3.2.2-62.*) (y/N)
+ Install/Upgrade/delete Package multipath-tools instance(s) - R(*:0.4.7-29.*) (y/N)
+ Install/Upgrade/delete Package pam instance(s) - R(*:0.99.6.3-29.1.*) (y/N)
+ Install/Upgrade/delete Package perl-AppConfig instance(s) - U(None:1.52-4.noarch -> *:1.63-17.*) (y/N)
+ Install/Upgrade/delete Package postfix instance(s) - R(*:2.3.2-28.*) (y/N)
+ Install/Upgrade/delete Package sysconfig instance(s) - R(*:0.60.4-3.*) (y/N)
+ Install/Upgrade/delete Package udev instance(s) - R(*:103-12.*) (y/N)
+
+GPG Keys
+--------
+
+GPG is used by RPM to 'sign' packages. All vendor packages are signed
+with the vendors GPG key. Additional signatures maybe added to the rpm
+file at the users discretion.
+
+It is normal to have multiple GPG keys installed. For example, SLES10
+out of the box has six GPG keys installed.
+
+To the RPM database all GPG 'packages' have the name 'gpg-pubkey', which
+may be nothing like the name of the file specified in the rpm -import
+command. For example on Centos 4 the file name is RPM-GPG-KEY-centos4.
+For SLES10 this means that there are six packages with the name
+'gpg-pubkey' installed.
+
+RPM does not check GPG keys at package installation, while YUM does.
+
+RPM uses the rpm command for installation and does not therefore check
+GPG signatures at package install time. RPM uses rpm-python for
+verification and does by default do signature checks as part of the
+client Inventory process. To do the signature check the appropriate
+GPG keys must be installed. rpm-python is not very friendly if the
+required key(s) is not installed (it crashes the client).
+
+The RPM driver detects, on a per package instance basis, if the
+appropriate key is installed. If it is not, a warning message is
+printed and the signature check is disabled for that package instance,
+for that client run only.
+
+GPG keys can be installed and removed by the RPM driver. To install a
+GPG key configure it in Pkgmgr/Rules as a package and add gpg-pubkey
+to the clients abstract configuration. The gpg-pubkey package/instance
+is treated as an install only package. gpg-pubkey packages are
+installed by the RPM driver with the rpm -import command.
+
+gpg-pubkey packages will be removed by ``bcfg2 -r packages`` if they are
+not in the clients configuration.
+
+Ignoring Files during Verification
+----------------------------------
+
+Ignore Tag
+^^^^^^^^^^
+
+The Ignore tag in Pkgmgr is used to "mask out" individual files from
+the RPM verification. This is done by comparing the verification
+failure results with the Ignore tag name. If there is a match, that
+entry is not used by the client to determine if a package has failed
+verification.
+
+Ignore tag entries can be specified at both the Package level, in which
+case they apply to all Instances, and/or at the Instance level, in which
+case they only apply to that instance.
+
+Ignore tag entries are used by the RPM driver. They can be specified
+in both old and new style Pkgmgr files.
+
+The Ignore Tag supports the following attributes:
+
++-----------+-------------+--------+
+| Attribute | Description | Values |
++===========+=============+========+
+| name | File name. | String |
++-----------+-------------+--------+
+
+Example
+
+.. code-block:: xml
+
+ <Package name='glibc' type='rpm'>
+ <Ignore name='/etc/rpc'/>
+ <Instance simplefile='glibc-2.3.4-2.25.x86_64.rpm' version='2.3.4' release='2.25' arch='x86_64'/>
+ </Package>
+
+POSIX 'ignore' Path entries
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The YUM analog to the Ignore Tag used by RPM is the use of Path
+entries of type 'ignore'. The following shows an example for the
+centos-release package which doesn't verify if you remove the default
+repos and replace them with a custom repo.
+
+.. code-block:: xml
+
+ <!-- Ignore verification failures for centos-release -->
+ <BoundPath name='/etc/yum.repos.d/CentOS-Base.repo' type='ignore'/>
+ <BoundPath name='/etc/yum.repos.d/CentOS-Media.repo' type='ignore'/>
diff --git a/doc/client/tools/yumng.txt b/doc/client/tools/yumng.txt
deleted file mode 100644
index 54003aea1..000000000
--- a/doc/client/tools/yumng.txt
+++ /dev/null
@@ -1,803 +0,0 @@
-.. -*- mode: rst -*-
-
-.. _client-tools-yumng:
-
-================================
-Bcfg2 RPMng/YUMng Client Drivers
-================================
-
-Introduction
-============
-
-The goal of this driver is to resolve the issues that exist with the
-RPM and Yum client tool drivers.
-
-For the most part, the issues are due to RPM being able to have multiple
-packages of the same name installed. This is an issue on all Red Hat
-and SUSE based distributions.
-
-Examples of this are:
-
-* SLES10 and openSUSE 10.2 both install six GPG keys. From an RPM
- perspective this means that there are six packages with the name
- gpg-pubkey.
-* YUM always installs, as opposed to upgrades, kernel packages. This is
- hard coded in YUM (actually it can be overridden in yum.conf),
- so systems using YUM will eventually have multiple kernel packages
- installed.
-* Red Hat family x86_64 based systems frequently have both an x86_64
- and an i386 version of the same package installed.
-
-The new Pkgmgr format files with Instances are therefore the only way to
-accurately describe an RPM based system. It is recommended that all RPM
-based systems be changed to use the new format configuration files and
-the RPMng driver. Alternatively, you can use the newer :ref:`Packages
-<server-plugins-generators-packages>` plugin.
-
-Development Status
-==================
-
-Initial development of the drivers was done on Centos 4.4 x86_64, with
-testing on openSUSE 10.2 x86_64. Centos has been tested with a new style
-Pkgmgr file and openSUSE with an old style file (see the Configuration
-section below for what this means). Testing has now moved to Centos 5
-x86_64 and old style files are no longer being tested.
-
-RPMng/YUMng are the default RPM drivers.
-
-Features
-========
-
-* Limited support for 0.9.4 and earlier Pkgmgr configuration files. See Configuration below for details.
-* Full RPM package identification using epoch, version, release and arch.
-* Support for multiple instances of packages with the Instance tag.
-* Better control of the RPM verification using the pkg_checks, pkg_verify and verify_flags attributes.
-* Support for install only packages such as the kernel packages.
-* Support for per instance ignoring of individual files for the RPM verification with the Ignore tag.
-* Multiple package Instances with full version information listed in interactive mode.
-* Support for installation and removal of gpg-pubkey packages.
-* Support for controlling what action is taken on package
- verification failure with the install_action, version_fail_action and
- verify_fail_action attributes.
-
-
-RPMng Driver Overview
-=====================
-
-The RPMng driver uses a mixture of rpm commands and rpm-python as detailed
-in the sections below.
-
-rpmtools module
----------------
-
-The rpmtools module conatins most of the rpm-python code and is imported
-by RPMng.py and YUMng.py.
-
-RPMng.RefreshPackages()
------------------------
-
-The RPMng.RefreshPackages method generates the installed dict using
-rpm-python code from the rpmtools module. Full name, epoch, version,
-release and arch information is stored.
-
-RPMng.VerifyPackages()
-----------------------
-
-The RPMng.VerifyPackages method generates a number of structures that
-record the state of the of the system compared to the Bcfg2 literal
-configuration retrieved from the server. These structures are mainly
-used by the RPMng.Install method.
-
-AS part of the verification process an rpm package level verification is
-carried out using rpm-python code from the rpmtools module. Full details
-of the failures are returned in a complicated dict/list structure for
-later use.
-
-RPMng.Install()
----------------
-
-The RPMng.Install method attempts to fix what the RPMng.VerifyPackages
-method found wrong. It does this by installing, reinstalling, deleting
-and upgrading RPMs. RPMng.Install does not use rpm-python. It does use
-the following rppm commands as appropriate::
-
- rpm -install
-
- rpm --import
-
- rpm -upgrade
-
-A method (RPMng.to reinstall_check()) to decide whether to do a reinstall
-of a package instance or not has been added, but is very simple at
-this stage. Currently it will prevent a reinstall if the only reason
-for a verification failure was due to an RPM configuration (%config)
-file. A package reinstall will not replace these, so there is no point
-reinstalling.
-
-RPMng.Remove()
---------------
-
-The RPMng.Remove method is written using rpm-python code in the rpmtools
-module. Full nevra information is used in the selection of the package
-removal.
-
-Installation
-============
-
-isprelink
----------
-
-This is a Python C extension module that checks to see if a file has
-been prelinked or not. It should be built and installed on systems that
-have the prelink package installed (only Red Hat family systems as far
-as I can tell). rpmtools will function without the isprelink module,
-but performance is not good.
-
-Source can be found here ftp://ftp.mcs.anl.gov/pub/bcfg/isprelink-0.1.2.tar.gz
-
-To compile and install prelink, execute::
-
- python setup.py install
-
-in the rpmtools directory. The elfutils-libelf-devel package is required
-for the compilation.
-
-There are Centos x86_64 RPMs here
-ftp://ftp.mcs.anl.gov/pub/bcfg/archive/redhat/
-
-Configuration and Usage
-=======================
-
-Loading of RPMng
-----------------
-
-The RPMng driver can be loaded by command line options, client
-configuration file options or as the default driver for RPM packages.
-
-From the command line::
-
- bcfg2 -n -v -d -D Action,POSIX,Chkconfig,RPMng
-
-This produces quite a bit of output so you may want to redirect the
-output to a file for review.
-
-In the ``bcfg2.conf`` file::
-
- [client]
- #drivers = Action,Chkconfig,POSIX,YUMng
- drivers = Action,Chkconfig,POSIX,RPMng
-
-.. note:: Note that loading this driver will unload the RPM driver, so the Yum driver will not work.
-
-Configuration File Options
---------------------------
-
-A number of paramters can be set in the client configuration for both
-the RPMng and YUMng drivers. Each driver has its own section. A full
-client configuration file with all the options specified is below::
-
- [communication]
- protocol = xmlrpc/ssl
- password = xxxxxx
- user = yyyyyyy
-
- [components]
- bcfg2 = https://bcfg2:6789
-
- [client]
- #drivers = Action,Chkconfig,POSIX,YUMng
- drivers = Action,Chkconfig,POSIX,RPMng
-
- [RPMng]
- pkg_checks = true
- pkg_verify = true
- erase_flags = allmatches
- installonlypackages = kernel, kernel-bigmem, kernel-enterprise, kernel-smp, kernel-modules, kernel-debug, kernel-unsupported, kernel-source, kernel-devel, kernel-default, kernel-largesmp-devel, kernel-largesmp, kernel-xen, gpg-pubkey
- install_action = install
- version_fail_action = upgrade
- verify_fail_action = reinstall
-
- [YUMng]
- pkg_checks = True
- pkg_verify = true
- erase_flags = allmatches
- autodep = true
- installonlypackages = kernel, kernel-bigmem, kernel-enterprise, kernel-smp, kernel-modules, kernel-debug, kernel-unsupported, kernel-source, kernel-devel, kernel-default, kernel-largesmp-devel, kernel-largesmp, kernel-xen, gpg-pubkey
- install_action = install
- version_fail_action = upgrade
- verify_fail_action = reinstall
-
-installOnlyPkgs
-^^^^^^^^^^^^^^^
-
-Install only packages are packages that should only ever be installed
-or deleted, not upgraded.
-
-The only packages for which this is an absolute on, are the gpg-pubkey
-packages. It is however 'best' practice to only ever install/delete
-kernel packages. The wisdom being that the package for the currently
-running kernel should always be installed. Doing an upgrade would delete
-the running kernel package.
-
-The RPMng driver follows the YUM practice of having a list of install
-only packages. A default list is hard coded in RPMng.py. This maybe over
-ridden in the client configuration file.
-
-Note that except for gpg-pubkey packages (which are always added to the
-list by the driver) the list in the client configuration file completely
-replaces the default list. An empty list means that there are no install
-only packages (except for gpg-pubkey), which is the behaviour of the
-old RPM driver.
-
-Example - an empty list::
-
- [RPMng]
- installonlypackages =
-
-Example - The default list::
-
- [RPMng]
- installonlypackages = kernel, kernel-bigmem, kernel-enterprise, kernel-smp, kernel-modules, kernel-debug, kernel-unsupported, kernel-source, kernel-devel, kernel-default, kernel-largesmp-devel, kernel-largesmp, kernel-xen, gpg-pubkey
-
-erase_flags
-^^^^^^^^^^^
-
-erase_flags are rpm options used by 'rpm -erase' in the client Remove()
-method. The RPMng erase is written using rpm-python and does not use
-the rpm command.
-
-The erase flags are specified in the client configuration file as a comma
-separated list and apply to all RPM erase operations. The default is::
-
- [RPMng]
- erase_flags = allmatches
-
-The following rpm erase options are supported, see the rpm man page
-for details.::
-
- noscripts
- notriggers
- repackage
- allmatches
- nodeps
-
-.. note:: Note that specifying erase_flags in the configuration file completely replaces the default.
-
-pkg_checks
-^^^^^^^^^^
-
-The RPMng/YUMng drivers do the following three checks/status:
-
-#. Installed
-#. Version
-#. rpm verify
-
-Setting pkg_checks = true (the default) in the client configuration file
-means that all three checks will be done for all packages.
-
-Setting pkg_checks = false in the client configuration file means that
-only the Installed check will be done for all packages.
-
-The true/false value can be any combination of upper and lower case.
-
-.. note::
- #. pkg_checks must evaluate true for both the client (this option) and the package (see the Package Tag pkg_checks attribute below) for the action to take place.
- #. If pkg_checks = false then the Pkgmgr entries do not need the version information. See the examples towards the bottom of the page.
-
-pkg_verify
-^^^^^^^^^^
-
-The RPMng/YUMng drivers do the following three checks/status:
-
-#. Installed
-#. Version
-#. rpm verify
-
-Setting pkg_verify = true (the default) in the client configuration
-file means that all three checks will be done for all packages as long
-as pkg_checks = true.
-
-Setting pkg_verify = false in the client configuration file means that
-the rpm verify wil not be done for all packages on the client.
-
-The true/false value can be any combination of upper and lower case.
-
-.. note::
- #. pkg_verify must evaluate true for both the client (this option) and the package instance (see the Instance Tag pkg_verify attribute below) for the action to take place.
-
-install_action
-^^^^^^^^^^^^^^
-
-The RPMng/YUMng drivers do the following three checks/status:
-
-#. Installed
-#. Version
-#. rpm verify
-
-install_action controls whether or not a package instance will be
-installed if the installed check fails (i.e. if the package instance
-isn't installed).
-
-If install_action = install then the package instance is installed.
-If install_action = none then the package instance is not installed.
-
-.. note::
- #. install_action must evaluate true for both the client (this option) and the package instance (see the Instance Tag install_action attribute below) for the action to take place.
-
-version_fail_action
-^^^^^^^^^^^^^^^^^^^
-
-The RPMng/YUMng drivers do the following three checks/status:
-
-#. Installed
-#. Version
-#. rpm verify
-
-version_fail_action controls whether or not a package instance will
-be updated if the version check fails (i.e. if the installed package
-instance isn't the same version as specified in the configuration).
-
-If version_fail_action = upgrade then the package instance is upgraded
-(or downgraded).
-
-If version_fail_action = none then the package instance is not upgraded
-(or downgraded).
-
-.. note::
- #. verion_fail_action must evaluate true for both the client (this option) and the package instance (see the Instance Tag version_fail_action attribute below) for the action to take place.
-
-verify_fail_action
-^^^^^^^^^^^^^^^^^^
-
-The RPMng/YUMng drivers do the following three checks/status:
-
-#. Installed
-#. Version
-#. rpm verify
-
-verify_fail_action controls whether or not a package instance will be
-reinstlled if the version check fails (i.e. if the installed package
-instance isn't the same version as specified in the configuration).
-
-If verify_fail_action = reinstall then the package instance is reinstalled.
-If verify_fail_action = none then the package instance is not reinstalled.
-
-.. note::
- #. verify_fail_action must evaluate true for both the client (this option) and the package instance (see the Instance Tag verify_fail_action attribute below) for the action to take place.
- #. yum cannot reinstall packages, so this option is really only relevant to RPMng.
- #. RPMng will not attempt to reinstall a package instance if the only failure is an RPM configuration file.
- #. RPMng will not attempt to reinstall a package instance if the only failure is an RPM dependency failure.
-
-Interactive Mode
-----------------
-
-Running the client in interactive mode (-I) prompts for the actions to
-be taken as before. Prompts are per package and may apply to multiple
-instances of that package. Each per package prompt will contain a list
-of actions per instance.
-
-Actions are encoded as
-
-D - Delete
-
-I - Install
-
-R - Reinstall
-
-U - Upgrade/Downgrade
-
-
-An example is below. The example is from a system that is still using
-the old Pkgmgr format, so the epoch and arch appear as '*'.::
-
- Install/Upgrade/delete Package aaa_base instance(s) - R(*:10.2-38.*) (y/N)
- Install/Upgrade/delete Package evms instance(s) - R(*:2.5.5-67.*) (y/N)
- Install/Upgrade/delete Package gpg-pubkey instance(s) - D(*:9c800aca-40d8063e.*) D(*:0dfb3188-41ed929b.*) D(*:7e2e3b05-44748aba.*) D(*:a1912208-446a0899.*) D(*:9c777da4-4515b5fd.*) D(*:307e3d54-44201d5d.*) (y/N)
- Install/Upgrade/delete Package module-init-tools instance(s) - R(*:3.2.2-62.*) (y/N)
- Install/Upgrade/delete Package multipath-tools instance(s) - R(*:0.4.7-29.*) (y/N)
- Install/Upgrade/delete Package pam instance(s) - R(*:0.99.6.3-29.1.*) (y/N)
- Install/Upgrade/delete Package perl-AppConfig instance(s) - U(None:1.52-4.noarch -> *:1.63-17.*) (y/N)
- Install/Upgrade/delete Package postfix instance(s) - R(*:2.3.2-28.*) (y/N)
- Install/Upgrade/delete Package sysconfig instance(s) - R(*:0.60.4-3.*) (y/N)
- Install/Upgrade/delete Package udev instance(s) - R(*:103-12.*) (y/N)
-
-GPG Keys
---------
-
-GPG is used by RPM to 'sign' packages. All vendor packages are signed
-with the vendors GPG key. Additional signatures maybe added to the rpm
-file at the users discretion.
-
-It is normal to have multiple GPG keys installed. For example, SLES10
-out of the box has six GPG keys installed.
-
-To the RPM database all GPG 'packages' have the name 'gpg-pubkey', which
-may be nothing like the name of the file specified in the rpm -import
-command. For example on Centos 4 the file name is RPM-GPG-KEY-centos4.
-For SLES10 this means that there are six packages with the name
-'gpg-pubkey' installed.
-
-RPM does not check GPG keys at package installation, YUM does.
-
-RPMng uses the rpm command for installation and does not therefore
-check GPG signatures at package install time. RPMng uses rpm-python
-for verification and does by default do signature checks as part of the
-client Inventory process. To do the signature check the appropriate GPG
-keys must be installed. rpm-python is not very friendly if the required
-key(s) is not installed (it crashes the client).
-
-The RPMng driver detects, on a per package instance basis, if the
-appropriate key is installed. If it is not, a warning message is printed
-and the signature check is disabled for that package instance, for that
-client run only.
-
-GPG keys can be installed and removed by the RPMng driver. To install a
-GPG key configure it in Pkgmgr/Rules as a package and add gpg-pubkey to
-the clients abstract configuration. The gpg-pubkey package/instance is
-treated as an install only package. gpg-pubkey packages are installed
-by the RPMng driver with the rpm -import command.
-
-gpg-pubkey packages will be removed by ``bcfg2 -r packages`` if they are
-not in the clients configuration.
-
-.. code-block:: xml
-
- <PackageList uri='http://fortress/' priority='0' type='rpm'>
- <Group name='Centos4.4-Standard'>
- <Group name='x86_64'>
- <Package name='gpg-pubkey' type='rpm'>
- <Instance simplefile='mrepo/Centos44-x86_64/disc1/RPM-GPG-KEY-centos4' version='443e1821' release='421f218f'/>
- <Instance simplefile='RPM-GPG-KEY-mbrady' version='9c777da4' release='4515b5fd'/>
- </Package>
- </Group>
- </Group>
- </PackageList>
-
-Example gpg-pubkey Pkgmgr configuration file.
-
-Pkgmgr Configuration
---------------------
-
-Also see the general :ref:`Pkgmgr <server-plugins-generators-pkgmgr>`
-and :ref:`server-plugins-structures-altsrc` pages.
-
-Package Tag (Old style)
-^^^^^^^^^^^^^^^^^^^^^^^
-
-Old style (meaning no Instance tag) Pkgmgr files have limited support.
-Specifically the multiarch and verify attributes are ignored.
-
-If multiarch type support is needed a new style format file must be used.
-
-If some control over the verification is needed, replace the verify
-attribute with the pkg_checks or verify_flags attributes. The pkg_checks
-and verify_flags attributes are detailed under the Instance tag heading.
-
-Package Tag (New Style) and Attributes
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The new style package tag supports the name and pkg_checks attributes
-and requires the use of Instance tag entries.
-
-New style configuration files must be generated from the RPM headers.
-Either from RPM files or from the RPM DB.
-
-The included pkgmgr_gen.py can be used as a starting point for generating
-configuration files from directories of RPM package files. pkgmgr_gen.py
---help for the options.
-
-The included pkgmgr_update.py can be used to update the package instance
-versions in configuration files from directories of package files.
-pkgmgr_update.py --help for the options.
-
-+------------+---------------------------------------+------------------------+
-| Attribute | Description | Values |
-+============+=======================================+========================+
-| name | Package name. | String |
-+------------+---------------------------------------+------------------------+
-| pkg_checks | Do the version and rpm verify checks. | true(default) or false |
-+------------+---------------------------------------+------------------------+
-
-Instance Tag and Attributes
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The instance tag supports the following attributes:
-
-+---------------------+----------------------------+--------------------------+
-| Attribute | Description | Values |
-+=====================+============================+==========================+
-| simplefile | Package file name. | String (see Notes below) |
-+---------------------+----------------------------+--------------------------+
-| epoch | Package epoch. | String (numeric only) |
-| | | (optional) |
-+---------------------+----------------------------+--------------------------+
-| version | Package version. | String |
-+---------------------+----------------------------+--------------------------+
-| release | Package release. | String |
-+---------------------+----------------------------+--------------------------+
-| arch | Package architecture. | Architecture String e.g. |
-| | | (i386|i586|i686|x86_64) |
-+---------------------+----------------------------+--------------------------+
-| verify_flags | Comma separated list of | nodeps, nodigest, |
-| | rpm --verify options. See | nofiles, noscripts, |
-| | the rpm man page for their | nosignature, nolinkto, |
-| | details. | nomd5, nosize, nouser, |
-| | | nogroup, nomtime, |
-| | | nomode, nordev |
-+---------------------+----------------------------+--------------------------+
-| pkg_verify | Do the rpm verify | true(default) or false |
-+---------------------+----------------------------+--------------------------+
-| install_action | Install package instance | install(default) or none |
-| | if it is not installed. | |
-+---------------------+----------------------------+--------------------------+
-| version_fail_action | Upgrade package if the | upgrade(default) or none |
-| | incorrect version is | |
-| | installed. | |
-+---------------------+----------------------------+--------------------------+
-| verify_fail_action | Reinstall the package | reinstall(default) or |
-| | instance if the rpm verify | none |
-| | failed | |
-+---------------------+----------------------------+--------------------------+
-
-.. note::
-
- The simplefile attribute doesn't need to be just the filename,
- meaning the basename. It is joined with the uri attribute from the
- PackageList Tag to form the URL that the client will use to download
- the package. So the uri could just be the host portion of the url
- and simple file could be the directory path.
-
- e.g.
-
- .. code-block:: xml
-
- <PackageList uri='http://fortress/' priority='0' type='rpm'>
- <Group name='Centos4.4-Standard'>
- <Group name='x86_64'>
- <Package name='gpg-pubkey' type='rpm'>
- <Instance simplefile='mrepo/Centos44-x86_64/disc1/RPM-GPG-KEY-centos4' version='443e1821' release='421f218f'/>
- <Instance simplefile='RPM-GPG-KEY-mbrady' version='9c777da4' release='4515b5fd'/>
- </Package>
- </Group>
- </Group>
- </PackageList>
-
-The values for epoch, version, release and arch attributes must come
-from the RPM header, not the RPM file name.
-
-Epoch is a strange thing. In short::
-
- epoch not set == epoch=None < epoch='0' < epoch='1'
-
-and it is an int, but elementtree attributes have to be str or unicode,
-so the driver is constantly converting.
-
-Ignore Tag
-^^^^^^^^^^
-
-The Ignore tag is used to "mask out" individual files from the RPM
-verification. This is done by comparing the verification failure results
-with the Ignore tag name. If there is a match, that entry is not used
-by the client to determine if a package has failed verification.
-
-Ignore tag entries can be specified at both the Package level, in which
-case they apply to all Instances, and/or at the Instance level, in which
-case they only apply to that instance.
-
-Ignore tag entries are used by the RPMng driver. They can be specified
-in both old and new style Pkgmgr files.
-
-The Ignore Tag supports the following attributes:
-
-+-----------+-------------+--------+
-| Attribute | Description | Values |
-+===========+=============+========+
-| name | File name. | String |
-+-----------+-------------+--------+
-
-Example
-
-.. code-block:: xml
-
- <Package name='glibc' type='rpm'>
- <Ignore name='/etc/rpc'/>
- <Instance simplefile='glibc-2.3.4-2.25.x86_64.rpm' version='2.3.4' release='2.25' arch='x86_64'/>
- </Package>
-
-POSIX 'ignore' Path entries
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The YUMng analog to the Ignore Tag used by RPMng is the use of Path
-entries of type 'ignore'. The following shows an example for the
-centos-release package which doesn't verify if you remove the default
-repos and replace them with a custom repo.
-
-.. code-block:: xml
-
- <!-- Ignore verification failures for centos-release -->
- <BoundPath name='/etc/yum.repos.d/CentOS-Base.repo' type='ignore'/>
- <BoundPath name='/etc/yum.repos.d/CentOS-Media.repo' type='ignore'/>
-
-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 RPMng
-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 RPMng driver. They do not appear
-to be supported in YUMng 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 YUMng a minimal entry is
-
-.. code-block:: xml
-
- <Package name="bcfg2" type="yum" pkg_checks="False"/>
-
-In fact for YUMng, 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 RPMng 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>
diff --git a/doc/server/plugins/generators/pkgmgr.txt b/doc/server/plugins/generators/pkgmgr.txt
index d3342feb6..76a8ec1a5 100644
--- a/doc/server/plugins/generators/pkgmgr.txt
+++ b/doc/server/plugins/generators/pkgmgr.txt
@@ -6,14 +6,6 @@
Pkgmgr
======
-.. note::
-
- See [wiki:ClientTools/RPMng#PackageTagNewStyleandAttributes
- RPMng#PackageTagNewStyleandAttributes].''' The way of showing the
- architecture of the RPM has changed. The new way is "arch". The
- old way is "multiarch". '''This document needs to be updated and
- include version of Bcfg2 where change took place.'''
-
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.
@@ -48,32 +40,60 @@ Group membership may be negated.
Tag Attributes in Pkgmgr
========================
-PackageList Tag
----------------
-
-The PackageList Tag may have the following attributes:
-
-+-----------+-----------------------------------------------+----------------+
-| Name | Description | Values |
-+===========+===============================================+================+
-| priority | Sets the priority for packages in the package | Integer |
-| | list. The higher value wins. | |
-+-----------+-----------------------------------------------+----------------+
-| type | Package type that applies to all packages in | deb|rpm|blast| |
-| | the list. This value is inherited by all | encap|sysv| |
-| | packages without an explicit type attribute. | portage|yum |
-+-----------+-----------------------------------------------+----------------+
-| uri | URI to prepend to filename sto fetch packages | String |
-| | in this list. | |
-+-----------+-----------------------------------------------+----------------+
-| multiarch | Comma-separated list of architectures that | String |
-| | apply to all packages in this list. Inherited | |
-| | by all package entries in the file that does | |
-| | not have this attribute explicitly. | |
-+-----------+-----------------------------------------------+----------------+
-| srcs | To be used with multiarch support. Inherited | String |
-| | by all Package entries without this attribute | |
-+-----------+-----------------------------------------------+----------------+
+Package Tag
+^^^^^^^^^^^
+
+The package tag supports the name and pkg_checks attributes and
+requires the use of Instance tag entries.
+
++------------+---------------------------------------+------------------------+
+| Attribute | Description | Values |
++============+=======================================+========================+
+| name | Package name. | String |
++------------+---------------------------------------+------------------------+
+| pkg_checks | Do the version and rpm verify checks. | true(default) or false |
++------------+---------------------------------------+------------------------+
+
+Instance Tag and Attributes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The instance tag supports the following attributes:
+
++---------------------+----------------------------+--------------------------+
+| Attribute | Description | Values |
++=====================+============================+==========================+
+| simplefile | Package file name. | String (see Notes below) |
++---------------------+----------------------------+--------------------------+
+| epoch | Package epoch. | String (numeric only) |
+| | | (optional) |
++---------------------+----------------------------+--------------------------+
+| version | Package version. | String |
++---------------------+----------------------------+--------------------------+
+| release | Package release. | String |
++---------------------+----------------------------+--------------------------+
+| arch | Package architecture. | Architecture String e.g. |
+| | | (i386|i586|i686|x86_64) |
++---------------------+----------------------------+--------------------------+
+| verify_flags | Comma separated list of | nodeps, nodigest, |
+| | rpm --verify options. See | nofiles, noscripts, |
+| | the rpm man page for their | nosignature, nolinkto, |
+| | details. | nomd5, nosize, nouser, |
+| | | nogroup, nomtime, |
+| | | nomode, nordev |
++---------------------+----------------------------+--------------------------+
+| pkg_verify | Do the rpm verify | true(default) or false |
++---------------------+----------------------------+--------------------------+
+| install_action | Install package instance | install(default) or none |
+| | if it is not installed. | |
++---------------------+----------------------------+--------------------------+
+| version_fail_action | Upgrade package if the | upgrade(default) or none |
+| | incorrect version is | |
+| | installed. | |
++---------------------+----------------------------+--------------------------+
+| verify_fail_action | Reinstall the package | reinstall(default) or |
+| | instance if the rpm verify | none |
+| | failed | |
++---------------------+----------------------------+--------------------------+
Pkgmgr Group Tag
----------------
@@ -88,40 +108,6 @@ The Pkgmgr Group Tag may have the following attributes:
| negate | Negate group membership (is not a member of) | True|False |
+--------+----------------------------------------------+------------+
-Package Tag
------------
-
-The Package Tag may have the following attributes:
-
-+------------+----------------------------------------------+------------+
-| Name | Description | Values |
-+============+==============================================+============+
-| name | Package Name | String |
-+------------+----------------------------------------------+------------+
-| version | Package version, set to ``auto`` to install | String |
-| | the latest version in the client's cache, or | |
-| | ``any`` to verify that any version of the | |
-| | package is installed on the client | |
-+------------+----------------------------------------------+------------+
-| file | Package file name. Several other attributes | String |
-| | (name, version) can be automatically defined | |
-| | based on regular expressions defined in the | |
-| | Pkgmgr plugin. | |
-+------------+----------------------------------------------+------------+
-| simplefile | Package file name. No name parsing is | String |
-| | performed, so no extra fields get set | |
-+------------+----------------------------------------------+------------+
-| verify | Whether package verification should be done | True|False |
-+------------+----------------------------------------------+------------+
-| multiarch | Comma-separated list of the architectures of | String |
-| | this package that should be installed. | |
-| | (Temporary work-around) | |
-+------------+----------------------------------------------+------------+
-| srcs | File name creation rules for multiarch | String |
-| | packages. (Temporary work-around) | |
-+------------+----------------------------------------------+------------+
-| type | Package type (rpm, yum, apt, sysv, blast) | String |
-+------------+----------------------------------------------+------------+
Client Tag
----------
@@ -323,11 +309,186 @@ implemented that should ease this situation considerably.
Altogether, this should move policy decisions about package architectures
to bundles/base.
-Client Driver (Plugins) Specific Attributes
-===========================================
+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::
-Not all the attributes that are available in Pkgmgr are honoured by all
-the client drivers. The following client drivers (plugins) have driver
-specific attributes:
+ 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.
-* :ref:`RPMng <client-tools-yumng>`
+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>
diff --git a/src/lib/Bcfg2/Client/Frame.py b/src/lib/Bcfg2/Client/Frame.py
index ef61940eb..b0032057a 100644
--- a/src/lib/Bcfg2/Client/Frame.py
+++ b/src/lib/Bcfg2/Client/Frame.py
@@ -84,11 +84,11 @@ class Frame(object):
for tool in list(tclass.values()):
try:
self.tools.append(tool(self.logger, setup, config))
- except Bcfg2.Client.Tools.toolInstantiationError:
+ except Bcfg2.Client.Tools.ToolInstantiationError:
continue
except:
- self.logger.error("Failed to instantiate tool %s" % \
- (tool), exc_info=1)
+ self.logger.error("Failed to instantiate tool %s" % tool,
+ exc_info=1)
for tool in self.tools[:]:
for conflict in getattr(tool, 'conflicts', []):
@@ -99,10 +99,15 @@ class Frame(object):
self.logger.info("Loaded tool drivers:")
self.logger.info([tool.name for tool in self.tools])
+ deprecated = [tool.name for tool in self.tools if tool.deprecated]
+ if deprecated:
+ self.logger.warning("Loaded deprecated tool drivers:")
+ self.logger.warning(deprecated)
+
# find entries not handled by any tools
self.unhandled = [entry for struct in config
- for entry in struct
- if entry not in self.handled]
+ for entry in struct
+ if entry not in self.handled]
if self.unhandled:
self.logger.error("The following entries are not handled by any "
diff --git a/src/lib/Bcfg2/Client/Tools/RPM.py b/src/lib/Bcfg2/Client/Tools/RPM.py
new file mode 100644
index 000000000..1e54dc449
--- /dev/null
+++ b/src/lib/Bcfg2/Client/Tools/RPM.py
@@ -0,0 +1,988 @@
+"""Bcfg2 Support for RPMS"""
+
+import os.path
+import rpm
+import rpmtools
+import Bcfg2.Client.Tools
+
+class RPM(Bcfg2.Client.Tools.PkgTool):
+ """Support for RPM packages."""
+ __execs__ = ['/bin/rpm', '/var/lib/rpm']
+ __handles__ = [('Package', 'rpm')]
+
+ __req__ = {'Package': ['name', 'version']}
+ __ireq__ = {'Package': ['url']}
+
+ __new_req__ = {'Package': ['name'],
+ 'Instance': ['version', 'release', 'arch']}
+ __new_ireq__ = {'Package': ['uri'], \
+ 'Instance': ['simplefile']}
+
+ __gpg_req__ = {'Package': ['name', 'version']}
+ __gpg_ireq__ = {'Package': ['name', 'version']}
+
+ __new_gpg_req__ = {'Package': ['name'],
+ 'Instance': ['version', 'release']}
+ __new_gpg_ireq__ = {'Package': ['name'],
+ 'Instance': ['version', 'release']}
+
+ conflicts = ['RPMng']
+
+ pkgtype = 'rpm'
+ pkgtool = ("rpm --oldpackage --replacepkgs --quiet -U %s", ("%s", ["url"]))
+
+ def __init__(self, logger, setup, config):
+ Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config)
+
+ # create a global ignore list used when ignoring particular
+ # files during package verification
+ self.ignores = [entry.get('name') for struct in config for entry in struct \
+ if entry.get('type') == 'ignore']
+ self.instance_status = {}
+ self.extra_instances = []
+ self.modlists = {}
+ self.gpg_keyids = self.getinstalledgpg()
+
+ opt_prefix = self.name.lower()
+ self.installOnlyPkgs = self.setup["%s_installonly" % opt_prefix]
+ if 'gpg-pubkey' not in self.installOnlyPkgs:
+ self.installOnlyPkgs.append('gpg-pubkey')
+ self.erase_flags = self.setup['%s_erase_flags' % opt_prefix]
+ self.pkg_checks = self.setup['%s_pkg_checks' % opt_prefix]
+ self.pkg_verify = self.setup['%s_pkg_verify' % opt_prefix]
+ self.installed_action = self.setup['%s_installed_action' % opt_prefix]
+ self.version_fail_action = self.setup['%s_version_fail_action' %
+ opt_prefix]
+ self.verify_fail_action = self.setup['%s_verify_fail_action' %
+ opt_prefix]
+ self.verify_flags = self.setup['%s_verify_flags' % opt_prefix]
+ if '' in self.verify_flags:
+ self.verify_flags.remove('')
+
+ self.logger.debug('%s: installOnlyPackages = %s' %
+ (self.name, self.installOnlyPkgs))
+ self.logger.debug('%s: erase_flags = %s' %
+ (self.name, self.erase_flags))
+ self.logger.debug('%s: pkg_checks = %s' %
+ (self.name, self.pkg_checks))
+ self.logger.debug('%s: pkg_verify = %s' %
+ (self.name, self.pkg_verify))
+ self.logger.debug('%s: installed_action = %s' %
+ (self.name, self.installed_action))
+ self.logger.debug('%s: version_fail_action = %s' %
+ (self.name, self.version_fail_action))
+ self.logger.debug('%s: verify_fail_action = %s' %
+ (self.name, self.verify_fail_action))
+ self.logger.debug('%s: verify_flags = %s' %
+ (self.name, self.verify_flags))
+
+ # Force a re- prelink of all packages if prelink exists.
+ # Many, if not most package verifies can be caused by out of
+ # date prelinking.
+ if os.path.isfile('/usr/sbin/prelink') and not self.setup['dryrun']:
+ cmdrc, output = self.cmd.run('/usr/sbin/prelink -a -mR')
+ if cmdrc == 0:
+ self.logger.debug('Pre-emptive prelink succeeded')
+ else:
+ # FIXME : this is dumb - what if the output is huge?
+ self.logger.error('Pre-emptive prelink failed: %s' % output)
+
+
+ def RefreshPackages(self):
+ """
+ Creates self.installed{} which is a dict of installed packages.
+
+ The dict items are lists of nevra dicts. This loosely matches the
+ config from the server and what rpmtools uses to specify pacakges.
+
+ e.g.
+
+ self.installed['foo'] = [ {'name':'foo', 'epoch':None,
+ 'version':'1', 'release':2,
+ 'arch':'i386'},
+ {'name':'foo', 'epoch':None,
+ 'version':'1', 'release':2,
+ 'arch':'x86_64'} ]
+ """
+ self.installed = {}
+ refresh_ts = rpmtools.rpmtransactionset()
+ # Don't bother with signature checks at this stage. The GPG keys might
+ # not be installed.
+ refresh_ts.setVSFlags(rpm._RPMVSF_NODIGESTS|rpm._RPMVSF_NOSIGNATURES)
+ for nevra in rpmtools.rpmpackagelist(refresh_ts):
+ self.installed.setdefault(nevra['name'], []).append(nevra)
+ if self.setup['debug']:
+ print("The following package instances are installed:")
+ for name, instances in list(self.installed.items()):
+ self.logger.debug(" " + name)
+ for inst in instances:
+ self.logger.debug(" %s" %self.str_evra(inst))
+ refresh_ts.closeDB()
+ del refresh_ts
+
+ def VerifyPackage(self, entry, modlist, pinned_version=None):
+ """
+ Verify Package status for entry.
+ Performs the following:
+ - Checks for the presence of required Package Instances.
+ - Compares the evra 'version' info against self.installed{}.
+ - RPM level package verify (rpm --verify).
+ - Checks for the presence of unrequired package instances.
+
+ Produces the following dict and list for RPM.Install() to use:
+ For installs/upgrades/fixes of required instances:
+ instance_status = { <Instance Element Object>:
+ { 'installed': True|False,
+ 'version_fail': True|False,
+ 'verify_fail': True|False,
+ 'pkg': <Package Element Object>,
+ 'modlist': [ <filename>, ... ],
+ 'verify' : [ <rpm --verify results> ]
+ }, ......
+ }
+
+ For deletions of unrequired instances:
+ extra_instances = [ <Package Element Object>, ..... ]
+
+ Constructs the text prompts for interactive mode.
+ """
+ instances = [inst for inst in entry if inst.tag == 'Instance' or inst.tag == 'Package']
+ if instances == []:
+ # We have an old style no Instance entry. Convert it to new style.
+ instance = Bcfg2.Client.XML.SubElement(entry, 'Package')
+ for attrib in list(entry.attrib.keys()):
+ instance.attrib[attrib] = entry.attrib[attrib]
+ if (self.pkg_checks and
+ entry.get('pkg_checks', 'true').lower() == 'true'):
+ if 'any' in [entry.get('version'), pinned_version]:
+ version, release = 'any', 'any'
+ elif entry.get('version') == 'auto':
+ if pinned_version != None:
+ version, release = pinned_version.split('-')
+ else:
+ return False
+ else:
+ version, release = entry.get('version').split('-')
+ instance.set('version', version)
+ instance.set('release', release)
+ if entry.get('verify', 'true') == 'false':
+ instance.set('verify', 'false')
+ instances = [ instance ]
+
+ self.logger.debug("Verifying package instances for %s" % entry.get('name'))
+ package_fail = False
+ qtext_versions = ''
+
+ if entry.get('name') in self.installed:
+ # There is at least one instance installed.
+ if (self.pkg_checks and
+ entry.get('pkg_checks', 'true').lower() == 'true'):
+ rpmTs = rpm.TransactionSet()
+ rpmHeader = None
+ for h in rpmTs.dbMatch(rpm.RPMTAG_NAME, entry.get('name')):
+ if rpmHeader is None or rpm.versionCompare(h, rpmHeader) > 0:
+ rpmHeader = h
+ rpmProvides = [ h['provides'] for h in \
+ rpmTs.dbMatch(rpm.RPMTAG_NAME, entry.get('name')) ]
+ rpmIntersection = set(rpmHeader['provides']) & \
+ set(self.installOnlyPkgs)
+ if len(rpmIntersection) > 0:
+ # Packages that should only be installed or removed.
+ # e.g. kernels.
+ self.logger.debug(" Install only package.")
+ for inst in instances:
+ self.instance_status.setdefault(inst, {})['installed'] = False
+ self.instance_status[inst]['version_fail'] = False
+ if inst.tag == 'Package' and len(self.installed[entry.get('name')]) > 1:
+ self.logger.error("WARNING: Multiple instances of package %s are installed." % \
+ (entry.get('name')))
+ for pkg in self.installed[entry.get('name')]:
+ if inst.get('version') == 'any' or self.pkg_vr_equal(inst, pkg) \
+ or self.inst_evra_equal(inst, pkg):
+ if inst.get('version') == 'any':
+ self.logger.error("got any version")
+ self.logger.debug(" %s" % self.str_evra(inst))
+ self.instance_status[inst]['installed'] = True
+
+ if (self.pkg_verify and
+ inst.get('pkg_verify', 'true').lower() == 'true'):
+ flags = inst.get('verify_flags', '').split(',') + self.verify_flags
+ if pkg.get('gpgkeyid', '')[-8:] not in self.gpg_keyids and \
+ entry.get('name') != 'gpg-pubkey':
+ flags += ['nosignature', 'nodigest']
+ self.logger.debug('WARNING: Package %s %s requires GPG Public key with ID %s'\
+ % (pkg.get('name'), self.str_evra(pkg), \
+ pkg.get('gpgkeyid', '')))
+ self.logger.debug(' Disabling signature check.')
+
+ if self.setup.get('quick', False):
+ if rpmtools.prelink_exists:
+ flags += ['nomd5', 'nosize']
+ else:
+ flags += ['nomd5']
+ self.logger.debug(" verify_flags = %s" % flags)
+
+ if inst.get('verify', 'true') == 'false':
+ self.instance_status[inst]['verify'] = None
+ else:
+ vp_ts = rpmtools.rpmtransactionset()
+ self.instance_status[inst]['verify'] = \
+ rpmtools.rpm_verify( vp_ts, pkg, flags)
+ vp_ts.closeDB()
+ del vp_ts
+
+ if self.instance_status[inst]['installed'] == False:
+ self.logger.info(" Package %s %s not installed." % \
+ (entry.get('name'), self.str_evra(inst)))
+
+ qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst)
+ entry.set('current_exists', 'false')
+ else:
+ # Normal Packages that can be upgraded.
+ for inst in instances:
+ self.instance_status.setdefault(inst, {})['installed'] = False
+ self.instance_status[inst]['version_fail'] = False
+
+ # Only installed packages with the same architecture are
+ # relevant.
+ if inst.get('arch', None) == None:
+ arch_match = self.installed[entry.get('name')]
+ else:
+ arch_match = [pkg for pkg in self.installed[entry.get('name')] \
+ if pkg.get('arch', None) == inst.get('arch', None)]
+
+ if len(arch_match) > 1:
+ self.logger.error("Multiple instances of package %s installed with the same achitecture." % \
+ (entry.get('name')))
+ elif len(arch_match) == 1:
+ # There is only one installed like there should be.
+ # Check that it is the right version.
+ for pkg in arch_match:
+ if inst.get('version') == 'any' or self.pkg_vr_equal(inst, pkg) or \
+ self.inst_evra_equal(inst, pkg):
+ self.logger.debug(" %s" % self.str_evra(inst))
+ self.instance_status[inst]['installed'] = True
+
+ if (self.pkg_verify and
+ inst.get('pkg_verify', 'true').lower() == 'true'):
+ flags = inst.get('verify_flags', '').split(',') + self.verify_flags
+ if pkg.get('gpgkeyid', '')[-8:] not in self.gpg_keyids and \
+ 'nosignature' not in flags:
+ flags += ['nosignature', 'nodigest']
+ self.logger.info('WARNING: Package %s %s requires GPG Public key with ID %s'\
+ % (pkg.get('name'), self.str_evra(pkg), \
+ pkg.get('gpgkeyid', '')))
+ self.logger.info(' Disabling signature check.')
+
+ if self.setup.get('quick', False):
+ if rpmtools.prelink_exists:
+ flags += ['nomd5', 'nosize']
+ else:
+ flags += ['nomd5']
+ self.logger.debug(" verify_flags = %s" % flags)
+
+ if inst.get('verify', 'true') == 'false':
+ self.instance_status[inst]['verify'] = None
+ else:
+ vp_ts = rpmtools.rpmtransactionset()
+ self.instance_status[inst]['verify'] = \
+ rpmtools.rpm_verify( vp_ts, pkg, flags )
+ vp_ts.closeDB()
+ del vp_ts
+
+ else:
+ # Wrong version installed.
+ self.instance_status[inst]['version_fail'] = True
+ self.logger.info(" Wrong version installed. Want %s, but have %s"\
+ % (self.str_evra(inst), self.str_evra(pkg)))
+
+ qtext_versions = qtext_versions + 'U(%s -> %s) ' % \
+ (self.str_evra(pkg), self.str_evra(inst))
+ elif len(arch_match) == 0:
+ # This instance is not installed.
+ self.instance_status[inst]['installed'] = False
+ self.logger.info(" %s is not installed." % self.str_evra(inst))
+ qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst)
+
+ # Check the rpm verify results.
+ for inst in instances:
+ instance_fail = False
+ # Dump the rpm verify results.
+ #****Write something to format this nicely.*****
+ if self.setup['debug'] and self.instance_status[inst].get('verify', None):
+ self.logger.debug(self.instance_status[inst]['verify'])
+
+ self.instance_status[inst]['verify_fail'] = False
+ if self.instance_status[inst].get('verify', None):
+ if len(self.instance_status[inst].get('verify')) > 1:
+ self.logger.info("WARNING: Verification of more than one package instance.")
+
+ for result in self.instance_status[inst]['verify']:
+
+ # Check header results
+ if result.get('hdr', None):
+ instance_fail = True
+ self.instance_status[inst]['verify_fail'] = True
+
+ # Check dependency results
+ if result.get('deps', None):
+ instance_fail = True
+ self.instance_status[inst]['verify_fail'] = True
+
+ # Check the rpm verify file results against the modlist
+ # and entry and per Instance Ignores.
+ ignores = [ig.get('name') for ig in entry.findall('Ignore')] + \
+ [ig.get('name') for ig in inst.findall('Ignore')] + \
+ self.ignores
+ for file_result in result.get('files', []):
+ if file_result[-1] not in modlist + ignores:
+ instance_fail = True
+ self.instance_status[inst]['verify_fail'] = True
+ else:
+ self.logger.debug(" Modlist/Ignore match: %s" % \
+ (file_result[-1]))
+
+ if instance_fail == True:
+ self.logger.debug("*** Instance %s failed RPM verification ***" % \
+ self.str_evra(inst))
+ qtext_versions = qtext_versions + 'R(%s) ' % self.str_evra(inst)
+ self.modlists[entry] = modlist
+
+ # Attach status structure for return to server for reporting.
+ inst.set('verify_status', str(self.instance_status[inst]))
+
+ if self.instance_status[inst]['installed'] == False or \
+ self.instance_status[inst].get('version_fail', False)== True or \
+ self.instance_status[inst].get('verify_fail', False) == True:
+ package_fail = True
+ self.instance_status[inst]['pkg'] = entry
+ self.modlists[entry] = modlist
+
+ # Find Installed Instances that are not in the Config.
+ extra_installed = self.FindExtraInstances(entry, self.installed[entry.get('name')])
+ if extra_installed != None:
+ package_fail = True
+ self.extra_instances.append(extra_installed)
+ for inst in extra_installed.findall('Instance'):
+ qtext_versions = qtext_versions + 'D(%s) ' % self.str_evra(inst)
+ self.logger.debug("Found Extra Instances %s" % qtext_versions)
+
+ if package_fail == True:
+ self.logger.info(" Package %s failed verification." % \
+ (entry.get('name')))
+ qtext = 'Install/Upgrade/delete Package %s instance(s) - %s (y/N) ' % \
+ (entry.get('name'), qtext_versions)
+ entry.set('qtext', qtext)
+
+ bcfg2_versions = ''
+ for bcfg2_inst in [inst for inst in instances if inst.tag == 'Instance']:
+ bcfg2_versions = bcfg2_versions + '(%s) ' % self.str_evra(bcfg2_inst)
+ if bcfg2_versions != '':
+ entry.set('version', bcfg2_versions)
+ installed_versions = ''
+
+ for installed_inst in self.installed[entry.get('name')]:
+ installed_versions = installed_versions + '(%s) ' % \
+ self.str_evra(installed_inst)
+
+ entry.set('current_version', installed_versions)
+ return False
+
+ else:
+ # There are no Instances of this package installed.
+ self.logger.debug("Package %s has no instances installed" % (entry.get('name')))
+ entry.set('current_exists', 'false')
+ bcfg2_versions = ''
+ for inst in instances:
+ qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst)
+ self.instance_status.setdefault(inst, {})['installed'] = False
+ self.modlists[entry] = modlist
+ self.instance_status[inst]['pkg'] = entry
+ if inst.tag == 'Instance':
+ bcfg2_versions = bcfg2_versions + '(%s) ' % self.str_evra(inst)
+ if bcfg2_versions != '':
+ entry.set('version', bcfg2_versions)
+ entry.set('qtext', "Install Package %s Instance(s) %s? (y/N) " % \
+ (entry.get('name'), qtext_versions))
+
+ return False
+ return True
+
+ def RemovePackages(self, packages):
+ """
+ Remove specified entries.
+
+ packages is a list of Package Entries with Instances generated
+ by FindExtraPackages().
+
+ """
+ self.logger.debug('Running RPM.RemovePackages()')
+
+ pkgspec_list = []
+ for pkg in packages:
+ for inst in pkg:
+ if pkg.get('name') != 'gpg-pubkey':
+ pkgspec = { 'name':pkg.get('name'),
+ 'epoch':inst.get('epoch', None),
+ 'version':inst.get('version'),
+ 'release':inst.get('release'),
+ 'arch':inst.get('arch') }
+ pkgspec_list.append(pkgspec)
+ else:
+ pkgspec = { 'name':pkg.get('name'),
+ 'version':inst.get('version'),
+ 'release':inst.get('release')}
+ self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\
+ % (pkgspec.get('name'), self.str_evra(pkgspec)))
+ self.logger.info(" This package will be deleted in a future version of the RPM driver.")
+ #pkgspec_list.append(pkg_spec)
+
+ erase_results = rpmtools.rpm_erase(pkgspec_list, self.erase_flags)
+ if erase_results == []:
+ self.modified += packages
+ for pkg in pkgspec_list:
+ self.logger.info("Deleted %s %s" % (pkg.get('name'), self.str_evra(pkg)))
+ else:
+ self.logger.info("Bulk erase failed with errors:")
+ self.logger.debug("Erase results = %s" % erase_results)
+ self.logger.info("Attempting individual erase for each package.")
+ pkgspec_list = []
+ for pkg in packages:
+ pkg_modified = False
+ for inst in pkg:
+ if pkg.get('name') != 'gpg-pubkey':
+ pkgspec = { 'name':pkg.get('name'),
+ 'epoch':inst.get('epoch', None),
+ 'version':inst.get('version'),
+ 'release':inst.get('release'),
+ 'arch':inst.get('arch') }
+ pkgspec_list.append(pkgspec)
+ else:
+ pkgspec = { 'name':pkg.get('name'),
+ 'version':inst.get('version'),
+ 'release':inst.get('release')}
+ self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\
+ % (pkgspec.get('name'), self.str_evra(pkgspec)))
+ self.logger.info(" This package will be deleted in a future version of the RPM driver.")
+ continue # Don't delete the gpg-pubkey packages for now.
+ erase_results = rpmtools.rpm_erase([pkgspec], self.erase_flags)
+ if erase_results == []:
+ pkg_modified = True
+ self.logger.info("Deleted %s %s" % \
+ (pkgspec.get('name'), self.str_evra(pkgspec)))
+ else:
+ self.logger.error("unable to delete %s %s" % \
+ (pkgspec.get('name'), self.str_evra(pkgspec)))
+ self.logger.debug("Failure = %s" % erase_results)
+ if pkg_modified == True:
+ self.modified.append(pkg)
+
+ self.RefreshPackages()
+ self.extra = self.FindExtraPackages()
+
+ def FixInstance(self, instance, inst_status):
+ """
+ Control if a reinstall of a package happens or not based on the
+ results from RPM.VerifyPackage().
+
+ Return True to reinstall, False to not reintstall.
+
+ """
+ fix = False
+
+ if inst_status.get('installed', False) == False:
+ if instance.get('installed_action', 'install') == "install" and \
+ self.installed_action == "install":
+ fix = True
+ else:
+ self.logger.debug('Installed Action for %s %s is to not install' % \
+ (inst_status.get('pkg').get('name'),
+ self.str_evra(instance)))
+
+ elif inst_status.get('version_fail', False) == True:
+ if instance.get('version_fail_action', 'upgrade') == "upgrade" and \
+ self.version_fail_action == "upgrade":
+ fix = True
+ else:
+ self.logger.debug('Version Fail Action for %s %s is to not upgrade' % \
+ (inst_status.get('pkg').get('name'),
+ self.str_evra(instance)))
+
+ elif inst_status.get('verify_fail', False) == True and self.name == "RPM":
+ # yum can't reinstall packages so only do this for rpm.
+ if instance.get('verify_fail_action', 'reinstall') == "reinstall" and \
+ self.verify_fail_action == "reinstall":
+ for inst in inst_status.get('verify'):
+ # This needs to be a for loop rather than a straight get()
+ # because the underlying routines handle multiple packages
+ # and return a list of results.
+ self.logger.debug('reinstall_check: %s %s:%s-%s.%s' % inst.get('nevra'))
+
+ if inst.get("hdr", False):
+ fix = True
+
+ elif inst.get('files', False):
+ # Parse rpm verify file results
+ for file_result in inst.get('files', []):
+ self.logger.debug('reinstall_check: file: %s' % file_result)
+ if file_result[-2] != 'c':
+ fix = True
+ break
+
+ # Shouldn't really need this, but included for clarity.
+ elif inst.get("deps", False):
+ fix = False
+ else:
+ self.logger.debug('Verify Fail Action for %s %s is to not reinstall' % \
+ (inst_status.get('pkg').get('name'),
+ self.str_evra(instance)))
+
+ return fix
+
+ def Install(self, packages, states):
+ """
+ Try and fix everything that RPM.VerifyPackages() found wrong for
+ each Package Entry. This can result in individual RPMs being
+ installed (for the first time), reinstalled, deleted, downgraded
+ or upgraded.
+
+ packages is a list of Package Elements that has
+ states[<Package Element>] == False
+
+ The following effects occur:
+ - states{} is conditionally updated for each package.
+ - self.installed{} is rebuilt, possibly multiple times.
+ - self.instance_statusi{} is conditionally updated for each instance
+ of a package.
+ - Each package will be added to self.modified[] if its states{}
+ entry is set to True.
+
+ """
+ self.logger.info('Runing RPM.Install()')
+
+ install_only_pkgs = []
+ gpg_keys = []
+ upgrade_pkgs = []
+
+ # Remove extra instances.
+ # Can not reverify because we don't have a package entry.
+ if len(self.extra_instances) > 0:
+ if (self.setup.get('remove') == 'all' or \
+ self.setup.get('remove') == 'packages') and\
+ not self.setup.get('dryrun'):
+ self.RemovePackages(self.extra_instances)
+ else:
+ self.logger.info("The following extra package instances will be removed by the '-r' option:")
+ for pkg in self.extra_instances:
+ for inst in pkg:
+ self.logger.info(" %s %s" % (pkg.get('name'), self.str_evra(inst)))
+
+ # Figure out which instances of the packages actually need something
+ # doing to them and place in the appropriate work 'queue'.
+ for pkg in packages:
+ for inst in [instn for instn in pkg if instn.tag \
+ in ['Instance', 'Package']]:
+ if self.FixInstance(inst, self.instance_status[inst]):
+ if pkg.get('name') == 'gpg-pubkey':
+ gpg_keys.append(inst)
+ elif pkg.get('name') in self.installOnlyPkgs:
+ install_only_pkgs.append(inst)
+ else:
+ upgrade_pkgs.append(inst)
+
+ # Fix installOnlyPackages
+ if len(install_only_pkgs) > 0:
+ self.logger.info("Attempting to install 'install only packages'")
+ install_args = " ".join([os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
+ inst.get('simplefile')) \
+ for inst in install_only_pkgs])
+ self.logger.debug("rpm --install --quiet --oldpackage %s" % install_args)
+ cmdrc, output = self.cmd.run("rpm --install --quiet --oldpackage --replacepkgs %s" % \
+ install_args)
+ if cmdrc == 0:
+ # The rpm command succeeded. All packages installed.
+ self.logger.info("Single Pass for InstallOnlyPkgs Succeded")
+ self.RefreshPackages()
+
+ else:
+ # The rpm command failed. No packages installed.
+ # Try installing instances individually.
+ self.logger.error("Single Pass for InstallOnlyPackages Failed")
+ installed_instances = []
+ for inst in install_only_pkgs:
+ install_args = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
+ inst.get('simplefile'))
+ self.logger.debug("rpm --install --quiet --oldpackage %s" % install_args)
+ cmdrc, output = self.cmd.run("rpm --install --quiet --oldpackage --replacepkgs %s" % \
+ install_args)
+ if cmdrc == 0:
+ installed_instances.append(inst)
+ else:
+ self.logger.debug("InstallOnlyPackage %s %s would not install." % \
+ (self.instance_status[inst].get('pkg').get('name'), \
+ self.str_evra(inst)))
+
+ install_pkg_set = set([self.instance_status[inst].get('pkg') \
+ for inst in install_only_pkgs])
+ self.RefreshPackages()
+
+ # Install GPG keys.
+ if len(gpg_keys) > 0:
+ for inst in gpg_keys:
+ self.logger.info("Installing GPG keys.")
+ key_arg = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
+ inst.get('simplefile'))
+ cmdrc, output = self.cmd.run("rpm --import %s" % key_arg)
+ if cmdrc != 0:
+ self.logger.debug("Unable to install %s-%s" % \
+ (self.instance_status[inst].get('pkg').get('name'), \
+ self.str_evra(inst)))
+ else:
+ self.logger.debug("Installed %s-%s-%s" % \
+ (self.instance_status[inst].get('pkg').get('name'), \
+ inst.get('version'), inst.get('release')))
+ self.RefreshPackages()
+ self.gpg_keyids = self.getinstalledgpg()
+ pkg = self.instance_status[gpg_keys[0]].get('pkg')
+ states[pkg] = self.VerifyPackage(pkg, [])
+
+ # Fix upgradeable packages.
+ if len(upgrade_pkgs) > 0:
+ self.logger.info("Attempting to upgrade packages")
+ upgrade_args = " ".join([os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
+ inst.get('simplefile')) \
+ for inst in upgrade_pkgs])
+ cmdrc, output = self.cmd.run("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % \
+ upgrade_args)
+ if cmdrc == 0:
+ # The rpm command succeeded. All packages upgraded.
+ self.logger.info("Single Pass for Upgraded Packages Succeded")
+ upgrade_pkg_set = set([self.instance_status[inst].get('pkg') \
+ for inst in upgrade_pkgs])
+ self.RefreshPackages()
+ else:
+ # The rpm command failed. No packages upgraded.
+ # Try upgrading instances individually.
+ self.logger.error("Single Pass for Upgrading Packages Failed")
+ upgraded_instances = []
+ for inst in upgrade_pkgs:
+ upgrade_args = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
+ inst.get('simplefile'))
+ #self.logger.debug("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % \
+ # upgrade_args)
+ cmdrc, output = self.cmd.run("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % upgrade_args)
+ if cmdrc == 0:
+ upgraded_instances.append(inst)
+ else:
+ self.logger.debug("Package %s %s would not upgrade." % \
+ (self.instance_status[inst].get('pkg').get('name'), \
+ self.str_evra(inst)))
+
+ upgrade_pkg_set = set([self.instance_status[inst].get('pkg') \
+ for inst in upgrade_pkgs])
+ self.RefreshPackages()
+
+ if not self.setup['kevlar']:
+ for pkg_entry in packages:
+ self.logger.debug("Reverifying Failed Package %s" % (pkg_entry.get('name')))
+ states[pkg_entry] = self.VerifyPackage(pkg_entry, \
+ self.modlists.get(pkg_entry, []))
+
+ for entry in [ent for ent in packages if states[ent]]:
+ self.modified.append(entry)
+
+ def canInstall(self, entry):
+ """Test if entry has enough information to be installed."""
+ if not self.handlesEntry(entry):
+ return False
+
+ if 'failure' in entry.attrib:
+ self.logger.error("Cannot install entry %s:%s with bind failure" % \
+ (entry.tag, entry.get('name')))
+ return False
+
+
+ instances = entry.findall('Instance')
+
+ # If the entry wasn't verifiable, then we really don't want to try and fix something
+ # that we don't know is broken.
+ if not self.canVerify(entry):
+ self.logger.debug("WARNING: Package %s was not verifiable, not passing to Install()" \
+ % entry.get('name'))
+ return False
+
+ if not instances:
+ # Old non Instance format, unmodified.
+ if entry.get('name') == 'gpg-pubkey':
+ # gpg-pubkey packages aren't really pacakges, so we have to do
+ # something a little different.
+ # Check that the Package Level has what we need for verification.
+ if [attr for attr in self.__gpg_ireq__[entry.tag] if attr not in entry.attrib]:
+ self.logger.error("Incomplete information for entry %s:%s; cannot install" \
+ % (entry.tag, entry.get('name')))
+ return False
+ else:
+ if [attr for attr in self.__ireq__[entry.tag] if attr not in entry.attrib]:
+ self.logger.error("Incomplete information for entry %s:%s; cannot install" \
+ % (entry.tag, entry.get('name')))
+ return False
+ else:
+ if entry.get('name') == 'gpg-pubkey':
+ # gpg-pubkey packages aren't really pacakges, so we have to do
+ # something a little different.
+ # Check that the Package Level has what we need for verification.
+ if [attr for attr in self.__new_gpg_ireq__[entry.tag] if attr not in entry.attrib]:
+ self.logger.error("Incomplete information for entry %s:%s; cannot install" \
+ % (entry.tag, entry.get('name')))
+ return False
+ # Check that the Instance Level has what we need for verification.
+ for inst in instances:
+ if [attr for attr in self.__new_gpg_ireq__[inst.tag] \
+ if attr not in inst.attrib]:
+ self.logger.error("Incomplete information for entry %s:%s; cannot install"\
+ % (inst.tag, entry.get('name')))
+ return False
+ else:
+ # New format with Instances.
+ # Check that the Package Level has what we need for verification.
+ if [attr for attr in self.__new_ireq__[entry.tag] if attr not in entry.attrib]:
+ self.logger.error("Incomplete information for entry %s:%s; cannot install" \
+ % (entry.tag, entry.get('name')))
+ self.logger.error(" Required attributes that may not be present are %s" \
+ % (self.__new_ireq__[entry.tag]))
+ return False
+ # Check that the Instance Level has what we need for verification.
+ for inst in instances:
+ if inst.tag == 'Instance':
+ if [attr for attr in self.__new_ireq__[inst.tag] \
+ if attr not in inst.attrib]:
+ self.logger.error("Incomplete information for %s of package %s; cannot install" \
+ % (inst.tag, entry.get('name')))
+ self.logger.error(" Required attributes that may not be present are %s" \
+ % (self.__new_ireq__[inst.tag]))
+ return False
+ return True
+
+ def canVerify(self, entry):
+ """
+ Test if entry has enough information to be verified.
+
+ Three types of entries are checked.
+ Old style Package
+ New style Package with Instances
+ pgp-pubkey packages
+
+ Also the old style entries get modified after the first
+ VerifyPackage() run, so there needs to be a second test.
+
+ """
+ if not self.handlesEntry(entry):
+ return False
+
+ if 'failure' in entry.attrib:
+ self.logger.error("Entry %s:%s reports bind failure: %s" % \
+ (entry.tag, entry.get('name'), entry.get('failure')))
+ return False
+
+ # We don't want to do any checks so we don't care what the entry has in it.
+ if (not self.pkg_checks or
+ entry.get('pkg_checks', 'true').lower() == 'false'):
+ return True
+
+ instances = entry.findall('Instance')
+
+ if not instances:
+ # Old non Instance format, unmodified.
+ if entry.get('name') == 'gpg-pubkey':
+ # gpg-pubkey packages aren't really pacakges, so we have to do
+ # something a little different.
+ # Check that the Package Level has what we need for verification.
+ if [attr for attr in self.__gpg_req__[entry.tag] if attr not in entry.attrib]:
+ self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
+ % (entry.tag, entry.get('name')))
+ return False
+ elif entry.tag == 'Path' and entry.get('type') == 'ignore':
+ # ignored Paths are only relevant during failed package
+ # verification
+ pass
+ else:
+ if [attr for attr in self.__req__[entry.tag] if attr not in entry.attrib]:
+ self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
+ % (entry.tag, entry.get('name')))
+ return False
+ else:
+ if entry.get('name') == 'gpg-pubkey':
+ # gpg-pubkey packages aren't really pacakges, so we have to do
+ # something a little different.
+ # Check that the Package Level has what we need for verification.
+ if [attr for attr in self.__new_gpg_req__[entry.tag] if attr not in entry.attrib]:
+ self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
+ % (entry.tag, entry.get('name')))
+ return False
+ # Check that the Instance Level has what we need for verification.
+ for inst in instances:
+ if [attr for attr in self.__new_gpg_req__[inst.tag] \
+ if attr not in inst.attrib]:
+ self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
+ % (inst.tag, inst.get('name')))
+ return False
+ else:
+ # New format with Instances, or old style modified.
+ # Check that the Package Level has what we need for verification.
+ if [attr for attr in self.__new_req__[entry.tag] if attr not in entry.attrib]:
+ self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
+ % (entry.tag, entry.get('name')))
+ return False
+ # Check that the Instance Level has what we need for verification.
+ for inst in instances:
+ if inst.tag == 'Instance':
+ if [attr for attr in self.__new_req__[inst.tag] \
+ if attr not in inst.attrib]:
+ self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
+ % (inst.tag, inst.get('name')))
+ return False
+ return True
+
+ def FindExtraPackages(self):
+ """Find extra packages."""
+ packages = [entry.get('name') for entry in self.getSupportedEntries()]
+ extras = []
+
+ for (name, instances) in list(self.installed.items()):
+ if name not in packages:
+ extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype)
+ for installed_inst in instances:
+ if self.setup['extra']:
+ self.logger.info("Extra Package %s %s." % \
+ (name, self.str_evra(installed_inst)))
+ tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \
+ version = installed_inst.get('version'), \
+ release = installed_inst.get('release'))
+ if installed_inst.get('epoch', None) != None:
+ tmp_entry.set('epoch', str(installed_inst.get('epoch')))
+ if installed_inst.get('arch', None) != None:
+ tmp_entry.set('arch', installed_inst.get('arch'))
+ extras.append(extra_entry)
+ return extras
+
+
+ def FindExtraInstances(self, pkg_entry, installed_entry):
+ """
+ Check for installed instances that are not in the config.
+ Return a Package Entry with Instances to remove, or None if there
+ are no Instances to remove.
+
+ """
+ name = pkg_entry.get('name')
+ extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype)
+ instances = [inst for inst in pkg_entry if inst.tag == 'Instance' or inst.tag == 'Package']
+ if name in self.installOnlyPkgs:
+ for installed_inst in installed_entry:
+ not_found = True
+ for inst in instances:
+ if self.pkg_vr_equal(inst, installed_inst) or \
+ self.inst_evra_equal(inst, installed_inst):
+ not_found = False
+ break
+ if not_found == True:
+ # Extra package.
+ self.logger.info("Extra InstallOnlyPackage %s %s." % \
+ (name, self.str_evra(installed_inst)))
+ tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \
+ version = installed_inst.get('version'), \
+ release = installed_inst.get('release'))
+ if installed_inst.get('epoch', None) != None:
+ tmp_entry.set('epoch', str(installed_inst.get('epoch')))
+ if installed_inst.get('arch', None) != None:
+ tmp_entry.set('arch', installed_inst.get('arch'))
+ else:
+ # Normal package, only check arch.
+ for installed_inst in installed_entry:
+ not_found = True
+ for inst in instances:
+ if installed_inst.get('arch', None) == inst.get('arch', None) or\
+ inst.tag == 'Package':
+ not_found = False
+ break
+ if not_found:
+ self.logger.info("Extra Normal Package Instance %s %s" % \
+ (name, self.str_evra(installed_inst)))
+ tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \
+ version = installed_inst.get('version'), \
+ release = installed_inst.get('release'))
+ if installed_inst.get('epoch', None) != None:
+ tmp_entry.set('epoch', str(installed_inst.get('epoch')))
+ if installed_inst.get('arch', None) != None:
+ tmp_entry.set('arch', installed_inst.get('arch'))
+
+ if len(extra_entry) == 0:
+ extra_entry = None
+
+ return extra_entry
+
+ def str_evra(self, instance):
+ """Convert evra dict entries to a string."""
+ if instance.get('epoch', '*') in ['*', None]:
+ return '%s-%s.%s' % (instance.get('version', '*'),
+ instance.get('release', '*'),
+ instance.get('arch', '*'))
+ else:
+ return '%s:%s-%s.%s' % (instance.get('epoch', '*'),
+ instance.get('version', '*'),
+ instance.get('release', '*'),
+ instance.get('arch', '*'))
+
+ def pkg_vr_equal(self, config_entry, installed_entry):
+ '''
+ Compare old style entry to installed entry. Which means ignore
+ the epoch and arch.
+ '''
+ if (config_entry.tag == 'Package' and \
+ config_entry.get('version') == installed_entry.get('version') and \
+ config_entry.get('release') == installed_entry.get('release')):
+ return True
+ else:
+ return False
+
+ def inst_evra_equal(self, config_entry, installed_entry):
+ """Compare new style instance to installed entry."""
+
+ if config_entry.get('epoch', None) != None:
+ epoch = int(config_entry.get('epoch'))
+ else:
+ epoch = None
+
+ if (config_entry.tag == 'Instance' and \
+ (epoch == installed_entry.get('epoch', 0) or \
+ (epoch == 0 and installed_entry.get('epoch', 0) == None) or \
+ (epoch == None and installed_entry.get('epoch', 0) == 0)) and \
+ config_entry.get('version') == installed_entry.get('version') and \
+ config_entry.get('release') == installed_entry.get('release') and \
+ config_entry.get('arch', None) == installed_entry.get('arch', None)):
+ return True
+ else:
+ return False
+
+ def getinstalledgpg(self):
+ """
+ Create a list of installed GPG key IDs.
+
+ The pgp-pubkey package version is the least significant 4 bytes
+ (big-endian) of the key ID which is good enough for our purposes.
+
+ """
+ init_ts = rpmtools.rpmtransactionset()
+ init_ts.setVSFlags(rpm._RPMVSF_NODIGESTS|rpm._RPMVSF_NOSIGNATURES)
+ gpg_hdrs = rpmtools.getheadersbykeyword(init_ts, **{'name':'gpg-pubkey'})
+ keyids = [ header[rpm.RPMTAG_VERSION] for header in gpg_hdrs]
+ keyids.append('None')
+ init_ts.closeDB()
+ del init_ts
+ return keyids
+
+ def VerifyPath(self, entry, _):
+ """
+ We don't do anything here since all
+ Paths are processed in __init__
+ """
+ return True
diff --git a/src/lib/Bcfg2/Client/Tools/RPMng.py b/src/lib/Bcfg2/Client/Tools/RPMng.py
index 91e2180ae..f5a234f8d 100644
--- a/src/lib/Bcfg2/Client/Tools/RPMng.py
+++ b/src/lib/Bcfg2/Client/Tools/RPMng.py
@@ -1,987 +1,8 @@
-"""Bcfg2 Support for RPMS"""
+""" RPM driver called 'RPMng' for backwards compat """
-import os.path
-import rpm
-import rpmtools
-import Bcfg2.Client.Tools
+from Bcfg2.Client.Tools.RPM import RPM
-class RPMng(Bcfg2.Client.Tools.PkgTool):
- """Support for RPM packages."""
- name = 'RPMng'
- __execs__ = ['/bin/rpm', '/var/lib/rpm']
- __handles__ = [('Package', 'rpm')]
-
- __req__ = {'Package': ['name', 'version']}
- __ireq__ = {'Package': ['url']}
-
- __new_req__ = {'Package': ['name'], 'Instance': ['version', 'release', 'arch']}
- __new_ireq__ = {'Package': ['uri'], \
- 'Instance': ['simplefile']}
-
- __gpg_req__ = {'Package': ['name', 'version']}
- __gpg_ireq__ = {'Package': ['name', 'version']}
-
- __new_gpg_req__ = {'Package': ['name'], 'Instance': ['version', 'release']}
- __new_gpg_ireq__ = {'Package': ['name'], 'Instance': ['version', 'release']}
-
- conflicts = ['RPM']
-
- pkgtype = 'rpm'
- pkgtool = ("rpm --oldpackage --replacepkgs --quiet -U %s", ("%s", ["url"]))
-
- def __init__(self, logger, setup, config):
- Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config)
-
- # create a global ignore list used when ignoring particular
- # files during package verification
- self.ignores = [entry.get('name') for struct in config for entry in struct \
- if entry.get('type') == 'ignore']
- self.instance_status = {}
- self.extra_instances = []
- self.modlists = {}
- self.gpg_keyids = self.getinstalledgpg()
-
- opt_prefix = self.name.lower()
- self.installOnlyPkgs = self.setup["%s_installonly" % opt_prefix]
- if 'gpg-pubkey' not in self.installOnlyPkgs:
- self.installOnlyPkgs.append('gpg-pubkey')
- self.erase_flags = self.setup['%s_erase_flags' % opt_prefix]
- self.pkg_checks = self.setup['%s_pkg_checks' % opt_prefix]
- self.pkg_verify = self.setup['%s_pkg_verify' % opt_prefix]
- self.installed_action = self.setup['%s_installed_action' % opt_prefix]
- self.version_fail_action = self.setup['%s_version_fail_action' %
- opt_prefix]
- self.verify_fail_action = self.setup['%s_verify_fail_action' %
- opt_prefix]
- self.verify_flags = self.setup['%s_verify_flags' % opt_prefix]
- if '' in self.verify_flags:
- self.verify_flags.remove('')
-
- self.logger.debug('%s: installOnlyPackages = %s' %
- (self.name, self.installOnlyPkgs))
- self.logger.debug('%s: erase_flags = %s' %
- (self.name, self.erase_flags))
- self.logger.debug('%s: pkg_checks = %s' %
- (self.name, self.pkg_checks))
- self.logger.debug('%s: pkg_verify = %s' %
- (self.name, self.pkg_verify))
- self.logger.debug('%s: installed_action = %s' %
- (self.name, self.installed_action))
- self.logger.debug('%s: version_fail_action = %s' %
- (self.name, self.version_fail_action))
- self.logger.debug('%s: verify_fail_action = %s' %
- (self.name, self.verify_fail_action))
- self.logger.debug('%s: verify_flags = %s' %
- (self.name, self.verify_flags))
-
- # Force a re- prelink of all packages if prelink exists.
- # Many, if not most package verifies can be caused by out of
- # date prelinking.
- if os.path.isfile('/usr/sbin/prelink') and not self.setup['dryrun']:
- cmdrc, output = self.cmd.run('/usr/sbin/prelink -a -mR')
- if cmdrc == 0:
- self.logger.debug('Pre-emptive prelink succeeded')
- else:
- # FIXME : this is dumb - what if the output is huge?
- self.logger.error('Pre-emptive prelink failed: %s' % output)
-
-
- def RefreshPackages(self):
- """
- Creates self.installed{} which is a dict of installed packages.
-
- The dict items are lists of nevra dicts. This loosely matches the
- config from the server and what rpmtools uses to specify pacakges.
-
- e.g.
-
- self.installed['foo'] = [ {'name':'foo', 'epoch':None,
- 'version':'1', 'release':2,
- 'arch':'i386'},
- {'name':'foo', 'epoch':None,
- 'version':'1', 'release':2,
- 'arch':'x86_64'} ]
- """
- self.installed = {}
- refresh_ts = rpmtools.rpmtransactionset()
- # Don't bother with signature checks at this stage. The GPG keys might
- # not be installed.
- refresh_ts.setVSFlags(rpm._RPMVSF_NODIGESTS|rpm._RPMVSF_NOSIGNATURES)
- for nevra in rpmtools.rpmpackagelist(refresh_ts):
- self.installed.setdefault(nevra['name'], []).append(nevra)
- if self.setup['debug']:
- print("The following package instances are installed:")
- for name, instances in list(self.installed.items()):
- self.logger.debug(" " + name)
- for inst in instances:
- self.logger.debug(" %s" %self.str_evra(inst))
- refresh_ts.closeDB()
- del refresh_ts
-
- def VerifyPackage(self, entry, modlist, pinned_version=None):
- """
- Verify Package status for entry.
- Performs the following:
- - Checks for the presence of required Package Instances.
- - Compares the evra 'version' info against self.installed{}.
- - RPM level package verify (rpm --verify).
- - Checks for the presence of unrequired package instances.
-
- Produces the following dict and list for RPMng.Install() to use:
- For installs/upgrades/fixes of required instances:
- instance_status = { <Instance Element Object>:
- { 'installed': True|False,
- 'version_fail': True|False,
- 'verify_fail': True|False,
- 'pkg': <Package Element Object>,
- 'modlist': [ <filename>, ... ],
- 'verify' : [ <rpm --verify results> ]
- }, ......
- }
-
- For deletions of unrequired instances:
- extra_instances = [ <Package Element Object>, ..... ]
-
- Constructs the text prompts for interactive mode.
- """
- instances = [inst for inst in entry if inst.tag == 'Instance' or inst.tag == 'Package']
- if instances == []:
- # We have an old style no Instance entry. Convert it to new style.
- instance = Bcfg2.Client.XML.SubElement(entry, 'Package')
- for attrib in list(entry.attrib.keys()):
- instance.attrib[attrib] = entry.attrib[attrib]
- if (self.pkg_checks and
- entry.get('pkg_checks', 'true').lower() == 'true'):
- if 'any' in [entry.get('version'), pinned_version]:
- version, release = 'any', 'any'
- elif entry.get('version') == 'auto':
- if pinned_version != None:
- version, release = pinned_version.split('-')
- else:
- return False
- else:
- version, release = entry.get('version').split('-')
- instance.set('version', version)
- instance.set('release', release)
- if entry.get('verify', 'true') == 'false':
- instance.set('verify', 'false')
- instances = [ instance ]
-
- self.logger.debug("Verifying package instances for %s" % entry.get('name'))
- package_fail = False
- qtext_versions = ''
-
- if entry.get('name') in self.installed:
- # There is at least one instance installed.
- if (self.pkg_checks and
- entry.get('pkg_checks', 'true').lower() == 'true'):
- rpmTs = rpm.TransactionSet()
- rpmHeader = None
- for h in rpmTs.dbMatch(rpm.RPMTAG_NAME, entry.get('name')):
- if rpmHeader is None or rpm.versionCompare(h, rpmHeader) > 0:
- rpmHeader = h
- rpmProvides = [ h['provides'] for h in \
- rpmTs.dbMatch(rpm.RPMTAG_NAME, entry.get('name')) ]
- rpmIntersection = set(rpmHeader['provides']) & \
- set(self.installOnlyPkgs)
- if len(rpmIntersection) > 0:
- # Packages that should only be installed or removed.
- # e.g. kernels.
- self.logger.debug(" Install only package.")
- for inst in instances:
- self.instance_status.setdefault(inst, {})['installed'] = False
- self.instance_status[inst]['version_fail'] = False
- if inst.tag == 'Package' and len(self.installed[entry.get('name')]) > 1:
- self.logger.error("WARNING: Multiple instances of package %s are installed." % \
- (entry.get('name')))
- for pkg in self.installed[entry.get('name')]:
- if inst.get('version') == 'any' or self.pkg_vr_equal(inst, pkg) \
- or self.inst_evra_equal(inst, pkg):
- if inst.get('version') == 'any':
- self.logger.error("got any version")
- self.logger.debug(" %s" % self.str_evra(inst))
- self.instance_status[inst]['installed'] = True
-
- if (self.pkg_verify and
- inst.get('pkg_verify', 'true').lower() == 'true'):
- flags = inst.get('verify_flags', '').split(',') + self.verify_flags
- if pkg.get('gpgkeyid', '')[-8:] not in self.gpg_keyids and \
- entry.get('name') != 'gpg-pubkey':
- flags += ['nosignature', 'nodigest']
- self.logger.debug('WARNING: Package %s %s requires GPG Public key with ID %s'\
- % (pkg.get('name'), self.str_evra(pkg), \
- pkg.get('gpgkeyid', '')))
- self.logger.debug(' Disabling signature check.')
-
- if self.setup.get('quick', False):
- if rpmtools.prelink_exists:
- flags += ['nomd5', 'nosize']
- else:
- flags += ['nomd5']
- self.logger.debug(" verify_flags = %s" % flags)
-
- if inst.get('verify', 'true') == 'false':
- self.instance_status[inst]['verify'] = None
- else:
- vp_ts = rpmtools.rpmtransactionset()
- self.instance_status[inst]['verify'] = \
- rpmtools.rpm_verify( vp_ts, pkg, flags)
- vp_ts.closeDB()
- del vp_ts
-
- if self.instance_status[inst]['installed'] == False:
- self.logger.info(" Package %s %s not installed." % \
- (entry.get('name'), self.str_evra(inst)))
-
- qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst)
- entry.set('current_exists', 'false')
- else:
- # Normal Packages that can be upgraded.
- for inst in instances:
- self.instance_status.setdefault(inst, {})['installed'] = False
- self.instance_status[inst]['version_fail'] = False
-
- # Only installed packages with the same architecture are
- # relevant.
- if inst.get('arch', None) == None:
- arch_match = self.installed[entry.get('name')]
- else:
- arch_match = [pkg for pkg in self.installed[entry.get('name')] \
- if pkg.get('arch', None) == inst.get('arch', None)]
-
- if len(arch_match) > 1:
- self.logger.error("Multiple instances of package %s installed with the same achitecture." % \
- (entry.get('name')))
- elif len(arch_match) == 1:
- # There is only one installed like there should be.
- # Check that it is the right version.
- for pkg in arch_match:
- if inst.get('version') == 'any' or self.pkg_vr_equal(inst, pkg) or \
- self.inst_evra_equal(inst, pkg):
- self.logger.debug(" %s" % self.str_evra(inst))
- self.instance_status[inst]['installed'] = True
-
- if (self.pkg_verify and
- inst.get('pkg_verify', 'true').lower() == 'true'):
- flags = inst.get('verify_flags', '').split(',') + self.verify_flags
- if pkg.get('gpgkeyid', '')[-8:] not in self.gpg_keyids and \
- 'nosignature' not in flags:
- flags += ['nosignature', 'nodigest']
- self.logger.info('WARNING: Package %s %s requires GPG Public key with ID %s'\
- % (pkg.get('name'), self.str_evra(pkg), \
- pkg.get('gpgkeyid', '')))
- self.logger.info(' Disabling signature check.')
-
- if self.setup.get('quick', False):
- if rpmtools.prelink_exists:
- flags += ['nomd5', 'nosize']
- else:
- flags += ['nomd5']
- self.logger.debug(" verify_flags = %s" % flags)
-
- if inst.get('verify', 'true') == 'false':
- self.instance_status[inst]['verify'] = None
- else:
- vp_ts = rpmtools.rpmtransactionset()
- self.instance_status[inst]['verify'] = \
- rpmtools.rpm_verify( vp_ts, pkg, flags )
- vp_ts.closeDB()
- del vp_ts
-
- else:
- # Wrong version installed.
- self.instance_status[inst]['version_fail'] = True
- self.logger.info(" Wrong version installed. Want %s, but have %s"\
- % (self.str_evra(inst), self.str_evra(pkg)))
-
- qtext_versions = qtext_versions + 'U(%s -> %s) ' % \
- (self.str_evra(pkg), self.str_evra(inst))
- elif len(arch_match) == 0:
- # This instance is not installed.
- self.instance_status[inst]['installed'] = False
- self.logger.info(" %s is not installed." % self.str_evra(inst))
- qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst)
-
- # Check the rpm verify results.
- for inst in instances:
- instance_fail = False
- # Dump the rpm verify results.
- #****Write something to format this nicely.*****
- if self.setup['debug'] and self.instance_status[inst].get('verify', None):
- self.logger.debug(self.instance_status[inst]['verify'])
-
- self.instance_status[inst]['verify_fail'] = False
- if self.instance_status[inst].get('verify', None):
- if len(self.instance_status[inst].get('verify')) > 1:
- self.logger.info("WARNING: Verification of more than one package instance.")
-
- for result in self.instance_status[inst]['verify']:
-
- # Check header results
- if result.get('hdr', None):
- instance_fail = True
- self.instance_status[inst]['verify_fail'] = True
-
- # Check dependency results
- if result.get('deps', None):
- instance_fail = True
- self.instance_status[inst]['verify_fail'] = True
-
- # Check the rpm verify file results against the modlist
- # and entry and per Instance Ignores.
- ignores = [ig.get('name') for ig in entry.findall('Ignore')] + \
- [ig.get('name') for ig in inst.findall('Ignore')] + \
- self.ignores
- for file_result in result.get('files', []):
- if file_result[-1] not in modlist + ignores:
- instance_fail = True
- self.instance_status[inst]['verify_fail'] = True
- else:
- self.logger.debug(" Modlist/Ignore match: %s" % \
- (file_result[-1]))
-
- if instance_fail == True:
- self.logger.debug("*** Instance %s failed RPM verification ***" % \
- self.str_evra(inst))
- qtext_versions = qtext_versions + 'R(%s) ' % self.str_evra(inst)
- self.modlists[entry] = modlist
-
- # Attach status structure for return to server for reporting.
- inst.set('verify_status', str(self.instance_status[inst]))
-
- if self.instance_status[inst]['installed'] == False or \
- self.instance_status[inst].get('version_fail', False)== True or \
- self.instance_status[inst].get('verify_fail', False) == True:
- package_fail = True
- self.instance_status[inst]['pkg'] = entry
- self.modlists[entry] = modlist
-
- # Find Installed Instances that are not in the Config.
- extra_installed = self.FindExtraInstances(entry, self.installed[entry.get('name')])
- if extra_installed != None:
- package_fail = True
- self.extra_instances.append(extra_installed)
- for inst in extra_installed.findall('Instance'):
- qtext_versions = qtext_versions + 'D(%s) ' % self.str_evra(inst)
- self.logger.debug("Found Extra Instances %s" % qtext_versions)
-
- if package_fail == True:
- self.logger.info(" Package %s failed verification." % \
- (entry.get('name')))
- qtext = 'Install/Upgrade/delete Package %s instance(s) - %s (y/N) ' % \
- (entry.get('name'), qtext_versions)
- entry.set('qtext', qtext)
-
- bcfg2_versions = ''
- for bcfg2_inst in [inst for inst in instances if inst.tag == 'Instance']:
- bcfg2_versions = bcfg2_versions + '(%s) ' % self.str_evra(bcfg2_inst)
- if bcfg2_versions != '':
- entry.set('version', bcfg2_versions)
- installed_versions = ''
-
- for installed_inst in self.installed[entry.get('name')]:
- installed_versions = installed_versions + '(%s) ' % \
- self.str_evra(installed_inst)
-
- entry.set('current_version', installed_versions)
- return False
-
- else:
- # There are no Instances of this package installed.
- self.logger.debug("Package %s has no instances installed" % (entry.get('name')))
- entry.set('current_exists', 'false')
- bcfg2_versions = ''
- for inst in instances:
- qtext_versions = qtext_versions + 'I(%s) ' % self.str_evra(inst)
- self.instance_status.setdefault(inst, {})['installed'] = False
- self.modlists[entry] = modlist
- self.instance_status[inst]['pkg'] = entry
- if inst.tag == 'Instance':
- bcfg2_versions = bcfg2_versions + '(%s) ' % self.str_evra(inst)
- if bcfg2_versions != '':
- entry.set('version', bcfg2_versions)
- entry.set('qtext', "Install Package %s Instance(s) %s? (y/N) " % \
- (entry.get('name'), qtext_versions))
-
- return False
- return True
-
- def RemovePackages(self, packages):
- """
- Remove specified entries.
-
- packages is a list of Package Entries with Instances generated
- by FindExtraPackages().
-
- """
- self.logger.debug('Running RPMng.RemovePackages()')
-
- pkgspec_list = []
- for pkg in packages:
- for inst in pkg:
- if pkg.get('name') != 'gpg-pubkey':
- pkgspec = { 'name':pkg.get('name'),
- 'epoch':inst.get('epoch', None),
- 'version':inst.get('version'),
- 'release':inst.get('release'),
- 'arch':inst.get('arch') }
- pkgspec_list.append(pkgspec)
- else:
- pkgspec = { 'name':pkg.get('name'),
- 'version':inst.get('version'),
- 'release':inst.get('release')}
- self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\
- % (pkgspec.get('name'), self.str_evra(pkgspec)))
- self.logger.info(" This package will be deleted in a future version of the RPMng driver.")
- #pkgspec_list.append(pkg_spec)
-
- erase_results = rpmtools.rpm_erase(pkgspec_list, self.erase_flags)
- if erase_results == []:
- self.modified += packages
- for pkg in pkgspec_list:
- self.logger.info("Deleted %s %s" % (pkg.get('name'), self.str_evra(pkg)))
- else:
- self.logger.info("Bulk erase failed with errors:")
- self.logger.debug("Erase results = %s" % erase_results)
- self.logger.info("Attempting individual erase for each package.")
- pkgspec_list = []
- for pkg in packages:
- pkg_modified = False
- for inst in pkg:
- if pkg.get('name') != 'gpg-pubkey':
- pkgspec = { 'name':pkg.get('name'),
- 'epoch':inst.get('epoch', None),
- 'version':inst.get('version'),
- 'release':inst.get('release'),
- 'arch':inst.get('arch') }
- pkgspec_list.append(pkgspec)
- else:
- pkgspec = { 'name':pkg.get('name'),
- 'version':inst.get('version'),
- 'release':inst.get('release')}
- self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\
- % (pkgspec.get('name'), self.str_evra(pkgspec)))
- self.logger.info(" This package will be deleted in a future version of the RPMng driver.")
- continue # Don't delete the gpg-pubkey packages for now.
- erase_results = rpmtools.rpm_erase([pkgspec], self.erase_flags)
- if erase_results == []:
- pkg_modified = True
- self.logger.info("Deleted %s %s" % \
- (pkgspec.get('name'), self.str_evra(pkgspec)))
- else:
- self.logger.error("unable to delete %s %s" % \
- (pkgspec.get('name'), self.str_evra(pkgspec)))
- self.logger.debug("Failure = %s" % erase_results)
- if pkg_modified == True:
- self.modified.append(pkg)
-
- self.RefreshPackages()
- self.extra = self.FindExtraPackages()
-
- def FixInstance(self, instance, inst_status):
- """
- Control if a reinstall of a package happens or not based on the
- results from RPMng.VerifyPackage().
-
- Return True to reinstall, False to not reintstall.
-
- """
- fix = False
-
- if inst_status.get('installed', False) == False:
- if instance.get('installed_action', 'install') == "install" and \
- self.installed_action == "install":
- fix = True
- else:
- self.logger.debug('Installed Action for %s %s is to not install' % \
- (inst_status.get('pkg').get('name'),
- self.str_evra(instance)))
-
- elif inst_status.get('version_fail', False) == True:
- if instance.get('version_fail_action', 'upgrade') == "upgrade" and \
- self.version_fail_action == "upgrade":
- fix = True
- else:
- self.logger.debug('Version Fail Action for %s %s is to not upgrade' % \
- (inst_status.get('pkg').get('name'),
- self.str_evra(instance)))
-
- elif inst_status.get('verify_fail', False) == True and self.name == "RPMng":
- # yum can't reinstall packages so only do this for rpm.
- if instance.get('verify_fail_action', 'reinstall') == "reinstall" and \
- self.verify_fail_action == "reinstall":
- for inst in inst_status.get('verify'):
- # This needs to be a for loop rather than a straight get()
- # because the underlying routines handle multiple packages
- # and return a list of results.
- self.logger.debug('reinstall_check: %s %s:%s-%s.%s' % inst.get('nevra'))
-
- if inst.get("hdr", False):
- fix = True
-
- elif inst.get('files', False):
- # Parse rpm verify file results
- for file_result in inst.get('files', []):
- self.logger.debug('reinstall_check: file: %s' % file_result)
- if file_result[-2] != 'c':
- fix = True
- break
-
- # Shouldn't really need this, but included for clarity.
- elif inst.get("deps", False):
- fix = False
- else:
- self.logger.debug('Verify Fail Action for %s %s is to not reinstall' % \
- (inst_status.get('pkg').get('name'),
- self.str_evra(instance)))
-
- return fix
-
- def Install(self, packages, states):
- """
- Try and fix everything that RPMng.VerifyPackages() found wrong for
- each Package Entry. This can result in individual RPMs being
- installed (for the first time), reinstalled, deleted, downgraded
- or upgraded.
-
- packages is a list of Package Elements that has
- states[<Package Element>] == False
-
- The following effects occur:
- - states{} is conditionally updated for each package.
- - self.installed{} is rebuilt, possibly multiple times.
- - self.instance_statusi{} is conditionally updated for each instance
- of a package.
- - Each package will be added to self.modified[] if its states{}
- entry is set to True.
-
- """
- self.logger.info('Runing RPMng.Install()')
-
- install_only_pkgs = []
- gpg_keys = []
- upgrade_pkgs = []
-
- # Remove extra instances.
- # Can not reverify because we don't have a package entry.
- if len(self.extra_instances) > 0:
- if (self.setup.get('remove') == 'all' or \
- self.setup.get('remove') == 'packages') and\
- not self.setup.get('dryrun'):
- self.RemovePackages(self.extra_instances)
- else:
- self.logger.info("The following extra package instances will be removed by the '-r' option:")
- for pkg in self.extra_instances:
- for inst in pkg:
- self.logger.info(" %s %s" % (pkg.get('name'), self.str_evra(inst)))
-
- # Figure out which instances of the packages actually need something
- # doing to them and place in the appropriate work 'queue'.
- for pkg in packages:
- for inst in [instn for instn in pkg if instn.tag \
- in ['Instance', 'Package']]:
- if self.FixInstance(inst, self.instance_status[inst]):
- if pkg.get('name') == 'gpg-pubkey':
- gpg_keys.append(inst)
- elif pkg.get('name') in self.installOnlyPkgs:
- install_only_pkgs.append(inst)
- else:
- upgrade_pkgs.append(inst)
-
- # Fix installOnlyPackages
- if len(install_only_pkgs) > 0:
- self.logger.info("Attempting to install 'install only packages'")
- install_args = " ".join([os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
- inst.get('simplefile')) \
- for inst in install_only_pkgs])
- self.logger.debug("rpm --install --quiet --oldpackage %s" % install_args)
- cmdrc, output = self.cmd.run("rpm --install --quiet --oldpackage --replacepkgs %s" % \
- install_args)
- if cmdrc == 0:
- # The rpm command succeeded. All packages installed.
- self.logger.info("Single Pass for InstallOnlyPkgs Succeded")
- self.RefreshPackages()
-
- else:
- # The rpm command failed. No packages installed.
- # Try installing instances individually.
- self.logger.error("Single Pass for InstallOnlyPackages Failed")
- installed_instances = []
- for inst in install_only_pkgs:
- install_args = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
- inst.get('simplefile'))
- self.logger.debug("rpm --install --quiet --oldpackage %s" % install_args)
- cmdrc, output = self.cmd.run("rpm --install --quiet --oldpackage --replacepkgs %s" % \
- install_args)
- if cmdrc == 0:
- installed_instances.append(inst)
- else:
- self.logger.debug("InstallOnlyPackage %s %s would not install." % \
- (self.instance_status[inst].get('pkg').get('name'), \
- self.str_evra(inst)))
-
- install_pkg_set = set([self.instance_status[inst].get('pkg') \
- for inst in install_only_pkgs])
- self.RefreshPackages()
-
- # Install GPG keys.
- if len(gpg_keys) > 0:
- for inst in gpg_keys:
- self.logger.info("Installing GPG keys.")
- key_arg = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
- inst.get('simplefile'))
- cmdrc, output = self.cmd.run("rpm --import %s" % key_arg)
- if cmdrc != 0:
- self.logger.debug("Unable to install %s-%s" % \
- (self.instance_status[inst].get('pkg').get('name'), \
- self.str_evra(inst)))
- else:
- self.logger.debug("Installed %s-%s-%s" % \
- (self.instance_status[inst].get('pkg').get('name'), \
- inst.get('version'), inst.get('release')))
- self.RefreshPackages()
- self.gpg_keyids = self.getinstalledgpg()
- pkg = self.instance_status[gpg_keys[0]].get('pkg')
- states[pkg] = self.VerifyPackage(pkg, [])
-
- # Fix upgradeable packages.
- if len(upgrade_pkgs) > 0:
- self.logger.info("Attempting to upgrade packages")
- upgrade_args = " ".join([os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
- inst.get('simplefile')) \
- for inst in upgrade_pkgs])
- cmdrc, output = self.cmd.run("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % \
- upgrade_args)
- if cmdrc == 0:
- # The rpm command succeeded. All packages upgraded.
- self.logger.info("Single Pass for Upgraded Packages Succeded")
- upgrade_pkg_set = set([self.instance_status[inst].get('pkg') \
- for inst in upgrade_pkgs])
- self.RefreshPackages()
- else:
- # The rpm command failed. No packages upgraded.
- # Try upgrading instances individually.
- self.logger.error("Single Pass for Upgrading Packages Failed")
- upgraded_instances = []
- for inst in upgrade_pkgs:
- upgrade_args = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
- inst.get('simplefile'))
- #self.logger.debug("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % \
- # upgrade_args)
- cmdrc, output = self.cmd.run("rpm --upgrade --quiet --oldpackage --replacepkgs %s" % upgrade_args)
- if cmdrc == 0:
- upgraded_instances.append(inst)
- else:
- self.logger.debug("Package %s %s would not upgrade." % \
- (self.instance_status[inst].get('pkg').get('name'), \
- self.str_evra(inst)))
-
- upgrade_pkg_set = set([self.instance_status[inst].get('pkg') \
- for inst in upgrade_pkgs])
- self.RefreshPackages()
-
- if not self.setup['kevlar']:
- for pkg_entry in packages:
- self.logger.debug("Reverifying Failed Package %s" % (pkg_entry.get('name')))
- states[pkg_entry] = self.VerifyPackage(pkg_entry, \
- self.modlists.get(pkg_entry, []))
-
- for entry in [ent for ent in packages if states[ent]]:
- self.modified.append(entry)
-
- def canInstall(self, entry):
- """Test if entry has enough information to be installed."""
- if not self.handlesEntry(entry):
- return False
-
- if 'failure' in entry.attrib:
- self.logger.error("Cannot install entry %s:%s with bind failure" % \
- (entry.tag, entry.get('name')))
- return False
-
-
- instances = entry.findall('Instance')
-
- # If the entry wasn't verifiable, then we really don't want to try and fix something
- # that we don't know is broken.
- if not self.canVerify(entry):
- self.logger.debug("WARNING: Package %s was not verifiable, not passing to Install()" \
- % entry.get('name'))
- return False
-
- if not instances:
- # Old non Instance format, unmodified.
- if entry.get('name') == 'gpg-pubkey':
- # gpg-pubkey packages aren't really pacakges, so we have to do
- # something a little different.
- # Check that the Package Level has what we need for verification.
- if [attr for attr in self.__gpg_ireq__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot install" \
- % (entry.tag, entry.get('name')))
- return False
- else:
- if [attr for attr in self.__ireq__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot install" \
- % (entry.tag, entry.get('name')))
- return False
- else:
- if entry.get('name') == 'gpg-pubkey':
- # gpg-pubkey packages aren't really pacakges, so we have to do
- # something a little different.
- # Check that the Package Level has what we need for verification.
- if [attr for attr in self.__new_gpg_ireq__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot install" \
- % (entry.tag, entry.get('name')))
- return False
- # Check that the Instance Level has what we need for verification.
- for inst in instances:
- if [attr for attr in self.__new_gpg_ireq__[inst.tag] \
- if attr not in inst.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot install"\
- % (inst.tag, entry.get('name')))
- return False
- else:
- # New format with Instances.
- # Check that the Package Level has what we need for verification.
- if [attr for attr in self.__new_ireq__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot install" \
- % (entry.tag, entry.get('name')))
- self.logger.error(" Required attributes that may not be present are %s" \
- % (self.__new_ireq__[entry.tag]))
- return False
- # Check that the Instance Level has what we need for verification.
- for inst in instances:
- if inst.tag == 'Instance':
- if [attr for attr in self.__new_ireq__[inst.tag] \
- if attr not in inst.attrib]:
- self.logger.error("Incomplete information for %s of package %s; cannot install" \
- % (inst.tag, entry.get('name')))
- self.logger.error(" Required attributes that may not be present are %s" \
- % (self.__new_ireq__[inst.tag]))
- return False
- return True
-
- def canVerify(self, entry):
- """
- Test if entry has enough information to be verified.
-
- Three types of entries are checked.
- Old style Package
- New style Package with Instances
- pgp-pubkey packages
-
- Also the old style entries get modified after the first
- VerifyPackage() run, so there needs to be a second test.
-
- """
- if not self.handlesEntry(entry):
- return False
-
- if 'failure' in entry.attrib:
- self.logger.error("Entry %s:%s reports bind failure: %s" % \
- (entry.tag, entry.get('name'), entry.get('failure')))
- return False
-
- # We don't want to do any checks so we don't care what the entry has in it.
- if (not self.pkg_checks or
- entry.get('pkg_checks', 'true').lower() == 'false'):
- return True
-
- instances = entry.findall('Instance')
-
- if not instances:
- # Old non Instance format, unmodified.
- if entry.get('name') == 'gpg-pubkey':
- # gpg-pubkey packages aren't really pacakges, so we have to do
- # something a little different.
- # Check that the Package Level has what we need for verification.
- if [attr for attr in self.__gpg_req__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (entry.tag, entry.get('name')))
- return False
- elif entry.tag == 'Path' and entry.get('type') == 'ignore':
- # ignored Paths are only relevant during failed package
- # verification
- pass
- else:
- if [attr for attr in self.__req__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (entry.tag, entry.get('name')))
- return False
- else:
- if entry.get('name') == 'gpg-pubkey':
- # gpg-pubkey packages aren't really pacakges, so we have to do
- # something a little different.
- # Check that the Package Level has what we need for verification.
- if [attr for attr in self.__new_gpg_req__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (entry.tag, entry.get('name')))
- return False
- # Check that the Instance Level has what we need for verification.
- for inst in instances:
- if [attr for attr in self.__new_gpg_req__[inst.tag] \
- if attr not in inst.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (inst.tag, inst.get('name')))
- return False
- else:
- # New format with Instances, or old style modified.
- # Check that the Package Level has what we need for verification.
- if [attr for attr in self.__new_req__[entry.tag] if attr not in entry.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (entry.tag, entry.get('name')))
- return False
- # Check that the Instance Level has what we need for verification.
- for inst in instances:
- if inst.tag == 'Instance':
- if [attr for attr in self.__new_req__[inst.tag] \
- if attr not in inst.attrib]:
- self.logger.error("Incomplete information for entry %s:%s; cannot verify" \
- % (inst.tag, inst.get('name')))
- return False
- return True
-
- def FindExtraPackages(self):
- """Find extra packages."""
- packages = [entry.get('name') for entry in self.getSupportedEntries()]
- extras = []
-
- for (name, instances) in list(self.installed.items()):
- if name not in packages:
- extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype)
- for installed_inst in instances:
- if self.setup['extra']:
- self.logger.info("Extra Package %s %s." % \
- (name, self.str_evra(installed_inst)))
- tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \
- version = installed_inst.get('version'), \
- release = installed_inst.get('release'))
- if installed_inst.get('epoch', None) != None:
- tmp_entry.set('epoch', str(installed_inst.get('epoch')))
- if installed_inst.get('arch', None) != None:
- tmp_entry.set('arch', installed_inst.get('arch'))
- extras.append(extra_entry)
- return extras
-
-
- def FindExtraInstances(self, pkg_entry, installed_entry):
- """
- Check for installed instances that are not in the config.
- Return a Package Entry with Instances to remove, or None if there
- are no Instances to remove.
-
- """
- name = pkg_entry.get('name')
- extra_entry = Bcfg2.Client.XML.Element('Package', name=name, type=self.pkgtype)
- instances = [inst for inst in pkg_entry if inst.tag == 'Instance' or inst.tag == 'Package']
- if name in self.installOnlyPkgs:
- for installed_inst in installed_entry:
- not_found = True
- for inst in instances:
- if self.pkg_vr_equal(inst, installed_inst) or \
- self.inst_evra_equal(inst, installed_inst):
- not_found = False
- break
- if not_found == True:
- # Extra package.
- self.logger.info("Extra InstallOnlyPackage %s %s." % \
- (name, self.str_evra(installed_inst)))
- tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \
- version = installed_inst.get('version'), \
- release = installed_inst.get('release'))
- if installed_inst.get('epoch', None) != None:
- tmp_entry.set('epoch', str(installed_inst.get('epoch')))
- if installed_inst.get('arch', None) != None:
- tmp_entry.set('arch', installed_inst.get('arch'))
- else:
- # Normal package, only check arch.
- for installed_inst in installed_entry:
- not_found = True
- for inst in instances:
- if installed_inst.get('arch', None) == inst.get('arch', None) or\
- inst.tag == 'Package':
- not_found = False
- break
- if not_found:
- self.logger.info("Extra Normal Package Instance %s %s" % \
- (name, self.str_evra(installed_inst)))
- tmp_entry = Bcfg2.Client.XML.SubElement(extra_entry, 'Instance', \
- version = installed_inst.get('version'), \
- release = installed_inst.get('release'))
- if installed_inst.get('epoch', None) != None:
- tmp_entry.set('epoch', str(installed_inst.get('epoch')))
- if installed_inst.get('arch', None) != None:
- tmp_entry.set('arch', installed_inst.get('arch'))
-
- if len(extra_entry) == 0:
- extra_entry = None
-
- return extra_entry
-
- def str_evra(self, instance):
- """Convert evra dict entries to a string."""
- if instance.get('epoch', '*') in ['*', None]:
- return '%s-%s.%s' % (instance.get('version', '*'),
- instance.get('release', '*'),
- instance.get('arch', '*'))
- else:
- return '%s:%s-%s.%s' % (instance.get('epoch', '*'),
- instance.get('version', '*'),
- instance.get('release', '*'),
- instance.get('arch', '*'))
-
- def pkg_vr_equal(self, config_entry, installed_entry):
- '''
- Compare old style entry to installed entry. Which means ignore
- the epoch and arch.
- '''
- if (config_entry.tag == 'Package' and \
- config_entry.get('version') == installed_entry.get('version') and \
- config_entry.get('release') == installed_entry.get('release')):
- return True
- else:
- return False
-
- def inst_evra_equal(self, config_entry, installed_entry):
- """Compare new style instance to installed entry."""
-
- if config_entry.get('epoch', None) != None:
- epoch = int(config_entry.get('epoch'))
- else:
- epoch = None
-
- if (config_entry.tag == 'Instance' and \
- (epoch == installed_entry.get('epoch', 0) or \
- (epoch == 0 and installed_entry.get('epoch', 0) == None) or \
- (epoch == None and installed_entry.get('epoch', 0) == 0)) and \
- config_entry.get('version') == installed_entry.get('version') and \
- config_entry.get('release') == installed_entry.get('release') and \
- config_entry.get('arch', None) == installed_entry.get('arch', None)):
- return True
- else:
- return False
-
- def getinstalledgpg(self):
- """
- Create a list of installed GPG key IDs.
-
- The pgp-pubkey package version is the least significant 4 bytes
- (big-endian) of the key ID which is good enough for our purposes.
-
- """
- init_ts = rpmtools.rpmtransactionset()
- init_ts.setVSFlags(rpm._RPMVSF_NODIGESTS|rpm._RPMVSF_NOSIGNATURES)
- gpg_hdrs = rpmtools.getheadersbykeyword(init_ts, **{'name':'gpg-pubkey'})
- keyids = [ header[rpm.RPMTAG_VERSION] for header in gpg_hdrs]
- keyids.append('None')
- init_ts.closeDB()
- del init_ts
- return keyids
-
- def VerifyPath(self, entry, _):
- """
- We don't do anything here since all
- Paths are processed in __init__
- """
- return True
+class RPMng(RPM):
+ """ RPM driver called 'RPMng' for backwards compat """
+ deprecated = True
diff --git a/src/lib/Bcfg2/Client/Tools/YUM.py b/src/lib/Bcfg2/Client/Tools/YUM.py
new file mode 100644
index 000000000..8a2ba6f87
--- /dev/null
+++ b/src/lib/Bcfg2/Client/Tools/YUM.py
@@ -0,0 +1,951 @@
+"""This provides bcfg2 support for yum."""
+
+import copy
+import os.path
+import sys
+import yum
+import yum.packages
+import yum.rpmtrans
+import yum.callbacks
+import yum.Errors
+import yum.misc
+import rpmUtils.arch
+import Bcfg2.Client.XML
+import Bcfg2.Client.Tools
+
+
+def build_yname(pkgname, inst):
+ """Build yum appropriate package name."""
+ d = {}
+ if isinstance(inst, yum.packages.PackageObject):
+ for i in ['name', 'epoch', 'version', 'release', 'arch']:
+ d[i] = getattr(inst, i)
+ else:
+ d['name'] = pkgname
+ if inst.get('version') != 'any':
+ d['version'] = inst.get('version')
+ if inst.get('epoch', False):
+ d['epoch'] = inst.get('epoch')
+ if inst.get('release', False) and inst.get('release') != 'any':
+ d['release'] = inst.get('release')
+ if inst.get('arch', False) and inst.get('arch') != 'any':
+ d['arch'] = inst.get('arch')
+ return d
+
+
+def short_yname(nevra):
+ d = nevra.copy()
+ if 'version' in d:
+ d['ver'] = d['version']
+ del d['version']
+ if 'release' in d:
+ d['rel'] = d['release']
+ del d['release']
+ return d
+
+
+def nevraString(p):
+ if isinstance(p, yum.packages.PackageObject):
+ return str(p)
+ else:
+ ret = ""
+ for i, j in [('epoch', '%s:'), ('name', '%s'), ('version', '-%s'),
+ ('release', '-%s'), ('arch', '.%s')]:
+ if i in p:
+ ret = "%s%s" % (ret, j % p[i])
+ return ret
+
+
+class RPMDisplay(yum.rpmtrans.RPMBaseCallback):
+ """We subclass the default RPM transaction callback so that we
+ can control Yum's verbosity and pipe it through the right logger."""
+
+ def __init__(self, logger):
+ yum.rpmtrans.RPMBaseCallback.__init__(self)
+ self.logger = logger
+ self.state = None
+ self.package = None
+
+ def event(self, package, action, te_current, te_total,
+ ts_current, ts_total):
+ """
+ @param package: A yum package object or simple string of a package name
+ @param action: A yum.constant transaction set state or in the obscure
+ rpm repackage case it could be the string 'repackaging'
+ @param te_current: Current number of bytes processed in the transaction
+ element being processed
+ @param te_total: Total number of bytes in the transaction element being
+ processed
+ @param ts_current: number of processes completed in whole transaction
+ @param ts_total: total number of processes in the transaction.
+ """
+
+ if self.package != str(package) or action != self.state:
+ msg = "%s: %s" % (self.action[action], package)
+ self.logger.info(msg)
+ self.state = action
+ self.package = str(package)
+
+ def scriptout(self, package, msgs):
+ """Handle output from package scripts."""
+
+ if msgs:
+ msg = "%s: %s" % (package, msgs)
+ self.logger.debug(msg)
+
+ def errorlog(self, msg):
+ """Deal with error reporting."""
+ self.logger.error(msg)
+
+
+class YumDisplay(yum.callbacks.ProcessTransBaseCallback):
+ """Class to handle display of what step we are in the Yum transaction
+ such as downloading packages, etc."""
+
+ def __init__(self, logger):
+ self.logger = logger
+
+
+class YUM(Bcfg2.Client.Tools.PkgTool):
+ """Support for Yum packages."""
+ pkgtype = 'yum'
+ __execs__ = []
+ __handles__ = [('Package', 'yum'),
+ ('Package', 'rpm'),
+ ('Path', 'ignore')]
+
+ __req__ = {'Package': ['name'],
+ 'Path': ['type']}
+ __ireq__ = {'Package': ['name']}
+
+ conflicts = ['YUM24', 'RPM', 'RPMng', 'YUMng']
+
+ def __init__(self, logger, setup, config):
+ self._loadYumBase(setup=setup, logger=logger)
+ Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config)
+ self.ignores = [entry.get('name') for struct in config \
+ for entry in struct \
+ if entry.tag == 'Path' and \
+ entry.get('type') == 'ignore']
+ self.instance_status = {}
+ self.extra_instances = []
+ self.modlists = {}
+ self._loadConfig()
+ self.__important__ = self.__important__ + \
+ [entry.get('name') for struct in config \
+ for entry in struct \
+ if entry.tag == 'Path' and \
+ (entry.get('name').startswith('/etc/yum.d') \
+ or entry.get('name').startswith('/etc/yum.repos.d')) \
+ or entry.get('name') == '/etc/yum.conf']
+ self.yum_avail = dict()
+ self.yum_installed = dict()
+
+ yup = self.yb.doPackageLists(pkgnarrow='updates')
+ if hasattr(self.yb.rpmdb, 'pkglist'):
+ yinst = self.yb.rpmdb.pkglist
+ else:
+ yinst = self.yb.rpmdb.getPkgList()
+ for dest, source in [(self.yum_avail, yup.updates),
+ (self.yum_installed, yinst)]:
+ for pkg in source:
+ if dest is self.yum_avail:
+ pname = pkg.name
+ data = [(pkg.arch, (pkg.epoch, pkg.version, pkg.release))]
+ else:
+ pname = pkg[0]
+ data = [(pkg[1], (pkg[2], pkg[3], pkg[4]))]
+ if pname in dest:
+ dest[pname].update(data)
+ else:
+ dest[pname] = dict(data)
+
+ def _loadYumBase(self, setup=None, logger=None):
+ ''' this may be called before PkgTool.__init__() is called on
+ this object (when the YUM object is first instantiated;
+ PkgTool.__init__() calls RefreshPackages(), which requires a
+ YumBase object already exist), or after __init__() has
+ completed, when we reload the yum config before installing
+ packages. Consequently, we support both methods by allowing
+ setup and logger, the only object properties we use in this
+ function, to be passed as keyword arguments or to be omitted
+ and drawn from the object itself.'''
+ self.yb = yum.YumBase()
+
+ if setup is None:
+ setup = self.setup
+ if logger is None:
+ logger = self.logger
+
+ if setup['debug']:
+ debuglevel = 3
+ elif setup['verbose']:
+ debuglevel = 2
+ else:
+ debuglevel = 0
+
+ # pylint: disable=E1121
+ try:
+ self.yb.preconf.debuglevel = debuglevel
+ self.yb._getConfig()
+ except AttributeError:
+ self.yb._getConfig(self.yb.conf.config_file_path,
+ debuglevel=debuglevel)
+ # pylint: enable=E1121
+
+ try:
+ self.yb.doConfigSetup()
+ self.yb.doTsSetup()
+ self.yb.doRpmDBSetup()
+ except yum.Errors.RepoError:
+ err = sys.exc_info()[1]
+ logger.error("YUM Repository error: %s" % err)
+ raise Bcfg2.Client.Tools.ToolInstantiationError
+ except Exception:
+ err = sys.exc_info()[1]
+ logger.error("Yum error: %s" % err)
+ raise Bcfg2.Client.Tools.ToolInstantiationError
+
+ def _loadConfig(self):
+ # Process the Yum section from the config file.
+ # These are all boolean flags, either we do stuff or we don't
+ self.pkg_checks = self.setup["yum_pkg_checks"]
+ self.pkg_verify = self.setup["yum_pkg_verify"]
+ self.doInstall = self.setup["yum_installed_action"] == "install"
+ self.doUpgrade = self.setup["yum_version_fail_action"] == "upgrade"
+ self.doReinst = self.setup["yum_verify_fail_action"] == "reinstall"
+ self.verifyFlags = self.setup["yum_verify_flags"]
+
+ self.installOnlyPkgs = self.yb.conf.installonlypkgs
+ if 'gpg-pubkey' not in self.installOnlyPkgs:
+ self.installOnlyPkgs.append('gpg-pubkey')
+
+ self.logger.debug("Yum: Install missing: %s" % self.doInstall)
+ self.logger.debug("Yum: pkg_checks: %s" % self.pkg_checks)
+ self.logger.debug("Yum: pkg_verify: %s" % self.pkg_verify)
+ self.logger.debug("Yum: Upgrade on version fail: %s" % self.doUpgrade)
+ self.logger.debug("Yum: Reinstall on verify fail: %s" % self.doReinst)
+ self.logger.debug("Yum: installOnlyPkgs: %s" % self.installOnlyPkgs)
+ self.logger.debug("Yum: verify_flags: %s" % self.verifyFlags)
+
+ def _fixAutoVersion(self, entry):
+ # old style entry; synthesize Instances from current installed
+ if entry.get('name') not in self.yum_installed and \
+ entry.get('name') not in self.yum_avail:
+ # new entry; fall back to default
+ entry.set('version', 'any')
+ else:
+ data = copy.copy(self.yum_installed[entry.get('name')])
+ if entry.get('name') in self.yum_avail:
+ # installed but out of date
+ data.update(self.yum_avail[entry.get('name')])
+ for (arch, (epoch, vers, rel)) in list(data.items()):
+ x = Bcfg2.Client.XML.SubElement(entry, "Instance",
+ name=entry.get('name'),
+ version=vers, arch=arch,
+ release=rel, epoch=epoch)
+ if 'verify_flags' in entry.attrib:
+ x.set('verify_flags', entry.get('verify_flags'))
+ if 'verify' in entry.attrib:
+ x.set('verify', entry.get('verify'))
+
+ def _buildInstances(self, entry):
+ instances = [inst for inst in entry \
+ if inst.tag == 'Instance' or inst.tag == 'Package']
+
+ # XXX: Uniquify instances. Cases where duplicates are returned.
+ # However, the elements aren't comparable.
+
+ if instances == []:
+ # We have an old style no Instance entry. Convert it to new style.
+ instance = Bcfg2.Client.XML.SubElement(entry, 'Package')
+ for attrib in list(entry.attrib.keys()):
+ instance.attrib[attrib] = entry.attrib[attrib]
+ instances = [instance]
+
+ return instances
+
+ def _getGPGKeysAsPackages(self):
+ """Return a list of the GPG RPM signing keys installed on the
+ system as a list of Package Objects."""
+
+ # XXX GPG keys existing in the RPMDB have numbered days
+ # and newer Yum versions will not return information about them
+ if hasattr(self.yb.rpmdb, 'returnGPGPubkeyPackages'):
+ return self.yb.rpmdb.returnGPGPubkeyPackages()
+ return self.yb.rpmdb.searchNevra(name='gpg-pubkey')
+
+ def _verifyHelper(self, po):
+ # This code primarly deals with a yum bug where the PO.verify()
+ # method does not properly take into count multilib sharing of files.
+ # Neither does RPM proper, really....it just ignores the problem.
+ def verify(p):
+ # disabling file checksums is a new feature yum 3.2.17-ish
+ try:
+ vResult = p.verify(fast=self.setup.get('quick', False))
+ except TypeError:
+ # Older Yum API
+ vResult = p.verify()
+ return vResult
+
+ key = (po.name, po.epoch, po.version, po.release, po.arch)
+ if key in self.verifyCache:
+ results = self.verifyCache[key]
+ else:
+ results = verify(po)
+ self.verifyCache[key] = results
+ if not rpmUtils.arch.isMultiLibArch():
+ return results
+
+ # Okay deal with a buggy yum multilib and verify
+ packages = self.yb.rpmdb.searchNevra(name=po.name, epoch=po.epoch,
+ ver=po.version, rel=po.release) # find all arches of pkg
+ if len(packages) == 1:
+ return results # No mathcing multilib packages
+
+ files = set(po.returnFileEntries()) # Will be the list of common fns
+ common = {}
+ for p in packages:
+ if p != po:
+ files = files & set(p.returnFileEntries())
+ for p in packages:
+ k = (p.name, p.epoch, p.version, p.release, p.arch)
+ self.logger.debug("Multilib Verify: comparing %s to %s" \
+ % (po, p))
+ if k in self.verifyCache:
+ v = self.verifyCache[k]
+ else:
+ v = verify(p)
+ self.verifyCache[k] = v
+
+ for fn, probs in list(v.items()):
+ # file problems must exist in ALL multilib packages to be real
+ if fn in files:
+ common[fn] = common.get(fn, 0) + 1
+
+ flag = len(packages) - 1
+ for fn, i in list(common.items()):
+ if i == flag:
+ # this fn had verify problems in all but one of the multilib
+ # packages. That means its correct in the package that's
+ # "on top." Therefore, this is a fake verify problem.
+ if fn in results:
+ del results[fn]
+
+ return results
+
+ def RefreshPackages(self):
+ """
+ Creates self.installed{} which is a dict of installed packages.
+
+ The dict items are lists of nevra dicts. This loosely matches the
+ config from the server and what rpmtools uses to specify pacakges.
+
+ e.g.
+
+ self.installed['foo'] = [ {'name':'foo', 'epoch':None,
+ 'version':'1', 'release':2,
+ 'arch':'i386'},
+ {'name':'foo', 'epoch':None,
+ 'version':'1', 'release':2,
+ 'arch':'x86_64'} ]
+ """
+
+ self.installed = {}
+ packages = self._getGPGKeysAsPackages() + \
+ self.yb.rpmdb.returnPackages()
+ for po in packages:
+ d = {}
+ for i in ['name', 'epoch', 'version', 'release', 'arch']:
+ if i == 'arch' and getattr(po, i) is None:
+ d[i] = 'noarch'
+ elif i == 'epoch' and getattr(po, i) is None:
+ d[i] = '0'
+ else:
+ d[i] = getattr(po, i)
+ self.installed.setdefault(po.name, []).append(d)
+
+ def VerifyPackage(self, entry, modlist, pinned_version=None):
+ """
+ Verify Package status for entry.
+ Performs the following:
+ - Checks for the presence of required Package Instances.
+ - Compares the evra 'version' info against self.installed{}.
+ - RPM level package verify (rpm --verify).
+ - Checks for the presence of unrequired package instances.
+
+ Produces the following dict and list for Yum.Install() to use:
+ For installs/upgrades/fixes of required instances:
+ instance_status = { <Instance Element Object>:
+ { 'installed': True|False,
+ 'version_fail': True|False,
+ 'verify_fail': True|False,
+ 'pkg': <Package Element Object>,
+ 'modlist': [ <filename>, ... ],
+ 'verify' : [ <rpm --verify results> ]
+ }, ......
+ }
+
+ For deletions of unrequired instances:
+ extra_instances = [ <Package Element Object>, ..... ]
+
+ Constructs the text prompts for interactive mode.
+ """
+
+ if entry.get('version', False) == 'auto':
+ self._fixAutoVersion(entry)
+
+ self.logger.debug("Verifying package instances for %s" %
+ entry.get('name'))
+
+ self.verifyCache = {} # Used for checking multilib packages
+ self.modlists[entry] = modlist
+ instances = self._buildInstances(entry)
+ packageCache = []
+ package_fail = False
+ qtext_versions = []
+ virtPkg = False
+ pkg_checks = self.pkg_checks and \
+ entry.get('pkg_checks', 'true').lower() == 'true'
+ pkg_verify = self.pkg_verify and \
+ entry.get('pkg_verify', 'true').lower() == 'true'
+
+ if entry.get('name') == 'gpg-pubkey':
+ POs = self._getGPGKeysAsPackages()
+ pkg_verify = False # No files here to verify
+ else:
+ POs = self.yb.rpmdb.searchNevra(name=entry.get('name'))
+ if len(POs) == 0:
+ # Some sort of virtual capability? Try to resolve it
+ POs = self.yb.rpmdb.searchProvides(entry.get('name'))
+ if len(POs) > 0:
+ virtPkg = True
+ self.logger.info("%s appears to be provided by:" %
+ entry.get('name'))
+ for p in POs:
+ self.logger.info(" %s" % p)
+
+ for inst in instances:
+ nevra = build_yname(entry.get('name'), inst)
+ snevra = short_yname(nevra)
+ if nevra in packageCache:
+ continue # Ignore duplicate instances
+ else:
+ packageCache.append(nevra)
+
+ self.logger.debug("Verifying: %s" % nevraString(nevra))
+
+ # Set some defaults here
+ stat = self.instance_status.setdefault(inst, {})
+ stat['installed'] = True
+ stat['version_fail'] = False
+ stat['verify'] = {}
+ stat['verify_fail'] = False
+ stat['pkg'] = entry
+ stat['modlist'] = modlist
+ if inst.get('verify_flags'):
+ # this splits on either space or comma
+ verify_flags = \
+ inst.get('verify_flags').lower().replace(' ',
+ ',').split(',')
+ else:
+ verify_flags = self.verifyFlags
+
+ if 'arch' in nevra:
+ # If arch is specified use it to select the package
+ _POs = [ p for p in POs if p.arch == nevra['arch'] ]
+ else:
+ _POs = POs
+ if len(_POs) == 0:
+ # Package (name, arch) not installed
+ entry.set('current_exists', 'false')
+ self.logger.debug(" %s is not installed" % nevraString(nevra))
+ stat['installed'] = False
+ package_fail = True
+ qtext_versions.append("I(%s)" % nevra)
+ continue
+
+ if not pkg_checks:
+ continue
+
+ # Check EVR
+ if virtPkg:
+ # we need to make sure that the version of the symbol
+ # provided matches the one required in the
+ # configuration
+ vlist = []
+ for attr in ["epoch", "version", "release"]:
+ vlist.append(nevra.get(attr))
+ if tuple(vlist) == (None, None, None):
+ # we just require the package name, no particular
+ # version, so just make a copy of POs since every
+ # package that provides this symbol satisfies the
+ # requirement
+ _POs = [po for po in POs]
+ else:
+ _POs = [po for po in POs
+ if po.checkPrco('provides',
+ (nevra["name"], 'EQ',
+ tuple(vlist)))]
+ elif entry.get('name') == 'gpg-pubkey':
+ if 'version' not in nevra:
+ m = "Skipping verify: gpg-pubkey without an RPM version."
+ self.logger.warning(m)
+ continue
+ if 'release' not in nevra:
+ m = "Skipping verify: gpg-pubkey without an RPM release."
+ self.logger.warning(m)
+ continue
+ _POs = [p for p in POs if p.version == nevra['version'] \
+ and p.release == nevra['release']]
+ else:
+ _POs = self.yb.rpmdb.searchNevra(**snevra)
+ if len(_POs) == 0:
+ package_fail = True
+ stat['version_fail'] = True
+ # Just chose the first pkg for the error message
+ if virtPkg:
+ provTuple = \
+ [p for p in POs[0].provides
+ if p[0] == entry.get("name")][0]
+ entry.set('current_version', "%s:%s-%s" % provTuple[2])
+ self.logger.info(" %s: Wrong version installed. "
+ "Want %s, but %s provides %s" %
+ (entry.get("name"),
+ nevraString(nevra),
+ nevraString(POs[0]),
+ yum.misc.prco_tuple_to_string(provTuple)))
+ else:
+ entry.set('current_version', "%s:%s-%s.%s" %
+ (POs[0].epoch,
+ POs[0].version,
+ POs[0].release,
+ POs[0].arch))
+ self.logger.info(" %s: Wrong version installed. "
+ "Want %s, but have %s" %
+ (entry.get("name"),
+ nevraString(nevra),
+ nevraString(POs[0])))
+ entry.set('version', "%s:%s-%s.%s" %
+ (nevra.get('epoch', 'any'),
+ nevra.get('version', 'any'),
+ nevra.get('release', 'any'),
+ nevra.get('arch', 'any')))
+ qtext_versions.append("U(%s)" % str(POs[0]))
+ continue
+
+ if self.setup.get('quick', False):
+ # Passed -q on the command line
+ continue
+ if not (pkg_verify and \
+ inst.get('pkg_verify', 'true').lower() == 'true'):
+ continue
+
+ # XXX: We ignore GPG sig checking the package as it
+ # has nothing to do with the individual file hash/size/etc.
+ # GPG checking the package only eaxmines some header/rpmdb
+ # wacky-ness, and will not properly detect a compromised rpmdb.
+ # Yum's verify routine does not support it for that reaosn.
+
+ if len(_POs) > 1:
+ self.logger.debug(" Verify Instance found many packages:")
+ for po in _POs:
+ self.logger.debug(" %s" % str(po))
+
+ try:
+ vResult = self._verifyHelper(_POs[0])
+ except Exception:
+ e = sys.exc_info()[1]
+ # Unknown Yum exception
+ self.logger.warning(" Verify Exception: %s" % str(e))
+ package_fail = True
+ continue
+
+ # Now take out the Yum specific objects / modlists / unproblems
+ ignores = [ig.get('name') for ig in entry.findall('Ignore')] + \
+ [ig.get('name') for ig in inst.findall('Ignore')] + \
+ self.ignores
+ for fn, probs in list(vResult.items()):
+ if fn in modlist:
+ self.logger.debug(" %s in modlist, skipping" % fn)
+ continue
+ if fn in ignores:
+ self.logger.debug(" %s in ignore list, skipping" % fn)
+ continue
+ tmp = []
+ for p in probs:
+ if p.type == 'missing' and os.path.islink(fn):
+ continue
+ elif 'no' + p.type in verify_flags:
+ continue
+ if p.type not in ['missingok', 'ghost']:
+ tmp.append((p.type, p.message))
+ if tmp != []:
+ stat['verify'][fn] = tmp
+
+ if stat['verify'] != {}:
+ stat['verify_fail'] = True
+ package_fail = True
+ self.logger.debug("It is suggested that you either manage "
+ "these files, revert the changes, or ignore "
+ "false failures:")
+ self.logger.debug(" Verify Problems:")
+ for fn, probs in list(stat['verify'].items()):
+ self.logger.debug(" %s" % fn)
+ for p in probs:
+ self.logger.debug(" %s: %s" % p)
+
+ if len(POs) > 0:
+ # Is this an install only package? We just look at the first one
+ provides = set([p[0] for p in POs[0].provides] + [POs[0].name])
+ install_only = len(set(self.installOnlyPkgs) & provides) > 0
+ else:
+ install_only = False
+
+ if virtPkg or (install_only and not self.setup['kevlar']):
+ # XXX: virtual capability supplied, we a probably dealing
+ # with multiple packages of different names. This check
+ # doesn't make a lot of since in this case
+ # XXX: install_only: Yum may clean some of these up itself.
+ # Otherwise having multiple instances of install only packages
+ # is considered correct
+ self.extra_instances = None
+ else:
+ self.extra_instances = self.FindExtraInstances(entry, POs)
+ if self.extra_instances is not None:
+ package_fail = True
+
+ return not package_fail
+
+ def FindExtraInstances(self, entry, POs):
+ """
+ Check for installed instances that are not in the config.
+ Return a Package Entry with Instances to remove, or None if there
+ are no Instances to remove.
+
+ """
+ if len(POs) == 0:
+ return None
+ name = entry.get('name')
+ extra_entry = Bcfg2.Client.XML.Element('Package', name=name,
+ type=self.pkgtype)
+ instances = self._buildInstances(entry)
+ _POs = [p for p in POs] # Shallow copy
+
+ # Algorythm is sensitive to duplicates, check for them
+ checked = []
+ for inst in instances:
+ nevra = build_yname(name, inst)
+ snevra = short_yname(nevra)
+ pkgs = self.yb.rpmdb.searchNevra(**snevra)
+ flag = True
+ if len(pkgs) > 0:
+ if pkgs[0] in checked:
+ continue # We've already taken care of this Instance
+ else:
+ checked.append(pkgs[0])
+ _POs.remove(pkgs[0])
+
+ for p in _POs:
+ self.logger.debug(" Extra Instance Found: %s" % str(p))
+ Bcfg2.Client.XML.SubElement(extra_entry, 'Instance',
+ epoch=p.epoch, name=p.name, version=p.version,
+ release=p.release, arch=p.arch)
+
+ if _POs == []:
+ return None
+ else:
+ return extra_entry
+
+ def FindExtraPackages(self):
+ """Find extra packages."""
+ packages = [e.get('name') for e in self.getSupportedEntries()]
+ extras = []
+
+ for p in list(self.installed.keys()):
+ if p not in packages:
+ entry = Bcfg2.Client.XML.Element('Package', name=p,
+ type=self.pkgtype)
+ for i in self.installed[p]:
+ inst = Bcfg2.Client.XML.SubElement(entry,
+ 'Instance',
+ epoch=i['epoch'],
+ version=i['version'],
+ release=i['release'],
+ arch=i['arch'])
+
+ extras.append(entry)
+
+ return extras
+
+ def _installGPGKey(self, inst, key_file):
+ """Examine the GPG keys carefully before installation. Avoid
+ installing duplicate keys. Returns True on successful install."""
+
+ # RPM Transaction Set
+ ts = self.yb.rpmdb.readOnlyTS()
+
+ if not os.path.exists(key_file):
+ self.logger.debug("GPG Key file %s not installed" % key_file)
+ return False
+
+ rawkey = open(key_file).read()
+ gpg = yum.misc.getgpgkeyinfo(rawkey)
+
+ ver = yum.misc.keyIdToRPMVer(gpg['keyid'])
+ rel = yum.misc.keyIdToRPMVer(gpg['timestamp'])
+ if not (ver == inst.get('version') and rel == inst.get('release')):
+ self.logger.info("GPG key file %s does not match gpg-pubkey-%s-%s"\
+ % (key_file, inst.get('version'),
+ inst.get('release')))
+ return False
+
+ if not yum.misc.keyInstalled(ts, gpg['keyid'],
+ gpg['timestamp']) == 0:
+ result = ts.pgpImportPubkey(yum.misc.procgpgkey(rawkey))
+ else:
+ self.logger.debug("gpg-pubkey-%s-%s already installed"\
+ % (inst.get('version'),
+ inst.get('release')))
+ return True
+
+ if result != 0:
+ self.logger.debug("Unable to install %s-%s" % \
+ (self.instance_status[inst].get('pkg').get('name'),
+ nevraString(inst)))
+ return False
+ else:
+ self.logger.debug("Installed %s-%s-%s" % \
+ (self.instance_status[inst].get('pkg').get('name'),
+ inst.get('version'), inst.get('release')))
+ return True
+
+ def _runYumTransaction(self):
+ def cleanup():
+ self.yb.closeRpmDB()
+ self.RefreshPackages()
+
+ rDisplay = RPMDisplay(self.logger)
+ yDisplay = YumDisplay(self.logger)
+ # Run the Yum Transaction
+ try:
+ rescode, restring = self.yb.buildTransaction()
+ except yum.Errors.YumBaseError:
+ e = sys.exc_info()[1]
+ self.logger.error("Yum transaction error: %s" % str(e))
+ cleanup()
+ return
+
+ self.logger.debug("Initial Yum buildTransaction() run said:")
+ self.logger.debug(" resultcode: %s, msgs: %s" \
+ % (rescode, restring))
+
+ if rescode != 1:
+ # Transaction built successfully, run it
+ try:
+ self.yb.processTransaction(callback=yDisplay,
+ rpmDisplay=rDisplay)
+ self.logger.info("Single Pass for Install Succeeded")
+ except yum.Errors.YumBaseError:
+ e = sys.exc_info()[1]
+ self.logger.error("Yum transaction error: %s" % str(e))
+ cleanup()
+ return
+ else:
+ # The yum command failed. No packages installed.
+ # Try installing instances individually.
+ self.logger.error("Single Pass Install of Packages Failed")
+ skipBroken = self.yb.conf.skip_broken
+ self.yb.conf.skip_broken = True
+ try:
+ rescode, restring = self.yb.buildTransaction()
+ if rescode != 1:
+ self.yb.processTransaction(callback=yDisplay,
+ rpmDisplay=rDisplay)
+ self.logger.debug(
+ "Second pass install did not install all packages")
+ else:
+ self.logger.error("Second pass yum install failed.")
+ self.logger.debug(" %s" % restring)
+ except yum.Errors.YumBaseError:
+ e = sys.exc_info()[1]
+ self.logger.error("Yum transaction error: %s" % str(e))
+
+ self.yb.conf.skip_broken = skipBroken
+
+ cleanup()
+
+ def Install(self, packages, states):
+ """
+ Try and fix everything that Yum.VerifyPackages() found wrong for
+ each Package Entry. This can result in individual RPMs being
+ installed (for the first time), deleted, downgraded
+ or upgraded.
+
+ packages is a list of Package Elements that has
+ states[<Package Element>] == False
+
+ The following effects occur:
+ - states{} is conditionally updated for each package.
+ - self.installed{} is rebuilt, possibly multiple times.
+ - self.instance_status{} is conditionally updated for each instance
+ of a package.
+ - Each package will be added to self.modified[] if its states{}
+ entry is set to True.
+
+ """
+ self.logger.debug('Running Yum.Install()')
+
+ install_pkgs = []
+ gpg_keys = []
+ upgrade_pkgs = []
+ reinstall_pkgs = []
+
+ def queuePkg(pkg, inst, queue):
+ if pkg.get('name') == 'gpg-pubkey':
+ gpg_keys.append(inst)
+ else:
+ queue.append(inst)
+
+ # Remove extra instances.
+ # Can not reverify because we don't have a package entry.
+ if self.extra_instances is not None and len(self.extra_instances) > 0:
+ if (self.setup.get('remove') == 'all' or \
+ self.setup.get('remove') == 'packages'):
+ self.RemovePackages(self.extra_instances)
+ else:
+ self.logger.info("The following extra package instances will be removed by the '-r' option:")
+ for pkg in self.extra_instances:
+ for inst in pkg:
+ self.logger.info(" %s %s" % \
+ ((pkg.get('name'), nevraString(inst))))
+
+ # Figure out which instances of the packages actually need something
+ # doing to them and place in the appropriate work 'queue'.
+ for pkg in packages:
+ insts = [pinst for pinst in pkg \
+ if pinst.tag in ['Instance', 'Package']]
+ if insts:
+ for inst in insts:
+ if inst not in self.instance_status:
+ m = " Asked to install/update package never verified"
+ p = nevraString(build_yname(pkg.get('name'), inst))
+ self.logger.warning("%s: %s" % (m, p))
+ continue
+ status = self.instance_status[inst]
+ if not status.get('installed', False) and self.doInstall:
+ queuePkg(pkg, inst, install_pkgs)
+ elif status.get('version_fail', False) and self.doUpgrade:
+ queuePkg(pkg, inst, upgrade_pkgs)
+ elif status.get('verify_fail', False) and self.doReinst:
+ queuePkg(pkg, inst, reinstall_pkgs)
+ else:
+ # Either there was no Install/Version/Verify
+ # task to be done or the user disabled the actions
+ # in the configuration. XXX Logging for the latter?
+ pass
+ else:
+ msg = "Yum: Package tag found where Instance expected: %s"
+ self.logger.warning(msg % pkg.get('name'))
+ queuePkg(pkg, pkg, install_pkgs)
+
+ # Install GPG keys.
+ # Alternatively specify the required keys using 'gpgkey' in the
+ # repository definition in yum.conf. YUM will install the keys
+ # automatically.
+ if len(gpg_keys) > 0:
+ self.logger.info("Installing GPG keys.")
+ for inst in gpg_keys:
+ if inst.get('simplefile') is None:
+ self.logger.error("GPG key has no simplefile attribute")
+ continue
+ key_file = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
+ inst.get('simplefile'))
+ self._installGPGKey(inst, key_file)
+
+ self.RefreshPackages()
+ pkg = self.instance_status[gpg_keys[0]].get('pkg')
+ states[pkg] = self.VerifyPackage(pkg, [])
+
+ # We want to reload all Yum configuration in case we've
+ # deployed new .repo files we should consider
+ self._loadYumBase()
+
+ # Install packages.
+ if len(install_pkgs) > 0:
+ self.logger.info("Attempting to install packages")
+
+ for inst in install_pkgs:
+ pkg_arg = self.instance_status[inst].get('pkg').get('name')
+ self.logger.debug("Installing %s" % pkg_arg)
+ try:
+ self.yb.install(**build_yname(pkg_arg, inst))
+ except yum.Errors.YumBaseError:
+ yume = sys.exc_info()[1]
+ self.logger.error("Error installing package %s: %s" %
+ (pkg_arg, yume))
+
+ if len(upgrade_pkgs) > 0:
+ self.logger.info("Attempting to upgrade packages")
+
+ for inst in upgrade_pkgs:
+ pkg_arg = self.instance_status[inst].get('pkg').get('name')
+ self.logger.debug("Upgrading %s" % pkg_arg)
+ try:
+ self.yb.update(**build_yname(pkg_arg, inst))
+ except yum.Errors.YumBaseError:
+ yume = sys.exc_info()[1]
+ self.logger.error("Error upgrading package %s: %s" %
+ (pkg_arg, yume))
+
+ if len(reinstall_pkgs) > 0:
+ self.logger.info("Attempting to reinstall packages")
+ for inst in reinstall_pkgs:
+ pkg_arg = self.instance_status[inst].get('pkg').get('name')
+ self.logger.debug("Reinstalling %s" % pkg_arg)
+ try:
+ self.yb.reinstall(**build_yname(pkg_arg, inst))
+ except yum.Errors.YumBaseError:
+ yume = sys.exc_info()[1]
+ self.logger.error("Error reinstalling package %s: %s" %
+ (pkg_arg, yume))
+
+ self._runYumTransaction()
+
+ if not self.setup['kevlar']:
+ for pkg_entry in [p for p in packages if self.canVerify(p)]:
+ self.logger.debug("Reverifying Failed Package %s" \
+ % (pkg_entry.get('name')))
+ states[pkg_entry] = self.VerifyPackage(pkg_entry,
+ self.modlists.get(pkg_entry, []))
+
+ for entry in [ent for ent in packages if states[ent]]:
+ self.modified.append(entry)
+
+ def RemovePackages(self, packages):
+ """
+ Remove specified entries.
+
+ packages is a list of Package Entries with Instances generated
+ by FindExtraPackages().
+ """
+ self.logger.debug('Running Yum.RemovePackages()')
+
+ erase_args = []
+ for pkg in packages:
+ for inst in pkg:
+ nevra = build_yname(pkg.get('name'), inst)
+ if pkg.get('name') != 'gpg-pubkey':
+ self.yb.remove(**nevra)
+ self.modified.append(pkg)
+ else:
+ self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s-%s"\
+ % (nevra['name'], nevra['version'], nevra['release']))
+ self.logger.info(" This package will be deleted in a future version of the Yum driver.")
+
+ self._runYumTransaction()
+ self.extra = self.FindExtraPackages()
+
+ def VerifyPath(self, entry, _):
+ """Do nothing here since we only verify Path type=ignore"""
+ return True
diff --git a/src/lib/Bcfg2/Client/Tools/YUM24.py b/src/lib/Bcfg2/Client/Tools/YUM24.py
index 2bc821db3..9107d7a0d 100644
--- a/src/lib/Bcfg2/Client/Tools/YUM24.py
+++ b/src/lib/Bcfg2/Client/Tools/YUM24.py
@@ -5,10 +5,7 @@ import os.path
import sys
import yum
import Bcfg2.Client.XML
-import Bcfg2.Client.Tools.RPMng
-
-if not hasattr(Bcfg2.Client.Tools.RPMng, 'RPMng'):
- raise ImportError
+from Bcfg2.Client.Tools.RPM import RPM
def build_yname(pkgname, inst):
@@ -27,11 +24,10 @@ def build_yname(pkgname, inst):
return ypname
-class YUM24(Bcfg2.Client.Tools.RPMng.RPMng):
+class YUM24(RPM):
"""Support for Yum packages."""
pkgtype = 'yum'
-
- name = 'YUM24'
+ deprecated = True
__execs__ = ['/usr/bin/yum', '/var/lib/rpm']
__handles__ = [('Package', 'yum'),
('Package', 'rpm'),
@@ -57,7 +53,7 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng):
'Instance': ['version', 'release']}
def __init__(self, logger, setup, config):
- Bcfg2.Client.Tools.RPMng.RPMng.__init__(self, logger, setup, config)
+ RPM.__init__(self, logger, setup, config)
self.__important__ = self.__important__ + \
[entry.get('name') for struct in config \
for entry in struct \
@@ -140,15 +136,15 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng):
if len(pkgDict) > 1:
# What do we do with multiple packages?
- s = "YUMng: returnPackagesByDep(%s) returned many packages"
+ s = "YUM24: returnPackagesByDep(%s) returned many packages"
self.logger.info(s % entry.get('name'))
- s = "YUMng: matching packages: %s"
+ s = "YUM24: matching packages: %s"
self.logger.info(s % str(list(pkgDict.keys())))
pkgs = set(pkgDict.keys()) & set(self.yum_installed.keys())
if len(pkgs) > 0:
# Virtual packages matches an installed real package
pkg = pkgDict[pkgs.pop()]
- s = "YUMng: chosing: %s" % pkg.name
+ s = "YUM24: chosing: %s" % pkg.name
self.logger.info(s)
else:
# What's the right package? This will fail verify
@@ -157,21 +153,20 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng):
elif len(pkgDict) == 1:
pkg = list(pkgDict.values())[0]
else: # len(pkgDict) == 0
- s = "YUMng: returnPackagesByDep(%s) returned no results"
+ s = "YUM24: returnPackagesByDep(%s) returned no results"
self.logger.info(s % entry.get('name'))
pkg = None
if pkg is not None:
- s = "YUMng: remapping virtual package %s to %s"
+ s = "YUM24: remapping virtual package %s to %s"
self.logger.info(s % (entry.get('name'), pkg.name))
entry.set('name', pkg.name)
- return Bcfg2.Client.Tools.RPMng.RPMng.VerifyPackage(self, entry,
- modlist)
+ return RPM.VerifyPackage(self, entry, modlist)
def Install(self, packages, states):
"""
- Try and fix everything that RPMng.VerifyPackages() found wrong for
+ Try and fix everything that YUM24.VerifyPackages() found wrong for
each Package Entry. This can result in individual RPMs being
installed (for the first time), deleted, downgraded
or upgraded.
@@ -191,7 +186,7 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng):
entry is set to True.
"""
- self.logger.info('Running YUMng.Install()')
+ self.logger.info('Running YUM24.Install()')
install_pkgs = []
gpg_keys = []
@@ -344,7 +339,7 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng):
packages is a list of Package Entries with Instances generated
by FindExtraPackages().
"""
- self.logger.debug('Running YUMng.RemovePackages()')
+ self.logger.debug('Running YUM24.RemovePackages()')
if self.autodep:
pkgtool = "/usr/bin/yum -d0 -y erase %s"
@@ -368,7 +363,7 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng):
'release': inst.get('release')}
self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\
% (pkgspec.get('name'), self.str_evra(pkgspec)))
- self.logger.info(" This package will be deleted in a future version of the RPMng driver.")
+ self.logger.info(" This package will be deleted in a future version of the YUM24 driver.")
cmdrc, output = self.cmd.run(pkgtool % " ".join(erase_args))
if cmdrc == 0:
@@ -392,7 +387,7 @@ class YUM24(Bcfg2.Client.Tools.RPMng.RPMng):
else:
self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s"\
% (pkg.get('name'), self.str_evra(pkg)))
- self.logger.info(" This package will be deleted in a future version of the RPMng driver.")
+ self.logger.info(" This package will be deleted in a future version of the YUM24 driver.")
continue
cmdrc, output = self.cmd.run(self.pkgtool % pkg_arg)
diff --git a/src/lib/Bcfg2/Client/Tools/YUMng.py b/src/lib/Bcfg2/Client/Tools/YUMng.py
index a93a48f9a..22fbba537 100644
--- a/src/lib/Bcfg2/Client/Tools/YUMng.py
+++ b/src/lib/Bcfg2/Client/Tools/YUMng.py
@@ -1,952 +1,9 @@
-"""This provides bcfg2 support for yum."""
+""" YUM driver called 'YUMng' for backwards compat """
-import copy
-import os.path
-import sys
-import yum
-import yum.packages
-import yum.rpmtrans
-import yum.callbacks
-import yum.Errors
-import yum.misc
-import rpmUtils.arch
-import Bcfg2.Client.XML
-import Bcfg2.Client.Tools
+from Bcfg2.Client.Tools.YUM import YUM
-def build_yname(pkgname, inst):
- """Build yum appropriate package name."""
- d = {}
- if isinstance(inst, yum.packages.PackageObject):
- for i in ['name', 'epoch', 'version', 'release', 'arch']:
- d[i] = getattr(inst, i)
- else:
- d['name'] = pkgname
- if inst.get('version') != 'any':
- d['version'] = inst.get('version')
- if inst.get('epoch', False):
- d['epoch'] = inst.get('epoch')
- if inst.get('release', False) and inst.get('release') != 'any':
- d['release'] = inst.get('release')
- if inst.get('arch', False) and inst.get('arch') != 'any':
- d['arch'] = inst.get('arch')
- return d
-
-def short_yname(nevra):
- d = nevra.copy()
- if 'version' in d:
- d['ver'] = d['version']
- del d['version']
- if 'release' in d:
- d['rel'] = d['release']
- del d['release']
- return d
-
-
-def nevraString(p):
- if isinstance(p, yum.packages.PackageObject):
- return str(p)
- else:
- ret = ""
- for i, j in [('epoch', '%s:'), ('name', '%s'), ('version', '-%s'),
- ('release', '-%s'), ('arch', '.%s')]:
- if i in p:
- ret = "%s%s" % (ret, j % p[i])
- return ret
-
-
-class RPMDisplay(yum.rpmtrans.RPMBaseCallback):
- """We subclass the default RPM transaction callback so that we
- can control Yum's verbosity and pipe it through the right logger."""
-
- def __init__(self, logger):
- yum.rpmtrans.RPMBaseCallback.__init__(self)
- self.logger = logger
- self.state = None
- self.package = None
-
- def event(self, package, action, te_current, te_total,
- ts_current, ts_total):
- """
- @param package: A yum package object or simple string of a package name
- @param action: A yum.constant transaction set state or in the obscure
- rpm repackage case it could be the string 'repackaging'
- @param te_current: Current number of bytes processed in the transaction
- element being processed
- @param te_total: Total number of bytes in the transaction element being
- processed
- @param ts_current: number of processes completed in whole transaction
- @param ts_total: total number of processes in the transaction.
- """
-
- if self.package != str(package) or action != self.state:
- msg = "%s: %s" % (self.action[action], package)
- self.logger.info(msg)
- self.state = action
- self.package = str(package)
-
- def scriptout(self, package, msgs):
- """Handle output from package scripts."""
-
- if msgs:
- msg = "%s: %s" % (package, msgs)
- self.logger.debug(msg)
-
- def errorlog(self, msg):
- """Deal with error reporting."""
- self.logger.error(msg)
-
-
-class YumDisplay(yum.callbacks.ProcessTransBaseCallback):
- """Class to handle display of what step we are in the Yum transaction
- such as downloading packages, etc."""
-
- def __init__(self, logger):
- self.logger = logger
-
-
-class YUMng(Bcfg2.Client.Tools.PkgTool):
- """Support for Yum packages."""
- pkgtype = 'yum'
-
- name = 'YUMng'
- __execs__ = []
- __handles__ = [('Package', 'yum'),
- ('Package', 'rpm'),
- ('Path', 'ignore')]
-
- __req__ = {'Package': ['name'],
- 'Path': ['type']}
- __ireq__ = {'Package': ['name']}
-
- conflicts = ['YUM24', 'RPMng']
-
- def __init__(self, logger, setup, config):
- self._loadYumBase(setup=setup, logger=logger)
- Bcfg2.Client.Tools.PkgTool.__init__(self, logger, setup, config)
- self.ignores = [entry.get('name') for struct in config \
- for entry in struct \
- if entry.tag == 'Path' and \
- entry.get('type') == 'ignore']
- self.instance_status = {}
- self.extra_instances = []
- self.modlists = {}
- self._loadConfig()
- self.__important__ = self.__important__ + \
- [entry.get('name') for struct in config \
- for entry in struct \
- if entry.tag == 'Path' and \
- (entry.get('name').startswith('/etc/yum.d') \
- or entry.get('name').startswith('/etc/yum.repos.d')) \
- or entry.get('name') == '/etc/yum.conf']
- self.yum_avail = dict()
- self.yum_installed = dict()
-
- yup = self.yb.doPackageLists(pkgnarrow='updates')
- if hasattr(self.yb.rpmdb, 'pkglist'):
- yinst = self.yb.rpmdb.pkglist
- else:
- yinst = self.yb.rpmdb.getPkgList()
- for dest, source in [(self.yum_avail, yup.updates),
- (self.yum_installed, yinst)]:
- for pkg in source:
- if dest is self.yum_avail:
- pname = pkg.name
- data = [(pkg.arch, (pkg.epoch, pkg.version, pkg.release))]
- else:
- pname = pkg[0]
- data = [(pkg[1], (pkg[2], pkg[3], pkg[4]))]
- if pname in dest:
- dest[pname].update(data)
- else:
- dest[pname] = dict(data)
-
- def _loadYumBase(self, setup=None, logger=None):
- ''' this may be called before PkgTool.__init__() is called on
- this object (when the YUMng object is first instantiated;
- PkgTool.__init__() calls RefreshPackages(), which requires a
- YumBase object already exist), or after __init__() has
- completed, when we reload the yum config before installing
- packages. Consequently, we support both methods by allowing
- setup and logger, the only object properties we use in this
- function, to be passed as keyword arguments or to be omitted
- and drawn from the object itself.'''
- self.yb = yum.YumBase()
-
- if setup is None:
- setup = self.setup
- if logger is None:
- logger = self.logger
-
- if setup['debug']:
- debuglevel = 3
- elif setup['verbose']:
- debuglevel = 2
- else:
- debuglevel = 0
-
- # pylint: disable=E1121
- try:
- self.yb.preconf.debuglevel = debuglevel
- self.yb._getConfig()
- except AttributeError:
- self.yb._getConfig(self.yb.conf.config_file_path,
- debuglevel=debuglevel)
- # pylint: enable=E1121
-
- try:
- self.yb.doConfigSetup()
- self.yb.doTsSetup()
- self.yb.doRpmDBSetup()
- except yum.Errors.RepoError:
- err = sys.exc_info()[1]
- logger.error("YUMng Repository error: %s" % err)
- raise Bcfg2.Client.Tools.toolInstantiationError
- except Exception:
- err = sys.exc_info()[1]
- logger.error("YUMng error: %s" % err)
- raise Bcfg2.Client.Tools.toolInstantiationError
-
- def _loadConfig(self):
- # Process the YUMng section from the config file.
- # These are all boolean flags, either we do stuff or we don't
- self.pkg_checks = self.setup["yumng_pkg_checks"]
- self.pkg_verify = self.setup["yumng_pkg_verify"]
- self.doInstall = self.setup["yumng_installed_action"] == "install"
- self.doUpgrade = self.setup["yumng_version_fail_action"] == "upgrade"
- self.doReinst = self.setup["yumng_verify_fail_action"] == "reinstall"
- self.verifyFlags = self.setup["yumng_verify_flags"]
-
- self.installOnlyPkgs = self.yb.conf.installonlypkgs
- if 'gpg-pubkey' not in self.installOnlyPkgs:
- self.installOnlyPkgs.append('gpg-pubkey')
-
- self.logger.debug("YUMng: Install missing: %s" % self.doInstall)
- self.logger.debug("YUMng: pkg_checks: %s" % self.pkg_checks)
- self.logger.debug("YUMng: pkg_verify: %s" % self.pkg_verify)
- self.logger.debug("YUMng: Upgrade on version fail: %s" % self.doUpgrade)
- self.logger.debug("YUMng: Reinstall on verify fail: %s" % self.doReinst)
- self.logger.debug("YUMng: installOnlyPkgs: %s" % self.installOnlyPkgs)
- self.logger.debug("YUMng: verify_flags: %s" % self.verifyFlags)
-
- def _fixAutoVersion(self, entry):
- # old style entry; synthesize Instances from current installed
- if entry.get('name') not in self.yum_installed and \
- entry.get('name') not in self.yum_avail:
- # new entry; fall back to default
- entry.set('version', 'any')
- else:
- data = copy.copy(self.yum_installed[entry.get('name')])
- if entry.get('name') in self.yum_avail:
- # installed but out of date
- data.update(self.yum_avail[entry.get('name')])
- for (arch, (epoch, vers, rel)) in list(data.items()):
- x = Bcfg2.Client.XML.SubElement(entry, "Instance",
- name=entry.get('name'),
- version=vers, arch=arch,
- release=rel, epoch=epoch)
- if 'verify_flags' in entry.attrib:
- x.set('verify_flags', entry.get('verify_flags'))
- if 'verify' in entry.attrib:
- x.set('verify', entry.get('verify'))
-
- def _buildInstances(self, entry):
- instances = [inst for inst in entry \
- if inst.tag == 'Instance' or inst.tag == 'Package']
-
- # XXX: Uniquify instances. Cases where duplicates are returned.
- # However, the elements aren't comparable.
-
- if instances == []:
- # We have an old style no Instance entry. Convert it to new style.
- instance = Bcfg2.Client.XML.SubElement(entry, 'Package')
- for attrib in list(entry.attrib.keys()):
- instance.attrib[attrib] = entry.attrib[attrib]
- instances = [instance]
-
- return instances
-
- def _getGPGKeysAsPackages(self):
- """Return a list of the GPG RPM signing keys installed on the
- system as a list of Package Objects."""
-
- # XXX GPG keys existing in the RPMDB have numbered days
- # and newer Yum versions will not return information about them
- if hasattr(self.yb.rpmdb, 'returnGPGPubkeyPackages'):
- return self.yb.rpmdb.returnGPGPubkeyPackages()
- return self.yb.rpmdb.searchNevra(name='gpg-pubkey')
-
- def _verifyHelper(self, po):
- # This code primarly deals with a yum bug where the PO.verify()
- # method does not properly take into count multilib sharing of files.
- # Neither does RPM proper, really....it just ignores the problem.
- def verify(p):
- # disabling file checksums is a new feature yum 3.2.17-ish
- try:
- vResult = p.verify(fast=self.setup.get('quick', False))
- except TypeError:
- # Older Yum API
- vResult = p.verify()
- return vResult
-
- key = (po.name, po.epoch, po.version, po.release, po.arch)
- if key in self.verifyCache:
- results = self.verifyCache[key]
- else:
- results = verify(po)
- self.verifyCache[key] = results
- if not rpmUtils.arch.isMultiLibArch():
- return results
-
- # Okay deal with a buggy yum multilib and verify
- packages = self.yb.rpmdb.searchNevra(name=po.name, epoch=po.epoch,
- ver=po.version, rel=po.release) # find all arches of pkg
- if len(packages) == 1:
- return results # No mathcing multilib packages
-
- files = set(po.returnFileEntries()) # Will be the list of common fns
- common = {}
- for p in packages:
- if p != po:
- files = files & set(p.returnFileEntries())
- for p in packages:
- k = (p.name, p.epoch, p.version, p.release, p.arch)
- self.logger.debug("Multilib Verify: comparing %s to %s" \
- % (po, p))
- if k in self.verifyCache:
- v = self.verifyCache[k]
- else:
- v = verify(p)
- self.verifyCache[k] = v
-
- for fn, probs in list(v.items()):
- # file problems must exist in ALL multilib packages to be real
- if fn in files:
- common[fn] = common.get(fn, 0) + 1
-
- flag = len(packages) - 1
- for fn, i in list(common.items()):
- if i == flag:
- # this fn had verify problems in all but one of the multilib
- # packages. That means its correct in the package that's
- # "on top." Therefore, this is a fake verify problem.
- if fn in results:
- del results[fn]
-
- return results
-
- def RefreshPackages(self):
- """
- Creates self.installed{} which is a dict of installed packages.
-
- The dict items are lists of nevra dicts. This loosely matches the
- config from the server and what rpmtools uses to specify pacakges.
-
- e.g.
-
- self.installed['foo'] = [ {'name':'foo', 'epoch':None,
- 'version':'1', 'release':2,
- 'arch':'i386'},
- {'name':'foo', 'epoch':None,
- 'version':'1', 'release':2,
- 'arch':'x86_64'} ]
- """
-
- self.installed = {}
- packages = self._getGPGKeysAsPackages() + \
- self.yb.rpmdb.returnPackages()
- for po in packages:
- d = {}
- for i in ['name', 'epoch', 'version', 'release', 'arch']:
- if i == 'arch' and getattr(po, i) is None:
- d[i] = 'noarch'
- elif i == 'epoch' and getattr(po, i) is None:
- d[i] = '0'
- else:
- d[i] = getattr(po, i)
- self.installed.setdefault(po.name, []).append(d)
-
- def VerifyPackage(self, entry, modlist, pinned_version=None):
- """
- Verify Package status for entry.
- Performs the following:
- - Checks for the presence of required Package Instances.
- - Compares the evra 'version' info against self.installed{}.
- - RPM level package verify (rpm --verify).
- - Checks for the presence of unrequired package instances.
-
- Produces the following dict and list for YUMng.Install() to use:
- For installs/upgrades/fixes of required instances:
- instance_status = { <Instance Element Object>:
- { 'installed': True|False,
- 'version_fail': True|False,
- 'verify_fail': True|False,
- 'pkg': <Package Element Object>,
- 'modlist': [ <filename>, ... ],
- 'verify' : [ <rpm --verify results> ]
- }, ......
- }
-
- For deletions of unrequired instances:
- extra_instances = [ <Package Element Object>, ..... ]
-
- Constructs the text prompts for interactive mode.
- """
-
- if entry.get('version', False) == 'auto':
- self._fixAutoVersion(entry)
-
- self.logger.debug("Verifying package instances for %s" %
- entry.get('name'))
-
- self.verifyCache = {} # Used for checking multilib packages
- self.modlists[entry] = modlist
- instances = self._buildInstances(entry)
- packageCache = []
- package_fail = False
- qtext_versions = []
- virtPkg = False
- pkg_checks = self.pkg_checks and \
- entry.get('pkg_checks', 'true').lower() == 'true'
- pkg_verify = self.pkg_verify and \
- entry.get('pkg_verify', 'true').lower() == 'true'
-
- if entry.get('name') == 'gpg-pubkey':
- POs = self._getGPGKeysAsPackages()
- pkg_verify = False # No files here to verify
- else:
- POs = self.yb.rpmdb.searchNevra(name=entry.get('name'))
- if len(POs) == 0:
- # Some sort of virtual capability? Try to resolve it
- POs = self.yb.rpmdb.searchProvides(entry.get('name'))
- if len(POs) > 0:
- virtPkg = True
- self.logger.info("%s appears to be provided by:" %
- entry.get('name'))
- for p in POs:
- self.logger.info(" %s" % p)
-
- for inst in instances:
- nevra = build_yname(entry.get('name'), inst)
- snevra = short_yname(nevra)
- if nevra in packageCache:
- continue # Ignore duplicate instances
- else:
- packageCache.append(nevra)
-
- self.logger.debug("Verifying: %s" % nevraString(nevra))
-
- # Set some defaults here
- stat = self.instance_status.setdefault(inst, {})
- stat['installed'] = True
- stat['version_fail'] = False
- stat['verify'] = {}
- stat['verify_fail'] = False
- stat['pkg'] = entry
- stat['modlist'] = modlist
- if inst.get('verify_flags'):
- # this splits on either space or comma
- verify_flags = \
- inst.get('verify_flags').lower().replace(' ',
- ',').split(',')
- else:
- verify_flags = self.verifyFlags
-
- if 'arch' in nevra:
- # If arch is specified use it to select the package
- _POs = [ p for p in POs if p.arch == nevra['arch'] ]
- else:
- _POs = POs
- if len(_POs) == 0:
- # Package (name, arch) not installed
- entry.set('current_exists', 'false')
- self.logger.debug(" %s is not installed" % nevraString(nevra))
- stat['installed'] = False
- package_fail = True
- qtext_versions.append("I(%s)" % nevra)
- continue
-
- if not pkg_checks:
- continue
-
- # Check EVR
- if virtPkg:
- # we need to make sure that the version of the symbol
- # provided matches the one required in the
- # configuration
- vlist = []
- for attr in ["epoch", "version", "release"]:
- vlist.append(nevra.get(attr))
- if tuple(vlist) == (None, None, None):
- # we just require the package name, no particular
- # version, so just make a copy of POs since every
- # package that provides this symbol satisfies the
- # requirement
- _POs = [po for po in POs]
- else:
- _POs = [po for po in POs
- if po.checkPrco('provides',
- (nevra["name"], 'EQ',
- tuple(vlist)))]
- elif entry.get('name') == 'gpg-pubkey':
- if 'version' not in nevra:
- m = "Skipping verify: gpg-pubkey without an RPM version."
- self.logger.warning(m)
- continue
- if 'release' not in nevra:
- m = "Skipping verify: gpg-pubkey without an RPM release."
- self.logger.warning(m)
- continue
- _POs = [p for p in POs if p.version == nevra['version'] \
- and p.release == nevra['release']]
- else:
- _POs = self.yb.rpmdb.searchNevra(**snevra)
- if len(_POs) == 0:
- package_fail = True
- stat['version_fail'] = True
- # Just chose the first pkg for the error message
- if virtPkg:
- provTuple = \
- [p for p in POs[0].provides
- if p[0] == entry.get("name")][0]
- entry.set('current_version', "%s:%s-%s" % provTuple[2])
- self.logger.info(" %s: Wrong version installed. "
- "Want %s, but %s provides %s" %
- (entry.get("name"),
- nevraString(nevra),
- nevraString(POs[0]),
- yum.misc.prco_tuple_to_string(provTuple)))
- else:
- entry.set('current_version', "%s:%s-%s.%s" %
- (POs[0].epoch,
- POs[0].version,
- POs[0].release,
- POs[0].arch))
- self.logger.info(" %s: Wrong version installed. "
- "Want %s, but have %s" %
- (entry.get("name"),
- nevraString(nevra),
- nevraString(POs[0])))
- entry.set('version', "%s:%s-%s.%s" %
- (nevra.get('epoch', 'any'),
- nevra.get('version', 'any'),
- nevra.get('release', 'any'),
- nevra.get('arch', 'any')))
- qtext_versions.append("U(%s)" % str(POs[0]))
- continue
-
- if self.setup.get('quick', False):
- # Passed -q on the command line
- continue
- if not (pkg_verify and \
- inst.get('pkg_verify', 'true').lower() == 'true'):
- continue
-
- # XXX: We ignore GPG sig checking the package as it
- # has nothing to do with the individual file hash/size/etc.
- # GPG checking the package only eaxmines some header/rpmdb
- # wacky-ness, and will not properly detect a compromised rpmdb.
- # Yum's verify routine does not support it for that reaosn.
-
- if len(_POs) > 1:
- self.logger.debug(" Verify Instance found many packages:")
- for po in _POs:
- self.logger.debug(" %s" % str(po))
-
- try:
- vResult = self._verifyHelper(_POs[0])
- except Exception:
- e = sys.exc_info()[1]
- # Unknown Yum exception
- self.logger.warning(" Verify Exception: %s" % str(e))
- package_fail = True
- continue
-
- # Now take out the Yum specific objects / modlists / unproblems
- ignores = [ig.get('name') for ig in entry.findall('Ignore')] + \
- [ig.get('name') for ig in inst.findall('Ignore')] + \
- self.ignores
- for fn, probs in list(vResult.items()):
- if fn in modlist:
- self.logger.debug(" %s in modlist, skipping" % fn)
- continue
- if fn in ignores:
- self.logger.debug(" %s in ignore list, skipping" % fn)
- continue
- tmp = []
- for p in probs:
- if p.type == 'missing' and os.path.islink(fn):
- continue
- elif 'no' + p.type in verify_flags:
- continue
- if p.type not in ['missingok', 'ghost']:
- tmp.append((p.type, p.message))
- if tmp != []:
- stat['verify'][fn] = tmp
-
- if stat['verify'] != {}:
- stat['verify_fail'] = True
- package_fail = True
- self.logger.debug("It is suggested that you either manage "
- "these files, revert the changes, or ignore "
- "false failures:")
- self.logger.debug(" Verify Problems:")
- for fn, probs in list(stat['verify'].items()):
- self.logger.debug(" %s" % fn)
- for p in probs:
- self.logger.debug(" %s: %s" % p)
-
- if len(POs) > 0:
- # Is this an install only package? We just look at the first one
- provides = set([p[0] for p in POs[0].provides] + [POs[0].name])
- install_only = len(set(self.installOnlyPkgs) & provides) > 0
- else:
- install_only = False
-
- if virtPkg or (install_only and not self.setup['kevlar']):
- # XXX: virtual capability supplied, we a probably dealing
- # with multiple packages of different names. This check
- # doesn't make a lot of since in this case
- # XXX: install_only: Yum may clean some of these up itself.
- # Otherwise having multiple instances of install only packages
- # is considered correct
- self.extra_instances = None
- else:
- self.extra_instances = self.FindExtraInstances(entry, POs)
- if self.extra_instances is not None:
- package_fail = True
-
- return not package_fail
-
- def FindExtraInstances(self, entry, POs):
- """
- Check for installed instances that are not in the config.
- Return a Package Entry with Instances to remove, or None if there
- are no Instances to remove.
-
- """
- if len(POs) == 0:
- return None
- name = entry.get('name')
- extra_entry = Bcfg2.Client.XML.Element('Package', name=name,
- type=self.pkgtype)
- instances = self._buildInstances(entry)
- _POs = [p for p in POs] # Shallow copy
-
- # Algorythm is sensitive to duplicates, check for them
- checked = []
- for inst in instances:
- nevra = build_yname(name, inst)
- snevra = short_yname(nevra)
- pkgs = self.yb.rpmdb.searchNevra(**snevra)
- flag = True
- if len(pkgs) > 0:
- if pkgs[0] in checked:
- continue # We've already taken care of this Instance
- else:
- checked.append(pkgs[0])
- _POs.remove(pkgs[0])
-
- for p in _POs:
- self.logger.debug(" Extra Instance Found: %s" % str(p))
- Bcfg2.Client.XML.SubElement(extra_entry, 'Instance',
- epoch=p.epoch, name=p.name, version=p.version,
- release=p.release, arch=p.arch)
-
- if _POs == []:
- return None
- else:
- return extra_entry
-
- def FindExtraPackages(self):
- """Find extra packages."""
- packages = [e.get('name') for e in self.getSupportedEntries()]
- extras = []
-
- for p in list(self.installed.keys()):
- if p not in packages:
- entry = Bcfg2.Client.XML.Element('Package', name=p,
- type=self.pkgtype)
- for i in self.installed[p]:
- inst = Bcfg2.Client.XML.SubElement(entry,
- 'Instance',
- epoch=i['epoch'],
- version=i['version'],
- release=i['release'],
- arch=i['arch'])
-
- extras.append(entry)
-
- return extras
-
- def _installGPGKey(self, inst, key_file):
- """Examine the GPG keys carefully before installation. Avoid
- installing duplicate keys. Returns True on successful install."""
-
- # RPM Transaction Set
- ts = self.yb.rpmdb.readOnlyTS()
-
- if not os.path.exists(key_file):
- self.logger.debug("GPG Key file %s not installed" % key_file)
- return False
-
- rawkey = open(key_file).read()
- gpg = yum.misc.getgpgkeyinfo(rawkey)
-
- ver = yum.misc.keyIdToRPMVer(gpg['keyid'])
- rel = yum.misc.keyIdToRPMVer(gpg['timestamp'])
- if not (ver == inst.get('version') and rel == inst.get('release')):
- self.logger.info("GPG key file %s does not match gpg-pubkey-%s-%s"\
- % (key_file, inst.get('version'),
- inst.get('release')))
- return False
-
- if not yum.misc.keyInstalled(ts, gpg['keyid'],
- gpg['timestamp']) == 0:
- result = ts.pgpImportPubkey(yum.misc.procgpgkey(rawkey))
- else:
- self.logger.debug("gpg-pubkey-%s-%s already installed"\
- % (inst.get('version'),
- inst.get('release')))
- return True
-
- if result != 0:
- self.logger.debug("Unable to install %s-%s" % \
- (self.instance_status[inst].get('pkg').get('name'),
- nevraString(inst)))
- return False
- else:
- self.logger.debug("Installed %s-%s-%s" % \
- (self.instance_status[inst].get('pkg').get('name'),
- inst.get('version'), inst.get('release')))
- return True
-
- def _runYumTransaction(self):
- def cleanup():
- self.yb.closeRpmDB()
- self.RefreshPackages()
-
- rDisplay = RPMDisplay(self.logger)
- yDisplay = YumDisplay(self.logger)
- # Run the Yum Transaction
- try:
- rescode, restring = self.yb.buildTransaction()
- except yum.Errors.YumBaseError:
- e = sys.exc_info()[1]
- self.logger.error("Yum transaction error: %s" % str(e))
- cleanup()
- return
-
- self.logger.debug("Initial Yum buildTransaction() run said:")
- self.logger.debug(" resultcode: %s, msgs: %s" \
- % (rescode, restring))
-
- if rescode != 1:
- # Transaction built successfully, run it
- try:
- self.yb.processTransaction(callback=yDisplay,
- rpmDisplay=rDisplay)
- self.logger.info("Single Pass for Install Succeeded")
- except yum.Errors.YumBaseError:
- e = sys.exc_info()[1]
- self.logger.error("Yum transaction error: %s" % str(e))
- cleanup()
- return
- else:
- # The yum command failed. No packages installed.
- # Try installing instances individually.
- self.logger.error("Single Pass Install of Packages Failed")
- skipBroken = self.yb.conf.skip_broken
- self.yb.conf.skip_broken = True
- try:
- rescode, restring = self.yb.buildTransaction()
- if rescode != 1:
- self.yb.processTransaction(callback=yDisplay,
- rpmDisplay=rDisplay)
- self.logger.debug(
- "Second pass install did not install all packages")
- else:
- self.logger.error("Second pass yum install failed.")
- self.logger.debug(" %s" % restring)
- except yum.Errors.YumBaseError:
- e = sys.exc_info()[1]
- self.logger.error("Yum transaction error: %s" % str(e))
-
- self.yb.conf.skip_broken = skipBroken
-
- cleanup()
-
- def Install(self, packages, states):
- """
- Try and fix everything that YUMng.VerifyPackages() found wrong for
- each Package Entry. This can result in individual RPMs being
- installed (for the first time), deleted, downgraded
- or upgraded.
-
- packages is a list of Package Elements that has
- states[<Package Element>] == False
-
- The following effects occur:
- - states{} is conditionally updated for each package.
- - self.installed{} is rebuilt, possibly multiple times.
- - self.instance_status{} is conditionally updated for each instance
- of a package.
- - Each package will be added to self.modified[] if its states{}
- entry is set to True.
-
- """
- self.logger.debug('Running YUMng.Install()')
-
- install_pkgs = []
- gpg_keys = []
- upgrade_pkgs = []
- reinstall_pkgs = []
-
- def queuePkg(pkg, inst, queue):
- if pkg.get('name') == 'gpg-pubkey':
- gpg_keys.append(inst)
- else:
- queue.append(inst)
-
- # Remove extra instances.
- # Can not reverify because we don't have a package entry.
- if self.extra_instances is not None and len(self.extra_instances) > 0:
- if (self.setup.get('remove') == 'all' or \
- self.setup.get('remove') == 'packages'):
- self.RemovePackages(self.extra_instances)
- else:
- self.logger.info("The following extra package instances will be removed by the '-r' option:")
- for pkg in self.extra_instances:
- for inst in pkg:
- self.logger.info(" %s %s" % \
- ((pkg.get('name'), nevraString(inst))))
-
- # Figure out which instances of the packages actually need something
- # doing to them and place in the appropriate work 'queue'.
- for pkg in packages:
- insts = [pinst for pinst in pkg \
- if pinst.tag in ['Instance', 'Package']]
- if insts:
- for inst in insts:
- if inst not in self.instance_status:
- m = " Asked to install/update package never verified"
- p = nevraString(build_yname(pkg.get('name'), inst))
- self.logger.warning("%s: %s" % (m, p))
- continue
- status = self.instance_status[inst]
- if not status.get('installed', False) and self.doInstall:
- queuePkg(pkg, inst, install_pkgs)
- elif status.get('version_fail', False) and self.doUpgrade:
- queuePkg(pkg, inst, upgrade_pkgs)
- elif status.get('verify_fail', False) and self.doReinst:
- queuePkg(pkg, inst, reinstall_pkgs)
- else:
- # Either there was no Install/Version/Verify
- # task to be done or the user disabled the actions
- # in the configuration. XXX Logging for the latter?
- pass
- else:
- msg = "YUMng: Package tag found where Instance expected: %s"
- self.logger.warning(msg % pkg.get('name'))
- queuePkg(pkg, pkg, install_pkgs)
-
- # Install GPG keys.
- # Alternatively specify the required keys using 'gpgkey' in the
- # repository definition in yum.conf. YUM will install the keys
- # automatically.
- if len(gpg_keys) > 0:
- self.logger.info("Installing GPG keys.")
- for inst in gpg_keys:
- if inst.get('simplefile') is None:
- self.logger.error("GPG key has no simplefile attribute")
- continue
- key_file = os.path.join(self.instance_status[inst].get('pkg').get('uri'), \
- inst.get('simplefile'))
- self._installGPGKey(inst, key_file)
-
- self.RefreshPackages()
- pkg = self.instance_status[gpg_keys[0]].get('pkg')
- states[pkg] = self.VerifyPackage(pkg, [])
-
- # We want to reload all Yum configuration in case we've
- # deployed new .repo files we should consider
- self._loadYumBase()
-
- # Install packages.
- if len(install_pkgs) > 0:
- self.logger.info("Attempting to install packages")
-
- for inst in install_pkgs:
- pkg_arg = self.instance_status[inst].get('pkg').get('name')
- self.logger.debug("Installing %s" % pkg_arg)
- try:
- self.yb.install(**build_yname(pkg_arg, inst))
- except yum.Errors.YumBaseError:
- yume = sys.exc_info()[1]
- self.logger.error("Error installing package %s: %s" %
- (pkg_arg, yume))
-
- if len(upgrade_pkgs) > 0:
- self.logger.info("Attempting to upgrade packages")
-
- for inst in upgrade_pkgs:
- pkg_arg = self.instance_status[inst].get('pkg').get('name')
- self.logger.debug("Upgrading %s" % pkg_arg)
- try:
- self.yb.update(**build_yname(pkg_arg, inst))
- except yum.Errors.YumBaseError:
- yume = sys.exc_info()[1]
- self.logger.error("Error upgrading package %s: %s" %
- (pkg_arg, yume))
-
- if len(reinstall_pkgs) > 0:
- self.logger.info("Attempting to reinstall packages")
- for inst in reinstall_pkgs:
- pkg_arg = self.instance_status[inst].get('pkg').get('name')
- self.logger.debug("Reinstalling %s" % pkg_arg)
- try:
- self.yb.reinstall(**build_yname(pkg_arg, inst))
- except yum.Errors.YumBaseError:
- yume = sys.exc_info()[1]
- self.logger.error("Error reinstalling package %s: %s" %
- (pkg_arg, yume))
-
- self._runYumTransaction()
-
- if not self.setup['kevlar']:
- for pkg_entry in [p for p in packages if self.canVerify(p)]:
- self.logger.debug("Reverifying Failed Package %s" \
- % (pkg_entry.get('name')))
- states[pkg_entry] = self.VerifyPackage(pkg_entry,
- self.modlists.get(pkg_entry, []))
-
- for entry in [ent for ent in packages if states[ent]]:
- self.modified.append(entry)
-
- def RemovePackages(self, packages):
- """
- Remove specified entries.
-
- packages is a list of Package Entries with Instances generated
- by FindExtraPackages().
- """
- self.logger.debug('Running YUMng.RemovePackages()')
-
- erase_args = []
- for pkg in packages:
- for inst in pkg:
- nevra = build_yname(pkg.get('name'), inst)
- if pkg.get('name') != 'gpg-pubkey':
- self.yb.remove(**nevra)
- self.modified.append(pkg)
- else:
- self.logger.info("WARNING: gpg-pubkey package not in configuration %s %s-%s"\
- % (nevra['name'], nevra['version'], nevra['release']))
- self.logger.info(" This package will be deleted in a future version of the YUMng driver.")
-
- self._runYumTransaction()
- self.extra = self.FindExtraPackages()
-
- def VerifyPath(self, entry, _):
- """Do nothing here since we only verify Path type=ignore"""
- return True
+class YUMng(YUM):
+ """ YUM driver called 'YUMng' for backwards compat """
+ deprecated = True
+ conflicts = ['YUM24', 'RPM', 'RPMng']
diff --git a/src/lib/Bcfg2/Client/Tools/__init__.py b/src/lib/Bcfg2/Client/Tools/__init__.py
index 51d3ceecf..c11b96ef7 100644
--- a/src/lib/Bcfg2/Client/Tools/__init__.py
+++ b/src/lib/Bcfg2/Client/Tools/__init__.py
@@ -42,6 +42,7 @@ class Tool(object):
__handles__ = []
__req__ = {}
__important__ = []
+ deprecated = False
def __init__(self, logger, setup, config):
self.setup = setup
@@ -144,7 +145,7 @@ class Tool(object):
required.extend(self.__req__[entry.tag][entry.get("type")])
except KeyError:
pass
-
+
return [attr for attr in required
if attr not in entry.attrib or not entry.attrib[attr]]
diff --git a/src/lib/Bcfg2/Options.py b/src/lib/Bcfg2/Options.py
index f1bc54d49..04233f165 100644
--- a/src/lib/Bcfg2/Options.py
+++ b/src/lib/Bcfg2/Options.py
@@ -776,55 +776,63 @@ CLIENT_PORTAGE_BINPKGONLY = \
default=False,
cf=('Portage', 'binpkgonly'),
cook=get_bool)
-CLIENT_RPMNG_INSTALLONLY = \
- Option('RPMng install-only packages',
+CLIENT_RPM_INSTALLONLY = \
+ Option('RPM install-only packages',
default=['kernel', 'kernel-bigmem', 'kernel-enterprise',
'kernel-smp', 'kernel-modules', 'kernel-debug',
'kernel-unsupported', 'kernel-devel', 'kernel-source',
'kernel-default', 'kernel-largesmp-devel',
'kernel-largesmp', 'kernel-xen', 'gpg-pubkey'],
- cf=('RPMng', 'installonlypackages'),
+ cf=('RPM', 'installonlypackages'),
+ deprecated_cf=('RPMng', 'installonlypackages'),
cook=list_split)
-CLIENT_RPMNG_PKG_CHECKS = \
- Option("Perform RPMng package checks",
+CLIENT_RPM_PKG_CHECKS = \
+ Option("Perform RPM package checks",
default=True,
- cf=('RPMng', 'pkg_checks'),
+ cf=('RPM', 'pkg_checks'),
+ deprecated_cf=('RPMng', 'pkg_checks'),
cook=get_bool)
-CLIENT_RPMNG_PKG_VERIFY = \
- Option("Perform RPMng package verify",
+CLIENT_RPM_PKG_VERIFY = \
+ Option("Perform RPM package verify",
default=True,
- cf=('RPMng', 'pkg_verify'),
+ cf=('RPM', 'pkg_verify'),
+ deprecated_cf=('RPMng', 'pkg_verify'),
cook=get_bool)
-CLIENT_RPMNG_INSTALLED_ACTION = \
- Option("RPMng installed action",
+CLIENT_RPM_INSTALLED_ACTION = \
+ Option("RPM installed action",
default="install",
- cf=('RPMng', 'installed_action'))
-CLIENT_RPMNG_ERASE_FLAGS = \
- Option("RPMng erase flags",
+ cf=('RPM', 'installed_action'),
+ deprecated_cf=('RPMng', 'installed_action'))
+CLIENT_RPM_ERASE_FLAGS = \
+ Option("RPM erase flags",
default=["allmatches"],
- cf=('RPMng', 'erase_flags'),
+ cf=('RPM', 'erase_flags'),
+ deprecated_cf=('RPMng', 'erase_flags'),
cook=list_split)
-CLIENT_RPMNG_VERSION_FAIL_ACTION = \
- Option("RPMng version fail action",
+CLIENT_RPM_VERSION_FAIL_ACTION = \
+ Option("RPM version fail action",
default="upgrade",
- cf=('RPMng', 'version_fail_action'))
-CLIENT_RPMNG_VERIFY_FAIL_ACTION = \
- Option("RPMng verify fail action",
+ cf=('RPM', 'version_fail_action'),
+ deprecated_cf=('RPMng', 'version_fail_action'))
+CLIENT_RPM_VERIFY_FAIL_ACTION = \
+ Option("RPM verify fail action",
default="reinstall",
- cf=('RPMng', 'verify_fail_action'))
-CLIENT_RPMNG_VERIFY_FLAGS = \
- Option("RPMng verify flags",
+ cf=('RPM', 'verify_fail_action'),
+ deprecated_cf=('RPMng', 'verify_fail_action'))
+CLIENT_RPM_VERIFY_FLAGS = \
+ Option("RPM verify flags",
default=[],
- cf=('RPMng', 'verify_flags'),
+ cf=('RPM', 'verify_flags'),
+ deprecated_cf=('RPMng', 'verify_flags'),
cook=list_split)
CLIENT_YUM24_INSTALLONLY = \
- Option('RPMng install-only packages',
+ Option('YUM24 install-only packages',
default=['kernel', 'kernel-bigmem', 'kernel-enterprise',
'kernel-smp', 'kernel-modules', 'kernel-debug',
'kernel-unsupported', 'kernel-devel', 'kernel-source',
'kernel-default', 'kernel-largesmp-devel',
'kernel-largesmp', 'kernel-xen', 'gpg-pubkey'],
- cf=('RPMng', 'installonlypackages'),
+ cf=('YUM24', 'installonlypackages'),
cook=list_split)
CLIENT_YUM24_PKG_CHECKS = \
Option("Perform YUM24 package checks",
@@ -863,32 +871,38 @@ CLIENT_YUM24_AUTODEP = \
default=True,
cf=('YUM24', 'autodep'),
cook=get_bool)
-CLIENT_YUMNG_PKG_CHECKS = \
- Option("Perform YUMng package checks",
+CLIENT_YUM_PKG_CHECKS = \
+ Option("Perform YUM package checks",
default=True,
- cf=('YUMng', 'pkg_checks'),
+ cf=('YUM', 'pkg_checks'),
+ deprecated_cf=('YUMng', 'pkg_checks'),
cook=get_bool)
-CLIENT_YUMNG_PKG_VERIFY = \
- Option("Perform YUMng package verify",
+CLIENT_YUM_PKG_VERIFY = \
+ Option("Perform YUM package verify",
default=True,
- cf=('YUMng', 'pkg_verify'),
+ cf=('YUM', 'pkg_verify'),
+ deprecated_cf=('YUMng', 'pkg_verify'),
cook=get_bool)
-CLIENT_YUMNG_INSTALLED_ACTION = \
- Option("YUMng installed action",
+CLIENT_YUM_INSTALLED_ACTION = \
+ Option("YUM installed action",
default="install",
- cf=('YUMng', 'installed_action'))
-CLIENT_YUMNG_VERSION_FAIL_ACTION = \
- Option("YUMng version fail action",
+ cf=('YUM', 'installed_action'),
+ deprecated_cf=('YUMng', 'installed_action'))
+CLIENT_YUM_VERSION_FAIL_ACTION = \
+ Option("YUM version fail action",
default="upgrade",
- cf=('YUMng', 'version_fail_action'))
-CLIENT_YUMNG_VERIFY_FAIL_ACTION = \
- Option("YUMng verify fail action",
+ cf=('YUM', 'version_fail_action'),
+ deprecated_cf=('YUMng', 'version_fail_action'))
+CLIENT_YUM_VERIFY_FAIL_ACTION = \
+ Option("YUM verify fail action",
default="reinstall",
- cf=('YUMng', 'verify_fail_action'))
-CLIENT_YUMNG_VERIFY_FLAGS = \
- Option("YUMng verify flags",
+ cf=('YUM', 'verify_fail_action'),
+ deprecated_cf=('YUMng', 'verify_fail_action'))
+CLIENT_YUM_VERIFY_FLAGS = \
+ Option("YUM verify flags",
default=[],
- cf=('YUMng', 'verify_flags'),
+ cf=('YUM', 'verify_flags'),
+ deprecated_cf=('YUMng', 'verify_flags'),
cook=list_split)
# Logging options
@@ -1008,14 +1022,14 @@ DRIVER_OPTIONS = \
apt_var_path=CLIENT_APT_TOOLS_VAR_PATH,
apt_etc_path=CLIENT_SYSTEM_ETC_PATH,
portage_binpkgonly=CLIENT_PORTAGE_BINPKGONLY,
- rpmng_installonly=CLIENT_RPMNG_INSTALLONLY,
- rpmng_pkg_checks=CLIENT_RPMNG_PKG_CHECKS,
- rpmng_pkg_verify=CLIENT_RPMNG_PKG_VERIFY,
- rpmng_installed_action=CLIENT_RPMNG_INSTALLED_ACTION,
- rpmng_erase_flags=CLIENT_RPMNG_ERASE_FLAGS,
- rpmng_version_fail_action=CLIENT_RPMNG_VERSION_FAIL_ACTION,
- rpmng_verify_fail_action=CLIENT_RPMNG_VERIFY_FAIL_ACTION,
- rpmng_verify_flags=CLIENT_RPMNG_VERIFY_FLAGS,
+ rpm_installonly=CLIENT_RPM_INSTALLONLY,
+ rpm_pkg_checks=CLIENT_RPM_PKG_CHECKS,
+ rpm_pkg_verify=CLIENT_RPM_PKG_VERIFY,
+ rpm_installed_action=CLIENT_RPM_INSTALLED_ACTION,
+ rpm_erase_flags=CLIENT_RPM_ERASE_FLAGS,
+ rpm_version_fail_action=CLIENT_RPM_VERSION_FAIL_ACTION,
+ rpm_verify_fail_action=CLIENT_RPM_VERIFY_FAIL_ACTION,
+ rpm_verify_flags=CLIENT_RPM_VERIFY_FLAGS,
yum24_installonly=CLIENT_YUM24_INSTALLONLY,
yum24_pkg_checks=CLIENT_YUM24_PKG_CHECKS,
yum24_pkg_verify=CLIENT_YUM24_PKG_VERIFY,
@@ -1025,12 +1039,12 @@ DRIVER_OPTIONS = \
yum24_verify_fail_action=CLIENT_YUM24_VERIFY_FAIL_ACTION,
yum24_verify_flags=CLIENT_YUM24_VERIFY_FLAGS,
yum24_autodep=CLIENT_YUM24_AUTODEP,
- yumng_pkg_checks=CLIENT_YUMNG_PKG_CHECKS,
- yumng_pkg_verify=CLIENT_YUMNG_PKG_VERIFY,
- yumng_installed_action=CLIENT_YUMNG_INSTALLED_ACTION,
- yumng_version_fail_action=CLIENT_YUMNG_VERSION_FAIL_ACTION,
- yumng_verify_fail_action=CLIENT_YUMNG_VERIFY_FAIL_ACTION,
- yumng_verify_flags=CLIENT_YUMNG_VERIFY_FLAGS)
+ yum_pkg_checks=CLIENT_YUM_PKG_CHECKS,
+ yum_pkg_verify=CLIENT_YUM_PKG_VERIFY,
+ yum_installed_action=CLIENT_YUM_INSTALLED_ACTION,
+ yum_version_fail_action=CLIENT_YUM_VERSION_FAIL_ACTION,
+ yum_verify_fail_action=CLIENT_YUM_VERIFY_FAIL_ACTION,
+ yum_verify_flags=CLIENT_YUM_VERIFY_FLAGS)
CLIENT_COMMON_OPTIONS = \
dict(extra=CLIENT_EXTRA_DISPLAY,