diff options
28 files changed, 378 insertions, 175 deletions
diff --git a/debian/changelog b/debian/changelog index 5722eeb97..2557dd66a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +bcfg2 (1.2.2-0.0) unstable; urgency=low + + * New upstream release + + -- Sol Jerome <sol.jerome@gmail.com> Sat, 17 Mar 2012 14:41:17 -0500 + bcfg2 (1.2.1-0.0) unstable; urgency=low * New upstream release diff --git a/doc/appendix/guides/ubuntu.txt b/doc/appendix/guides/ubuntu.txt index d85c34b02..f72247220 100644 --- a/doc/appendix/guides/ubuntu.txt +++ b/doc/appendix/guides/ubuntu.txt @@ -154,7 +154,7 @@ Create Packages layout (as per :ref:`packages-exampleusage`) in [global] root@lucid:~# cat /var/lib/bcfg2/Packages/sources.xml <Sources> - <Group name="lucid"> + <Group name="ubuntu-lucid"> <Source type="apt" url="http://archive.ubuntu.com/ubuntu" version="lucid"> <Component>main</Component> <Component>multiverse</Component> diff --git a/doc/conf.py b/doc/conf.py index 7e9c8b59c..38160715d 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -55,7 +55,7 @@ else: # The short X.Y version. version = '1.2' # The full version, including alpha/beta/rc tags. -release = '1.2.1' +release = '1.2.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/installation/source.txt b/doc/installation/source.txt index 3ea0404ad..1406a5ceb 100644 --- a/doc/installation/source.txt +++ b/doc/installation/source.txt @@ -2,6 +2,7 @@ .. _GPG1: http://pgp.mit.edu:11371/pks/lookup?op=get&search=0x75BF2C177F7D197E .. _GPG2: http://pgp.mit.edu:11371/pks/lookup?op=get&search=0x80B8492FA88FFF4B +.. _Download: http://trac.mcs.anl.gov/projects/bcfg2/wiki/Download .. _source: @@ -14,7 +15,7 @@ Download Tarball ^^^^^^^ -The Bcfg2 source tarball can be grabbed from the Download_ page. +The Bcfg2 source tarball can be grabbed from the `Download`_ page. All tarballs are signed with GPG keys `7F7D197E <GPG1>`_ or `A88FFF4B <GPG2>`_. You can verify your download by importing the keys and running :: diff --git a/doc/server/plugins/grouping/metadata.txt b/doc/server/plugins/grouping/metadata.txt index c52ac7612..305857578 100644 --- a/doc/server/plugins/grouping/metadata.txt +++ b/doc/server/plugins/grouping/metadata.txt @@ -276,22 +276,37 @@ A special client metadata class is available to the MetadataQuery ------------- -This class provides query routines for the servers Metadata. +This class provides query methods for the metadata of all clients +known to the Bcfg2 server. Note that ``*by_groups()`` and +``*by_profiles()`` behave differently; for a client to be included in +the return value of a ``by_groups()`` method, it must be a member of +*all* groups listed in the argument; for a client to be included in +the return value of a ``by_profiles()`` method, it must have any group +listed as its profile group. +------------------------------+------------------------------------------------+-------------------+ | Method | Description | Value | +==============================+================================================+===================+ | by_name(client) | Get ClientMetadata object for 'client' | ClientMetadata | +------------------------------+------------------------------------------------+-------------------+ -| names_by_groups(groups) | All client names in the list of 'groups' | List | +| by_groups(groups) | Get ClientMetadata object for clients in all | List of | +| | listed groups | ClientMetadata | +------------------------------+------------------------------------------------+-------------------+ -| names_by_profiles(profiles) | All client names in the list of 'profiles' | List | +| by_profiles(client) | Get ClientMetadata objects for clients whose | List of | +| | profile matches any listed profile group | ClientMetadata | +------------------------------+------------------------------------------------+-------------------+ -| all_clients() | All known client hostnames | List | +| names_by_groups(groups) | Get the names of all clients in all listed | List of strings | +| | groups | | +------------------------------+------------------------------------------------+-------------------+ -| all_groups() | All known group names | List | +| names_by_profiles(profiles) | Get the names of clients whose profile matches | List of strings | +| | any listed profile group | | +------------------------------+------------------------------------------------+-------------------+ -| all_groups_in_category(cat) | All groups in category 'cat' | List | +| all_clients() | All known client hostnames | List of strings | +------------------------------+------------------------------------------------+-------------------+ -| all() | Get ClientMetadata for all clients | List | +| all_groups() | All known group names | List of strings | ++------------------------------+------------------------------------------------+-------------------+ +| all_groups_in_category(cat) | The names of all groups in category 'cat' | List of strings | ++------------------------------+------------------------------------------------+-------------------+ +| all() | Get ClientMetadata for all clients | List of | +| | | ClientMetadata | +------------------------------+------------------------------------------------+-------------------+ diff --git a/examples/bcfg2-lint.conf b/examples/bcfg2-lint.conf index 9c0d2c72a..6ca3fb61f 100644 --- a/examples/bcfg2-lint.conf +++ b/examples/bcfg2-lint.conf @@ -22,7 +22,7 @@ cfg_keywords = probe_comments = Maintainer,Purpose,Groups,Other Output [Validate] -schema=/usr/share/bcfg2/schema +schema=/usr/share/bcfg2/schemas [MergeFiles] threshold=85 diff --git a/misc/bcfg2.spec b/misc/bcfg2.spec index 982f5795c..9fa119edf 100644 --- a/misc/bcfg2.spec +++ b/misc/bcfg2.spec @@ -6,33 +6,61 @@ %{!?_initrddir: %define _initrddir %{_sysconfdir}/rc.d/init.d} Name: bcfg2 -Version: 1.2.1 +Version: 1.2.2 Release: %{release} Summary: Configuration management system +%if 0%{?suse_version} +# http://en.opensuse.org/openSUSE:Package_group_guidelines +Group: System/Management +%else Group: Applications/System +%endif License: BSD URL: http://bcfg2.org Source0: ftp://ftp.mcs.anl.gov/pub/bcfg/%{name}-%{version}.tar.gz +%if 0%{?suse_version} +# SUSEs OBS does not understand the id macro below. +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release} +%else BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - +%endif BuildArch: noarch BuildRequires: python-devel BuildRequires: python-lxml +%if 0%{?mandriva_version} +# mandriva seems to behave differently than other distros and needs this explicitly. +BuildRequires: python-setuptools +%endif +%if 0%{?mandriva_version} == 201100 +# mandriva 2011 has multiple providers for libsane, so (at least when building on OBS) +# one must be chosen explicitly: +# "have choice for libsane.so.1 needed by python-imaging: libsane1 sane-backends-iscan" +BuildRequires: libsane1 +%endif # %{rhel} wasn't set before rhel 6. so this checks for old RHEL # %systems (and potentially very old Fedora systems, too) -%if "%{_vendor}" == "redhat" && 0%{?rhel} <= 6 && 0%{?fedora} == 0 -BuildRequires: python-sphinx10 +%if "%{_vendor}" == "redhat" && 0%{?rhel} < 6 && 0%{?fedora} == 0 +BuildRequires: python-sphinx10 # the python-sphinx10 package doesn't set sys.path correctly, so we # have to do it for them -%define pythonpath /usr/lib/python%{py_ver}/site-packages/Sphinx-1.0.4-py%{py_ver}.egg +%define pythonpath %(find /usr/lib/python%{py_ver}/site-packages -name %Sphinx*.egg) %else -BuildRequires: python-sphinx >= 0.6 +BuildRequires: python-sphinx >= 0.6 %endif Requires: python-lxml >= 0.9 +%if 0%{?rhel_version} +# the debian init script needs redhat-lsb. +# iff we switch to the redhat one, this might not be needed anymore. +Requires: redhat-lsb +%endif +%if 0%{?fedora} == 0 +# fedora 15 and 16 (and possibly other distros) do not know this tag. +Recommends: cron +%endif %description Bcfg2 helps system administrators produce a consistent, reproducible, @@ -60,17 +88,23 @@ systems are constantly changing; if required in your environment, Bcfg2 can enable the construction of complex change management and deployment strategies. +This package includes the Bcfg2 client software. + %package -n bcfg2-server -Version: %{version} -Summary: Bcfg2 Server -Group: System Tools -Requires: bcfg2 +Version: 1.2.2 +Summary: Bcfg2 Server +%if 0%{?suse_version} +Group: System/Management +%else +Group: System Tools +%endif +Requires: bcfg2 %if "%{py_ver}" < "2.6" Requires: python-ssl %endif Requires: python-lxml >= 1.2.1 %if "%{_vendor}" == "redhat" -Requires: gamin-python +Requires: gamin-python %endif %description -n bcfg2-server @@ -99,24 +133,59 @@ systems are constantly changing; if required in your environment, Bcfg2 can enable the construction of complex change management and deployment strategies. +This package includes the Bcfg2 server software. + %package -n bcfg2-doc Summary: Configuration management system documentation +%if 0%{?suse_version} +Group: Documentation/HTML +%else Group: Documentation +%endif %description -n bcfg2-doc -Configuration management system documentation +Bcfg2 helps system administrators produce a consistent, reproducible, +and verifiable description of their environment, and offers +visualization and reporting tools to aid in day-to-day administrative +tasks. It is the fifth generation of configuration management tools +developed in the Mathematics and Computer Science Division of Argonne +National Laboratory. + +It is based on an operational model in which the specification can be +used to validate and optionally change the state of clients, but in a +feature unique to bcfg2 the client's response to the specification can +also be used to assess the completeness of the specification. Using +this feature, bcfg2 provides an objective measure of how good a job an +administrator has done in specifying the configuration of client +systems. Bcfg2 is therefore built to help administrators construct an +accurate, comprehensive specification. + +Bcfg2 has been designed from the ground up to support gentle +reconciliation between the specification and current client states. It +is designed to gracefully cope with manual system modifications. + +Finally, due to the rapid pace of updates on modern networks, client +systems are constantly changing; if required in your environment, +Bcfg2 can enable the construction of complex change management and +deployment strategies. + +This package includes the Bcfg2 documentation. %package -n bcfg2-web -Version: %{version} -Summary: Bcfg2 Web Reporting Interface -Group: System Tools -Requires: bcfg2-server -Requires: httpd,Django +Version: 1.2.2 +Summary: Bcfg2 Web Reporting Interface +%if 0%{?suse_version} +Group: System/Management +%else +Group: System Tools +%endif +Requires: bcfg2-server +Requires: httpd,Django %if "%{_vendor}" == "redhat" -Requires: mod_wsgi +Requires: mod_wsgi %define apache_conf %{_sysconfdir}/httpd %else -Requires: apache2-mod_wsgi +Requires: apache2-mod_wsgi %define apache_conf %{_sysconfdir}/apache2 %endif @@ -146,6 +215,8 @@ systems are constantly changing; if required in your environment, Bcfg2 can enable the construction of complex change management and deployment strategies. +This package includes the Bcfg2 reports web frontend. + %prep %setup -q -n bcfg2-%{version} @@ -166,6 +237,9 @@ deployment strategies. %{__install} -d %{buildroot}%{_sysconfdir}/cron.hourly %{__install} -d %{buildroot}%{_prefix}/lib/bcfg2 mkdir -p %{buildroot}%{_defaultdocdir}/bcfg2-doc-%{version} +%if 0%{?suse_version} +%{__install} -d %{buildroot}/var/adm/fillup-templates +%endif %{__mv} %{buildroot}/usr/bin/bcfg2* %{buildroot}%{_sbindir} %{__install} -m 755 debian/bcfg2.init %{buildroot}%{_initrddir}/bcfg2 @@ -175,6 +249,12 @@ mkdir -p %{buildroot}%{_defaultdocdir}/bcfg2-doc-%{version} %{__install} -m 755 debian/bcfg2.cron.daily %{buildroot}%{_sysconfdir}/cron.daily/bcfg2 %{__install} -m 755 debian/bcfg2.cron.hourly %{buildroot}%{_sysconfdir}/cron.hourly/bcfg2 %{__install} -m 755 tools/bcfg2-cron %{buildroot}%{_prefix}/lib/bcfg2/bcfg2-cron +%if 0%{?suse_version} +%{__install} -m 755 debian/bcfg2.default %{buildroot}/var/adm/fillup-templates/sysconfig.bcfg2 +%{__install} -m 755 debian/bcfg2-server.default %{buildroot}/var/adm/fillup-templates/sysconfig.bcfg2-server +ln -s %{_initrddir}/bcfg2 %{buildroot}%{_sbindir}/rcbcfg2 +ln -s %{_initrddir}/bcfg2-server %{buildroot}%{_sbindir}/rcbcfg2-server +%endif mv build/sphinx/html/* %{buildroot}%{_defaultdocdir}/bcfg2-doc-%{version} mv build/dtd %{buildroot}%{_defaultdocdir}/bcfg2-doc-%{version}/ @@ -190,7 +270,9 @@ mv build/dtd %{buildroot}%{_defaultdocdir}/bcfg2-doc-%{version}/ %files -n bcfg2 %defattr(-,root,root,-) %{_sbindir}/bcfg2 +%dir %{python_sitelib}/Bcfg2 %{python_sitelib}/Bcfg2/*.py* +%dir %{python_sitelib}/Bcfg2/Client %{python_sitelib}/Bcfg2/Client/* %{_mandir}/man1/bcfg2.1* %{_mandir}/man5/bcfg2.conf.5* @@ -200,15 +282,59 @@ mv build/dtd %{buildroot}%{_defaultdocdir}/bcfg2-doc-%{version}/ %{_sysconfdir}/cron.daily/bcfg2 %{_prefix}/lib/bcfg2/bcfg2-cron %{_localstatedir}/cache/bcfg2 +%if 0%{?suse_version} +%{_sbindir}/rcbcfg2 +%config(noreplace) /var/adm/fillup-templates/sysconfig.bcfg2 +%endif +%if 0%{?mandriva_version} == 0 +# mandriva (on OBS, at least) can't handle %ghost +%ghost %attr(0600,root,root) %{_sysconfdir}/bcfg2.conf +%endif %post -n bcfg2-server -/sbin/chkconfig --add bcfg2-server +# enable daemon on first install only (not on update). +if [ $1 -eq 1 ]; then +%if 0%{?suse_version} + %fillup_and_insserv -f bcfg2-server +%else + /sbin/chkconfig --add bcfg2-server +%endif +fi + +%preun -n bcfg2 +%if 0%{?suse_version} +# stop on removal (not on update). +if [ $1 -eq 0 ]; then + %stop_on_removal bcfg2 +fi +%endif + +%preun -n bcfg2-server +%if 0%{?suse_version} +if [ $1 -eq 0 ]; then + %stop_on_removal bcfg2-server +fi +%endif + +%postun -n bcfg2 +%if 0%{?suse_version} +if [ $1 -eq 0 ]; then + %insserv_cleanup +fi +%endif + +%postun -n bcfg2-server +%if 0%{?suse_version} +if [ $1 -eq 0 ]; then + # clean up on removal. + %insserv_cleanup +fi +%endif %files -n bcfg2-server %defattr(-,root,root,-) - %{_initrddir}/bcfg2-server - +%dir %{python_sitelib}/Bcfg2 %{python_sitelib}/Bcfg2/Server %if "%{pythonversion}" >= "2.5" @@ -230,24 +356,42 @@ mv build/dtd %{buildroot}%{_defaultdocdir}/bcfg2-doc-%{version}/ %{_sbindir}/bcfg2-server %{_sbindir}/bcfg2-yum-helper %{_sbindir}/bcfg2-test +%if 0%{?suse_version} +%{_sbindir}/rcbcfg2-server +%config(noreplace) /var/adm/fillup-templates/sysconfig.bcfg2-server +%endif %{_mandir}/man5/bcfg2-lint.conf.5* %{_mandir}/man8/*.8* %dir %{_prefix}/lib/bcfg2 +%if 0%{?mandriva_version} == 0 +%ghost %attr(0600,root,root) %{_sysconfdir}/bcfg2.conf +%endif -%files doc +%files -n bcfg2-doc %defattr(-,root,root,-) %doc %{_defaultdocdir}/bcfg2-doc-%{version} %files -n bcfg2-web %defattr(-,root,root,-) - %{_datadir}/bcfg2/reports.wsgi %{_datadir}/bcfg2/site_media - +%dir %{apache_conf} +%dir %{apache_conf}/conf.d %config(noreplace) %{apache_conf}/conf.d/wsgi_bcfg2.conf +%if 0%{?mandriva_version} == 0 +%ghost %attr(0600,root,root) %{_sysconfdir}/bcfg2-web.conf +%endif %changelog +* Sat Feb 18 2012 Christopher 'm4z' Holm <686f6c6d@googlemail.com> 1.2.1 +- Added Fedora and Mandriva compatibilty (for Open Build Service). +- Added missing dependency redhat-lsb. + +* Tue Feb 14 2012 Christopher 'm4z' Holm <686f6c6d@googlemail.com> 1.2.1 +- Added openSUSE compatibility. +- Various changes to satisfy rpmlint. + * Thu Jan 27 2011 Chris St. Pierre <stpierreca@ornl.gov> 1.2.0pre1-0.0 - Added -doc sub-package diff --git a/osx/Makefile b/osx/Makefile index 279ad0f6f..72751ff32 100644 --- a/osx/Makefile +++ b/osx/Makefile @@ -29,9 +29,9 @@ SITELIBDIR = /Library/Python/${PYVERSION}/site-packages # an Info.plist file for packagemaker to look at for package creation # and substitute the version strings. Major/Minor versions can only be # integers (e.g. "1" and "00" for bcfg2 version 1.0.0. -BCFGVER = 1.2.1 +BCFGVER = 1.2.2 MAJOR = 1 -MINOR = 21 +MINOR = 22 default: clean client diff --git a/redhat/VERSION b/redhat/VERSION index 6085e9465..23aa83906 100644 --- a/redhat/VERSION +++ b/redhat/VERSION @@ -1 +1 @@ -1.2.1 +1.2.2 diff --git a/reports/xsl-transforms/xsl-transform-includes/html-templates.xsl b/reports/xsl-transforms/xsl-transform-includes/html-templates.xsl index 74adbfe94..ad29f0411 100644 --- a/reports/xsl-transforms/xsl-transform-includes/html-templates.xsl +++ b/reports/xsl-transforms/xsl-transform-includes/html-templates.xsl @@ -4,7 +4,7 @@ <xsl:if test="count(Statistics/Good)+count(Statistics/Bad)+count(Statistics/Extra)+count(Statistics/Modified)+count(Statistics/Stale) > 0"> <a name="{Client/@name}}"></a> - <div class="nodebox""> + <div class="nodebox"> <span class="notebox">Time Ran: <xsl:value-of select="Statistics/@time" /></span> <span class="configbox">(<xsl:value-of select="Client/@profile" />)</span> @@ -121,7 +121,7 @@ if sys.hexversion < 0x03000000 and os.path.exists(py3lib): setup(cmdclass=cmdclass, name="Bcfg2", - version="1.2.1", + version="1.2.2", description="Bcfg2 Server", author="Narayan Desai", author_email="desai@mcs.anl.gov", diff --git a/solaris/Makefile b/solaris/Makefile index be98f345d..77d9019eb 100644 --- a/solaris/Makefile +++ b/solaris/Makefile @@ -1,26 +1,28 @@ #!/usr/sfw/bin/gmake -PYTHON="/opt/csw/bin/python" -VERS=1.2.1-1 +PYTHON="/usr/local/bin/python" +VERS=1.2.2-1 PYVERSION := $(shell $(PYTHON) -c "import sys; print sys.version[0:3]") default: clean package package: - -mkdir tmp tmp/bcfg2-server tmp/bcfg2 - -cd ../ && $(PYTHON) setup.py install --prefix=$(PWD) + -mkdir tmp tmp/bcfg2-server tmp/bcfg2 + -mkdir -p build/lib/$(PYVERSION)/site-packages + -cd ../ && PYTHONPATH=$(PYTHONPATH):$(PWD)/build/lib/python2.6/site-packages/ $(PYTHON) setup.py install --single-version-externally-managed --record=/dev/null --prefix=$(PWD)/build + #setuptools appears to use a restictive umask + -chmod -R o+r build/ -cat bin/bcfg2 | sed -e 's!/usr/bin/python!$(PYTHON)!' > bin/bcfg2.new && mv bin/bcfg2.new bin/bcfg2 - # Set python version to whichever version is installed - -cat prototype.bcfg2 | sed -e 's!PYVERSION!python$(PYVERSION)!' > prototype.bcfg2.fixed - -cat prototype.bcfg2-server | sed -e 's!PYVERSION!python$(PYVERSION)!' > prototype.bcfg2-server.fixed - -pkgmk -o -a `uname -m` -f prototype.bcfg2.fixed -d $(PWD)/tmp -r $(PWD) - -pkgmk -o -a `uname -m` -f prototype.bcfg2-server.fixed -d $(PWD)/tmp -r $(PWD) + -./gen-prototypes.sh + -pkgmk -o -a `uname -m` -f prototype.bcfg2 -d $(PWD)/tmp -r $(PWD)/build + -pkgmk -o -a `uname -m` -f prototype.bcfg2-server -d $(PWD)/tmp -r $(PWD)/build -pkgtrans -o -s $(PWD)/tmp $(PWD)/bcfg2-$(VERS) SCbcfg2 -pkgtrans -o -s $(PWD)/tmp $(PWD)/bcfg2-server-$(VERS) SCbcfg2-server -gzip -f $(PWD)/bcfg2-$(VERS) -gzip -f $(PWD)/bcfg2-server-$(VERS) clean: - -rm -rf tmp bin lib share + -rm -rf tmp build -rm -rf bcfg2-$(VERS).gz bcfg2-server-$(VERS).gz -rm -rf prototype.bcfg2.fixed prototype.bcfg2-server.fixed + -rm -f prototype.* diff --git a/solaris/gen-prototypes.sh b/solaris/gen-prototypes.sh new file mode 100644 index 000000000..ea0b4bb13 --- /dev/null +++ b/solaris/gen-prototypes.sh @@ -0,0 +1,24 @@ +#!/bin/sh +cd build +PP="./"`ls -1d lib/*`"/site-packages/" + +#bcfg2 +echo "i pkginfo=./pkginfo.bcfg2" > ../prototype.tmp +find . | grep man[15] | pkgproto >> ../prototype.tmp +echo "./bin" | pkgproto >> ../prototype.tmp +echo "./bin/bcfg2" | pkgproto >> ../prototype.tmp +echo "${PP}Bcfg2" | pkgproto >> ../prototype.tmp +ls -1 ${PP}Bcfg2/*.py | pkgproto >> ../prototype.tmp +find ${PP}Bcfg2/Client/ ! -name "*.pyc" | pkgproto >> ../prototype.tmp +sed "s/`id | sed 's/uid=[0-9]*(\(.*\)) gid=[0-9]*(\(.*\))/\1 \2/'`/bin bin/" ../prototype.tmp > ../prototype.bcfg2 + +#bcfg2-server +echo "i pkginfo=./pkginfo.bcfg2-server" > ../prototype.tmp +find . | grep man8 | pkgproto >> ../prototype.tmp +find share/bcfg2 | pkgproto >> ../prototype.tmp +echo "./bin" | pkgproto >> ../prototype.tmp +ls -1 bin/bcfg2-* | pkgproto >> ../prototype.tmp +find ${PP}Bcfg2/Server/ ! -name "*.pyc" | pkgproto >> ../prototype.tmp +sed "s/`id | sed 's/uid=[0-9]*(\(.*\)) gid=[0-9]*(\(.*\))/\1 \2/'`/bin bin/" ../prototype.tmp > ../prototype.bcfg2-server + +rm ../prototype.tmp diff --git a/solaris/pkginfo.bcfg2 b/solaris/pkginfo.bcfg2 index c4633f209..0ff18516d 100644 --- a/solaris/pkginfo.bcfg2 +++ b/solaris/pkginfo.bcfg2 @@ -1,7 +1,7 @@ PKG="SCbcfg2" NAME="bcfg2" ARCH="sparc" -VERSION="1.2.1" +VERSION="1.2.2" CATEGORY="application" VENDOR="Argonne National Labratory" EMAIL="bcfg-dev@mcs.anl.gov" diff --git a/solaris/pkginfo.bcfg2-server b/solaris/pkginfo.bcfg2-server index 762625967..a0958f9e4 100644 --- a/solaris/pkginfo.bcfg2-server +++ b/solaris/pkginfo.bcfg2-server @@ -1,7 +1,7 @@ PKG="SCbcfg2-server" NAME="bcfg2-server" ARCH="sparc" -VERSION="1.2.1" +VERSION="1.2.2" CATEGORY="application" VENDOR="Argonne National Labratory" EMAIL="bcfg-dev@mcs.anl.gov" diff --git a/src/lib/Client/Tools/RPMng.py b/src/lib/Client/Tools/RPMng.py index 00f4aedd7..b28bec030 100644 --- a/src/lib/Client/Tools/RPMng.py +++ b/src/lib/Client/Tools/RPMng.py @@ -7,12 +7,6 @@ import Bcfg2.Client.Tools # Compatibility import from Bcfg2.Bcfg2Py3k import ConfigParser -# Fix for python2.3 -try: - set -except NameError: - from sets import Set as set - class RPMng(Bcfg2.Client.Tools.PkgTool): """Support for RPM packages.""" name = 'RPMng' diff --git a/src/lib/Client/Tools/YUM24.py b/src/lib/Client/Tools/YUM24.py index cee1319a8..4e488b9da 100644 --- a/src/lib/Client/Tools/YUM24.py +++ b/src/lib/Client/Tools/YUM24.py @@ -9,12 +9,6 @@ import Bcfg2.Client.Tools.RPMng # Compatibility import from Bcfg2.Bcfg2Py3k import ConfigParser -# Fix for python2.3 -try: - set -except NameError: - from sets import Set as set - YAD = True CP = ConfigParser.ConfigParser() try: diff --git a/src/lib/Client/Tools/YUMng.py b/src/lib/Client/Tools/YUMng.py index 967221b8b..154676764 100644 --- a/src/lib/Client/Tools/YUMng.py +++ b/src/lib/Client/Tools/YUMng.py @@ -15,12 +15,6 @@ import Bcfg2.Client.Tools # Compatibility import from Bcfg2.Bcfg2Py3k import ConfigParser -# Fix for python2.3 -try: - set -except NameError: - from sets import Set as set - def build_yname(pkgname, inst): """Build yum appropriate package name.""" diff --git a/src/lib/Client/Tools/__init__.py b/src/lib/Client/Tools/__init__.py index 924ede9a2..c6cb6e239 100644 --- a/src/lib/Client/Tools/__init__.py +++ b/src/lib/Client/Tools/__init__.py @@ -1,8 +1,4 @@ """This contains all Bcfg2 Tool modules""" -# suppress popen2 warnings for python 2.3 -import warnings -warnings.filterwarnings("ignore", "The popen2 module is deprecated.*", - DeprecationWarning) import os import stat import sys diff --git a/src/lib/Options.py b/src/lib/Options.py index dc2d06eea..527b42d00 100644 --- a/src/lib/Options.py +++ b/src/lib/Options.py @@ -26,12 +26,7 @@ class Option(object): def getCFP(self): if not self.__cfp: self.__cfp = ConfigParser.ConfigParser() - # FIXME: Remove this hack when except: pass below is fixed - try: - self.__cfp.readfp(open(self.cfpath)) - except IOError: - e = sys.exc_info()[1] - print("Unable to read bcfg2.conf: %s" % e) + self.__cfp.readfp(open(self.cfpath)) return self.__cfp cfp = property(getCFP) @@ -115,11 +110,7 @@ class Option(object): self.value = self.get_cooked_value(os.environ[self.env]) return if self.cf: - """ - FIXME: This is masking any sort of error present in getCFP, we - need to remove this catchall exception and figure out something - better - """ + # FIXME: This is potentially masking a lot of errors try: self.value = self.get_cooked_value(self.cfp.get(*self.cf)) return @@ -382,3 +373,9 @@ class OptionParser(OptionSet): Option.cfpath = self.Bootstrap['configfile'] Option.__cfp = False OptionSet.__init__(self, args) + try: + f = open(Option.cfpath, 'r') + f.close() + except IOError: + e = sys.exc_info()[1] + print("Warning! Unable to read specified configuration file: %s" % e) diff --git a/src/lib/Server/Plugin.py b/src/lib/Server/Plugin.py index db4cbaee7..e66c23b2b 100644 --- a/src/lib/Server/Plugin.py +++ b/src/lib/Server/Plugin.py @@ -989,6 +989,12 @@ class EntrySet: self.entry_init(event) else: if event.filename not in self.entries: + logger.warning("Got %s event for unknown file %s" % + (action, event.filename)) + if action == 'changed': + # received a bogus changed event; warn, but treat + # it like a created event + self.entry_init(event) return if action == 'changed': self.entries[event.filename].handle_event(event) @@ -1153,8 +1159,11 @@ class GroupSpool(Plugin, Generator): # a directory was deleted del self.entries[fbase] del self.Entries['Path'][fbase] - else: + elif ident in self.entries: self.entries[ident].handle_event(event) + elif ident not in self.entries: + self.logger.warning("Got deleted event for unknown file %s" % + ident) def AddDirectoryMonitor(self, relative): """Add new directory to FAM structures.""" diff --git a/src/lib/Server/Plugins/Cfg.py b/src/lib/Server/Plugins/Cfg.py index d5de086a5..03d56fdc2 100644 --- a/src/lib/Server/Plugins/Cfg.py +++ b/src/lib/Server/Plugins/Cfg.py @@ -220,32 +220,32 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet): return "%s.H_%s" % (bfname, specific.hostname) def write_update(self, specific, new_entry, log): - # FIXME: need to redo print with python's logging module if 'text' in new_entry: name = self.build_filename(specific) if os.path.exists("%s.genshi" % name): - print("Cfg: Unable to pull data for genshi types") + self.logger.error("Cfg: Unable to pull data for genshi types") raise Bcfg2.Server.Plugin.PluginExecutionError elif os.path.exists("%s.cheetah" % name): - print("Cfg: Unable to pull data for cheetah types") + self.logger.error("Cfg: Unable to pull data for cheetah types") raise Bcfg2.Server.Plugin.PluginExecutionError try: etext = new_entry['text'].encode(self.encoding) except: - print("Cfg: Cannot encode content of %s as %s" % (name, self.encoding)) + self.logger.error("Cfg: Cannot encode content of %s as %s" % (name, self.encoding)) raise Bcfg2.Server.Plugin.PluginExecutionError open(name, 'w').write(etext) - if log: - print("Wrote file %s" % name) + self.debug_log("Wrote file %s" % name, flag=log) badattr = [attr for attr in ['owner', 'group', 'perms'] if attr in new_entry] if badattr: # check for info files and inform user of their removal if os.path.exists(self.path + "/:info"): - print("Removing :info file and replacing with info.xml") + self.logger.info("Removing :info file and replacing with " + "info.xml") os.remove(self.path + "/:info") if os.path.exists(self.path + "/info"): - print("Removing info file and replacing with info.xml") + self.logger.info("Removing info file and replacing with " + "info.xml") os.remove(self.path + "/info") metadata_updates = {} metadata_updates.update(self.metadata) @@ -258,8 +258,8 @@ class CfgEntrySet(Bcfg2.Server.Plugin.EntrySet): ofile = open(self.path + "/info.xml", "w") ofile.write(lxml.etree.tostring(infoxml, pretty_print=True)) ofile.close() - if log: - print("Wrote file %s" % (self.path + "/info.xml")) + self.debug_log("Wrote file %s" % (self.path + "/info.xml"), + flag=log) class Cfg(Bcfg2.Server.Plugin.GroupSpool, diff --git a/src/lib/Server/Plugins/FileProbes.py b/src/lib/Server/Plugins/FileProbes.py index 98c1f66bf..a76d7cac4 100644 --- a/src/lib/Server/Plugins/FileProbes.py +++ b/src/lib/Server/Plugins/FileProbes.py @@ -5,6 +5,7 @@ client, it can either be updated in the specification or replaced on the client """ import os +import sys import errno import binascii import lxml.etree @@ -87,33 +88,27 @@ class FileProbes(Bcfg2.Server.Plugin.Plugin, interpreter="/usr/bin/env python") probe.text = probecode % path self.probes[metadata.hostname].append(probe) - self.logger.debug("Adding file probe for %s to %s" % - (path, metadata.hostname)) + self.debug_log("Adding file probe for %s to %s" % + (path, metadata.hostname)) return self.probes[metadata.hostname] def ReceiveData(self, metadata, datalist): """Receive data from probe.""" - self.logger.debug("Receiving file probe data from %s" % - metadata.hostname) + self.debug_log("Receiving file probe data from %s" % metadata.hostname) for data in datalist: if data.text is None: self.logger.error("Got null response to %s file probe from %s" % (data.get('name'), metadata.hostname)) else: - self.logger.debug("%s:fileprobe:%s:%s" % - (metadata.hostname, - data.get("name"), - data.text)) try: - filedata = lxml.etree.XML(data.text) - self.write_file(filedata, metadata) + self.write_data(lxml.etree.XML(data.text), metadata) except lxml.etree.XMLSyntaxError: # if we didn't get XML back from the probe, assume # it's an error message self.logger.error(data.text) - def write_file(self, data, metadata): + def write_data(self, data, metadata): """Write the probed file data to the bcfg2 specification.""" filename = data.get("name") contents = binascii.a2b_base64(data.text) @@ -137,74 +132,80 @@ class FileProbes(Bcfg2.Server.Plugin.Plugin, entrydata = entry.text if create: - self.logger.info("Writing new probed file %s" % fileloc) - try: - os.makedirs(os.path.dirname(fileloc)) - except OSError, err: - if err.errno == errno.EEXIST: - pass - else: - raise - open(fileloc, 'wb').write(contents) - - infoxml = os.path.join("%s%s" % (cfg.data, filename), - "info.xml") - if not os.path.exists(infoxml): - self.write_infoxml(infoxml, entry, data) - - # Service the FAM events queued up by the key generation - # so the data structure entries will be available for - # binding. - # - # NOTE: We wait for up to ten seconds. There is some - # potential for race condition, because if the file - # monitor doesn't get notified about the new key files in - # time, those entries won't be available for binding. In - # practice, this seems "good enough". - tries = 0 - is_bound = False - while not is_bound: - if tries >= 10: - self.logger.error("%s still not registered" % filename) - raise Bcfg2.Server.Plugin.PluginExecutionError - self.core.fam.handle_events_in_interval(1) - try: - cfg.entries[filename].bind_entry(entry, metadata) - is_bound = True - except Bcfg2.Server.Plugin.PluginExecutionError: - pass - tries += 1 + self.logger.info("Writing new probed file %s" % fileloc) + self.write_file(fileloc, contents) + self.verify_file(filename, contents, metadata) + infoxml = os.path.join("%s%s" % (cfg.data, filename), "info.xml") + self.write_infoxml(infoxml, entry, data) elif entrydata == contents: - self.logger.debug("Existing %s contents match probed contents" % - filename) + self.debug_log("Existing %s contents match probed contents" % + filename) return elif (entry.get('update', 'false').lower() == "true"): self.logger.info("Writing updated probed file %s" % fileloc) - open(fileloc, 'wb').write(contents) - - # service FAM events - tries = 0 - updated = False - while not updated: - if tries >= 10: - self.logger.error("%s still not registered" % filename) - raise Bcfg2.Server.Plugin.PluginExecutionError - self.core.fam.handle_events_in_interval(1) - cfg.entries[filename].bind_entry(entry, metadata) - # get current entry data - if entry.get("encoding") == "base64": - entrydata = binascii.a2b_base64(entry.text) - else: - entrydata = entry.text - if entrydata == contents: - updated = True - tries += 1 + self.write_file(fileloc, contents) + self.verify_file(filename, contents, metadata) else: self.logger.info("Skipping updated probed file %s" % fileloc) return + + def write_file(self, fileloc, contents): + try: + os.makedirs(os.path.dirname(fileloc)) + except OSError: + err = sys.exc_info()[1] + if err.errno == errno.EEXIST: + pass + else: + self.logger.error("Could not create parent directories for %s: " + "%s" % (fileloc, err)) + return + + try: + open(fileloc, 'wb').write(contents) + except IOError: + err = sys.exc_info()[1] + self.logger.error("Could not write %s: %s" % (fileloc, err)) + return + + def verify_file(self, filename, contents, metadata): + # Service the FAM events queued up by the key generation so + # the data structure entries will be available for binding. + # + # NOTE: We wait for up to ten seconds. There is some potential + # for race condition, because if the file monitor doesn't get + # notified about the new key files in time, those entries + # won't be available for binding. In practice, this seems + # "good enough". + entry = self.entries[metadata.hostname][filename] + cfg = self.core.plugins['Cfg'] + tries = 0 + updated = False + while not updated: + if tries >= 10: + self.logger.error("%s still not registered" % filename) + return + self.core.fam.handle_events_in_interval(1) + try: + cfg.entries[filename].bind_entry(entry, metadata) + except Bcfg2.Server.Plugin.PluginExecutionError: + tries += 1 + continue + + # get current entry data + if entry.get("encoding") == "base64": + entrydata = binascii.a2b_base64(entry.text) + else: + entrydata = entry.text + if entrydata == contents: + updated = True + tries += 1 def write_infoxml(self, infoxml, entry, data): """ write an info.xml for the file """ + if os.path.exists(infoxml): + return + self.logger.info("Writing info.xml at %s for %s" % (infoxml, data.get("name"))) info = \ @@ -220,5 +221,10 @@ class FileProbes(Bcfg2.Server.Plugin.Plugin, root = lxml.etree.Element("FileInfo") root.append(info) - open(infoxml, "w").write(lxml.etree.tostring(root, - pretty_print=True)) + try: + open(infoxml, "w").write(lxml.etree.tostring(root, + pretty_print=True)) + except IOError: + err = sys.exc_info()[1] + self.logger.error("Could not write %s: %s" % (fileloc, err)) + return diff --git a/src/lib/Server/Plugins/Packages/Source.py b/src/lib/Server/Plugins/Packages/Source.py index 910a90cac..1dfeecc40 100644 --- a/src/lib/Server/Plugins/Packages/Source.py +++ b/src/lib/Server/Plugins/Packages/Source.py @@ -136,7 +136,7 @@ class Source(Bcfg2.Server.Plugin.Debuggable): def get_repo_name(self, url_map): # try to find a sensible name for a repo if url_map['component']: - return url_map['component'] + rname = url_map['component'] else: name = None for repo_re in (self.mrepo_re, @@ -144,14 +144,18 @@ class Source(Bcfg2.Server.Plugin.Debuggable): self.genericrepo_re): match = repo_re.search(url_map['url']) if match: - name = match.group(1).replace('/', '-') break if name is None: # couldn't figure out the name from the URL or URL map # (which probably means its a screwy URL), so we just # generate a random one name = base64.b64encode(os.urandom(16))[:-2] - return "%s-%s" % (self.groups[0], name) + rname = "%s-%s" % (self.groups[0], name) + # see yum/__init__.py in the yum source, lines 441-449, for + # the source of this regex. yum doesn't like anything but + # string.ascii_letters, string.digits, and [-_.:]. There + # doesn't seem to be a reason for this, because yum. + return re.sub(r'[^A-Za-z0-9-_.:]', '-', rname) def __str__(self): if self.rawurl: diff --git a/src/lib/Server/Plugins/Packages/Yum.py b/src/lib/Server/Plugins/Packages/Yum.py index a5fe706cd..416602b27 100644 --- a/src/lib/Server/Plugins/Packages/Yum.py +++ b/src/lib/Server/Plugins/Packages/Yum.py @@ -124,6 +124,7 @@ class YumCollection(Collection): mainopts = dict(cachedir=self.cachefile, keepcache="0", sslverify="0", + debuglevel="0", reposdir="/dev/null") try: for opt in self.config.options("yum"): @@ -394,6 +395,11 @@ class YumCollection(Collection): if rv: self.logger.error("Packages: error running bcfg2-yum-helper " "(returned %d): %s" % (rv, stderr)) + elif self.debug_flag: + self.logger.debug("Packages: debug info from bcfg2-yum-helper: %s" % + stderr) + self.logger.debug("Packages: output from bcfg2-yum-helper: %s" % + stderr) try: return json.loads(stdout) except ValueError: diff --git a/src/lib/Server/Plugins/SSHbase.py b/src/lib/Server/Plugins/SSHbase.py index 4db5fc379..2e247caa7 100644 --- a/src/lib/Server/Plugins/SSHbase.py +++ b/src/lib/Server/Plugins/SSHbase.py @@ -233,6 +233,8 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, if entry.specific.match(event.filename): entry.handle_event(event) if event.filename.endswith(".pub"): + self.logger.info("New public key %s; invalidating " + "ssh_known_hosts cache" % event.filename) self.skn = False return @@ -242,6 +244,8 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, return if event.filename.endswith('.static'): + self.logger.info("Static key %s %s; invalidating ssh_known_hosts " + "cache" % (event.filename, action)) if action == "deleted" and event.filename in self.static: del self.static[event.filename] self.skn = False diff --git a/src/lib/Server/Plugins/Trigger.py b/src/lib/Server/Plugins/Trigger.py index 9c0994ebe..b0d21545c 100644 --- a/src/lib/Server/Plugins/Trigger.py +++ b/src/lib/Server/Plugins/Trigger.py @@ -25,12 +25,19 @@ class Trigger(Bcfg2.Server.Plugin.Plugin, try: os.stat(self.data) except: - self.logger.error("Trigger: spool directory %s does not exist; unloading" % self.data) + self.logger.error("Trigger: spool directory %s does not exist; " + "unloading" % self.data) raise Bcfg2.Server.Plugin.PluginInitError def process_statistics(self, metadata, _): args = [metadata.hostname, '-p', metadata.profile, '-g', ':'.join([g for g in metadata.groups])] for notifier in os.listdir(self.data): - n = self.data + '/' + notifier - async_run(n, args) + if ((notifier[-1] == '~') or + (notifier[:2] == '.#') or + (notifier[-4:] == '.swp') or + (notifier in ['SCCS', '.svn', '4913'])): + continue + npath = self.data + '/' + notifier + self.logger.debug("Running %s %s" % (npath, " ".join(args))) + async_run(npath, args) diff --git a/src/lib/Server/Reports/reports/templates/base.html b/src/lib/Server/Reports/reports/templates/base.html index a12bf66ba..f541c0d2b 100644 --- a/src/lib/Server/Reports/reports/templates/base.html +++ b/src/lib/Server/Reports/reports/templates/base.html @@ -87,7 +87,7 @@ <div style='clear:both'></div> </div><!-- document --> <div id="footer"> - <span>Bcfg2 Version 1.2.1</span> + <span>Bcfg2 Version 1.2.2</span> </div> <div id="calendar_div" style='position:absolute; visibility:hidden; background-color:white; layer-background-color:white;'></div> |