diff options
-rw-r--r-- | doc/development/plugins.txt | 4 | ||||
-rw-r--r-- | doc/releases/1.4.0pre2.txt | 3 | ||||
-rw-r--r-- | doc/server/plugins/generators/examples/jinja2/extends.txt | 5 | ||||
-rw-r--r-- | doc/server/plugins/generators/examples/jinja2/include.txt | 5 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/Tools/__init__.py | 2 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/__init__.py | 10 | ||||
-rw-r--r-- | src/lib/Bcfg2/Options/Parser.py | 11 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Admin.py | 4 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Core.py | 19 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugin/helpers.py | 36 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/Metadata.py | 2 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/NagiosGen.py | 9 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 2 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/SSLServer.py | 4 | ||||
-rw-r--r-- | testsuite/Testsrc/Testlib/TestOptions/TestOptions.py | 7 | ||||
-rw-r--r-- | testsuite/common.py | 4 |
16 files changed, 67 insertions, 60 deletions
diff --git a/doc/development/plugins.txt b/doc/development/plugins.txt index 5993c4e29..d292c9dd7 100644 --- a/doc/development/plugins.txt +++ b/doc/development/plugins.txt @@ -171,12 +171,12 @@ perf``. This data can be invaluable for locating bottlenecks or other performance issues. The simplest way to track statistics is to use the -:func:`Bcfg2.Server.Plugin.helpers.track_statistics` decorator to +:func:`Bcfg2.Server.Statistics.track_statistics` decorator to decorate functions that you would like to track execution times for: .. code-block:: python - from Bcfg2.Server.Plugin import track_statistics + from Bcfg2.Server.Statistics import track_statistics @track_statistics() def do_something(self, ...): diff --git a/doc/releases/1.4.0pre2.txt b/doc/releases/1.4.0pre2.txt index 7bbed5603..572748f73 100644 --- a/doc/releases/1.4.0pre2.txt +++ b/doc/releases/1.4.0pre2.txt @@ -17,6 +17,8 @@ and as such is not likely suitable for general production deployment. That said, please help us test the release in non- and preproduction environments. +* NagiosGen: Add bundles to configuration + backwards-incompatible user-facing changes ------------------------------------------ @@ -35,3 +37,4 @@ Special thanks to the following contributors for this release * Alexander Sulfrain * Matt Kemp + * Jeremie Banier diff --git a/doc/server/plugins/generators/examples/jinja2/extends.txt b/doc/server/plugins/generators/examples/jinja2/extends.txt index a0eeb5c03..3c6dd06ab 100644 --- a/doc/server/plugins/generators/examples/jinja2/extends.txt +++ b/doc/server/plugins/generators/examples/jinja2/extends.txt @@ -1,8 +1,9 @@ .. -*- mode: rst -*- +.. vim: ft=rst -========================= +=========================== Extending Jinja2 Templates -========================= +=========================== Jinja2 templates can use the {% extends %} directive to inherit file fragments which might be common to many configuration files. diff --git a/doc/server/plugins/generators/examples/jinja2/include.txt b/doc/server/plugins/generators/examples/jinja2/include.txt index 49be7c277..466ea6b97 100644 --- a/doc/server/plugins/generators/examples/jinja2/include.txt +++ b/doc/server/plugins/generators/examples/jinja2/include.txt @@ -1,8 +1,9 @@ .. -*- mode: rst -*- +.. vim: ft=rst -========================= +=========================== Including Jinja2 Templates -========================= +=========================== Jinja2 templates can use the {% include %} directive to include file fragments which might be common to many configuration files. diff --git a/src/lib/Bcfg2/Client/Tools/__init__.py b/src/lib/Bcfg2/Client/Tools/__init__.py index ae7fa3aed..67cdd4d6d 100644 --- a/src/lib/Bcfg2/Client/Tools/__init__.py +++ b/src/lib/Bcfg2/Client/Tools/__init__.py @@ -205,6 +205,8 @@ class Tool(object): continue try: states[entry] = func(entry, mods) + except KeyboardInterrupt: + raise except: # pylint: disable=W0702 self.logger.error("%s: Unexpected failure verifying %s" % (self.name, diff --git a/src/lib/Bcfg2/Client/__init__.py b/src/lib/Bcfg2/Client/__init__.py index d834576c9..359d7ac73 100644 --- a/src/lib/Bcfg2/Client/__init__.py +++ b/src/lib/Bcfg2/Client/__init__.py @@ -617,6 +617,8 @@ class Client(object): for tool in self.tools: try: self.states.update(tool.Inventory()) + except KeyboardInterrupt: + raise except: # pylint: disable=W0702 self.logger.error("%s.Inventory() call failed:" % tool.name, exc_info=1) @@ -734,6 +736,8 @@ class Client(object): continue try: self.states.update(tool.Install(handled)) + except KeyboardInterrupt: + raise except: # pylint: disable=W0702 self.logger.error("%s.Install() call failed:" % tool.name, exc_info=1) @@ -754,6 +758,8 @@ class Client(object): for tool, bundle in tbm: try: self.states.update(tool.Inventory(structures=[bundle])) + except KeyboardInterrupt: + raise except: # pylint: disable=W0702 self.logger.error("%s.Inventory() call failed:" % tool.name, @@ -785,6 +791,8 @@ class Client(object): for tool in self.tools: try: self.states.update(tool.BundleNotUpdated(bundle)) + except KeyboardInterrupt: + raise except: # pylint: disable=W0702 self.logger.error('%s.BundleNotUpdated(%s:%s) call failed:' % (tool.name, bundle.tag, @@ -794,6 +802,8 @@ class Client(object): for tool in self.tools: try: self.states.update(tool.BundleNotUpdated(indep)) + except KeyboardInterrupt: + raise except: # pylint: disable=W0702 self.logger.error("%s.BundleNotUpdated(%s:%s) call failed:" % (tool.name, indep.tag, diff --git a/src/lib/Bcfg2/Options/Parser.py b/src/lib/Bcfg2/Options/Parser.py index c846e8093..d146e3aa2 100644 --- a/src/lib/Bcfg2/Options/Parser.py +++ b/src/lib/Bcfg2/Options/Parser.py @@ -6,7 +6,7 @@ import sys from Bcfg2.version import __version__ from Bcfg2.Compat import ConfigParser -from Bcfg2.Options import Option, PathOption, BooleanOption, _debug +from Bcfg2.Options import Option, PathOption, _debug __all__ = ["setup", "OptionParserException", "Parser", "get_parser", "new_parser"] @@ -43,9 +43,16 @@ class Parser(argparse.ArgumentParser): help="Path to configuration file", default="/etc/bcfg2.conf") + #: Verbose version string that is printed if executed with --version + _version_string = "%s %s on Python %s" % ( + os.path.basename(sys.argv[0]), + __version__, + ".".join(str(v) for v in sys.version_info[0:3])) + #: Builtin options that apply to all commands options = [configfile, - BooleanOption('--version', help="Print the version and exit"), + Option('--version', help="Print the version and exit", + action="version", version=_version_string), Option('-E', '--encoding', metavar='<encoding>', default='UTF-8', help="Encoding of config files", cf=('components', 'encoding'))] diff --git a/src/lib/Bcfg2/Server/Admin.py b/src/lib/Bcfg2/Server/Admin.py index ef7741880..c294e6be5 100644 --- a/src/lib/Bcfg2/Server/Admin.py +++ b/src/lib/Bcfg2/Server/Admin.py @@ -1198,7 +1198,9 @@ class CLI(Bcfg2.Options.CommandRegistry): def run(self): """ Run bcfg2-admin """ try: - self.commands[Bcfg2.Options.setup.subcommand].setup() + cmd = self.commands[Bcfg2.Options.setup.subcommand] + if hasattr(cmd, 'setup'): + cmd.setup() return self.runcommand() finally: self.shutdown() diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index bc305e47a..03ab40343 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -22,7 +22,7 @@ from Bcfg2.Server.Cache import Cache from Bcfg2.Compat import xmlrpclib, wraps # pylint: disable=W0622 from Bcfg2.Server.Plugin.exceptions import * # pylint: disable=W0401,W0614 from Bcfg2.Server.Plugin.interfaces import * # pylint: disable=W0401,W0614 -from Bcfg2.Server.Plugin import track_statistics +from Bcfg2.Server.Statistics import track_statistics try: from django.core.exceptions import ImproperlyConfigured @@ -495,7 +495,7 @@ class Core(object): (self.__class__.__name__, hook), time.time() - start) - @Bcfg2.Server.Statistics.track_statistics() + @track_statistics() def validate_structures(self, metadata, data): """ Checks the data structures by calling the :func:`Bcfg2.Server.Plugin.interfaces.StructureValidator.validate_structures` @@ -522,7 +522,7 @@ class Core(object): self.logger.error("Plugin %s: unexpected structure validation " "failure" % plugin.name, exc_info=1) - @Bcfg2.Server.Statistics.track_statistics() + @track_statistics() def validate_goals(self, metadata, data): """ Checks that the config matches the goals enforced by :class:`Bcfg2.Server.Plugin.interfaces.GoalValidator` plugins @@ -548,7 +548,7 @@ class Core(object): self.logger.error("Plugin %s: unexpected goal validation " "failure" % plugin.name, exc_info=1) - @Bcfg2.Server.Statistics.track_statistics() + @track_statistics() def GetStructures(self, metadata): """ Get all structures (i.e., bundles) for the given client @@ -560,14 +560,15 @@ class Core(object): structures = list( chain(*[struct.BuildStructures(metadata) for struct in self.plugins_by_type(Structure)])) - sbundles = [b.get('name') for b in structures if b.tag == 'Bundle'] + sbundles = [b.get('name') for b in structures + if b.tag == 'Bundle' or b.tag == 'Independent'] missing = [b for b in metadata.bundles if b not in sbundles] if missing: self.logger.error("Client %s configuration missing bundles: %s" % (metadata.hostname, ':'.join(missing))) return structures - @Bcfg2.Server.Statistics.track_statistics() + @track_statistics() def BindStructures(self, structures, metadata, config): """ Given a list of structures (i.e. bundles), bind all the entries in them and add the structures to the config. @@ -588,7 +589,7 @@ class Core(object): except: self.logger.error("error in BindStructure", exc_info=1) - @Bcfg2.Server.Statistics.track_statistics() + @track_statistics() def BindStructure(self, structure, metadata): """ Bind all elements in a single structure (i.e., bundle). @@ -821,7 +822,7 @@ class Core(object): % plugin.name, exc_info=1) return result - @Bcfg2.Server.Statistics.track_statistics() + @track_statistics() def check_acls(self, address, rmi): """ Check client IP address and metadata object against all :class:`Bcfg2.Server.Plugin.interfaces.ClientACLs` plugins. @@ -876,7 +877,7 @@ class Core(object): "%s" % (client, rmi, sys.exc_info()[1])) return False # failsafe - @Bcfg2.Server.Statistics.track_statistics() + @track_statistics() def build_metadata(self, client_name): """ Build initial client metadata for a client diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 559612d1e..2aab231c6 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -3,7 +3,6 @@ import os import re import sys -import time import copy import glob import logging @@ -35,41 +34,6 @@ except ImportError: LOGGER = logging.getLogger(__name__) -class track_statistics(object): # pylint: disable=C0103 - """ Decorator that tracks execution time for the given - :class:`Plugin` method with :mod:`Bcfg2.Statistics` for reporting - via ``bcfg2-admin perf`` """ - - def __init__(self, name=None): - """ - :param name: The name under which statistics for this function - will be tracked. By default, the name will be - the name of the function concatenated with the - name of the class the function is a member of. - :type name: string - """ - # if this is None, it will be set later during __call_ - self.name = name - - def __call__(self, func): - if self.name is None: - self.name = func.__name__ - - @wraps(func) - def inner(obj, *args, **kwargs): - """ The decorated function """ - name = "%s:%s" % (obj.__class__.__name__, self.name) - - start = time.time() - try: - return func(obj, *args, **kwargs) - finally: - Bcfg2.Server.Statistics.stats.add_value(name, - time.time() - start) - - return inner - - def removecomment(stream): """ A Genshi filter that removes comments from the stream. This function is a generator. diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py index 1d15656af..26f39e50d 100644 --- a/src/lib/Bcfg2/Server/Plugins/Metadata.py +++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py @@ -502,6 +502,8 @@ class Metadata(Bcfg2.Server.Plugin.Metadata, """This class contains data for bcfg2 server metadata.""" __author__ = 'bcfg-dev@mcs.anl.gov' sort_order = 500 + __rmi__ = Bcfg2.Server.Plugin.DatabaseBacked.__rmi__ + ['list_clients', + 'remove_client'] options = Bcfg2.Server.Plugin.DatabaseBacked.options + [ Bcfg2.Options.Common.password, diff --git a/src/lib/Bcfg2/Server/Plugins/NagiosGen.py b/src/lib/Bcfg2/Server/Plugins/NagiosGen.py index 045e46350..d3c38ef19 100644 --- a/src/lib/Bcfg2/Server/Plugins/NagiosGen.py +++ b/src/lib/Bcfg2/Server/Plugins/NagiosGen.py @@ -45,7 +45,11 @@ class NagiosGen(Plugin, Generator): raise PluginExecutionError("Failed to find IP address for %s" % metadata.hostname) host_groups = [grp for grp in metadata.groups - if os.path.isfile('%s/%s-group.cfg' % (self.data, grp))] + if os.path.isfile('%s/%s-group.cfg' % + (self.data, grp))] + \ + [bundle for bundle in metadata.bundles + if os.path.isfile('%s/%s-bundle.cfg' % + (self.data, bundle))] host_config = ['define host {', self.line_fmt % ('host_name', metadata.hostname), self.line_fmt % ('alias', metadata.hostname), @@ -81,7 +85,8 @@ class NagiosGen(Plugin, Generator): def createserverconfig(self, entry, _): """Build monolithic server configuration file.""" host_configs = glob.glob(os.path.join(self.data, '*-host.cfg')) - group_configs = glob.glob(os.path.join(self.data, '*-group.cfg')) + group_configs = glob.glob(os.path.join(self.data, '*-group.cfg')) + \ + glob.glob(os.path.join(self.data, '*-bundle.cfg')) host_data = [] group_data = [] for host in host_configs: diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index f26ded4c5..b6e9f13eb 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -1231,7 +1231,7 @@ class YumSource(Source): self.provides[arch][prov] = list() self.provides[arch][prov].append(pkgname) - @Bcfg2.Server.Plugin.track_statistics() + @track_statistics() def parse_group(self, data): """ parse comps.xml.gz data """ for group in data.getchildren(): diff --git a/src/lib/Bcfg2/Server/SSLServer.py b/src/lib/Bcfg2/Server/SSLServer.py index 6ad5b5635..1f8febd0e 100644 --- a/src/lib/Bcfg2/Server/SSLServer.py +++ b/src/lib/Bcfg2/Server/SSLServer.py @@ -43,8 +43,10 @@ class XMLRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher): params = (address, ) + params response = self.instance._dispatch(method, params, self.funcs) # py3k compatibility - if type(response) not in [bool, str, list, dict]: + if type(response) not in [bool, str, list, dict, set, type(None)]: response = (response.decode('utf-8'), ) + elif type(response) == set: + response = (list(response), ) else: response = (response, ) raw_response = xmlrpclib.dumps(response, methodresponse=True, diff --git a/testsuite/Testsrc/Testlib/TestOptions/TestOptions.py b/testsuite/Testsrc/Testlib/TestOptions/TestOptions.py index a2dc8ffe2..034a4580a 100644 --- a/testsuite/Testsrc/Testlib/TestOptions/TestOptions.py +++ b/testsuite/Testsrc/Testlib/TestOptions/TestOptions.py @@ -185,6 +185,13 @@ class TestBasicOptions(OptionTestCase): options = self._test_options(env={"TEST_PATH_OPTION": "/foo"}) self.assertEqual(options.test_path_option, "/foo") + def test_version(self): + """print version and exit on --version""" + self.assertRaises( + SystemExit, + self._test_options, + options=['--version']) + def test_set_boolean_in_cli(self): """set boolean options in CLI options.""" # passing the option yields the reverse of the default, no diff --git a/testsuite/common.py b/testsuite/common.py index a86e9c5d9..4b29e5f52 100644 --- a/testsuite/common.py +++ b/testsuite/common.py @@ -16,9 +16,9 @@ import lxml.etree import Bcfg2.Options from mock import patch, MagicMock, _patch, DEFAULT try: - from unittest import skip, skipIf, skipUnless, TestCase -except ImportError: from unittest2 import skip, skipIf, skipUnless, TestCase +except ImportError: + from unittest import skip, skipIf, skipUnless, TestCase #: The XInclude namespace name XI_NAMESPACE = "http://www.w3.org/2001/XInclude" |