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/Core.py') 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 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/Core.py') 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/Core.py') 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/Core.py') 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 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/Core.py') 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 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/Core.py') 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 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/Core.py') 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