diff options
Diffstat (limited to 'src/lib/Server')
43 files changed, 272 insertions, 189 deletions
diff --git a/src/lib/Server/Admin/Client.py b/src/lib/Server/Admin/Client.py index 11853f7a2..0eee22ae4 100644 --- a/src/lib/Server/Admin/Client.py +++ b/src/lib/Server/Admin/Client.py @@ -25,7 +25,7 @@ class Client(Bcfg2.Server.Admin.MetadataCore): attr_d = {} for i in args[2:]: attr, val = i.split('=', 1) - if attr not in ['profile', 'uuid', 'password', + if attr not in ['profile', 'uuid', 'password', 'location', 'secure', 'address']: print "Attribute %s unknown" % attr raise SystemExit(1) @@ -39,7 +39,7 @@ class Client(Bcfg2.Server.Admin.MetadataCore): attr_d = {} for i in args[2:]: attr, val = i.split('=', 1) - if attr not in ['profile', 'uuid', 'password', + if attr not in ['profile', 'uuid', 'password', 'location', 'secure', 'address']: print "Attribute %s unknown" % attr raise SystemExit(1) diff --git a/src/lib/Server/Admin/Group.py b/src/lib/Server/Admin/Group.py index c9619d534..6a1c13775 100644 --- a/src/lib/Server/Admin/Group.py +++ b/src/lib/Server/Admin/Group.py @@ -25,8 +25,8 @@ class Group(Bcfg2.Server.Admin.MetadataCore): attr_d = {} for i in args[2:]: attr, val = i.split('=', 1) - if attr not in ['profile', 'public', 'default', - 'name', 'auth', 'toolset', 'category', + if attr not in ['profile', 'public', 'default', + 'name', 'auth', 'toolset', 'category', 'comment']: print "Attribute %s unknown" % attr raise SystemExit(1) @@ -40,8 +40,8 @@ class Group(Bcfg2.Server.Admin.MetadataCore): attr_d = {} for i in args[2:]: attr, val = i.split('=', 1) - if attr not in ['profile', 'public', 'default', - 'name', 'auth', 'toolset', 'category', + if attr not in ['profile', 'public', 'default', + 'name', 'auth', 'toolset', 'category', 'comment']: print "Attribute %s unknown" % attr raise SystemExit(1) diff --git a/src/lib/Server/Admin/Init.py b/src/lib/Server/Admin/Init.py index c12fcf9a8..9fc2a23fe 100644 --- a/src/lib/Server/Admin/Init.py +++ b/src/lib/Server/Admin/Init.py @@ -75,14 +75,14 @@ os_list = [ ] # Complete list of plugins -plugin_list = ['Account', 'Base', 'Bundler', 'Cfg', - 'Decisions', 'Deps', 'Metadata', 'Packages', - 'Pkgmgr', 'Probes', 'Properties', 'Rules', - 'Snapshots', 'SSHbase', 'Statistics', 'Svcmgr', +plugin_list = ['Account', 'Base', 'Bundler', 'Cfg', + 'Decisions', 'Deps', 'Metadata', 'Packages', + 'Pkgmgr', 'Probes', 'Properties', 'Rules', + 'Snapshots', 'SSHbase', 'Statistics', 'Svcmgr', 'TCheetah', 'TGenshi'] # Default list of plugins to use -default_plugins = ['SSHbase', 'Cfg', 'Pkgmgr', 'Rules', +default_plugins = ['SSHbase', 'Cfg', 'Pkgmgr', 'Rules', 'Metadata', 'Base', 'Bundler'] def gen_password(length): @@ -188,13 +188,13 @@ class Init(Bcfg2.Server.Admin.Mode): "(without echoing; leave blank for a random): ").strip() if len(newpassword) != 0: self.password = newpassword - + def _prompt_server(self): """Ask for the server name""" - newserver = raw_input( "Input the server location [%s]: " % self.server_uri) + newserver = raw_input("Input the server location [%s]: " % self.server_uri) if newserver != '': self.server_uri = newserver - + def _prompt_groups(self): """Create the groups.xml file""" prompt = '''Input base Operating System for clients:\n''' @@ -241,15 +241,15 @@ class Init(Bcfg2.Server.Admin.Mode): '''Setup a new repo''' # Create the contents of the configuration file keypath = os.path.dirname(os.path.abspath(self.configfile)) - confdata = config % ( - self.repopath, + confdata = config % ( + self.repopath, ','.join(self.opts['plugins']), - self.opts['sendmail'], + self.opts['sendmail'], self.opts['proto'], - self.password, - keypath, - keypath, - self.server_uri + self.password, + keypath, + keypath, + self.server_uri ) # Create the configuration file and SSL key @@ -257,7 +257,7 @@ class Init(Bcfg2.Server.Admin.Mode): create_key(keypath) # Create the repository - path = "%s/%s" % (self.repopath, 'etc') + path = "%s/%s" % (self.repopath, 'etc') os.makedirs(path) self._init_plugins() print "Repository created successfuly in %s" % (self.repopath) diff --git a/src/lib/Server/Admin/Minestruct.py b/src/lib/Server/Admin/Minestruct.py index d5af2f809..f1ffa129a 100644 --- a/src/lib/Server/Admin/Minestruct.py +++ b/src/lib/Server/Admin/Minestruct.py @@ -1,6 +1,9 @@ '''Minestruct Admin Mode''' +import getopt +import lxml.etree +import sys + import Bcfg2.Server.Admin -import lxml.etree, sys, getopt class Minestruct(Bcfg2.Server.Admin.StructureMode): '''Pull extra entries out of statistics''' @@ -30,7 +33,7 @@ class Minestruct(Bcfg2.Server.Admin.StructureMode): except: self.log.error(self.__shorthelp__) raise SystemExit(1) - + client = args[0] output = sys.stdout groups = [] @@ -65,4 +68,3 @@ class Minestruct(Bcfg2.Server.Admin.StructureMode): tree = lxml.etree.ElementTree(root) tree.write(output, pretty_print=True) - diff --git a/src/lib/Server/Admin/Perf.py b/src/lib/Server/Admin/Perf.py index 3d17372e0..df6f51dd4 100644 --- a/src/lib/Server/Admin/Perf.py +++ b/src/lib/Server/Admin/Perf.py @@ -15,12 +15,12 @@ class Perf(Bcfg2.Server.Admin.Mode): def __call__(self, args): output = [('Name', 'Min', 'Max', 'Mean', 'Count')] optinfo = { + 'ca': Bcfg2.Options.CLIENT_CA + 'certificate': Bcfg2.Options.CLIENT_CERT, + 'key': Bcfg2.Options.SERVER_KEY, + 'password': Bcfg2.Options.SERVER_PASSWORD, 'server': Bcfg2.Options.SERVER_LOCATION, 'user': Bcfg2.Options.CLIENT_USER, - 'password': Bcfg2.Options.SERVER_PASSWORD, - 'key': Bcfg2.Options.SERVER_KEY, - 'certificate' : Bcfg2.Options.CLIENT_CERT, - 'ca' : Bcfg2.Options.CLIENT_CA } setup = Bcfg2.Options.OptionParser(optinfo) setup.parse(sys.argv[2:]) @@ -35,4 +35,3 @@ class Perf(Bcfg2.Server.Admin.Mode): data = tuple(["%.06f" % (item) for item in value[:-1]] + [value[-1]]) output.append((key, ) + data) self.print_table(output) - diff --git a/src/lib/Server/Admin/Pull.py b/src/lib/Server/Admin/Pull.py index 81ae9c433..993dbc0c5 100644 --- a/src/lib/Server/Admin/Pull.py +++ b/src/lib/Server/Admin/Pull.py @@ -28,7 +28,7 @@ class Pull(Bcfg2.Server.Admin.MetadataCore): self.__usage__) self.log = False self.mode = 'interactive' - + def __call__(self, args): Bcfg2.Server.Admin.Mode.__call__(self, args) try: @@ -76,7 +76,7 @@ class Pull(Bcfg2.Server.Admin.MetadataCore): for choice in choices: print "Plugin returned choice:" if id(choice) == id(choices[0]): - print "(current entry)", + print "(current entry)", if choice.all: print " => global entry" elif choice.group: diff --git a/src/lib/Server/Admin/Snapshots.py b/src/lib/Server/Admin/Snapshots.py index cda8a3cd4..c7ea3a376 100644 --- a/src/lib/Server/Admin/Snapshots.py +++ b/src/lib/Server/Admin/Snapshots.py @@ -146,10 +146,10 @@ class Snapshots(Bcfg2.Server.Admin.Mode): rows = [] labels = ('Client', 'Correct', 'Revision', 'Time') for snap in snaps: - rows.append([snap.client.name, - snap.correct, - snap.revision, - snap.timestamp]) + rows.append([snap.client.name, + snap.correct, + snap.revision, + snap.timestamp]) self.print_table([labels]+rows, justify='left', hdr=True, diff --git a/src/lib/Server/Admin/Tidy.py b/src/lib/Server/Admin/Tidy.py index 5f3145602..3e51d9d75 100644 --- a/src/lib/Server/Admin/Tidy.py +++ b/src/lib/Server/Admin/Tidy.py @@ -1,5 +1,8 @@ +import os +import re +import socket + import Bcfg2.Server.Admin -import re, os, socket class Tidy(Bcfg2.Server.Admin.Mode): __shorthelp__ = "Clean up useless files in the repo" diff --git a/src/lib/Server/Admin/Viz.py b/src/lib/Server/Admin/Viz.py index 3945591f7..f49df37e8 100644 --- a/src/lib/Server/Admin/Viz.py +++ b/src/lib/Server/Admin/Viz.py @@ -44,7 +44,8 @@ class Viz(Bcfg2.Server.Admin.MetadataCore): except getopt.GetoptError, msg: print msg - rset = False + #FIXME: is this for --raw? + #rset = False hset = False bset = False kset = False diff --git a/src/lib/Server/Core.py b/src/lib/Server/Core.py index acee2542f..7aa859143 100644 --- a/src/lib/Server/Core.py +++ b/src/lib/Server/Core.py @@ -60,7 +60,7 @@ class Core(Component): if '' in plugins: plugins.remove('') - + for plugin in plugins: if not plugin in self.plugins: self.init_plugins(plugin) @@ -132,8 +132,8 @@ class Core(Component): except PluginInitError: logger.error("Failed to instantiate plugin %s" % (plugin)) except: - logger.error("Unexpected instantiation failure for plugin %s" % - (plugin), exc_info=1) + logger.error("Unexpected instantiation failure for plugin %s" % + (plugin), exc_info=1) def shutdown(self): for plugin in self.plugins.values(): @@ -216,9 +216,9 @@ class Core(Component): gen.HandlesEntry(entry, metadata)] if len(g2list) == 1: return g2list[0].HandleEntry(entry, metadata) - entry.set('failure', 'no matching generator') + entry.set('failure', 'no matching generator') raise PluginExecutionError, (entry.tag, entry.get('name')) - + def BuildConfiguration(self, client): '''Build Configuration for client''' start = time.time() @@ -250,7 +250,7 @@ class Core(Component): else: esrcs[key] = entry.get('altsrc', None) del esrcs - + for astruct in structures: try: self.BindStructure(astruct, meta) diff --git a/src/lib/Server/FileMonitor.py b/src/lib/Server/FileMonitor.py index 4d42f4261..9538cf428 100644 --- a/src/lib/Server/FileMonitor.py +++ b/src/lib/Server/FileMonitor.py @@ -90,7 +90,7 @@ class FileMonitor(object): class FamFam(object): '''The fam object is a set of callbacks for file alteration events (FAM support)''' - + def __init__(self): object.__init__(self) self.fm = _fam.open() @@ -168,7 +168,7 @@ class Fam(FileMonitor): The fam object is a set of callbacks for file alteration events (FAM support) ''' - + def __init__(self, debug=False): FileMonitor.__init__(self, debug) self.fm = _fam.open() @@ -198,7 +198,7 @@ class Pseudo(FileMonitor): The fam object is a set of callbacks for file alteration events (static monitor support) ''' - + def __init__(self, debug=False): FileMonitor.__init__(self, debug=False) self.pending_events = [] @@ -228,7 +228,8 @@ class Pseudo(FileMonitor): try: - from gamin import WatchMonitor, GAMCreated, GAMExists, GAMEndExist, GAMChanged, GAMDeleted, GAMMoved + from gamin import WatchMonitor, GAMCreated, GAMExists, GAMEndExist, \ + GAMChanged, GAMDeleted, GAMMoved class GaminEvent(Event): ''' diff --git a/src/lib/Server/Plugin.py b/src/lib/Server/Plugin.py index 712f12ea9..afe4c85d2 100644 --- a/src/lib/Server/Plugin.py +++ b/src/lib/Server/Plugin.py @@ -13,10 +13,10 @@ from lxml.etree import XML, XMLSyntaxError import Bcfg2.Options # grab default metadata info from bcfg2.conf -opts = {'owner':Bcfg2.Options.MDATA_OWNER, - 'group':Bcfg2.Options.MDATA_GROUP, - 'perms':Bcfg2.Options.MDATA_PERMS, - 'paranoid':Bcfg2.Options.MDATA_PARANOID} +opts = {'owner': Bcfg2.Options.MDATA_OWNER, + 'group': Bcfg2.Options.MDATA_GROUP, + 'perms': Bcfg2.Options.MDATA_PERMS, + 'paranoid': Bcfg2.Options.MDATA_PARANOID} mdata_setup = Bcfg2.Options.OptionParser(opts) mdata_setup.parse([]) del mdata_setup['args'] @@ -28,7 +28,7 @@ default_file_metadata = mdata_setup info_regex = re.compile( \ '^owner:(\s)*(?P<owner>\S+)|group:(\s)*(?P<group>\S+)|' + 'perms:(\s)*(?P<perms>\w+)|encoding:(\s)*(?P<encoding>\w+)|' + - '(?P<paranoid>paranoid(\s)*)|mtime:(\s)*(?P<mtime>\w+)$' ) + '(?P<paranoid>paranoid(\s)*)|mtime:(\s)*(?P<mtime>\w+)$') class PluginInitError(Exception): '''Error raised in cases of Plugin initialization errors''' @@ -74,7 +74,7 @@ class Plugin(object): os.stat(ppath) except: os.mkdir(ppath) - + @classmethod def init_repo(cls, repo): path = "%s/%s" % (repo, cls.name) @@ -152,7 +152,7 @@ class PullSource(object): class PullTarget(object): def AcceptChoices(self, entry, metadata): raise PluginExecutionError - + def AcceptPullData(self, specific, new_entry, verbose): '''This is the null per-plugin implementation of bcfg2-admin pull''' @@ -190,7 +190,7 @@ class FileBacked(object): HandleEvent is called whenever fam registers an event. Index can parse the data into member data as required. This object is meant to be used as a part of DirectoryBacked.''' - + def __init__(self, name): object.__init__(self) self.data = '' @@ -205,7 +205,7 @@ class FileBacked(object): self.Index() except IOError: logger.error("Failed to read file %s" % (self.name)) - + def Index(self): '''Update local data structures based on current file state''' pass @@ -323,7 +323,7 @@ class StructFile(XMLFileBacked): cmd = "lambda x:'%s' not in x.groups and predicate(x)" else: cmd = "lambda x:'%s' in x.groups and predicate(x)" - + newpred = eval(cmd % (group.get('name')), {'predicate':predicate}) work[newpred] = group.getchildren() @@ -343,7 +343,7 @@ class INode: 'Group':"lambda x:'%s' not in x.groups and predicate(x)"} containers = ['Group', 'Client'] ignore = [] - + def __init__(self, data, idict, parent=None): self.data = data self.contents = {} @@ -439,7 +439,7 @@ class XMLSrc(XMLFileBacked): class XMLDirectoryBacked(DirectoryBacked): '''Directorybacked for *.xml''' - patterns = re.compile('.*\.xml') + patterns = re.compile('.*\.xml') class PrioDir(Plugin, Generator, XMLDirectoryBacked): '''This is a generator that handles package assignments''' @@ -734,13 +734,13 @@ class GroupSpool(Plugin, Generator): if posixpath.isdir(epath): self.AddDirectoryMonitor(epath[len(self.data):]) if ident not in self.entries: - dirpath = "".join([self.data, ident]) + dirpath = "".join([self.data, ident]) self.entries[ident] = self.es_cls(self.filename_pattern, dirpath, self.es_child_cls, self.encoding) - self.Entries['ConfigFile'][ident] = self.entries[ident].bind_entry - self.Entries['Path'][ident] = self.entries[ident].bind_entry + self.Entries['ConfigFile'][ident] = self.entries[ident].bind_entry + self.Entries['Path'][ident] = self.entries[ident].bind_entry if not posixpath.isdir(epath): # do not pass through directory events self.entries[ident].handle_event(event) @@ -755,7 +755,7 @@ class GroupSpool(Plugin, Generator): del self.Entries['Path'][fbase] else: self.entries[ident].handle_event(event) - + def AddDirectoryMonitor(self, relative): '''Add new directory to FAM structures''' if not relative.endswith('/'): diff --git a/src/lib/Server/Plugins/BB.py b/src/lib/Server/Plugins/BB.py index 18719f2be..dd23f6ec9 100644 --- a/src/lib/Server/Plugins/BB.py +++ b/src/lib/Server/Plugins/BB.py @@ -1,4 +1,4 @@ -import lxml.etree +import lxml.etree import Bcfg2.Server.Plugin import glob import os @@ -41,7 +41,7 @@ class BBfile(Bcfg2.Server.Plugin.XMLFileBacked): else: logger.error("%s" % lxml.etree.tostring(node)) self.users[node.get('name')] = node.get('user',"").split(':') - + def enforce_bootlinks(self): for mac, target in self.bootlinks: path = self.tftppath + '/' + mac @@ -53,7 +53,7 @@ class BBfile(Bcfg2.Server.Plugin.XMLFileBacked): os.symlink(target, path) except: logger.error("Failed to modify link %s" % path) - + class BBDirectoryBacked(Bcfg2.Server.Plugin.DirectoryBacked): __child__ = BBfile @@ -71,21 +71,14 @@ class BB(Bcfg2.Server.Plugin.Plugin, self.store = BBDirectoryBacked(self.data, core.fam) def get_additional_data(self, metadata): - + users = {} for user in self.store.entries['bb.xml'].users.get(metadata.hostname.split(".")[0], []): pubkeys = [] for fname in glob.glob('/home/%s/.ssh/*.pub'%user): pubkeys.append(open(fname).read()) - - users[user] = pubkeys - - return dict([('users', users), - ('macs', self.store.entries['bb.xml'].macs)]) - + users[user] = pubkeys - - - - + return dict([('users', users), + ('macs', self.store.entries['bb.xml'].macs)]) diff --git a/src/lib/Server/Plugins/Base.py b/src/lib/Server/Plugins/Base.py index b96c9b3d1..e6f124432 100644 --- a/src/lib/Server/Plugins/Base.py +++ b/src/lib/Server/Plugins/Base.py @@ -6,15 +6,15 @@ import copy import lxml.etree class Base(Bcfg2.Server.Plugin.Plugin, - Bcfg2.Server.Plugin.Structure, + Bcfg2.Server.Plugin.Structure, Bcfg2.Server.Plugin.XMLDirectoryBacked): '''This Structure is good for the pile of independent configs needed for most actual systems''' - name = 'Base' + name = 'Base' __version__ = '$Id$' __author__ = 'bcfg-dev@mcs.anl.gov' __child__ = Bcfg2.Server.Plugin.StructFile - + '''base creates independent clauses based on client metadata''' def __init__(self, core, datastore): Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) @@ -26,7 +26,7 @@ class Base(Bcfg2.Server.Plugin.Plugin, except OSError: self.logger.error("Failed to load Base repository") raise Bcfg2.Server.Plugin.PluginInitError - + def BuildStructures(self, metadata): '''Build structures for client described by metadata''' ret = lxml.etree.Element("Independent", version='2.0') diff --git a/src/lib/Server/Plugins/Bundler.py b/src/lib/Server/Plugins/Bundler.py index ee7edb49c..914da3cee 100644 --- a/src/lib/Server/Plugins/Bundler.py +++ b/src/lib/Server/Plugins/Bundler.py @@ -1,11 +1,16 @@ '''This provides bundle clauses with translation functionality''' __revision__ = '$Revision$' -import copy, lxml.etree, Bcfg2.Server.Plugin, re +import copy +import lxml.etree +import re + +import Bcfg2.Server.Plugin try: + import genshi.template + import genshi.template.base import Bcfg2.Server.Plugins.SGenshi - import genshi.template, genshi.template.base have_genshi = True except: have_genshi = False @@ -21,11 +26,11 @@ class Bundler(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.Structure, Bcfg2.Server.Plugin.XMLDirectoryBacked): '''The bundler creates dependent clauses based on the bundle/translation scheme from bcfg1''' - name = 'Bundler' + name = 'Bundler' __version__ = '$Id$' __author__ = 'bcfg-dev@mcs.anl.gov' patterns = re.compile('^(?P<name>.*)\.(xml|genshi)$') - + def __init__(self, core, datastore): Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) Bcfg2.Server.Plugin.Structure.__init__(self) @@ -69,4 +74,3 @@ class Bundler(Bcfg2.Server.Plugin.Plugin, self.logger.error("Got multiple matches for bundle %s" \ % (bundlename)) return bundleset - diff --git a/src/lib/Server/Plugins/Cfg.py b/src/lib/Server/Plugins/Cfg.py index d26012205..ace400692 100644 --- a/src/lib/Server/Plugins/Cfg.py +++ b/src/lib/Server/Plugins/Cfg.py @@ -1,7 +1,13 @@ '''This module implements a config file repository''' __revision__ = '$Revision$' -import binascii, logging, os, re, tempfile, Bcfg2.Server.Plugin +import binascii +import logging +import os +import re +import tempfile + +import Bcfg2.Server.Plugin logger = logging.getLogger('Bcfg2.Plugins.Cfg') @@ -148,4 +154,3 @@ class Cfg(Bcfg2.Server.Plugin.GroupSpool, def AcceptPullData(self, specific, new_entry, log): return self.entries[new_entry.get('name')].write_update(specific, new_entry, log) - diff --git a/src/lib/Server/Plugins/DBStats.py b/src/lib/Server/Plugins/DBStats.py index c9d11a1f4..3b6909eda 100644 --- a/src/lib/Server/Plugins/DBStats.py +++ b/src/lib/Server/Plugins/DBStats.py @@ -13,7 +13,7 @@ class DBStats(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.PullSource): name = 'DBStats' __version__ = '$Id$' - + def __init__(self, core, datastore): Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) Bcfg2.Server.Plugin.Statistics.__init__(self) @@ -34,7 +34,7 @@ class DBStats(Bcfg2.Server.Plugin.Plugin, e.append(newstats) container = lxml.etree.Element("ConfigStatistics") container.append(e) - + # FIXME need to build a metadata interface to expose a list of clients # FIXME Server processing the request should be mentionned here start = time.time() @@ -71,7 +71,7 @@ class DBStats(Bcfg2.Server.Plugin.Plugin, ret.append(getattr(entry.reason, t)) else: ret.append(getattr(entry.reason, "current_%s" % t)) - + if entry.reason.current_diff != '': ret.append('\n'.join(difflib.restore(\ entry.reason.current_diff.split('\n'), 1))) diff --git a/src/lib/Server/Plugins/Decisions.py b/src/lib/Server/Plugins/Decisions.py index 95db433a7..1aba88840 100644 --- a/src/lib/Server/Plugins/Decisions.py +++ b/src/lib/Server/Plugins/Decisions.py @@ -14,7 +14,7 @@ class DecisionFile(Bcfg2.Server.Plugin.SpecificData): class DecisionSet(Bcfg2.Server.Plugin.EntrySet): def __init__(self, path, fam, encoding): """Container for decision specification files - + Arguments: - `path`: repository path - `fam`: reference to the file monitor @@ -51,7 +51,7 @@ class Decisions(DecisionSet, def __init__(self, core, datastore): """Decisions plugins - + Arguments: - `core`: Bcfg2.Core instance - `datastore`: File repository location @@ -59,4 +59,4 @@ class Decisions(DecisionSet, Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) Bcfg2.Server.Plugin.Decision.__init__(self) DecisionSet.__init__(self, self.data, core.fam, core.encoding) - + diff --git a/src/lib/Server/Plugins/Deps.py b/src/lib/Server/Plugins/Deps.py index b6359a476..cdf23833b 100644 --- a/src/lib/Server/Plugins/Deps.py +++ b/src/lib/Server/Plugins/Deps.py @@ -1,13 +1,15 @@ '''This plugin provides automatic dependency handling''' __revision__ = '$Revision$' -import Bcfg2.Server.Plugin, lxml.etree +import lxml.etree + +import Bcfg2.Server.Plugin class DNode(Bcfg2.Server.Plugin.INode): '''DNode provides supports for single predicate types for dependencies''' raw = {'Group':"lambda x:'%s' in x.groups and predicate(x)"} containers = ['Group'] - + def __init__(self, data, idict, parent=None): self.data = data self.contents = {} @@ -49,7 +51,7 @@ class Deps(Bcfg2.Server.Plugin.PrioDir, def HandleEvent(self, event): self.cache = {} Bcfg2.Server.Plugin.PrioDir.HandleEvent(self, event) - + def validate_structures(self, metadata, structures): entries = [] prereqs = [] @@ -67,7 +69,7 @@ class Deps(Bcfg2.Server.Plugin.PrioDir, prereqs = self.cache[(entries, gdata)] else: [src.Cache(metadata) for src in self.entries.values()] - + toexamine = list(entries[:]) while toexamine: entry = toexamine.pop() @@ -91,7 +93,7 @@ class Deps(Bcfg2.Server.Plugin.PrioDir, toexamine.append(prq) prereqs.append(prq) self.cache[(entries, gdata)] = prereqs - + newstruct = lxml.etree.Element("Independent") for tag, name in prereqs: try: diff --git a/src/lib/Server/Plugins/Editor.py b/src/lib/Server/Plugins/Editor.py index 1e84ccb2f..76adaf4cb 100644 --- a/src/lib/Server/Plugins/Editor.py +++ b/src/lib/Server/Plugins/Editor.py @@ -64,7 +64,7 @@ class Editor(Bcfg2.Server.Plugin.GroupSpool, probe = lxml.etree.Element('probe') probe.set('name', name) probe.set('source', "Editor") - probe.text = "cat %s" %name + probe.text = "cat %s" % name probelist.append(probe) return probelist diff --git a/src/lib/Server/Plugins/Fossil.py b/src/lib/Server/Plugins/Fossil.py index 2b17de2c9..82850e602 100644 --- a/src/lib/Server/Plugins/Fossil.py +++ b/src/lib/Server/Plugins/Fossil.py @@ -31,12 +31,12 @@ class Fossil(Bcfg2.Server.Plugin.Plugin, raise Bcfg2.Server.Plugin.PluginInitError logger.debug("Initialized Fossil.py plugin with %(ffile)s at revision %(frev)s" \ - % {'ffile': fossil_file, 'frev': revision} ) + % {'ffile': fossil_file, 'frev': revision}) def get_revision(self): '''Read fossil revision information for the bcfg2 repository''' try: - data = Popen("env LC_ALL=C fossil info", + data = Popen("env LC_ALL=C fossil info", shell=True, cwd=self.datastore, stdout=PIPE).stdout.readlines() diff --git a/src/lib/Server/Plugins/GroupPatterns.py b/src/lib/Server/Plugins/GroupPatterns.py index de25d0143..3801a6a08 100644 --- a/src/lib/Server/Plugins/GroupPatterns.py +++ b/src/lib/Server/Plugins/GroupPatterns.py @@ -1,5 +1,6 @@ +import lxml.etree +import re -import re, lxml.etree import Bcfg2.Server.Plugin class PackedDigitRange(object): diff --git a/src/lib/Server/Plugins/Metadata.py b/src/lib/Server/Plugins/Metadata.py index 609e8ecd4..d78592f14 100644 --- a/src/lib/Server/Plugins/Metadata.py +++ b/src/lib/Server/Plugins/Metadata.py @@ -106,9 +106,9 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, def init_repo(cls, repo, groups, os_selection, clients): path = '%s/%s' % (repo, cls.name) cls.make_path(path) - open("%s/Metadata/groups.xml" % - repo, "w").write(groups % os_selection) - open("%s/Metadata/clients.xml" % + open("%s/Metadata/groups.xml" % + repo, "w").write(groups % os_selection) + open("%s/Metadata/clients.xml" % repo, "w").write(clients % socket.getfqdn()) def get_groups(self): @@ -356,7 +356,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, 'cert+password') if 'uuid' in client.attrib: self.uuid[client.get('uuid')] = clname - if client.get('secure', 'false') == 'true' : + if client.get('secure', 'false') == 'true': self.secure.append(clname) if client.get('location', 'fixed') == 'floating': self.floating.append(clname) @@ -478,7 +478,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, pretty_print='true')) fcntl.lockf(fd, fcntl.LOCK_UN) datafile.close() - + def locked(self, fd): try: fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) @@ -554,7 +554,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, all_groups = set() [all_groups.update(g[1]) for g in self.groups.values()] return all_groups - + def get_client_names_by_profiles(self, profiles): return [client for client, profile in self.clients.iteritems() \ if profile in profiles] @@ -583,7 +583,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, def merge_additional_data(self, imd, source, data): if not hasattr(imd, source): setattr(imd, source, data) - imd.connectors.append(source) + imd.connectors.append(source) def validate_client_address(self, client, address): '''Check address against client''' @@ -603,7 +603,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, self.logger.error("Got request for %s from incorrect address %s" \ % (client, address)) return False - + def AuthenticateConnection(self, cert, user, password, address): '''This function checks auth creds''' if cert: @@ -677,7 +677,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, % (client)) cli[0].set('auth', 'cert') self.write_back_clients() - + def viz(self, hosts, bundles, key, colors): '''admin mode viz support''' groups_tree = lxml.etree.parse(self.data + "/groups.xml") @@ -712,7 +712,7 @@ class Metadata(Bcfg2.Server.Plugin.Plugin, if bund.get('name') not in bundles] bundles.sort() for bundle in bundles: - viz_str += '''\t"bundle-%s" [ label="%s", shape="septagon"];\n''' \ + viz_str += '''\t"bundle-%s" [ label="%s", shape="septagon"];\n''' \ % (bundle, bundle) gseen = [] for group in egroups: diff --git a/src/lib/Server/Plugins/NagiosGen.py b/src/lib/Server/Plugins/NagiosGen.py index 8ea0a1547..82326b760 100644 --- a/src/lib/Server/Plugins/NagiosGen.py +++ b/src/lib/Server/Plugins/NagiosGen.py @@ -1,6 +1,11 @@ '''This module implements a Nagios configuration generator''' -import re, os, glob, socket, logging +import glob +import logging +import os +import re +import socket + import Bcfg2.Server.Plugin LOGGER = logging.getLogger('Bcfg2.Plugins.NagiosGen') @@ -20,16 +25,16 @@ class NagiosGen(Bcfg2.Server.Plugin.Plugin, name = 'NagiosGen' __version__ = '0.6' __author__ = 'bcfg-dev@mcs.anl.gov' - + def __init__(self, core, datastore): Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) Bcfg2.Server.Plugin.Generator.__init__(self) self.Entries = {'ConfigFile': {'/etc/nagiosgen.status' : self.createhostconfig, '/etc/nagios/nagiosgen.cfg': self.createserverconfig}} - + self.client_attrib = {'encoding': 'ascii', 'owner':'root', \ - 'group':'root', 'perms':'0400'} + 'group':'root', 'perms':'0400'} self.server_attrib = {'encoding': 'ascii', 'owner':'nagios', \ 'group':'nagios', 'perms':'0440'} @@ -39,7 +44,7 @@ class NagiosGen(Bcfg2.Server.Plugin.Plugin, host_groups = [grp for grp in metadata.groups if \ os.path.isfile('%s/%s-group.cfg' % (self.data, grp))] host_config = host_config_fmt % \ - (metadata.hostname, metadata.hostname, host_address ) + (metadata.hostname, metadata.hostname, host_address) if host_groups: host_config += ' hostgroups %s\n' % (",".join(host_groups)) @@ -48,9 +53,9 @@ class NagiosGen(Bcfg2.Server.Plugin.Plugin, 'NagiosGen.xml' in metadata.Properties and \ metadata.Properties['NagiosGen.xml'].data.find(metadata.hostname) \ is not None: - directives = list (metadata.Properties['NagiosGen.xml'].data.find(metadata.hostname)) + directives = list(metadata.Properties['NagiosGen.xml'].data.find(metadata.hostname)) for item in directives: - host_config += ' %-32s %s\n' % ( item.tag, item.text ) + host_config += ' %-32s %s\n' % (item.tag, item.text) else: host_config += ' use default\n' @@ -58,17 +63,17 @@ class NagiosGen(Bcfg2.Server.Plugin.Plugin, host_config += '}\n' entry.text = host_config [entry.attrib.__setitem__(key, value) for \ - (key, value) in self.client_attrib.iteritems()] + (key, value) in self.client_attrib.iteritems()] try: - fileh = open( "%s/%s-host.cfg" % \ - (self.data, metadata.hostname), 'w' ) + fileh = open("%s/%s-host.cfg" % \ + (self.data, metadata.hostname), 'w') fileh.write(host_config) fileh.close() except OSError, ioerr: LOGGER.error("Failed to write %s/%s-host.cfg" % \ (self.data, metadata.hostname)) LOGGER.error(ioerr) - + def createserverconfig(self, entry, _): '''Build monolithic server configuration file''' host_configs = glob.glob('%s/*-host.cfg' % self.data) @@ -76,20 +81,20 @@ class NagiosGen(Bcfg2.Server.Plugin.Plugin, host_data = "" group_data = "" for host in host_configs: - hostfile = open( host, 'r' ) + hostfile = open(host, 'r') host_data += hostfile.read() hostfile.close() for group in group_configs: group_name = re.sub("(-group.cfg|.*/(?=[^/]+))", "", group) if host_data.find(group_name) != -1: - groupfile = open( group, 'r' ) + groupfile = open(group, 'r') group_data += groupfile.read() groupfile.close() entry.text = group_data + host_data [entry.attrib.__setitem__(key, value) for \ - (key, value) in self.server_attrib.iteritems()] + (key, value) in self.server_attrib.iteritems()] try: - fileh = open( "%s/nagiosgen.cfg" % (self.data), 'w' ) + fileh = open("%s/nagiosgen.cfg" % (self.data), 'w') fileh.write(group_data + host_data) fileh.close() except OSError, ioerr: diff --git a/src/lib/Server/Plugins/Ohai.py b/src/lib/Server/Plugins/Ohai.py index ea31b4460..b20218792 100644 --- a/src/lib/Server/Plugins/Ohai.py +++ b/src/lib/Server/Plugins/Ohai.py @@ -11,7 +11,7 @@ class OhaiCache(object): def __setitem__(self, item, value): self.cache[item] = json.loads(value) - file("%s/%s.json" % (self.dirname, item), 'w').write(value) + file("%s/%s.json" % (self.dirname, item), 'w').write(value) def __getitem__(self, item): if item not in self.cache: diff --git a/src/lib/Server/Plugins/POSIXCompat.py b/src/lib/Server/Plugins/POSIXCompat.py index d2e530407..4ea2c490c 100644 --- a/src/lib/Server/Plugins/POSIXCompat.py +++ b/src/lib/Server/Plugins/POSIXCompat.py @@ -15,6 +15,7 @@ COMPAT_DICT = {'configfile': 'ConfigFile', 'permissions': 'Permissions', 'symlink': 'SymLink'} + class POSIXCompat(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.GoalValidator): name = 'POSIXCompat' diff --git a/src/lib/Server/Plugins/Packages.py b/src/lib/Server/Plugins/Packages.py index bf532ee50..7bc9d1e27 100644 --- a/src/lib/Server/Plugins/Packages.py +++ b/src/lib/Server/Plugins/Packages.py @@ -1,9 +1,17 @@ -import copy, gzip, lxml.etree, re, urllib2, logging -import os, cPickle -import Bcfg2.Server.Plugin, Bcfg2.Logger +import cPickle +import copy +import gzip +import logging +import lxml.etree +import os +import re +import urllib2 + +import Bcfg2.Logger +import Bcfg2.Server.Plugin # build sources.list? -# caching for yum +# caching for yum class NoData(Exception): pass @@ -86,7 +94,7 @@ class Source(object): def read_files(self): pass - + def update(self): for url in self.urls: logger.info("Packages: Updating %s" % url) @@ -102,7 +110,7 @@ class Source(object): def applies(self, metadata): return len([g for g in self.basegroups if g in metadata.groups]) != 0 and \ len([g for g in metadata.groups if g in self.groups]) \ - == len(self.groups) + == len(self.groups) def get_arches(self, metadata): return ['global'] + [a for a in self.arches if a in metadata.groups] @@ -219,7 +227,7 @@ class YUMSource(Source): fl = '{http://linux.duke.edu/metadata/filelists}' basegroups = ['redhat', 'centos'] ptype = 'yum' - + def __init__(self, basepath, url, version, arches, components, groups, rawurl): Source.__init__(self, basepath, url, version, arches, components, groups, rawurl) @@ -294,7 +302,7 @@ class YUMSource(Source): continue self.packages[key] = self.packages['global'].difference(self.packages[key]) self.save_state() - + def parse_filelist(self, data, arch): for pkg in data.findall(self.fl + 'package'): for fentry in [fe for fe in pkg.findall(self.fl + 'file') \ @@ -325,7 +333,7 @@ class YUMSource(Source): if entry.get('name').startswith('/'): self.needed_paths.add(entry.get('name')) pro = pdata.find(self.rp + 'provides') - if pro != None: + if pro != None: for entry in pro.getchildren(): prov = entry.get('name') if prov not in self.provides[arch]: @@ -343,7 +351,7 @@ class YUMSource(Source): arches = [a for a in self.arches if a in metadata.groups] if not arches: raise NoData - if required in self.provides['global']: + if required in self.provides['global']: ret.update(Source.get_provides(self, metadata, required)) elif required in self.provides[arches[0]]: ret.update(Source.get_provides(self, metadata, required)) @@ -363,7 +371,7 @@ class YUMSource(Source): class APTSource(Source): basegroups = ['debian', 'ubuntu', 'nexenta'] ptype = 'deb' - + def __init__(self, basepath, url, version, arches, components, groups, rawurl): Source.__init__(self, basepath, url, version, arches, components, groups, rawurl) self.cachefile = self.escape_url(self.url) + '.data' @@ -478,7 +486,7 @@ class Packages(Bcfg2.Server.Plugin.Plugin, name = 'Packages' experimental = True __rmi__ = ['Refresh'] - + def __init__(self, core, datastore): Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) Bcfg2.Server.Plugin.StructureValidator.__init__(self) @@ -517,7 +525,7 @@ class Packages(Bcfg2.Server.Plugin.Plugin, entry.set('version', 'auto') for source in self.sources: if [x for x in metadata.groups if x in source.basegroups]: - entry.set('type', source.ptype) + entry.set('type', source.ptype) def complete(self, meta, packages, debug=False): '''Build the transitive closure of all package dependencies diff --git a/src/lib/Server/Plugins/Pkgmgr.py b/src/lib/Server/Plugins/Pkgmgr.py index e154c4449..7c334bea7 100644 --- a/src/lib/Server/Plugins/Pkgmgr.py +++ b/src/lib/Server/Plugins/Pkgmgr.py @@ -147,7 +147,7 @@ class Pkgmgr(Bcfg2.Server.Plugin.PrioDir): [entry.remove(inst) for inst in \ entry.findall('Instance') \ if inst.get('arch') not in arches] - + def HandlesEntry(self, entry, metadata): return entry.tag == 'Package' and entry.get('name').split(':')[0] in self.Entries['Package'].keys() diff --git a/src/lib/Server/Plugins/Probes.py b/src/lib/Server/Plugins/Probes.py index edfee0884..42ae2fe37 100644 --- a/src/lib/Server/Plugins/Probes.py +++ b/src/lib/Server/Plugins/Probes.py @@ -1,4 +1,7 @@ -import Bcfg2.Server.Plugin, lxml.etree, re +import lxml.etree +import re + +import Bcfg2.Server.Plugin specific_probe_matcher = re.compile("(.*/)?(?P<basename>\S+)(.(?P<mode>[GH])_\S+)") probe_matcher = re.compile("(.*/)?(?P<basename>\S+)") @@ -22,7 +25,7 @@ class ProbeSet(Bcfg2.Server.Plugin.EntrySet): ret = [] build = dict() candidates = self.get_matching(metadata) - candidates.sort(lambda x,y: cmp(x.specific, y.specific)) + candidates.sort(lambda x, y: cmp(x.specific, y.specific)) for entry in candidates: rem = specific_probe_matcher.match(entry.name) if not rem: @@ -30,7 +33,7 @@ class ProbeSet(Bcfg2.Server.Plugin.EntrySet): pname = rem.group('basename') if pname not in build: build[pname] = entry - + for (name, entry) in build.iteritems(): probe = lxml.etree.Element('probe') probe.set('name', name.split('/')[-1]) @@ -55,7 +58,7 @@ class Probes(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) Bcfg2.Server.Plugin.Connector.__init__(self) Bcfg2.Server.Plugin.Probing.__init__(self) - + try: self.probes = ProbeSet(self.data, core.fam, core.encoding, self.name) @@ -65,7 +68,7 @@ class Probes(Bcfg2.Server.Plugin.Plugin, self.probedata = dict() self.cgroups = dict() self.load_data() - + def write_data(self): '''write probe data out for use with bcfg2-info''' top = lxml.etree.Element("Probed") @@ -125,7 +128,7 @@ class Probes(Bcfg2.Server.Plugin.Plugin, self.probedata[client.hostname] = {data.get('name'): ''} return dlines = data.text.split('\n') - self.logger.debug("%s:probe:%s:%s" % (client.hostname, + self.logger.debug("%s:probe:%s:%s" % (client.hostname, data.get('name'), [line.strip() for line in dlines])) for line in dlines[:]: if line.split(':')[0] == 'group': @@ -135,9 +138,9 @@ class Probes(Bcfg2.Server.Plugin.Plugin, dlines.remove(line) dtext = "\n".join(dlines) try: - self.probedata[client.hostname].update({ data.get('name'):dtext }) + self.probedata[client.hostname].update({data.get('name'):dtext}) except KeyError: - self.probedata[client.hostname] = { data.get('name'):dtext } + self.probedata[client.hostname] = {data.get('name'):dtext} def get_additional_groups(self, meta): return self.cgroups.get(meta.hostname, list()) diff --git a/src/lib/Server/Plugins/Properties.py b/src/lib/Server/Plugins/Properties.py index 498b496ac..fe3b077d5 100644 --- a/src/lib/Server/Plugins/Properties.py +++ b/src/lib/Server/Plugins/Properties.py @@ -1,8 +1,12 @@ -import copy, lxml.etree +import copy +import lxml.etree + import Bcfg2.Server.Plugin + class PropertyFile(Bcfg2.Server.Plugin.XMLFileBacked): '''Class for properties files''' + def Index(self): '''Build data into an xml object''' try: @@ -10,12 +14,17 @@ class PropertyFile(Bcfg2.Server.Plugin.XMLFileBacked): except lxml.etree.XMLSyntaxError: Bcfg2.Server.Plugin.logger.error("Failed to parse %s" % self.name) + class PropDirectoryBacked(Bcfg2.Server.Plugin.DirectoryBacked): __child__ = PropertyFile + class Properties(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.Connector): - '''The properties plugin maps property files into client metadata instances''' + ''' + The properties plugin maps property + files into client metadata instances + ''' name = 'Properties' version = '$Revision$' experimental = True diff --git a/src/lib/Server/Plugins/Rules.py b/src/lib/Server/Plugins/Rules.py index b23a52980..bd0850c49 100644 --- a/src/lib/Server/Plugins/Rules.py +++ b/src/lib/Server/Plugins/Rules.py @@ -3,6 +3,7 @@ __revision__ = '$Revision$' import Bcfg2.Server.Plugin + class Rules(Bcfg2.Server.Plugin.PrioDir): '''This is a generator that handles service assignments''' name = 'Rules' diff --git a/src/lib/Server/Plugins/SGenshi.py b/src/lib/Server/Plugins/SGenshi.py index 6c06a25d0..6f17e5ede 100644 --- a/src/lib/Server/Plugins/SGenshi.py +++ b/src/lib/Server/Plugins/SGenshi.py @@ -1,13 +1,18 @@ '''This module implements a templating generator based on Genshi''' __revision__ = '$Revision$' -import Bcfg2.Server.Plugin, Bcfg2.Server.Plugins.TGenshi -import lxml.etree, logging import genshi.template +import lxml.etree +import logging + +import Bcfg2.Server.Plugin +import Bcfg2.Server.Plugins.TGenshi logger = logging.getLogger('Bcfg2.Plugins.SGenshi') + class SGenshiTemplateFile(Bcfg2.Server.Plugins.TGenshi.TemplateFile): + def get_xml_value(self, metadata): if not hasattr(self, 'template'): logger.error("No parsed template information for %s" % (self.name)) @@ -17,10 +22,12 @@ class SGenshiTemplateFile(Bcfg2.Server.Plugins.TGenshi.TemplateFile): data = stream.render('xml', strip_whitespace=False) return lxml.etree.XML(data) + class SGenshiEntrySet(Bcfg2.Server.Plugin.EntrySet): + def __init__(self, path, fam, encoding): fpattern = '\S+\.xml' - Bcfg2.Server.Plugin.EntrySet.__init__(self, fpattern, path, + Bcfg2.Server.Plugin.EntrySet.__init__(self, fpattern, path, SGenshiTemplateFile, encoding) fam.AddMonitor(path, self) @@ -40,6 +47,7 @@ class SGenshiEntrySet(Bcfg2.Server.Plugin.EntrySet): logger.error("SGenshi: Failed to template file %s" % entry.name) return ret + class SGenshi(SGenshiEntrySet, Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.Structure): @@ -58,5 +66,3 @@ class SGenshi(SGenshiEntrySet, logger.error("Failed to load %s repository; disabling %s" \ % (self.name, self.name)) raise Bcfg2.Server.Plugin.PluginInitError - - diff --git a/src/lib/Server/Plugins/SSHbase.py b/src/lib/Server/Plugins/SSHbase.py index 388cc53fc..a3690a05a 100644 --- a/src/lib/Server/Plugins/SSHbase.py +++ b/src/lib/Server/Plugins/SSHbase.py @@ -8,6 +8,7 @@ import tempfile from subprocess import Popen, PIPE import Bcfg2.Server.Plugin + class SSHbase(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.Generator, Bcfg2.Server.Plugin.DirectoryBacked, @@ -54,13 +55,13 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, self.logger.error(ioerr) raise Bcfg2.Server.Plugin.PluginInitError self.Entries = {'ConfigFile': - {'/etc/ssh/ssh_known_hosts':self.build_skn, - '/etc/ssh/ssh_host_dsa_key':self.build_hk, - '/etc/ssh/ssh_host_rsa_key':self.build_hk, - '/etc/ssh/ssh_host_dsa_key.pub':self.build_hk, - '/etc/ssh/ssh_host_rsa_key.pub':self.build_hk, - '/etc/ssh/ssh_host_key':self.build_hk, - '/etc/ssh/ssh_host_key.pub':self.build_hk}} + {'/etc/ssh/ssh_known_hosts': self.build_skn, + '/etc/ssh/ssh_host_dsa_key': self.build_hk, + '/etc/ssh/ssh_host_rsa_key': self.build_hk, + '/etc/ssh/ssh_host_dsa_key.pub': self.build_hk, + '/etc/ssh/ssh_host_rsa_key.pub': self.build_hk, + '/etc/ssh/ssh_host_key': self.build_hk, + '/etc/ssh/ssh_host_key.pub': self.build_hk}} self.ipcache = {} self.__skn = False @@ -209,7 +210,7 @@ class SSHbase(Bcfg2.Server.Plugin.Plugin, "H_%s" % client]) tempdir = tempfile.mkdtemp() temploc = "%s/%s" % (tempdir, hostkey) - cmd = 'ssh-keygen -q -f %s -N "" -t %s -C root@%s < /dev/null' + cmd = 'ssh-keygen -q -f %s -N "" -t %s -C root@%s < /dev/null' os.system(cmd % (temploc, keytype, client)) open(fileloc, 'w').write(open(temploc).read()) open(publoc, 'w').write(open("%s.pub" % temploc).read()) diff --git a/src/lib/Server/Plugins/Snapshots.py b/src/lib/Server/Plugins/Snapshots.py index 3b2949e7a..871d77b68 100644 --- a/src/lib/Server/Plugins/Snapshots.py +++ b/src/lib/Server/Plugins/Snapshots.py @@ -15,6 +15,7 @@ datafields = {'Package': ['version'], 'Service': ['status'], 'ConfigFile': ['owner', 'group', 'perms']} + def build_snap_ent(entry): basefields = [] if entry.tag in ['Package', 'Service']: @@ -39,17 +40,19 @@ def build_snap_ent(entry): diff = binascii.a2b_base64(entry.get('current_bdiff')) state['contents'] = unicode( \ '\n'.join(difflib.restore(diff.split('\n'), 1))) - + state.update([(key, unicode(entry.get('current_' + key, entry.get(key)))) \ for key in datafields[entry.tag]]) if entry.tag == 'ConfigFile' and entry.get('exists', 'true') == 'false': state = None return [desired, state] + class Snapshots(Bcfg2.Server.Plugin.Statistics, Bcfg2.Server.Plugin.Plugin): name = 'Snapshots' experimental = True + def __init__(self, core, datastore): Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore) Bcfg2.Server.Plugin.Statistics.__init__(self) diff --git a/src/lib/Server/Plugins/Statistics.py b/src/lib/Server/Plugins/Statistics.py index 90860e3e4..492e06e9c 100644 --- a/src/lib/Server/Plugins/Statistics.py +++ b/src/lib/Server/Plugins/Statistics.py @@ -1,13 +1,18 @@ '''This file manages the statistics collected by the BCFG2 Server''' __revision__ = '$Revision$' +import binascii +import copy +import difflib +import logging from lxml.etree import XML, SubElement, Element, XMLSyntaxError +import lxml.etree +import os from time import asctime, localtime, time, strptime, mktime -import binascii, difflib, logging, lxml.etree, os, copy - import Bcfg2.Server.Plugin + class StatisticsStore(object): '''Manages the memory and file copy of statistics collected about client runs''' __min_write_delay__ = 0 @@ -23,7 +28,7 @@ class StatisticsStore(object): def WriteBack(self, force=0): '''Write statistics changes back to persistent store''' # FIXME switch to a thread writer - if (self.dirty and (self.lastwrite + self.__min_write_delay__ <= time()) ) \ + if (self.dirty and (self.lastwrite + self.__min_write_delay__ <= time())) \ or force: try: fout = open(self.filename + '.new', 'w') @@ -53,11 +58,11 @@ class StatisticsStore(object): def updateStats(self, xml, client): '''Updates the statistics of a current node with new data''' - # Current policy: + # Current policy: # - Keep anything less than 24 hours old # - Keep latest clean run for clean nodes # - Keep latest clean and dirty run for dirty nodes - newstat = xml.find('Statistics') + newstat = xml.find('Statistics') if newstat.get('state') == 'clean': node_dirty = 0 @@ -98,7 +103,6 @@ class StatisticsStore(object): self.dirty = 1 self.WriteBack(force=1) - def isOlderThan24h(self, testTime): '''Helper function to determine if <time> string is older than 24 hours''' now = time() @@ -107,6 +111,7 @@ class StatisticsStore(object): return (now-utime) > secondsPerDay + class Statistics(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.Statistics, Bcfg2.Server.Plugin.PullSource): @@ -129,7 +134,7 @@ class Statistics(Bcfg2.Server.Plugin.Plugin, in rt.findall('Statistics')]) return [stat for stat in rt.findall('Statistics') \ if strptime(stat.get('time')) == maxtime][0] - + def GetExtra(self, client): return [(entry.tag, entry.get('name')) for entry \ in self.FindCurrent(client).xpath('.//Extra/*')] diff --git a/src/lib/Server/Plugins/Svcmgr.py b/src/lib/Server/Plugins/Svcmgr.py index ab951be35..396c5145c 100644 --- a/src/lib/Server/Plugins/Svcmgr.py +++ b/src/lib/Server/Plugins/Svcmgr.py @@ -3,6 +3,7 @@ __revision__ = '$Revision$' import Bcfg2.Server.Plugin + class Svcmgr(Bcfg2.Server.Plugin.PrioDir): '''This is a generator that handles service assignments''' name = 'Svcmgr' diff --git a/src/lib/Server/Plugins/Svn.py b/src/lib/Server/Plugins/Svn.py index d8fd70ead..db90fff3b 100644 --- a/src/lib/Server/Plugins/Svn.py +++ b/src/lib/Server/Plugins/Svn.py @@ -6,6 +6,7 @@ import Bcfg2.Server.Plugin import logging logger = logging.getLogger('Bcfg2.Plugins.Svn') + class Svn(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.Version): name = 'Svn' @@ -42,4 +43,3 @@ class Svn(Bcfg2.Server.Plugin.Plugin, logger.error('''Ran command "svn info %s"''' % (self.datastore)) logger.error("Got output: %s" % data) raise Bcfg2.Server.Plugin.PluginInitError - diff --git a/src/lib/Server/Plugins/TCheetah.py b/src/lib/Server/Plugins/TCheetah.py index 87358684c..9988b80e4 100644 --- a/src/lib/Server/Plugins/TCheetah.py +++ b/src/lib/Server/Plugins/TCheetah.py @@ -15,15 +15,17 @@ except: logger.error("TCheetah: Failed to import Cheetah. Is it installed?") raise + class TemplateFile: '''Template file creates Cheetah template structures for the loaded file''' + def __init__(self, name, specific, encoding): self.name = name self.specific = specific self.encoding = encoding self.template = None self.searchlist = dict() - + def handle_event(self, event): '''Handle all fs events for this template''' if event.code2str() == 'deleted': @@ -36,7 +38,7 @@ class TemplateFile: except Cheetah.Parser.ParseError, perror: logger.error("Cheetah parse error for file %s" % (self.name)) logger.error(perror.report()) - + def bind_entry(self, entry, metadata): '''Build literal file information''' self.template.metadata = metadata @@ -45,11 +47,11 @@ class TemplateFile: self.searchlist['path'] = entry.get('realname', entry.get('name')) self.template.source_path = self.name self.searchlist['source_path'] = self.name - + try: if type(self.template) == unicode: entry.text = self.template - else : + else: entry.text = unicode(str(self.template), self.encoding) except: (a, b, c) = sys.exc_info() diff --git a/src/lib/Server/Plugins/TGenshi.py b/src/lib/Server/Plugins/TGenshi.py index 4bec8b2f1..b38bdfb0b 100644 --- a/src/lib/Server/Plugins/TGenshi.py +++ b/src/lib/Server/Plugins/TGenshi.py @@ -10,10 +10,12 @@ except: have_ntt = False import logging import Bcfg2.Server.Plugin -import genshi.core, genshi.input +import genshi.core +import genshi.input logger = logging.getLogger('Bcfg2.Plugins.TGenshi') + def removecomment(stream): """A genshi filter that removes comments from the stream.""" for kind, data, pos in stream: @@ -21,8 +23,10 @@ def removecomment(stream): continue yield kind, data, pos + class TemplateFile: '''Template file creates Genshi template structures for the loaded file''' + def __init__(self, name, specific, encoding): self.name = name self.specific = specific @@ -43,7 +47,7 @@ class TemplateFile: else: self.template_cls = MarkupTemplate self.HandleEvent = self.handle_event - + def handle_event(self, event=None): '''Handle all fs events for this template''' if event and event.code2str() == 'deleted': @@ -59,7 +63,7 @@ class TemplateFile: logger.error('Genshi template error: %s' % terror) except genshi.input.ParseError, perror: logger.error('Genshi parse error: %s' % perror) - + def bind_entry(self, entry, metadata): '''Build literal file information''' fname = entry.get('realname', entry.get('name')) @@ -96,6 +100,7 @@ class TemplateFile: logger.error('Genshi template loading error: %s' % err) raise Bcfg2.Server.Plugin.PluginExecutionError + class TGenshi(Bcfg2.Server.Plugin.GroupSpool): ''' The TGenshi generator implements a templating diff --git a/src/lib/Server/Plugins/Trigger.py b/src/lib/Server/Plugins/Trigger.py index d73e143ee..b45743134 100644 --- a/src/lib/Server/Plugins/Trigger.py +++ b/src/lib/Server/Plugins/Trigger.py @@ -1,6 +1,7 @@ import os import Bcfg2.Server.Plugin + def async_run(prog, args): pid = os.fork() if pid: @@ -11,6 +12,7 @@ def async_run(prog, args): os.system(" ".join([prog] + args)) os._exit(0) + class Trigger(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.Statistics): name = 'Trigger' diff --git a/src/lib/Server/Snapshots/__init__.py b/src/lib/Server/Snapshots/__init__.py index eb849e715..c13dee42e 100644 --- a/src/lib/Server/Snapshots/__init__.py +++ b/src/lib/Server/Snapshots/__init__.py @@ -1,6 +1,9 @@ __all__ = ['models', 'db_from_config', 'setup_session'] -import sqlalchemy, sqlalchemy.orm, ConfigParser +import sqlalchemy +import sqlalchemy.orm +import ConfigParser + def db_from_config(fname='/etc/bcfg2.conf'): cp = ConfigParser.ConfigParser() diff --git a/src/lib/Server/Snapshots/model.py b/src/lib/Server/Snapshots/model.py index cd2e617f5..cbb14be79 100644 --- a/src/lib/Server/Snapshots/model.py +++ b/src/lib/Server/Snapshots/model.py @@ -1,11 +1,14 @@ -from sqlalchemy import Table, Column, Integer, Unicode, ForeignKey, Boolean, DateTime, UnicodeText, desc +from sqlalchemy import Table, Column, Integer, Unicode, ForeignKey, Boolean, \ + DateTime, UnicodeText, desc import datetime import sqlalchemy.exceptions from sqlalchemy.orm import relation, backref from sqlalchemy.ext.declarative import declarative_base + class Uniquer(object): force_rt = True + @classmethod def by_value(cls, session, **kwargs): if cls.force_rt: @@ -22,6 +25,7 @@ class Uniquer(object): Base = declarative_base() + class Administrator(Uniquer, Base): __tablename__ = 'administrator' id = Column(Integer, primary_key=True) @@ -36,6 +40,7 @@ admin_group = Table('admin_group', Base.metadata, Column('admin_id', Integer, ForeignKey('administrator.id')), Column('group_id', Integer, ForeignKey('group.id'))) + class Client(Uniquer, Base): __tablename__ = 'client' id = Column(Integer, primary_key=True) @@ -46,6 +51,7 @@ class Client(Uniquer, Base): online = Column(Boolean, default=True) online_ts = Column(DateTime) + class Group(Uniquer, Base): __tablename__ = 'group' id = Column(Integer, primary_key=True) @@ -53,6 +59,7 @@ class Group(Uniquer, Base): admins = relation("Administrator", secondary=admin_group, backref='groups') + class ConnectorKeyVal(Uniquer, Base): __tablename__ = 'connkeyval' id = Column(Integer, primary_key=True) @@ -68,6 +75,7 @@ meta_conn = Table('meta_conn', Base.metadata, Column('metadata_id', Integer, ForeignKey('metadata.id')), Column('connkeyval_id', Integer, ForeignKey('connkeyval.id'))) + class Metadata(Base): __tablename__ = 'metadata' id = Column(Integer, primary_key=True) @@ -96,6 +104,7 @@ class Metadata(Base): value=unicode(value))) return m + class Package(Base, Uniquer): __tablename__ = 'package' id = Column(Integer, primary_key=True) @@ -104,13 +113,15 @@ class Package(Base, Uniquer): version = Column(Unicode(16)) verification_status = Column(Boolean) + class CorrespondenceType(object): mtype = Package + @classmethod def from_record(cls, mysession, record): (mod, corr, name, s_dict, e_dict) = record if not s_dict: - start=None + start = None else: start = cls.mtype.by_value(mysession, name=name, **s_dict) if s_dict != e_dict: @@ -119,6 +130,7 @@ class CorrespondenceType(object): end = start return cls(start=start, end=end, modified=mod, correct=corr) + class PackageCorrespondence(Base, CorrespondenceType): mtype = Package __tablename__ = 'package_pair' @@ -134,6 +146,7 @@ package_snap = Table('package_snap', Base.metadata, Column('ppair_id', Integer, ForeignKey('package_pair.id')), Column('snapshot_id', Integer, ForeignKey('snapshot.id'))) + class Service(Base, Uniquer): __tablename__ = 'service' id = Column(Integer, primary_key=True) @@ -141,6 +154,7 @@ class Service(Base, Uniquer): type = Column(Unicode(12)) status = Column(Boolean) + class ServiceCorrespondence(Base, CorrespondenceType): mtype = Service __tablename__ = 'service_pair' @@ -156,6 +170,7 @@ service_snap = Table('service_snap', Base.metadata, Column('spair_id', Integer, ForeignKey('service_pair.id')), Column('snapshot_id', Integer, ForeignKey('snapshot.id'))) + class File(Base, Uniquer): __tablename__ = 'file' id = Column(Integer, primary_key=True) @@ -166,6 +181,7 @@ class File(Base, Uniquer): perms = Column(Integer(5)) contents = Column(UnicodeText) + class FileCorrespondence(Base, CorrespondenceType): mtype = File __tablename__ = 'file_pair' @@ -193,6 +209,7 @@ extra_service_snap = Table('extra_service_snap', Base.metadata, Column('service_id', Integer, ForeignKey('service.id')), Column('snapshot_id', Integer, ForeignKey('snapshot.id'))) + class Action(Base): __tablename__ = 'action' id = Column(Integer, primary_key=True) @@ -204,6 +221,7 @@ action_snap = Table('action_snap', Base.metadata, Column('action_id', Integer, ForeignKey('action.id')), Column('snapshot_id', Integer, ForeignKey('snapshot.id'))) + class Snapshot(Base): __tablename__ = 'snapshot' id = Column(Integer, primary_key=True) diff --git a/src/lib/Server/__init__.py b/src/lib/Server/__init__.py index 5c5c89031..931345168 100644 --- a/src/lib/Server/__init__.py +++ b/src/lib/Server/__init__.py @@ -2,6 +2,5 @@ '''This is the set of modules for Bcfg2.Server''' __revision__ = '$Revision$' -__all__ = ["Admin", "Core", "FileMonitor", "Plugin", "Plugins", - "Hostbase", "Reports", "Snapshots"] - +__all__ = ["Admin", "Core", "FileMonitor", "Plugin", "Plugins", + "Hostbase", "Reports", "Snapshots"] |