summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSol Jerome <sol.jerome@gmail.com>2015-01-03 13:07:14 -0600
committerSol Jerome <sol.jerome@gmail.com>2015-01-03 13:07:14 -0600
commit99f7a6addbad7c7f4bc4e1bcb5238f039e1c5692 (patch)
tree852aa12fe61fb9559f3888fed7b1bf234de6b9e9 /src
parent128efd62c9acf84c54f071043e1ea954da3361dd (diff)
parentd4ae5e04739d9a8e0732dd35ee28c14b0ff96957 (diff)
downloadbcfg2-99f7a6addbad7c7f4bc4e1bcb5238f039e1c5692.tar.gz
bcfg2-99f7a6addbad7c7f4bc4e1bcb5238f039e1c5692.tar.bz2
bcfg2-99f7a6addbad7c7f4bc4e1bcb5238f039e1c5692.zip
Merge branch 'bundle-modification-deps' of https://github.com/AlexanderS/bcfg2
Conflicts: src/lib/Bcfg2/Client/__init__.py
Diffstat (limited to 'src')
-rw-r--r--src/lib/Bcfg2/Client/Tools/BundleDeps.py34
-rw-r--r--src/lib/Bcfg2/Client/__init__.py59
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Bundler.py28
3 files changed, 105 insertions, 16 deletions
diff --git a/src/lib/Bcfg2/Client/Tools/BundleDeps.py b/src/lib/Bcfg2/Client/Tools/BundleDeps.py
new file mode 100644
index 000000000..aaa090633
--- /dev/null
+++ b/src/lib/Bcfg2/Client/Tools/BundleDeps.py
@@ -0,0 +1,34 @@
+""" Bundle dependency support """
+
+import Bcfg2.Client.Tools
+
+
+class BundleDeps(Bcfg2.Client.Tools.Tool):
+ """Bundle dependency helper for Bcfg2. It handles Bundle tags inside the
+ bundles that references the required other bundles that should change the
+ modification status if the referenced bundles is modified."""
+
+ name = 'Bundle'
+ __handles__ = [('Bundle', None)]
+ __req__ = {'Bundle': ['name']}
+
+ def InstallBundle(self, _):
+ """Simple no-op because we only need the BundleUpdated hook."""
+ return dict()
+
+ def VerifyBundle(self, entry, _): # pylint: disable=W0613
+ """Simple no-op because we only need the BundleUpdated hook."""
+ return True
+
+ def BundleUpdated(self, entry):
+ """This handles the dependencies on this bundle. It searches all
+ Bundle tags in other bundles that references the current bundle name
+ and marks those tags as modified to trigger the modification hook on
+ the other bundles."""
+
+ bundle_name = entry.get('name')
+ for bundle in self.config.findall('./Bundle/Bundle'):
+ if bundle.get('name') == bundle_name and \
+ bundle not in self.modified:
+ self.modified.append(bundle)
+ return dict()
diff --git a/src/lib/Bcfg2/Client/__init__.py b/src/lib/Bcfg2/Client/__init__.py
index e07eef2fb..359d7ac73 100644
--- a/src/lib/Bcfg2/Client/__init__.py
+++ b/src/lib/Bcfg2/Client/__init__.py
@@ -774,29 +774,29 @@ class Client(object):
if not Bcfg2.Options.setup.interactive:
self.DispatchInstallCalls(clobbered)
- for bundle in self.config.findall('.//Bundle'):
+ all_bundles = self.config.findall('./Bundle')
+ mbundles.extend(self._get_all_modified_bundles(mbundles, all_bundles))
+
+ for bundle in all_bundles:
if (Bcfg2.Options.setup.only_bundles and
bundle.get('name') not in
Bcfg2.Options.setup.only_bundles):
# prune out unspecified bundles when running with -b
continue
if bundle in mbundles:
- self.logger.debug("Bundle %s was modified" %
- bundle.get('name'))
- func = "BundleUpdated"
- else:
- self.logger.debug("Bundle %s was not modified" %
- bundle.get('name'))
- func = "BundleNotUpdated"
+ continue
+
+ self.logger.debug("Bundle %s was not modified" %
+ bundle.get('name'))
for tool in self.tools:
try:
- self.states.update(getattr(tool, func)(bundle))
+ self.states.update(tool.BundleNotUpdated(bundle))
except KeyboardInterrupt:
raise
except: # pylint: disable=W0702
- self.logger.error("%s.%s(%s:%s) call failed:" %
- (tool.name, func, bundle.tag,
- bundle.get("name")), exc_info=1)
+ self.logger.error('%s.BundleNotUpdated(%s:%s) call failed:'
+ % (tool.name, bundle.tag,
+ bundle.get('name')), exc_info=1)
for indep in self.config.findall('.//Independent'):
for tool in self.tools:
@@ -809,6 +809,41 @@ class Client(object):
% (tool.name, indep.tag,
indep.get("name")), exc_info=1)
+ def _get_all_modified_bundles(self, mbundles, all_bundles):
+ """This gets all modified bundles by calling BundleUpdated until no
+ new bundles get added to the modification list."""
+ new_mbundles = mbundles
+ add_mbundles = []
+
+ while new_mbundles:
+ for bundle in self.config.findall('./Bundle'):
+ if (Bcfg2.Options.setup.only_bundles and
+ bundle.get('name') not in
+ Bcfg2.Options.setup.only_bundles):
+ # prune out unspecified bundles when running with -b
+ continue
+ if bundle not in new_mbundles:
+ continue
+
+ self.logger.debug('Bundle %s was modified' %
+ bundle.get('name'))
+ for tool in self.tools:
+ try:
+ self.states.update(tool.BundleUpdated(bundle))
+ except: # pylint: disable=W0702
+ self.logger.error('%s.BundleUpdated(%s:%s) call '
+ 'failed:' % (tool.name, bundle.tag,
+ bundle.get("name")),
+ exc_info=1)
+
+ mods = self.modified
+ new_mbundles = [struct for struct in all_bundles
+ if any(True for mod in mods if mod in struct)
+ and struct not in mbundles + add_mbundles]
+ add_mbundles.extend(new_mbundles)
+
+ return add_mbundles
+
def Remove(self):
"""Remove extra entries."""
for tool in self.tools:
diff --git a/src/lib/Bcfg2/Server/Plugins/Bundler.py b/src/lib/Bcfg2/Server/Plugins/Bundler.py
index 41ee57b6d..6c35ada59 100644
--- a/src/lib/Bcfg2/Server/Plugins/Bundler.py
+++ b/src/lib/Bcfg2/Server/Plugins/Bundler.py
@@ -8,6 +8,7 @@ import fnmatch
import lxml.etree
from Bcfg2.Server.Plugin import StructFile, Plugin, Structure, \
StructureValidator, XMLDirectoryBacked, Generator
+from Bcfg2.version import Bcfg2VersionInfo
from genshi.template import TemplateError
@@ -116,17 +117,36 @@ class Bundler(Plugin,
for el in child.getchildren():
data.append(el)
data.remove(child)
- elif child.get("name"):
+ else:
+ # no children -- wat
+ self.logger.warning("Bundler: Useless empty Bundle tag "
+ "in %s" % self.name)
+ data.remove(child)
+
+ for child in data.findall('RequiredBundle'):
+ if child.get("name"):
# dependent bundle -- add it to the list of
# bundles for this client
if child.get("name") not in bundles_added:
bundles.append(child.get("name"))
bundles_added.add(child.get("name"))
+ if child.get('inherit_modification', 'false') == 'true':
+ if metadata.version_info >= \
+ Bcfg2VersionInfo('1.4.0pre2'):
+ lxml.etree.SubElement(data, 'Bundle',
+ name=child.get('name'))
+ else:
+ self.logger.warning(
+ 'Bundler: inherit_modification="true" is '
+ 'only supported for clients starting '
+ '1.4.0pre2')
data.remove(child)
else:
- # neither name or children -- wat
- self.logger.warning("Bundler: Useless empty Bundle tag "
- "in %s" % self.name)
+ # no name -- wat
+ self.logger.warning('Bundler: Missing required name in '
+ 'RequiredBundle tag in %s' %
+ self.name)
data.remove(child)
+
bundleset.append(data)
return bundleset