diff options
author | Narayan Desai <desai@mcs.anl.gov> | 2006-01-23 22:35:40 +0000 |
---|---|---|
committer | Narayan Desai <desai@mcs.anl.gov> | 2006-01-23 22:35:40 +0000 |
commit | edca0b698637c3fd0a70af7e4752a46afca938d3 (patch) | |
tree | 658fad717833200ccb4e3725c811ccce7c10fc8d /src/lib/Server/Plugins/Cfg.py | |
parent | 8ca8a153dfc6bd81ede9f5cff1ee3f111ae053ee (diff) | |
download | bcfg2-edca0b698637c3fd0a70af7e4752a46afca938d3.tar.gz bcfg2-edca0b698637c3fd0a70af7e4752a46afca938d3.tar.bz2 bcfg2-edca0b698637c3fd0a70af7e4752a46afca938d3.zip |
last step of repo switches
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@1716 ce84e21b-d406-0410-9b95-82705330c041
Diffstat (limited to 'src/lib/Server/Plugins/Cfg.py')
-rw-r--r-- | src/lib/Server/Plugins/Cfg.py | 147 |
1 files changed, 68 insertions, 79 deletions
diff --git a/src/lib/Server/Plugins/Cfg.py b/src/lib/Server/Plugins/Cfg.py index 953401e7a..b325144e5 100644 --- a/src/lib/Server/Plugins/Cfg.py +++ b/src/lib/Server/Plugins/Cfg.py @@ -1,7 +1,6 @@ '''This module implements a config file repository''' __revision__ = '$Revision$' -from binascii import b2a_base64 from os import stat from re import compile as regcompile from stat import S_ISDIR, ST_MODE @@ -9,54 +8,73 @@ from syslog import syslog, LOG_INFO, LOG_ERR from Bcfg2.Server.Plugin import Plugin, PluginExecutionError, FileBacked +import binascii +import exceptions + +specific = regcompile('(.*/)(?P<filename>[\S\-.]+)\.((H_(?P<hostname>\S+))|' + + '(G(?P<prio>\d+)_(?P<group>\S+)))$') + +class SpecificityError(Exception): + '''Thrown in case of filename parse failure''' + pass + class FileEntry(FileBacked): '''The File Entry class pertains to the config files contained in a particular directory. This includes :info, all base files and deltas''' - - def __init__(self, name, all, image, classes, bundles, attribs, hostname): + + def __init__(self, myid, name): FileBacked.__init__(self, name) - self.all = all - self.image = image - self.bundles = bundles - self.classes = classes - self.attributes = attribs - self.hostname = hostname + self.name = name + self.identity = myid + self.all = False + self.hostname = False + self.group = False + self.op = False + self.prio = False + if name.split('.')[-1] in ['cat', 'diff']: + self.op = name.split('.')[-1] + name = name[:-(len(self.op) + 1)] + if self.name.split('/')[-1] == myid.split('/')[-1]: + self.all = True + else: + data = specific.match(name) + if not data: + syslog(LOG_ERR, "Cfg: Failed to match %s" % name) + raise SpecificityError + if data.group('hostname') != None: + self.hostname = data.group('hostname') + else: + self.group = data.group('group') + self.prio = int(data.group('prio')) def __cmp__(self, other): - fields = ['all', 'image', 'classes', 'bundles', 'attributes', 'hostname'] - try: - most1 = [index for index in range(len(fields)) if getattr(self, fields[index])][0] - except IndexError: - most1 = 0 - try: - most2 = [index for index in range(len(fields)) if getattr(other, fields[index])][0] - except IndexError: - most2 = 0 - if most1 == most2: - if self.name.split('.')[-1] in ['cat', 'diff']: - meta1 = self.name.split('.')[-2] - else: - meta1 = self.name.split('.')[-1] - if other.name.split('.')[-1] in ['cat', 'diff']: - meta2 = other.name.split('.')[-2] + data = [[getattr(self, field) for field in ['all', 'group', 'hostname']], + [getattr(other, field) for field in ['all', 'group', 'hostname']]] + for index in range(3): + if data[0][index] and not data[1][index]: + return -1 + elif data[1][index] and not data[0][index]: + return 1 + elif data[0][index] and data[1][index]: + if hasattr(self, 'prio') and hasattr(other, 'prio'): + return self.prio - other.prio + else: + return 0 else: - meta2 = other.name.split('.')[-1] + pass + syslog(LOG_ERR, "Cfg: Critical: Ran off of the end of the world sorting %s" % (self.name)) - if meta1[0] not in ['C', 'B']: - return 0 - # need to tiebreak with numeric prio - prio1 = int(meta1[1:3]) - prio2 = int(meta2[1:3]) - return prio1 - prio2 + def applies(self, metadata): + '''Predicate if fragment matches client metadata''' + if self.all or (self.hostname == metadata.hostname) or \ + (self.group in metadata.groups): + return True else: - return most1 - most2 + return False class ConfigFileEntry(object): '''ConfigFileEntry is a repository entry for a single file, containing all data for all clients.''' - specific = regcompile('(.*/)(?P<filename>[\S\-.]+)\.((H_(?P<hostname>\S+))|' + - '(B(?P<bprio>\d+)_(?P<bundle>\S+))|(A(?P<aprio>\d+)_(?P<attr>\S+))|' + - '(I_(?P<image>\S+))|(C(?P<cprio>\d+)_(?P<class>\S+)))$') info = regcompile('^owner:(\s)*(?P<owner>\w+)|group:(\s)*(?P<group>\w+)|' + 'perms:(\s)*(?P<perms>\w+)|encoding:(\s)*(?P<encoding>\w+)|' + '(?P<paranoid>paranoid(\s)*)$') @@ -65,8 +83,7 @@ class ConfigFileEntry(object): object.__init__(self) self.path = path self.repopath = repopath - self.basefiles = [] - self.deltas = [] + self.fragments = [] self.metadata = {'encoding': 'ascii', 'owner':'root', 'group':'root', 'perms':'0644'} self.paranoid = False @@ -94,41 +111,15 @@ class ConfigFileEntry(object): def AddEntry(self, name): '''add new file additions for a single cf file''' - delta = False - oldname = name if name[-5:] == ':info': return self.read_info() - if name.split('/')[-1] == self.path.split('/')[-1]: - self.basefiles.append(FileEntry(name, True, None, [], [], [], None)) - self.basefiles.sort() - return - - if name.split('/')[-1].split('.')[-1] in ['cat']: - delta = True - oldname = name - name = name[:-4] - - specmatch = self.specific.match(name) - if specmatch == None: - syslog(LOG_ERR, "Cfg: Failed to match file %s" % (name)) + try: + self.fragments.append(FileEntry(self.path, name)) + self.fragments.sort() + except SpecificityError: return - data = {} - for item, value in specmatch.groupdict().iteritems(): - if value != None: - data[item] = value - - cfile = FileEntry(oldname, False, data.get('image', None), data.get('class', []), - data.get('bundle', []), data.get('attr', []), data.get('hostname', None)) - - if delta: - self.deltas.append(cfile) - self.deltas.sort() - else: - self.basefiles.append(cfile) - self.basefiles.sort() - def HandleEvent(self, event): '''Handle FAM updates''' action = event.code2str() @@ -136,11 +127,11 @@ class ConfigFileEntry(object): if action in ['changed', 'exists', 'created']: return self.read_info() if event.filename != self.path.split('/')[-1]: - if not self.specific.match('/' + event.filename): + if not specific.match('/' + event.filename): syslog(LOG_INFO, 'Cfg: Suppressing event for bogus file %s' % event.filename) return - entries = [entry for entry in self.basefiles + self.deltas if + entries = [entry for entry in self.fragments if entry.name.split('/')[-1] == event.filename] if len(entries) == 0: @@ -152,10 +143,8 @@ class ConfigFileEntry(object): syslog(LOG_INFO, "Cfg: Removing entry %s" % event.filename) for entry in entries: syslog(LOG_INFO, "Cfg: Removing entry %s" % (entry.name)) - if entry in self.basefiles: - self.basefiles.remove(entry) - if entry in self.deltas: - self.deltas.remove(entry) + self.fragments.remove(entry) + self.fragments.sort() syslog(LOG_INFO, "Cfg: Entry deletion completed") elif action in ['changed', 'exists', 'created']: [entry.HandleEvent(event) for entry in entries] @@ -168,13 +157,13 @@ class ConfigFileEntry(object): filedata = "" # first find basefile try: - basefile = [bfile for bfile in self.basefiles if metadata.Applies(bfile)][-1] + basefile = [bfile for bfile in self.fragments if bfile.applies(metadata) and not bfile.op][-1] except IndexError: syslog(LOG_ERR, "Cfg: Failed to locate basefile for %s" % name) raise PluginExecutionError, ('basefile', name) filedata += basefile.data - for delta in [x for x in self.deltas if metadata.Applies(x)]: + for delta in [delta for delta in self.fragments if delta.applies(metadata) and delta.op]: # find applicable deltas lines = filedata.split('\n') if not lines[-1]: @@ -188,15 +177,15 @@ class ConfigFileEntry(object): lines.append(line[1:]) filedata = "\n".join(lines) + "\n" - [entry.attrib.__setitem__(x,y) for (x,y) in self.metadata.iteritems()] + [entry.attrib.__setitem__(key, value) for (key, value) in self.metadata.iteritems()] if self.paranoid: entry.attrib['paranoid'] = 'true' if entry.attrib['encoding'] == 'base64': - entry.text = b2a_base64(filedata) + entry.text = binascii.b2a_base64(filedata) else: try: entry.text = filedata - except: + except exceptions.AttributeError: syslog(LOG_ERR, "Failed to marshall file %s. Mark it as base64" % (entry.get('name'))) class Cfg(Plugin): |