From 3ac796ffdd6777814e85cf8cffdb1c733c69feb0 Mon Sep 17 00:00:00 2001 From: Dan Foster Date: Sun, 29 Dec 2013 17:01:08 +0000 Subject: Reset essential package list to an empty set when Packages is refreshed --- src/lib/Bcfg2/Server/Plugins/Packages/Apt.py | 1 + 1 file changed, 1 insertion(+) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py b/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py index a82a183d8..27a725f23 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Apt.py @@ -77,6 +77,7 @@ class AptSource(Source): def read_files(self): bdeps = dict() bprov = dict() + self.essentialpkgs = set() depfnames = ['Depends', 'Pre-Depends'] if self.recommended: depfnames.append('Recommends') -- cgit v1.2.3-1-g7c22 From 334d210d6be5b262578e8b60e722647a25e799be Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 31 Dec 2013 14:10:24 -0500 Subject: bcfg2-lint: expand wildcard xincludes when validating XML --- src/lib/Bcfg2/Server/Lint/Validate.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Lint/Validate.py b/src/lib/Bcfg2/Server/Lint/Validate.py index ced16770b..3efcc890d 100644 --- a/src/lib/Bcfg2/Server/Lint/Validate.py +++ b/src/lib/Bcfg2/Server/Lint/Validate.py @@ -84,6 +84,7 @@ class Validate(Bcfg2.Server.Lint.ServerlessPlugin): "xml-failed-to-parse": "error", "xml-failed-to-read": "error", "xml-failed-to-verify": "error", + "xinclude-does-not-exist": "error", "input-output-error": "error"} def check_properties(self): @@ -109,6 +110,7 @@ class Validate(Bcfg2.Server.Lint.ServerlessPlugin): try: xdata = lxml.etree.parse(filename) if self.files is None: + self._expand_wildcard_xincludes(xdata) xdata.xinclude() return xdata except (lxml.etree.XIncludeError, SyntaxError): @@ -127,6 +129,33 @@ class Validate(Bcfg2.Server.Lint.ServerlessPlugin): "Failed to open file %s" % filename) return False + def _expand_wildcard_xincludes(self, xdata): + """ a lightweight version of + :func:`Bcfg2.Server.Plugin.helpers.XMLFileBacked._follow_xincludes` """ + xinclude = '%sinclude' % Bcfg2.Server.XI_NAMESPACE + for el in xdata.findall('//' + xinclude): + name = el.get("href") + if name.startswith("/"): + fpath = name + else: + fpath = os.path.join(os.path.dirname(xdata.docinfo.URL), name) + + # expand globs in xinclude, a bcfg2-specific extension + extras = glob.glob(fpath) + if not extras: + msg = "%s: %s does not exist, skipping: %s" % \ + (xdata.docinfo.URL, name, self.RenderXML(el)) + if el.findall('./%sfallback' % Bcfg2.Server.XI_NAMESPACE): + self.logger.debug(msg) + else: + self.LintError("xinclude-does-not-exist", msg) + + parent = el.getparent() + parent.remove(el) + for extra in extras: + if extra != xdata.docinfo.URL: + lxml.etree.SubElement(parent, xinclude, href=extra) + def validate(self, filename, schemafile, schema=None): """ Validate a file against the given schema. -- cgit v1.2.3-1-g7c22 From e3e1936fedb8d5845c576124c46677c90ca7fff2 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 16 Jan 2014 10:36:49 -0500 Subject: FAM: Get full traceback when event handling errors --- src/lib/Bcfg2/Server/FileMonitor/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/FileMonitor/__init__.py b/src/lib/Bcfg2/Server/FileMonitor/__init__.py index e430e3160..52c3906fa 100644 --- a/src/lib/Bcfg2/Server/FileMonitor/__init__.py +++ b/src/lib/Bcfg2/Server/FileMonitor/__init__.py @@ -237,7 +237,8 @@ class FileMonitor(Debuggable): except: # pylint: disable=W0702 err = sys.exc_info()[1] LOGGER.error("Error in handling of event %s for %s: %s" % - (event.code2str(), event.filename, err)) + (event.code2str(), event.filename, err), + exc_info=1) def handle_event_set(self, lock=None): """ Handle all pending events. -- cgit v1.2.3-1-g7c22 From 2defc9cf5155f21a988855c31049fad3e40ecdd1 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 29 Jan 2014 07:43:06 -0500 Subject: load correct JSON library on py2.4 --- src/lib/Bcfg2/Server/Lint/ValidateJSON.py | 3 ++- src/lib/Bcfg2/Server/Plugins/Ohai.py | 3 ++- src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 3 ++- src/lib/Bcfg2/Server/Plugins/Probes.py | 3 ++- src/lib/Bcfg2/Server/Plugins/Properties.py | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Lint/ValidateJSON.py b/src/lib/Bcfg2/Server/Lint/ValidateJSON.py index c4a82a5d2..31bbadeb2 100644 --- a/src/lib/Bcfg2/Server/Lint/ValidateJSON.py +++ b/src/lib/Bcfg2/Server/Lint/ValidateJSON.py @@ -10,7 +10,8 @@ import Bcfg2.Server.Lint try: import json -except ImportError: + json.loads # py2.4 json library is structured differently +except (ImportError, AttributeError): import simplejson as json diff --git a/src/lib/Bcfg2/Server/Plugins/Ohai.py b/src/lib/Bcfg2/Server/Plugins/Ohai.py index 1ec3cbd60..f5bde1820 100644 --- a/src/lib/Bcfg2/Server/Plugins/Ohai.py +++ b/src/lib/Bcfg2/Server/Plugins/Ohai.py @@ -10,7 +10,8 @@ import Bcfg2.Server.Plugin try: import json -except ImportError: + json.loads # py2.4 json library is structured differently +except (ImportError, AttributeError): import simplejson as json PROBECODE = """#!/bin/sh diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index 66f8e9dbe..43a54471c 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -87,7 +87,8 @@ try: import yum try: import json - except ImportError: + json.loads # py2.4 json library is structured differently + except (ImportError, AttributeError): import simplejson as json HAS_YUM = True except ImportError: diff --git a/src/lib/Bcfg2/Server/Plugins/Probes.py b/src/lib/Bcfg2/Server/Plugins/Probes.py index fdc047283..471ebfdaf 100644 --- a/src/lib/Bcfg2/Server/Plugins/Probes.py +++ b/src/lib/Bcfg2/Server/Plugins/Probes.py @@ -34,8 +34,9 @@ except ImportError: try: import json + json.loads # py2.4 json library is structured differently HAS_JSON = True -except ImportError: +except (ImportError, AttributeError): try: import simplejson as json HAS_JSON = True diff --git a/src/lib/Bcfg2/Server/Plugins/Properties.py b/src/lib/Bcfg2/Server/Plugins/Properties.py index 89f2d21ff..b6090c4d1 100644 --- a/src/lib/Bcfg2/Server/Plugins/Properties.py +++ b/src/lib/Bcfg2/Server/Plugins/Properties.py @@ -17,8 +17,9 @@ except ImportError: try: import json + json.loads # py2.4 json library is structured differently HAS_JSON = True -except ImportError: +except (ImportError, AttributeError): try: import simplejson as json HAS_JSON = True -- cgit v1.2.3-1-g7c22 From 8ac001a3dffebf8e7d3fa7db20f13e58b90dd5b4 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 30 Jan 2014 07:30:18 -0500 Subject: fixed pylint tests --- src/lib/Bcfg2/Server/Lint/ValidateJSON.py | 3 ++- src/lib/Bcfg2/Server/Plugins/Ohai.py | 3 ++- src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 3 ++- src/lib/Bcfg2/Server/Plugins/Probes.py | 3 ++- src/lib/Bcfg2/Server/Plugins/Properties.py | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Lint/ValidateJSON.py b/src/lib/Bcfg2/Server/Lint/ValidateJSON.py index 31bbadeb2..1f55962eb 100644 --- a/src/lib/Bcfg2/Server/Lint/ValidateJSON.py +++ b/src/lib/Bcfg2/Server/Lint/ValidateJSON.py @@ -10,7 +10,8 @@ import Bcfg2.Server.Lint try: import json - json.loads # py2.4 json library is structured differently + # py2.4 json library is structured differently + json.loads # pylint: disable=W0104 except (ImportError, AttributeError): import simplejson as json diff --git a/src/lib/Bcfg2/Server/Plugins/Ohai.py b/src/lib/Bcfg2/Server/Plugins/Ohai.py index f5bde1820..0853ea993 100644 --- a/src/lib/Bcfg2/Server/Plugins/Ohai.py +++ b/src/lib/Bcfg2/Server/Plugins/Ohai.py @@ -10,7 +10,8 @@ import Bcfg2.Server.Plugin try: import json - json.loads # py2.4 json library is structured differently + # py2.4 json library is structured differently + json.loads # pylint: disable=W0104 except (ImportError, AttributeError): import simplejson as json diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index 43a54471c..f038ec9c0 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -87,7 +87,8 @@ try: import yum try: import json - json.loads # py2.4 json library is structured differently + # py2.4 json library is structured differently + json.loads # pylint: disable=W0104 except (ImportError, AttributeError): import simplejson as json HAS_YUM = True diff --git a/src/lib/Bcfg2/Server/Plugins/Probes.py b/src/lib/Bcfg2/Server/Plugins/Probes.py index 471ebfdaf..48be1ac26 100644 --- a/src/lib/Bcfg2/Server/Plugins/Probes.py +++ b/src/lib/Bcfg2/Server/Plugins/Probes.py @@ -34,7 +34,8 @@ except ImportError: try: import json - json.loads # py2.4 json library is structured differently + # py2.4 json library is structured differently + json.loads # pylint: disable=W0104 HAS_JSON = True except (ImportError, AttributeError): try: diff --git a/src/lib/Bcfg2/Server/Plugins/Properties.py b/src/lib/Bcfg2/Server/Plugins/Properties.py index b6090c4d1..8c6cf799a 100644 --- a/src/lib/Bcfg2/Server/Plugins/Properties.py +++ b/src/lib/Bcfg2/Server/Plugins/Properties.py @@ -17,7 +17,8 @@ except ImportError: try: import json - json.loads # py2.4 json library is structured differently + # py2.4 json library is structured differently + json.loads # pylint: disable=W0104 HAS_JSON = True except (ImportError, AttributeError): try: -- cgit v1.2.3-1-g7c22 From ea25166d42aaf5d8a48ef7a172a3f8e1f87767d9 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 31 Jan 2014 14:39:33 -0500 Subject: Metadata: fix check for Groups with options in duplicate groups test --- src/lib/Bcfg2/Server/Plugins/Metadata.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py index 343e14162..f734c98d0 100644 --- a/src/lib/Bcfg2/Server/Plugins/Metadata.py +++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py @@ -1657,8 +1657,8 @@ class MetadataLint(Bcfg2.Server.Lint.ServerPlugin): "client") def duplicate_groups(self): - """ Check for groups that are defined more than once. There - are two ways this can happen: + """ Check for groups that are defined more than once. There are two + ways this can happen: 1. The group is listed twice with contradictory options. 2. The group is listed with no options *first*, and then with @@ -1674,7 +1674,8 @@ class MetadataLint(Bcfg2.Server.Lint.ServerPlugin): grpname = grp.get("name") if grpname in duplicates: duplicates[grpname].append(grp) - elif len(grp.attrib) > 1: # group has options + elif set(grp.attrib.keys()).difference(['negate', 'name']): + # group has options if grpname in groups: duplicates[grpname] = [grp, groups[grpname]] else: -- cgit v1.2.3-1-g7c22 From 5ca328cf8a4eb4f82b134b292c858fe9f20d4548 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 13 Feb 2014 07:40:59 -0500 Subject: Core: explicitly close database connections at the end of each client run --- src/lib/Bcfg2/Server/Core.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index c2cf6b7a4..587afefe0 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -726,6 +726,11 @@ class BaseCore(object): self.validate_goals(meta, config) self.client_run_hook("end_client_run", meta) + if self._database_available: + from django import db + self.logger.debug("%s: Closing database connection" % + threading.current_thread().name) + db.close_connection() sort_xml(config, key=lambda e: e.get('name')) -- cgit v1.2.3-1-g7c22 From 9ac25c247afc348c90197f33039c066d2a9d4247 Mon Sep 17 00:00:00 2001 From: Richard Connon Date: Fri, 14 Feb 2014 12:04:43 +0000 Subject: Lint checking for invalid default ACLs --- src/lib/Bcfg2/Server/Lint/RequiredAttrs.py | 33 +++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py b/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py index e49779a10..77934d720 100644 --- a/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py +++ b/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py @@ -119,6 +119,7 @@ class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin): POSIXUser={None: dict(name=is_username)}) def Run(self): + self.check_default_acls() self.check_packages() if "Defaults" in self.core.plugins: self.logger.info("Defaults plugin enabled; skipping required " @@ -129,12 +130,42 @@ class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin): @classmethod def Errors(cls): - return {"unknown-entry-type": "error", + return {"missing-elements": "error", + "unknown-entry-type": "error", "unknown-entry-tag": "error", "required-attrs-missing": "error", "required-attr-format": "error", "extra-attrs": "warning"} + def check_default_acls(self): + """ Check Path entries have valid default ACLs """ + def check_acl(path): + """ Check that a default ACL contains either no entries or minimum + required entries """ + defaults = 1 if len(path.xpath( + "/ACL[@type='default' and @scope='user']")) else 0 + defaults += 1 if len(path.xpath( + "/ACL[@type='default' and @scope='user']")) else 0 + defaults += 1 if len(path.xpath( + "/ACL[@type='default' and @scope='user']")) else 0 + if defaults > 0 and defaults < 3: + self.LintError( + "missing-elements", + "A Path must have either no default ACLs or at" + " least default:user::, default:group:: and" + " default:other::") + + if 'Bundler' in self.core.plugins: + for bundle in self.core.plugins['Bundler'].entries.values(): + xdata = bundle.pnode.data + for path in xdata.xpath("//BoundPath"): + check_acl(path) + if 'Rules' in self.core.plugins: + for rules in self.core.plugins['Rules'].entries.values(): + xdata = rules.pnode.data + for path in xdata.xpath("//Path"): + check_acl(path) + def check_packages(self): """ Check Packages sources for Source entries with missing attributes. """ -- cgit v1.2.3-1-g7c22 From 06bc91f8a8c919e5e552f46386841a75fcc3619a Mon Sep 17 00:00:00 2001 From: Richard Connon Date: Fri, 14 Feb 2014 12:10:04 +0000 Subject: Correct XML source for bundles in default ACL Lint --- src/lib/Bcfg2/Server/Lint/RequiredAttrs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py b/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py index 77934d720..fce90154e 100644 --- a/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py +++ b/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py @@ -157,7 +157,7 @@ class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin): if 'Bundler' in self.core.plugins: for bundle in self.core.plugins['Bundler'].entries.values(): - xdata = bundle.pnode.data + xdata = lxml.etree.XML(bundle.data) for path in xdata.xpath("//BoundPath"): check_acl(path) if 'Rules' in self.core.plugins: -- cgit v1.2.3-1-g7c22 From e4b2b05de382743883ee613236d4647c588d811d Mon Sep 17 00:00:00 2001 From: Richard Connon Date: Fri, 14 Feb 2014 23:29:48 +0000 Subject: Working lint check for invalid default ACLs --- src/lib/Bcfg2/Server/Lint/RequiredAttrs.py | 47 ++++++++++++------------------ 1 file changed, 18 insertions(+), 29 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py b/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py index fce90154e..bb0d6956a 100644 --- a/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py +++ b/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py @@ -119,7 +119,6 @@ class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin): POSIXUser={None: dict(name=is_username)}) def Run(self): - self.check_default_acls() self.check_packages() if "Defaults" in self.core.plugins: self.logger.info("Defaults plugin enabled; skipping required " @@ -137,34 +136,21 @@ class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin): "required-attr-format": "error", "extra-attrs": "warning"} - def check_default_acls(self): - """ Check Path entries have valid default ACLs """ - def check_acl(path): - """ Check that a default ACL contains either no entries or minimum - required entries """ - defaults = 1 if len(path.xpath( - "/ACL[@type='default' and @scope='user']")) else 0 - defaults += 1 if len(path.xpath( - "/ACL[@type='default' and @scope='user']")) else 0 - defaults += 1 if len(path.xpath( - "/ACL[@type='default' and @scope='user']")) else 0 - if defaults > 0 and defaults < 3: - self.LintError( - "missing-elements", - "A Path must have either no default ACLs or at" - " least default:user::, default:group:: and" - " default:other::") - - if 'Bundler' in self.core.plugins: - for bundle in self.core.plugins['Bundler'].entries.values(): - xdata = lxml.etree.XML(bundle.data) - for path in xdata.xpath("//BoundPath"): - check_acl(path) - if 'Rules' in self.core.plugins: - for rules in self.core.plugins['Rules'].entries.values(): - xdata = rules.pnode.data - for path in xdata.xpath("//Path"): - check_acl(path) + def check_default_acl(self, path): + """ Check that a default ACL contains either no entries or minimum + required entries """ + defaults = 1 if path.xpath( + "ACL[@type='default' and @scope='user' and @user='']") else 0 + defaults += 1 if path.xpath( + "ACL[@type='default' and @scope='group' and @group='']") else 0 + defaults += 1 if path.xpath( + "ACL[@type='default' and @scope='other']") else 0 + if defaults > 0 and defaults < 3: + self.LintError( + "missing-elements", + "A Path must have either no default ACLs or at" + " least default:user::, default:group:: and" + " default:other::") def check_packages(self): """ Check Packages sources for Source entries with missing @@ -265,6 +251,9 @@ class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin): required_attrs['major'] = is_device_mode required_attrs['minor'] = is_device_mode + if tag == 'Path': + self.check_default_acl(entry) + if tag == 'ACL' and 'scope' in required_attrs: required_attrs[entry.get('scope')] = is_username -- cgit v1.2.3-1-g7c22 From 2de76a7b44c148f2ce9e851060c16513581174ff Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 18 Feb 2014 08:53:35 -0500 Subject: ensure that DB connections are always closed at thread/process exit --- src/lib/Bcfg2/Server/Core.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index 587afefe0..cc9270a17 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -414,7 +414,7 @@ class BaseCore(object): :type plugin: string :returns: None """ - self.logger.debug("Loading plugin %s" % plugin) + self.logger.debug("%s: Loading plugin %s" % (self.name, plugin)) try: mod = getattr(__import__("Bcfg2.Server.Plugins.%s" % (plugin)).Server.Plugins, plugin) @@ -450,14 +450,18 @@ class BaseCore(object): def shutdown(self): """ Perform plugin and FAM shutdown tasks. """ - self.logger.info("Shutting down core...") + self.logger.info("%s: Shutting down core..." % self.name) if not self.terminate.isSet(): self.terminate.set() - self.fam.shutdown() - self.logger.info("FAM shut down") - for plugin in list(self.plugins.values()): - plugin.shutdown() - self.logger.info("All plugins shut down") + self.fam.shutdown() + self.logger.info("%s: FAM shut down" % self.name) + for plugin in list(self.plugins.values()): + plugin.shutdown() + self.logger.info("%s: All plugins shut down" % self.name) + if self._database_available: + from django import db + self.logger.info("%s: Closing database connection" % self.name) + db.close_connection() @property def metadata_cache_mode(self): -- cgit v1.2.3-1-g7c22 From f9efbc106c454bcef4c24708958dedceb56ba242 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 18 Feb 2014 09:16:41 -0500 Subject: Core: add default name for base Core implementation --- src/lib/Bcfg2/Server/Core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index cc9270a17..702b66983 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -1,4 +1,4 @@ -""" Bcfg2.Server.Core provides the base core object that server core +y""" Bcfg2.Server.Core provides the base core object that server core implementations inherit from. """ import os @@ -86,6 +86,7 @@ class BaseCore(object): """ The server core is the container for all Bcfg2 server logic and modules. All core implementations must inherit from ``BaseCore``. """ + name = "core" def __init__(self, setup): # pylint: disable=R0912,R0915 """ -- cgit v1.2.3-1-g7c22 From a9f17d383460d0894e3a101c133be472f300ba94 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 18 Feb 2014 09:32:51 -0500 Subject: Fixed typo. Need coffee. --- src/lib/Bcfg2/Server/Core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index 702b66983..38daa870e 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -1,4 +1,4 @@ -y""" Bcfg2.Server.Core provides the base core object that server core +""" Bcfg2.Server.Core provides the base core object that server core implementations inherit from. """ import os -- cgit v1.2.3-1-g7c22 From 304cf13f4988312a4ec6ac14fff79bc74737e3ee Mon Sep 17 00:00:00 2001 From: Richard Connon Date: Tue, 18 Feb 2014 14:46:49 +0000 Subject: support python 2.4 for default ACL checking in Lint --- src/lib/Bcfg2/Server/Lint/RequiredAttrs.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py b/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py index bb0d6956a..1d12ee461 100644 --- a/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py +++ b/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py @@ -139,12 +139,13 @@ class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin): def check_default_acl(self, path): """ Check that a default ACL contains either no entries or minimum required entries """ - defaults = 1 if path.xpath( - "ACL[@type='default' and @scope='user' and @user='']") else 0 - defaults += 1 if path.xpath( - "ACL[@type='default' and @scope='group' and @group='']") else 0 - defaults += 1 if path.xpath( - "ACL[@type='default' and @scope='other']") else 0 + defaults = 0 + if path.xpath("ACL[@type='default' and @scope='user' and @user='']"): + defaults += 1 + if path.xpath("ACL[@type='default' and @scope='group' and @group='']"): + defaults += 1 + if path.xpath("ACL[@type='default' and @scope='other']"): + defaults += 1 if defaults > 0 and defaults < 3: self.LintError( "missing-elements", -- cgit v1.2.3-1-g7c22 From 92d94a3f6164f74d7ff48703b002e9127d7d7821 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 19 Feb 2014 08:08:28 -0500 Subject: FAM: Only shut down inotify notifier once --- src/lib/Bcfg2/Server/FileMonitor/Inotify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/FileMonitor/Inotify.py b/src/lib/Bcfg2/Server/FileMonitor/Inotify.py index 2cdf27ed8..bce7ce7c2 100644 --- a/src/lib/Bcfg2/Server/FileMonitor/Inotify.py +++ b/src/lib/Bcfg2/Server/FileMonitor/Inotify.py @@ -212,7 +212,7 @@ class Inotify(Pseudo, pyinotify.ProcessEvent): AddMonitor.__doc__ = Pseudo.AddMonitor.__doc__ def shutdown(self): - if self.notifier: + if self.started and self.notifier: self.notifier.stop() shutdown.__doc__ = Pseudo.shutdown.__doc__ -- cgit v1.2.3-1-g7c22 From 8a8a47998438707f988838b505b98b99a11ce687 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 19 Feb 2014 08:08:37 -0500 Subject: core: only shut down core once --- src/lib/Bcfg2/Server/Core.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index 38daa870e..03bc7bff4 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -189,6 +189,12 @@ class BaseCore(object): self.setup = setup atexit.register(self.shutdown) + #: if :func:`Bcfg2.Server.Core.shutdown` is called explicitly, + #: then :mod:`atexit` calls it *again*, so it gets called + #: twice. This is potentially bad, so we use + #: :attr:`Bcfg2.Server.Core._running` as a flag to determine + #: if the core needs to be shutdown, and only do it once. + self._running = True #: Threading event to signal worker threads (e.g., #: :attr:`fam_thread`) to shutdown @@ -451,9 +457,13 @@ class BaseCore(object): def shutdown(self): """ Perform plugin and FAM shutdown tasks. """ + if not self._running: + self.logger.debug("%s: Core already shut down" % self.name) + return self.logger.info("%s: Shutting down core..." % self.name) if not self.terminate.isSet(): self.terminate.set() + self._running = False self.fam.shutdown() self.logger.info("%s: FAM shut down" % self.name) for plugin in list(self.plugins.values()): -- cgit v1.2.3-1-g7c22 From 58cee8566fba7b48d127227d96c98549b7db3028 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Mon, 10 Feb 2014 09:24:56 -0500 Subject: testsuite: Fixed several pylint 1.0 issues --- src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 2 +- src/lib/Bcfg2/Server/Plugins/Packages/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index f038ec9c0..7b5475ecc 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -323,7 +323,7 @@ class YumCollection(Collection): self.fam) @property - def disableMetaData(self): + def disableMetaData(self): # pylint: disable=C0103 """ Report whether or not metadata processing is enabled. This duplicates code in Packages/__init__.py, and can probably be removed in Bcfg2 1.4 when we have a module-level setup diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py index 479138ef1..4b58c0fdb 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py @@ -188,7 +188,7 @@ class Packages(Bcfg2.Server.Plugin.Plugin, set_debug.__doc__ = Bcfg2.Server.Plugin.Plugin.set_debug.__doc__ @property - def disableResolver(self): + def disableResolver(self): # pylint: disable=C0103 """ Report the state of the resolver. This can be disabled in the configuration. Note that disabling metadata (see :attr:`disableMetaData`) implies disabling the resolver. @@ -213,7 +213,7 @@ class Packages(Bcfg2.Server.Plugin.Plugin, default="enabled").lower() == "disabled" @property - def disableMetaData(self): + def disableMetaData(self): # pylint: disable=C0103 """ Report whether or not metadata processing is enabled. This property cannot be set. """ -- cgit v1.2.3-1-g7c22 From c9e234dc15b527c930bbb5a1e7e0e7d9212168b1 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 21 Feb 2014 08:39:18 -0500 Subject: Yum: only fork to find bcfg2-yum-helper once, for real --- src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index 7b5475ecc..71c6d003c 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -354,7 +354,7 @@ class YumCollection(Collection): a call to it; I wish there was a way to do this without forking, but apparently not); finally we check in /usr/sbin, the default location. """ - if not self._helper: + if not self.__class___helper: # pylint: disable=W0212 try: self.__class__._helper = self.setup.cfp.get("packages:yum", @@ -368,7 +368,7 @@ class YumCollection(Collection): except OSError: self.__class__._helper = "/usr/sbin/bcfg2-yum-helper" # pylint: enable=W0212 - return self._helper + return self.__class__._helper @property def use_yum(self): -- cgit v1.2.3-1-g7c22 From 673c947a552ab601b159e7a95e3506870d837328 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 21 Feb 2014 08:53:09 -0500 Subject: Yum: fix pylint tests --- src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index 71c6d003c..a149ccfe2 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -354,8 +354,8 @@ class YumCollection(Collection): a call to it; I wish there was a way to do this without forking, but apparently not); finally we check in /usr/sbin, the default location. """ + # pylint: disable=W0212 if not self.__class___helper: - # pylint: disable=W0212 try: self.__class__._helper = self.setup.cfp.get("packages:yum", "helper") @@ -367,8 +367,8 @@ class YumCollection(Collection): self.__class__._helper = 'bcfg2-yum-helper' except OSError: self.__class__._helper = "/usr/sbin/bcfg2-yum-helper" - # pylint: enable=W0212 return self.__class__._helper + # pylint: enable=W0212 @property def use_yum(self): -- cgit v1.2.3-1-g7c22 From 9d12865d7598544bbbe2bb4b40c085c101b3d42e Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 21 Feb 2014 09:09:51 -0500 Subject: Fixed typo Note to self: do not push code before 9 am --- src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index a149ccfe2..67ff05ca1 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -355,7 +355,7 @@ class YumCollection(Collection): forking, but apparently not); finally we check in /usr/sbin, the default location. """ # pylint: disable=W0212 - if not self.__class___helper: + if not self.__class__._helper: try: self.__class__._helper = self.setup.cfp.get("packages:yum", "helper") -- cgit v1.2.3-1-g7c22 From c6a1de59fbd49b3e1b24a7fb4e55f109e8a54e2e Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Sun, 23 Feb 2014 15:55:03 -0500 Subject: Metadata: reread client list from database This fixes two related bugs: One causes Metadata to use an out-of-date cached list of clients when a client is deleted or added with bcfg2-admin; the other causes child worker processes to use an out-of-date cached list of clients when a client is added with a Bcfg2 run when the multiprocessing core is in use. --- src/lib/Bcfg2/Server/MultiprocessingCore.py | 1 + src/lib/Bcfg2/Server/Plugin/interfaces.py | 4 +++ src/lib/Bcfg2/Server/Plugins/Metadata.py | 41 +++++++++++++++++++++++++---- 3 files changed, 41 insertions(+), 5 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/MultiprocessingCore.py b/src/lib/Bcfg2/Server/MultiprocessingCore.py index 6d41bbcbb..2cb3adae3 100644 --- a/src/lib/Bcfg2/Server/MultiprocessingCore.py +++ b/src/lib/Bcfg2/Server/MultiprocessingCore.py @@ -303,6 +303,7 @@ class ChildCore(BaseCore): @exposed def GetConfig(self, client): """ Render the configuration for a client """ + self.metadata.update_client_list() self.logger.debug("%s: Building configuration for %s" % (self.name, client)) return lxml.etree.tostring(self.BuildConfiguration(client)) diff --git a/src/lib/Bcfg2/Server/Plugin/interfaces.py b/src/lib/Bcfg2/Server/Plugin/interfaces.py index 33f6d338c..07717a710 100644 --- a/src/lib/Bcfg2/Server/Plugin/interfaces.py +++ b/src/lib/Bcfg2/Server/Plugin/interfaces.py @@ -213,6 +213,10 @@ class Metadata(object): """ raise NotImplementedError + def update_client_list(self): + """ Re-read the cached list of clients """ + raise NotImplementedError + class Connector(object): """ Connector plugins augment client metadata instances with diff --git a/src/lib/Bcfg2/Server/Plugins/Metadata.py b/src/lib/Bcfg2/Server/Plugins/Metadata.py index f734c98d0..d6febcff6 100644 --- a/src/lib/Bcfg2/Server/Plugins/Metadata.py +++ b/src/lib/Bcfg2/Server/Plugins/Metadata.py @@ -668,7 +668,7 @@ class Metadata(Bcfg2.Server.Plugin.Metadata, except MetadataClientModel.DoesNotExist: client = MetadataClientModel(hostname=client_name) client.save() - self.clients = self.list_clients() + self.update_client_list() return client else: try: @@ -721,7 +721,15 @@ class Metadata(Bcfg2.Server.Plugin.Metadata, attribs, alias=True) def list_clients(self): - """ List all clients in client database """ + """ List all clients in client database. + + Making ``self.clients`` a property and reading the client list + dynamically from the database on every call to + ``self.clients`` can result in very high rates of database + reads, so we cache the ``list_clients()`` results to reduce + the database load. When the database is in use, the client + list is reread periodically with + :func:`Bcfg2.Server.Plugins.Metadata.update_client_list`. """ if self._use_db: return set([c.hostname for c in MetadataClientModel.objects.all()]) else: @@ -772,7 +780,7 @@ class Metadata(Bcfg2.Server.Plugin.Metadata, self.logger.warning(msg) raise Bcfg2.Server.Plugin.MetadataConsistencyError(msg) client.delete() - self.clients = self.list_clients() + self.update_client_list() else: return self._remove_xdata(self.clients_xml, "Client", client_name) @@ -841,8 +849,7 @@ class Metadata(Bcfg2.Server.Plugin.Metadata, except KeyError: self.clientgroups[clname] = [profile] self.states['clients.xml'] = True - if self._use_db: - self.clients = self.list_clients() + self.update_client_list() def _get_condition(self, element): """ Return a predicate that returns True if a client meets @@ -1434,6 +1441,30 @@ class Metadata(Bcfg2.Server.Plugin.Metadata, return True # pylint: enable=R0911,R0912 + def update_client_list(self): + """ Re-read the client list from the database (if the database is in + use) """ + if self._use_db: + self.logger.debug("Metadata: Re-reading client list from database") + old = set(self.clients) + self.clients = self.list_clients() + new = set(self.clients) + added = new - old + removed = old - new + self.logger.debug("Metadata: Added %s clients: %s" % + (len(added), added)) + self.logger.debug("Metadata: Removed %s clients: %s" % + (len(removed), removed)) + # we could do this with set.symmetric_difference(), but we + # want detailed numbers of added/removed clients for + # logging + for client in added.union(removed): + self.expire_cache(client) + + def start_client_run(self, metadata): + """ Hook to reread client list if the database is in use """ + self.update_client_list() + def end_statistics(self, metadata): """ Hook to toggle clients in bootstrap mode """ if self.auth.get(metadata.hostname, -- cgit v1.2.3-1-g7c22 From 1f0515a25551eee4dce6af96210aef8f6fdc0e8c Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Sun, 23 Feb 2014 23:54:28 -0500 Subject: bcfg2-lint: Verify abstract Package tags --- src/lib/Bcfg2/Server/Lint/RequiredAttrs.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py b/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py index 1d12ee461..ce8b237b9 100644 --- a/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py +++ b/src/lib/Bcfg2/Server/Lint/RequiredAttrs.py @@ -214,6 +214,16 @@ class RequiredAttrs(Bcfg2.Server.Lint.ServerPlugin): xdata.xpath("//*[substring(name(), 1, 5) = 'Bound']"): self.check_entry(path, bundle.name) + # ensure that abstract Package tags have either name + # or group specified + for package in xdata.xpath("//Package"): + if ('name' not in package.attrib and + 'group' not in package.attrib): + self.LintError( + "required-attrs-missing", + "Package tags require either a 'name' or 'group' " + "attribute: \n%s" % self.RenderXML(package)) + def check_entry(self, entry, filename): """ Generic entry check. -- cgit v1.2.3-1-g7c22 From 7f93c994854fb6876a4008baf172cdb432eed612 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 25 Feb 2014 14:08:56 -0500 Subject: helpers: better error message when failing to read FileBacked --- src/lib/Bcfg2/Server/Plugin/helpers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 3e7d68cd8..de02adc4e 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -1145,7 +1145,8 @@ class SpecificData(object): except UnicodeDecodeError: self.data = open(self.name, mode='rb').read() except: # pylint: disable=W0201 - LOGGER.error("Failed to read file %s" % self.name) + LOGGER.error("Failed to read file %s: %s" % (self.name, + sys.exc_info()[1])) class EntrySet(Debuggable): -- cgit v1.2.3-1-g7c22 From a6ae7149bd9ba423fb55eacc6eb8f0c1f49c2dc7 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Mon, 3 Mar 2014 09:03:46 -0500 Subject: Core: close all database connections at the end of XML-RPC requests --- src/lib/Bcfg2/Server/Core.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index 03bc7bff4..a8069ff1b 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -18,7 +18,7 @@ import Bcfg2.Server.FileMonitor from Bcfg2.Cache import Cache import Bcfg2.Statistics from itertools import chain -from Bcfg2.Compat import xmlrpclib # pylint: disable=W0622 +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 @@ -67,6 +67,24 @@ def sort_xml(node, key=None): node[:] = sorted_children +def close_db_connection(func): + """ Decorator that closes the Django database connection at the end of + the function. This should decorate any exposed function that + might open a database connection. """ + @wraps(func) + def inner(self, *args, **kwargs): + """ The decorated function """ + rv = func(self, *args, **kwargs) + if self._database_available: # pylint: disable=W0212 + from django import db + self.logger.debug("%s: Closing database connection" % + threading.current_thread().name) + db.close_connection() + return rv + + return inner + + class CoreInitError(Exception): """ Raised when the server core cannot be initialized. """ pass @@ -741,11 +759,6 @@ class BaseCore(object): self.validate_goals(meta, config) self.client_run_hook("end_client_run", meta) - if self._database_available: - from django import db - self.logger.debug("%s: Closing database connection" % - threading.current_thread().name) - db.close_connection() sort_xml(config, key=lambda e: e.get('name')) @@ -1089,6 +1102,7 @@ class BaseCore(object): @exposed @track_statistics() + @close_db_connection def DeclareVersion(self, address, version): """ Declare the client version. @@ -1111,6 +1125,7 @@ class BaseCore(object): return True @exposed + @close_db_connection def GetProbes(self, address): """ Fetch probes for the client. @@ -1136,6 +1151,7 @@ class BaseCore(object): (client, err)) @exposed + @close_db_connection def RecvProbeData(self, address, probedata): """ Receive probe data from clients. @@ -1183,6 +1199,7 @@ class BaseCore(object): return True @exposed + @close_db_connection def AssertProfile(self, address, profile): """ Set profile for a client. @@ -1202,6 +1219,7 @@ class BaseCore(object): return True @exposed + @close_db_connection def GetConfig(self, address): """ Build config for a client by calling :func:`BuildConfiguration`. @@ -1221,6 +1239,7 @@ class BaseCore(object): self.critical_error("Metadata consistency failure for %s" % client) @exposed + @close_db_connection def RecvStats(self, address, stats): """ Act on statistics upload with :func:`process_statistics`. @@ -1258,6 +1277,7 @@ class BaseCore(object): address) @exposed + @close_db_connection def GetDecisionList(self, address, mode): """ Get the decision list for the client with :func:`GetDecisions`. -- cgit v1.2.3-1-g7c22 From b1b2b53f484d266089d9f043042729e29245382a Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Mon, 3 Mar 2014 09:33:57 -0500 Subject: cleared pylint error on PluginDatabaseModel metadata options --- src/lib/Bcfg2/Server/Plugin/helpers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index de02adc4e..170af50ac 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -199,7 +199,8 @@ class PluginDatabaseModel(object): inherit from. This is just a mixin; models must also inherit from django.db.models.Model to be valid Django models.""" - class Meta: # pylint: disable=C0111,W0232 + class Meta(object): # pylint: disable=W0232 + """ Model metadata options """ app_label = "Server" -- cgit v1.2.3-1-g7c22 From 16072ab1b2c3785b7a35c54b1f28a7142563330b Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Fri, 14 Mar 2014 09:46:03 -0400 Subject: Core: better error messages when altsrc bind fails --- src/lib/Bcfg2/Server/Core.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/lib/Bcfg2/Server') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index a8069ff1b..4375512e9 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -681,9 +681,10 @@ class BaseCore(object): del entry.attrib['realname'] return ret except: - self.logger.error("Failed binding entry %s:%s with altsrc %s" % - (entry.tag, entry.get('realname'), - entry.get('name'))) + self.logger.error( + "Failed binding entry %s:%s with altsrc %s: %s" % + (entry.tag, entry.get('realname'), entry.get('name'), + sys.exc_info()[1])) entry.set('name', oldname) self.logger.error("Falling back to %s:%s" % (entry.tag, entry.get('name'))) -- cgit v1.2.3-1-g7c22