diff options
author | Narayan Desai <desai@mcs.anl.gov> | 2005-09-07 17:35:15 +0000 |
---|---|---|
committer | Narayan Desai <desai@mcs.anl.gov> | 2005-09-07 17:35:15 +0000 |
commit | 12bea82110171b5f4c114c5c5f66f2de34b9f5c8 (patch) | |
tree | 4d93df4e1996e3ec1706342c17508d97b7968955 /src/lib/Server/Generators/Cfg.py | |
parent | 818863a8bad4764c67837bc718697d936746a264 (diff) | |
download | bcfg2-12bea82110171b5f4c114c5c5f66f2de34b9f5c8.tar.gz bcfg2-12bea82110171b5f4c114c5c5f66f2de34b9f5c8.tar.bz2 bcfg2-12bea82110171b5f4c114c5c5f66f2de34b9f5c8.zip |
update to new Plugin API
}(Logical change 1.300)
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@1203 ce84e21b-d406-0410-9b95-82705330c041
Diffstat (limited to 'src/lib/Server/Generators/Cfg.py')
-rw-r--r-- | src/lib/Server/Generators/Cfg.py | 278 |
1 files changed, 0 insertions, 278 deletions
diff --git a/src/lib/Server/Generators/Cfg.py b/src/lib/Server/Generators/Cfg.py deleted file mode 100644 index 659ad714f..000000000 --- a/src/lib/Server/Generators/Cfg.py +++ /dev/null @@ -1,278 +0,0 @@ -'''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 -from syslog import syslog, LOG_INFO, LOG_ERR - -from Bcfg2.Server.Generator import Generator, GeneratorError, FileBacked - -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): - FileBacked.__init__(self, name) - self.all = all - self.image = image - self.bundles = bundles - self.classes = classes - self.attributes = attribs - self.hostname = hostname - - 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] - else: - meta2 = other.name.split('.')[-1] - - 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 - else: - return most1 - most2 - -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)*)$') - - def __init__(self, path, repopath): - object.__init__(self) - self.path = path - self.repopath = repopath - self.basefiles = [] - self.deltas = [] - self.metadata = {'encoding': 'ascii', 'owner':'root', 'group':'root', 'perms':'0644'} - self.paranoid = False - - def read_info(self): - '''read in :info metadata''' - filename = "%s/:info" % self.repopath - for line in open(filename).readlines(): - match = self.info.match(line) - if not match: - continue - else: - mgd = match.groupdict() - if mgd['owner']: - self.metadata['owner'] = mgd['owner'] - elif mgd['group']: - self.metadata['group'] = mgd['group'] - elif mgd['encoding']: - self.metadata['encoding'] = mgd['encoding'] - elif mgd['perms']: - self.metadata['perms'] = mgd['perms'] - if len(self.metadata['perms']) == 3: - self.metadata['perms'] = "0%s" % (self.metadata['perms']) - elif mgd['paranoid']: - self.paranoid = True - - 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)) - 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() - if event.filename == ':info': - if action in ['changed', 'exists', 'created']: - return self.read_info() - if event.filename != self.path.split('/')[-1]: - if not self.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 - entry.name.split('/')[-1] == event.filename] - - if len(entries) == 0: - syslog(LOG_ERR, "Cfg: Failed to match entry for spec %s" % (event.filename)) - elif len(entries) > 1: - syslog(LOG_ERR, "Cfg: Matched multiple entries for spec %s" % (event.filename)) - - if action == 'deleted': - 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) - syslog(LOG_INFO, "Cfg: Entry deletion completed") - elif action in ['changed', 'exists', 'created']: - if action == 'changed': - syslog(LOG_INFO, "Cfg: File %s changed" % event.filename) - [entry.HandleEvent(event) for entry in entries] - else: - syslog(LOG_ERR, "Cfg: Unhandled Action %s for file %s" % (action, event.filename)) - - def GetConfigFile(self, entry, metadata): - '''Fetch config file from repository''' - name = entry.attrib['name'] - filedata = "" - # first find basefile - try: - basefile = [bfile for bfile in self.basefiles if metadata.Applies(bfile)][-1] - except IndexError: - syslog(LOG_ERR, "Cfg: Failed to locate basefile for %s" % name) - raise GeneratorError, ('basefile', name) - filedata += basefile.data - - for delta in [x for x in self.deltas if metadata.Applies(x)]: - # find applicable deltas - lines = filedata.split('\n') - if not lines[-1]: - lines = lines[:-1] - dlines = [dline for dline in delta.data.split('\n') if dline] - for line in dlines: - if line[0] == '-': - if line[1:] in lines: - lines.remove(line[1:]) - else: - lines.append(line[1:]) - filedata = "\n".join(lines) + "\n" - - entry.attrib.update(self.metadata) - if self.paranoid: - entry.attrib['paranoid'] = 'true' - if self.metadata['encoding'] == 'base64': - entry.text = b2a_base64(filedata) - else: - entry.text = filedata - -class Cfg(Generator): - '''This generator in the configuration file repository for bcfg2''' - __name__ = 'Cfg' - __version__ = '$Id$' - __author__ = 'bcfg-dev@mcs.anl.gov' - tempfile = regcompile("^.*~$|^.*\.swp") - - def __init__(self, core, datastore): - Generator.__init__(self, core, datastore) - self.entries = {} - self.__provides__ = {'ConfigFile':{}} - self.famID = {} - self.directories = [] - self.AddDirectoryMonitor(self.data) - # eventually flush fam events here so that all entries built here - # ready to go - - def AddDirectoryMonitor(self, name): - '''Add new directory to FAM structures''' - if name not in self.directories: - try: - stat(name) - except OSError: - self.LogError("Failed to open directory %s" % (name)) - return - reqid = self.core.fam.AddMonitor(name, self) - self.famID[reqid] = name - self.directories.append(name) - - def AddEntry(self, name, event): - '''Add new entry to FAM structures''' - try: - sdata = stat(name)[ST_MODE] - except OSError: - return - - if S_ISDIR(sdata): - self.AddDirectoryMonitor(name) - else: - # file entries shouldn't contain path-to-repo - shortname = '/'+ '/'.join(name[len(self.data)+1:].split('/')[:-1]) - repodir = '/' + '/'.join(name.split('/')[:-1]) - if not self.entries.has_key(shortname): - self.entries[shortname] = ConfigFileEntry(shortname, repodir) - self.__provides__['ConfigFile'][shortname] = self.entries[shortname].GetConfigFile - self.entries[shortname].AddEntry(name) - self.entries[shortname].HandleEvent(event) - - def HandleEvent(self, event): - '''Handle FAM updates''' - action = event.code2str() - if self.tempfile.match(event.filename): - syslog(LOG_INFO, "Cfg: Suppressed event for file %s" % event.filename) - return - if event.filename[0] != '/': - filename = "%s/%s" % (self.famID[event.requestID], event.filename) - else: - filename = event.filename - configfile = filename[len(self.data):-(len(event.filename)+1)] - - if ((action in ['exists', 'created']) and (filename != self.data)): - self.AddEntry(filename, event) - elif action == 'changed': - # pass the event down the chain to the ConfigFileEntry - if self.entries.has_key(configfile): - self.entries[configfile].HandleEvent(event) - else: - if filename != self.data: - self.AddEntry(filename, event) - else: - self.LogError("Ignoring event for %s"%(configfile)) - elif action == 'deleted': - if self.entries.has_key(configfile): - self.entries[configfile].HandleEvent(event) - elif action in ['exists', 'endExist']: - pass - else: - self.LogError("Got unknown event %s %s:%s" % (action, event.requestID, event.filename)) |