From 432f448983ff27452d82d62314d91c942f31bce5 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Mon, 25 Mar 2013 11:19:11 -0400 Subject: Packages: properly implemented deepcopy() for PackagesSources objects --- src/lib/Bcfg2/Server/Plugin/helpers.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 0b81077a3..93f690e18 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -1601,3 +1601,36 @@ class GroupSpool(Plugin, Generator): return reqid = self.core.fam.AddMonitor(name, self) self.handles[reqid] = relative + + +class DeepcopyMixin(object): + """ Mixin that adds a __deepcopy__() function that tries to do the + right thing by: + + #. Creating a new object of the same type by calling the + constructor with the arguments returned by + :func:`Bcfg2.Server.Plugin.helpers.DeepcopyMixin._deepcopy_constructor_args`; + #. Individually copying each attribute of the original object that + a) is not magical (``__whatever__``); b) is not callable; c) is + not a property; and d) is not in + :attr:`Bcfg2.Server.Plugin.helpers.DeepcopyMixin._deepcopy_exclude`. + """ + + #: Exclude the named attributes from the copy. + _deepcopy_exclude = ["fam", "logger", "setup"] + + def _deepcopy_constructor_args(self): + """ Get a tuple of arguments that will be passed to the + constructor of this class to create a base object before the + individual attributes are deepcopied. """ + raise NotImplementedError + + def __deepcopy__(self, memo): + rv = self.__class__(*self._deepcopy_constructor_args()) + for attr in dir(self): + if (not callable(getattr(self, attr)) and + (not attr.startswith("__") or not attr.endswith("__")) and + attr not in self._deepcopy_exclude and + not isinstance(getattr(self.__class__, attr, None), property)): + setattr(rv, attr, copy.deepcopy(getattr(self, attr), memo)) + return rv -- cgit v1.2.3-1-g7c22 From 70cc6bb182245d20c54afba79a265ef40f1ed080 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Mon, 25 Mar 2013 11:39:50 -0400 Subject: Revert "Packages: properly implemented deepcopy() for PackagesSources objects" This reverts commit 432f448983ff27452d82d62314d91c942f31bce5. --- src/lib/Bcfg2/Server/Plugin/helpers.py | 33 --------------------------------- 1 file changed, 33 deletions(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 93f690e18..0b81077a3 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -1601,36 +1601,3 @@ class GroupSpool(Plugin, Generator): return reqid = self.core.fam.AddMonitor(name, self) self.handles[reqid] = relative - - -class DeepcopyMixin(object): - """ Mixin that adds a __deepcopy__() function that tries to do the - right thing by: - - #. Creating a new object of the same type by calling the - constructor with the arguments returned by - :func:`Bcfg2.Server.Plugin.helpers.DeepcopyMixin._deepcopy_constructor_args`; - #. Individually copying each attribute of the original object that - a) is not magical (``__whatever__``); b) is not callable; c) is - not a property; and d) is not in - :attr:`Bcfg2.Server.Plugin.helpers.DeepcopyMixin._deepcopy_exclude`. - """ - - #: Exclude the named attributes from the copy. - _deepcopy_exclude = ["fam", "logger", "setup"] - - def _deepcopy_constructor_args(self): - """ Get a tuple of arguments that will be passed to the - constructor of this class to create a base object before the - individual attributes are deepcopied. """ - raise NotImplementedError - - def __deepcopy__(self, memo): - rv = self.__class__(*self._deepcopy_constructor_args()) - for attr in dir(self): - if (not callable(getattr(self, attr)) and - (not attr.startswith("__") or not attr.endswith("__")) and - attr not in self._deepcopy_exclude and - not isinstance(getattr(self.__class__, attr, None), property)): - setattr(rv, attr, copy.deepcopy(getattr(self, attr), memo)) - return rv -- cgit v1.2.3-1-g7c22 From 9c603d8267c0a511968a8a553d7fa0b2d5bf9b73 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Mon, 25 Mar 2013 13:31:21 -0400 Subject: Handle FAM monitor failures more gracefully: * Where possible, create the file or directory that is about to be monitored. This ensures that content can be added later without need to restart Bcfg2. (Otherwise, adding the monitor would fail, and so when you did create the file in question, bcfg2-server would never be notified of it.) * When not possible, give better error messages. --- src/lib/Bcfg2/Server/Plugin/helpers.py | 47 +++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 9 deletions(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 0b81077a3..448d8b3b6 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -193,7 +193,7 @@ class PluginDatabaseModel(object): app_label = "Server" -class FileBacked(object): +class FileBacked(Debuggable): """ This object caches file data in memory. FileBacked objects are principally meant to be used as a part of :class:`Bcfg2.Server.Plugin.helpers.DirectoryBacked`. """ @@ -206,7 +206,7 @@ class FileBacked(object): changes :type fam: Bcfg2.Server.FileMonitor.FileMonitor """ - object.__init__(self) + Debuggable.__init__(self) #: A string containing the raw data in this file self.data = '' @@ -246,7 +246,7 @@ class FileBacked(object): return "%s: %s" % (self.__class__.__name__, self.name) -class DirectoryBacked(object): +class DirectoryBacked(Debuggable): """ DirectoryBacked objects represent a directory that contains files, represented by objects of the type listed in :attr:`__child__`, and other directories recursively. It monitors @@ -280,7 +280,7 @@ class DirectoryBacked(object): .. ----- .. autoattribute:: __child__ """ - object.__init__(self) + Debuggable.__init__(self) self.data = os.path.normpath(data) self.fam = fam @@ -299,8 +299,17 @@ class DirectoryBacked(object): self.handles = {} # Monitor everything in the plugin's directory + if not os.path.exists(self.data): + self.logger.warning("%s does not exist, creating" % self.data) + os.makedirs(self.data) self.add_directory_monitor('') + def set_debug(self, debug): + for entry in self.entries.values(): + if isinstance(entry, Debuggable): + entry.set_debug(debug) + return Debuggable.set_debug(self, debug) + def __getitem__(self, key): return self.entries[key] @@ -459,7 +468,11 @@ class XMLFileBacked(FileBacked): #: behavior, set ``__identifier__`` to ``None``. __identifier__ = 'name' - def __init__(self, filename, fam=None, should_monitor=False): + #: If ``create`` is set, then it overrides the ``create`` argument + #: to the constructor. + create = None + + def __init__(self, filename, fam=None, should_monitor=False, create=None): """ :param filename: The full path to the file to cache and monitor :type filename: string @@ -474,6 +487,13 @@ class XMLFileBacked(FileBacked): :class:`Bcfg2.Server.Plugin.helpers.XMLDirectoryBacked` object). :type should_monitor: bool + :param create: Create the file if it doesn't exist. + ``create`` can be either an + :class:`lxml.etree._Element` object, which will + be used as initial content, or a string, which + will be used as the name of the (empty) tag + that will be the initial content of the file. + :type create: lxml.etree._Element or string .. ----- .. autoattribute:: __identifier__ @@ -497,6 +517,17 @@ class XMLFileBacked(FileBacked): #: "Extra" files included in this file by XInclude. self.extras = [] + if ((create or (self.create is not None and self.create)) + and not os.path.exists(self.name)): + toptag = create or self.create + self.logger.warning("%s does not exist, creating" % self.name) + if hasattr(toptag, "getroottree"): + el = toptag + else: + el = lxml.etree.Element(toptag) + el.getroottree().write(self.name, xml_declaration=False, + pretty_print=True) + #: Whether or not to monitor this file for changes. self.should_monitor = should_monitor if fam and should_monitor: @@ -776,8 +807,8 @@ class XMLSrc(XMLFileBacked): __cacheobj__ = dict __priority_required__ = True - def __init__(self, filename, fam=None, should_monitor=False): - XMLFileBacked.__init__(self, filename, fam, should_monitor) + def __init__(self, filename, fam=None, should_monitor=False, create=None): + XMLFileBacked.__init__(self, filename, fam, should_monitor, create) self.items = {} self.cache = None self.pnode = None @@ -1450,8 +1481,6 @@ class GroupSpool(Plugin, Generator): def __init__(self, core, datastore): Plugin.__init__(self, core, datastore) Generator.__init__(self) - if self.data[-1] == '/': - self.data = self.data[:-1] #: See :class:`Bcfg2.Server.Plugins.interfaces.Generator` for #: details on the Entries attribute. -- cgit v1.2.3-1-g7c22 From 64eec5fe6a9b640bb77dd65f10f3fac5a586347c Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 26 Mar 2013 12:47:14 -0400 Subject: testsuite: fixed issues found by latest version of pep8 --- src/lib/Bcfg2/Server/Plugin/helpers.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 448d8b3b6..bddd0ba20 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -25,15 +25,15 @@ except ImportError: HAS_DJANGO = False #: A dict containing default metadata for Path entries from bcfg2.conf -DEFAULT_FILE_METADATA = Bcfg2.Options.OptionParser(dict( - configfile=Bcfg2.Options.CFILE, - owner=Bcfg2.Options.MDATA_OWNER, - group=Bcfg2.Options.MDATA_GROUP, - mode=Bcfg2.Options.MDATA_MODE, - secontext=Bcfg2.Options.MDATA_SECONTEXT, - important=Bcfg2.Options.MDATA_IMPORTANT, - paranoid=Bcfg2.Options.MDATA_PARANOID, - sensitive=Bcfg2.Options.MDATA_SENSITIVE)) +DEFAULT_FILE_METADATA = Bcfg2.Options.OptionParser( + dict(configfile=Bcfg2.Options.CFILE, + owner=Bcfg2.Options.MDATA_OWNER, + group=Bcfg2.Options.MDATA_GROUP, + mode=Bcfg2.Options.MDATA_MODE, + secontext=Bcfg2.Options.MDATA_SECONTEXT, + important=Bcfg2.Options.MDATA_IMPORTANT, + paranoid=Bcfg2.Options.MDATA_PARANOID, + sensitive=Bcfg2.Options.MDATA_SENSITIVE)) DEFAULT_FILE_METADATA.parse([Bcfg2.Options.CFILE.cmd, Bcfg2.Options.CFILE]) del DEFAULT_FILE_METADATA['args'] del DEFAULT_FILE_METADATA['configfile'] @@ -786,14 +786,14 @@ class InfoNode (INode): Client="lambda m, e: '%(name)s' == m.hostname and predicate(m, e)", Group="lambda m, e: '%(name)s' in m.groups and predicate(m, e)", Path="lambda m, e: ('%(name)s' == e.get('name') or " + - "'%(name)s' == e.get('realname')) and " + - "predicate(m, e)") + "'%(name)s' == e.get('realname')) and " + + "predicate(m, e)") nraw = dict( Client="lambda m, e: '%(name)s' != m.hostname and predicate(m, e)", Group="lambda m, e: '%(name)s' not in m.groups and predicate(m, e)", Path="lambda m, e: '%(name)s' != e.get('name') and " + - "'%(name)s' != e.get('realname') and " + - "predicate(m, e)") + "'%(name)s' != e.get('realname') and " + + "predicate(m, e)") containers = ['Group', 'Client', 'Path'] -- cgit v1.2.3-1-g7c22 From 6c996f42c53a36fc0406f836d64b8c1bec6f4bcc Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 26 Mar 2013 13:27:41 -0400 Subject: testsuite: fixed issues found by latest version of pylint --- src/lib/Bcfg2/Server/Plugin/helpers.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index bddd0ba20..a7cdea879 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -41,15 +41,15 @@ del DEFAULT_FILE_METADATA['configfile'] LOGGER = logging.getLogger(__name__) #: a compiled regular expression for parsing info and :info files -INFO_REGEX = re.compile('owner:(\s)*(?P\S+)|' + - 'group:(\s)*(?P\S+)|' + - 'mode:(\s)*(?P\w+)|' + - 'secontext:(\s)*(?P\S+)|' + - 'paranoid:(\s)*(?P\S+)|' + - 'sensitive:(\s)*(?P\S+)|' + - 'encoding:(\s)*(?P\S+)|' + - 'important:(\s)*(?P\S+)|' + - 'mtime:(\s)*(?P\w+)|') +INFO_REGEX = re.compile(r'owner:(\s)*(?P\S+)|' + + r'group:(\s)*(?P\S+)|' + + r'mode:(\s)*(?P\w+)|' + + r'secontext:(\s)*(?P\S+)|' + + r'paranoid:(\s)*(?P\S+)|' + + r'sensitive:(\s)*(?P\S+)|' + + r'encoding:(\s)*(?P\S+)|' + + r'important:(\s)*(?P\S+)|' + + r'mtime:(\s)*(?P\w+)|') def bind_info(entry, metadata, infoxml=None, default=DEFAULT_FILE_METADATA): @@ -873,7 +873,7 @@ class XMLDirectoryBacked(DirectoryBacked): #: Only track and include files whose names (not paths) match this #: compiled regex. - patterns = re.compile('^.*\.xml$') + patterns = re.compile(r'^.*\.xml$') #: The type of child objects to create for files contained within #: the directory that is tracked. Default is @@ -1142,7 +1142,7 @@ class EntrySet(Debuggable): #: file is encountered that does not match the ``basename`` #: argument passed to the constructor or ``ignore``, then a #: warning will be produced. - ignore = re.compile("^(\.#.*|.*~|\\..*\\.(sw[px])|.*\\.genshi_include)$") + ignore = re.compile(r'^(\.#.*|.*~|\\..*\\.(sw[px])|.*\\.genshi_include)$') # The ``basename`` argument passed to the constructor will be #: processed as a string that contains a regular expression (i.e., @@ -1205,8 +1205,8 @@ class EntrySet(Debuggable): base_pat = basename else: base_pat = re.escape(basename) - pattern = '(.*/)?%s(\.((H_(?P\S+))|' % base_pat - pattern += '(G(?P\d+)_(?P\S+))))?$' + pattern = r'(.*/)?%s(\.((H_(?P\S+))|' % base_pat + pattern += r'(G(?P\d+)_(?P\S+))))?$' #: ``specific`` is a regular expression that is used to #: determine the specificity of a file in this entry set. It -- cgit v1.2.3-1-g7c22 From 7ad5c9c34a92080a5c426f9498ac4d09b615ec35 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 26 Mar 2013 17:18:01 -0400 Subject: Plugin: use appropriate loggers for Debuggable helper objects --- src/lib/Bcfg2/Server/Plugin/helpers.py | 69 +++++++++++++++++----------------- 1 file changed, 35 insertions(+), 34 deletions(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index a7cdea879..4bfef89f3 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -231,10 +231,10 @@ class FileBacked(Debuggable): self.Index() except IOError: err = sys.exc_info()[1] - LOGGER.error("Failed to read file %s: %s" % (self.name, err)) + self.logger.error("Failed to read file %s: %s" % (self.name, err)) except: err = sys.exc_info()[1] - LOGGER.error("Failed to parse file %s: %s" % (self.name, err)) + self.logger.error("Failed to parse file %s: %s" % (self.name, err)) def Index(self): """ Index() is called by :func:`HandleEvent` every time the @@ -329,7 +329,7 @@ class DirectoryBacked(Debuggable): dirpathname = os.path.join(self.data, relative) if relative not in self.handles.values(): if not os.path.isdir(dirpathname): - LOGGER.error("%s is not a directory" % dirpathname) + self.logger.error("%s is not a directory" % dirpathname) return reqid = self.fam.AddMonitor(dirpathname, self) self.handles[reqid] = relative @@ -374,8 +374,8 @@ class DirectoryBacked(Debuggable): return if event.requestID not in self.handles: - LOGGER.warn("Got %s event with unknown handle (%s) for %s" % - (action, event.requestID, event.filename)) + self.logger.warn("Got %s event with unknown handle (%s) for %s" % + (action, event.requestID, event.filename)) return # Clean up path names @@ -385,7 +385,7 @@ class DirectoryBacked(Debuggable): event.filename = event.filename[len(self.data) + 1:] if self.ignore and self.ignore.search(event.filename): - LOGGER.debug("Ignoring event %s" % event.filename) + self.logger.debug("Ignoring event %s" % event.filename) return # Calculate the absolute and relative paths this event refers to @@ -420,19 +420,20 @@ class DirectoryBacked(Debuggable): # class doesn't support canceling, so at least let # the user know that a restart might be a good # idea. - LOGGER.warn("Directory properties for %s changed, please " - " consider restarting the server" % abspath) + self.logger.warn("Directory properties for %s changed, " + "please consider restarting the server" % + abspath) else: # Got a "changed" event for a directory that we # didn't know about. Go ahead and treat it like a # "created" event, but log a warning, because this # is unexpected. - LOGGER.warn("Got %s event for unexpected dir %s" % - (action, abspath)) + self.logger.warn("Got %s event for unexpected dir %s" % + (action, abspath)) self.add_directory_monitor(relpath) else: - LOGGER.warn("Got unknown dir event %s %s %s" % - (event.requestID, event.code2str(), abspath)) + self.logger.warn("Got unknown dir event %s %s %s" % + (event.requestID, event.code2str(), abspath)) elif self.patterns.search(event.filename): if action in ['exists', 'created']: self.add_entry(relpath, event) @@ -444,16 +445,15 @@ class DirectoryBacked(Debuggable): # know about. Go ahead and treat it like a # "created" event, but log a warning, because this # is unexpected. - LOGGER.warn("Got %s event for unexpected file %s" % - (action, - abspath)) + self.logger.warn("Got %s event for unexpected file %s" % + (action, abspath)) self.add_entry(relpath, event) else: - LOGGER.warn("Got unknown file event %s %s %s" % - (event.requestID, event.code2str(), abspath)) + self.logger.warn("Got unknown file event %s %s %s" % + (event.requestID, event.code2str(), abspath)) else: - LOGGER.warn("Could not process filename %s; ignoring" % - event.filename) + self.logger.warn("Could not process filename %s; ignoring" % + event.filename) class XMLFileBacked(FileBacked): @@ -559,9 +559,9 @@ class XMLFileBacked(FileBacked): if not extras: msg = "%s: %s does not exist, skipping" % (self.name, name) if el.findall('./%sfallback' % Bcfg2.Server.XI_NAMESPACE): - LOGGER.debug(msg) + self.logger.debug(msg) else: - LOGGER.warning(msg) + self.logger.warning(msg) parent = el.getparent() parent.remove(el) @@ -581,7 +581,8 @@ class XMLFileBacked(FileBacked): self.xdata.getroottree().xinclude() except lxml.etree.XIncludeError: err = sys.exc_info()[1] - LOGGER.error("XInclude failed on %s: %s" % (self.name, err)) + self.logger.error("XInclude failed on %s: %s" % (self.name, + err)) self.entries = self.xdata.getchildren() if self.__identifier__ is not None: @@ -820,7 +821,7 @@ class XMLSrc(XMLFileBacked): data = open(self.name).read() except IOError: msg = "Failed to read file %s: %s" % (self.name, sys.exc_info()[1]) - LOGGER.error(msg) + self.logger.error(msg) raise PluginExecutionError(msg) self.items = {} try: @@ -828,7 +829,7 @@ class XMLSrc(XMLFileBacked): except lxml.etree.XMLSyntaxError: msg = "Failed to parse file %s: %s" % (self.name, sys.exc_info()[1]) - LOGGER.error(msg) + self.logger.error(msg) raise PluginExecutionError(msg) self.pnode = self.__node__(xdata, self.items) self.cache = None @@ -838,7 +839,7 @@ class XMLSrc(XMLFileBacked): if self.__priority_required__: msg = "Got bogus priority %s for file %s" % \ (xdata.get('priority'), self.name) - LOGGER.error(msg) + self.logger.error(msg) raise PluginExecutionError(msg) del xdata, data @@ -848,8 +849,8 @@ class XMLSrc(XMLFileBacked): if self.cache is None or self.cache[0] != metadata: cache = (metadata, self.__cacheobj__()) if self.pnode is None: - LOGGER.error("Cache method called early for %s; " - "forcing data load" % self.name) + self.logger.error("Cache method called early for %s; " + "forcing data load" % self.name) self.HandleEvent() return self.pnode.Match(metadata, cache[1]) @@ -1285,8 +1286,8 @@ class EntrySet(Debuggable): self.entry_init(event) else: if event.filename not in self.entries: - LOGGER.warning("Got %s event for unknown file %s" % - (action, event.filename)) + self.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 @@ -1322,7 +1323,7 @@ class EntrySet(Debuggable): entry_type = self.entry_type if event.filename in self.entries: - LOGGER.warn("Got duplicate add for %s" % event.filename) + self.logger.warn("Got duplicate add for %s" % event.filename) else: fpath = os.path.join(self.path, event.filename) try: @@ -1330,8 +1331,8 @@ class EntrySet(Debuggable): specific=specific) except SpecificityError: if not self.ignore.match(event.filename): - LOGGER.error("Could not process filename %s; ignoring" % - fpath) + self.logger.error("Could not process filename %s; ignoring" + % fpath) return self.entries[event.filename] = entry_type(fpath, spec, self.encoding) @@ -1396,8 +1397,8 @@ class EntrySet(Debuggable): for line in open(fpath).readlines(): match = INFO_REGEX.match(line) if not match: - LOGGER.warning("Failed to match line in %s: %s" % (fpath, - line)) + self.logger.warning("Failed to match line in %s: %s" % + (fpath, line)) continue else: mgd = match.groupdict() -- cgit v1.2.3-1-g7c22 From f6b458324f0be89f48229d4d1b5f3be9ae047497 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 26 Mar 2013 17:18:31 -0400 Subject: testsuite: can't disable pylint R0924, since it doesn't exist on older pylint and pylint barfs --- src/lib/Bcfg2/Server/Plugin/helpers.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 4bfef89f3..0123d68a1 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -313,6 +313,15 @@ class DirectoryBacked(Debuggable): def __getitem__(self, key): return self.entries[key] + def __len__(self): + return len(self.entries) + + def __delitem__(self, key): + del self.entries[key] + + def __setitem__(self, key, val): + self.entries[key] = val + def __iter__(self): return iter(list(self.entries.items())) -- cgit v1.2.3-1-g7c22 From 1ab5df5b1ed6b6082ba453677450bb1b177fcfc0 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 26 Mar 2013 17:19:45 -0400 Subject: fixed regex errors introduced by 6c996f42c53a36fc0406f836d64b8c1bec6f4bcc --- src/lib/Bcfg2/Server/Plugin/helpers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 0123d68a1..8cc1439e0 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -1152,7 +1152,7 @@ class EntrySet(Debuggable): #: file is encountered that does not match the ``basename`` #: argument passed to the constructor or ``ignore``, then a #: warning will be produced. - ignore = re.compile(r'^(\.#.*|.*~|\\..*\\.(sw[px])|.*\\.genshi_include)$') + ignore = re.compile(r'^(\.#.*|.*~|\..*\.(sw[px])|.*\.genshi_include)$') # The ``basename`` argument passed to the constructor will be #: processed as a string that contains a regular expression (i.e., @@ -1215,8 +1215,8 @@ class EntrySet(Debuggable): base_pat = basename else: base_pat = re.escape(basename) - pattern = r'(.*/)?%s(\.((H_(?P\S+))|' % base_pat - pattern += r'(G(?P\d+)_(?P\S+))))?$' + pattern = r'(.*/)?' + base_pat + \ + r'(\.((H_(?P\S+))|(G(?P\d+)_(?P\S+))))?$' #: ``specific`` is a regular expression that is used to #: determine the specificity of a file in this entry set. It -- cgit v1.2.3-1-g7c22 From bc35aa70ab8794b73019d90a41eb252fbb80ff52 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 26 Mar 2013 22:12:20 -0400 Subject: testsuite: fixed more unit test stuff --- src/lib/Bcfg2/Server/Plugin/helpers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 8cc1439e0..00b55a83b 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -796,14 +796,14 @@ class InfoNode (INode): Client="lambda m, e: '%(name)s' == m.hostname and predicate(m, e)", Group="lambda m, e: '%(name)s' in m.groups and predicate(m, e)", Path="lambda m, e: ('%(name)s' == e.get('name') or " + - "'%(name)s' == e.get('realname')) and " + - "predicate(m, e)") + "'%(name)s' == e.get('realname')) and " + + "predicate(m, e)") nraw = dict( Client="lambda m, e: '%(name)s' != m.hostname and predicate(m, e)", Group="lambda m, e: '%(name)s' not in m.groups and predicate(m, e)", Path="lambda m, e: '%(name)s' != e.get('name') and " + - "'%(name)s' != e.get('realname') and " + - "predicate(m, e)") + "'%(name)s' != e.get('realname') and " + + "predicate(m, e)") containers = ['Group', 'Client', 'Path'] -- cgit v1.2.3-1-g7c22 From b90d6dccd515551829f2661a5d855f92d1e23103 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Wed, 27 Mar 2013 13:40:46 -0400 Subject: XMLFileBacked: track FAM monitors separately from processed xincludes to avoid infinite loop with pseudo FAM --- src/lib/Bcfg2/Server/Plugin/helpers.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 00b55a83b..2b878d7e2 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -526,6 +526,10 @@ class XMLFileBacked(FileBacked): #: "Extra" files included in this file by XInclude. self.extras = [] + #: Extra FAM monitors set by this object for files included by + #: XInclude. + self.extra_monitors = [] + if ((create or (self.create is not None and self.create)) and not os.path.exists(self.name)): toptag = create or self.create @@ -576,9 +580,11 @@ class XMLFileBacked(FileBacked): parent.remove(el) for extra in extras: if extra != self.name and extra not in self.extras: - self.add_monitor(extra) + self.extras.append(extra) lxml.etree.SubElement(parent, xinclude, href=extra) self._follow_xincludes(fname=extra) + if extra not in self.extra_monitors: + self.add_monitor(extra) def Index(self): self.xdata = lxml.etree.XML(self.data, base_url=self.name, @@ -607,7 +613,7 @@ class XMLFileBacked(FileBacked): :type fpath: string :returns: None """ - self.extras.append(fpath) + self.extra_monitors.append(fpath) if self.fam and self.should_monitor: self.fam.AddMonitor(fpath, self) -- cgit v1.2.3-1-g7c22 From 9a1ea02d4adedb867e04dd3b9698c4819762777c Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 28 Mar 2013 15:24:50 -0400 Subject: XMLFileBacked: fixed deprecated logic when create is lxml.etree._Element object --- src/lib/Bcfg2/Server/Plugin/helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/lib/Bcfg2/Server/Plugin/helpers.py') diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index 2b878d7e2..b14968d77 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -530,8 +530,8 @@ class XMLFileBacked(FileBacked): #: XInclude. self.extra_monitors = [] - if ((create or (self.create is not None and self.create)) - and not os.path.exists(self.name)): + if ((create is not None or self.create not in [None, False]) and + not os.path.exists(self.name)): toptag = create or self.create self.logger.warning("%s does not exist, creating" % self.name) if hasattr(toptag, "getroottree"): -- cgit v1.2.3-1-g7c22