diff options
52 files changed, 381 insertions, 289 deletions
diff --git a/src/lib/Component.py b/src/lib/Component.py index 3842a1922..58d893cd5 100644 --- a/src/lib/Component.py +++ b/src/lib/Component.py @@ -23,14 +23,14 @@ logger = logging.getLogger() class NoExposedMethod (Exception): """There is no method exposed with the given name.""" -def run_component (component_cls, location, daemon, pidfile_name, argv=None, - register=True, state_name=False, cls_kwargs={}, - extra_getopt='', time_out=10, protocol='xmlrpc/ssl', - certfile=None, keyfile=None, ca=None): - +def run_component(component_cls, location, daemon, pidfile_name, argv=None, + register=True, state_name=False, cls_kwargs={}, + extra_getopt='', time_out=10, protocol='xmlrpc/ssl', + certfile=None, keyfile=None, ca=None): + # default settings level = logging.INFO - + logging.getLogger().setLevel(level) Bcfg2.Logger.setup_logging(component_cls.implementation, True, True) @@ -38,20 +38,20 @@ def run_component (component_cls, location, daemon, pidfile_name, argv=None, child_pid = os.fork() if child_pid != 0: return - + os.setsid() - + child_pid = os.fork() if child_pid != 0: os._exit(0) - + redirect_file = open("/dev/null", "w+") os.dup2(redirect_file.fileno(), sys.__stdin__.fileno()) os.dup2(redirect_file.fileno(), sys.__stdout__.fileno()) os.dup2(redirect_file.fileno(), sys.__stderr__.fileno()) - + os.chdir(os.sep) - + pidfile = open(pidfile_name or "/dev/null", "w") print >> pidfile, os.getpid() pidfile.close() @@ -68,21 +68,21 @@ def run_component (component_cls, location, daemon, pidfile_name, argv=None, logger.error("Server startup failed") os._exit(1) server.register_instance(component) - + try: server.serve_forever() finally: server.server_close() -def exposed (func): +def exposed(func): """Mark a method to be exposed publically. - + Examples: class MyComponent (Component): @expose def my_method (self, param1, param2): do_stuff() - + class MyComponent (Component): def my_method (self, param1, param2): do_stuff() @@ -91,47 +91,47 @@ def exposed (func): func.exposed = True return func -def automatic (func, period=10): +def automatic(func, period=10): """Mark a method to be run periodically.""" func.automatic = True func.automatic_period = period func.automatic_ts = -1 return func -def locking (func): +def locking(func): """Mark a function as being internally thread safe""" func.locking = True return func -def readonly (func): +def readonly(func): """Mark a function as read-only -- no data effects in component inst""" func.readonly = True return func class Component (object): - + """Base component. - + Intended to be served as an instance by Cobalt.Component.XMLRPCServer >>> server = Cobalt.Component.XMLRPCServer(location, keyfile) >>> component = Cobalt.Component.Component() >>> server.serve_instance(component) - + Class attributes: name -- logical component name (e.g., "queue-manager", "process-manager") implementation -- implementation identifier (e.g., "BlueGene/L", "BlueGene/P") - + Methods: save -- pickle the component to a file do_tasks -- perform automatic tasks for the component """ - + name = "component" implementation = "generic" - - def __init__ (self, **kwargs): + + def __init__(self, **kwargs): """Initialize a new component. - + Keyword arguments: statefile -- file in which to save state automatically """ @@ -139,10 +139,10 @@ class Component (object): self.logger = logging.getLogger("%s %s" % (self.implementation, self.name)) self.lock = threading.Lock() self.instance_statistics = Statistics() - - def do_tasks (self): + + def do_tasks(self): """Perform automatic tasks for the component. - + Automatic tasks are member callables with an attribute automatic == True. """ @@ -171,9 +171,9 @@ class Component (object): self.instance_statistics.add_value(name, mt2-mt1) func.__dict__['automatic_ts'] = time.time() - def _resolve_exposed_method (self, method_name): + def _resolve_exposed_method(self, method_name): """Resolve an exposed method. - + Arguments: method_name -- name of the method to resolve """ @@ -185,9 +185,9 @@ class Component (object): raise NoExposedMethod(method_name) return func - def _dispatch (self, method, args, dispatch_dict): + def _dispatch(self, method, args, dispatch_dict): """Custom XML-RPC dispatcher for components. - + method -- XML-RPC method name args -- tuple of paramaters to method """ @@ -204,7 +204,7 @@ class Component (object): if getattr(e, "log", True): self.logger.error(e, exc_info=True) raise xmlrpclib.Fault(getattr(e, "fault_code", 1), str(e)) - + if getattr(method_func, 'locking', False): need_to_lock = False if need_to_lock: @@ -229,7 +229,7 @@ class Component (object): return result @exposed - def listMethods (self): + def listMethods(self): """Custom XML-RPC introspective method list.""" return [ name for name, func in inspect.getmembers(self, callable) @@ -237,9 +237,9 @@ class Component (object): ] @exposed - def methodHelp (self, method_name): + def methodHelp(self, method_name): """Custom XML-RPC introspective method help. - + Arguments: method_name -- name of method to get help on """ @@ -248,18 +248,18 @@ class Component (object): except NoExposedMethod: return "" return pydoc.getdoc(func) - - def get_name (self): + + def get_name(self): """The name of the component.""" return self.name get_name = exposed(get_name) - - def get_implementation (self): + + def get_implementation(self): """The implementation of the component.""" return self.implementation get_implementation = exposed(get_implementation) - def get_statistics (self, _): + def get_statistics(self, _): """Get current statistics about component execution""" return self.instance_statistics.display() get_statistics = exposed(get_statistics) diff --git a/src/lib/Logger.py b/src/lib/Logger.py index db4c4dd09..de5466cd4 100644 --- a/src/lib/Logger.py +++ b/src/lib/Logger.py @@ -21,7 +21,7 @@ def print_text(text): ''' Add text to the output (which will need normalising ''' charmap = {'<':'<', '>':'>', '&':'&'} return ''.join([charmap.get(char, char) for char in text]) + '\n' - + def xml_print(element, running_indent=0, indent=4): ''' Add an element and its children to the return string ''' if (len(element.getchildren()) == 0) and (not element.text): @@ -31,11 +31,11 @@ def xml_print(element, running_indent=0, indent=4): child_indent = running_indent + indent ret = (' ' * running_indent) ret += '<%s%s>\n' % (element.tag, print_attributes(element)) - if element.text: + if element.text: ret += (' '* child_indent) + print_text(element.text) for child in element.getchildren(): ret += xml_print(child, child_indent, indent) - ret += (' ' * running_indent) + '</%s>\n' % (element.tag) + ret += (' ' * running_indent) + '</%s>\n' % (element.tag) if element.tail: ret += (' ' * child_indent) + print_text(element.tail) return ret @@ -141,7 +141,7 @@ class FragmentingSysLogHandler(logging.handlers.SysLogHandler): def setup_logging(procname, to_console=True, to_syslog=True, syslog_facility='daemon', level=0, to_file=None): '''setup logging for bcfg2 software''' if hasattr(logging, 'already_setup'): - return + return # add the handler to the root logger if to_console: console = logging.StreamHandler(sys.stdout) @@ -170,23 +170,23 @@ def setup_logging(procname, to_console=True, to_syslog=True, syslog_facility='da logging.root.setLevel(level) logging.already_setup = True -def trace_process (**kwargs): - +def trace_process(**kwargs): + """Literally log every line of python code as it runs. - + Keyword arguments: log -- file (name) to log to (default stderr) scope -- base scope to log to (default Cobalt)""" - + file_name = kwargs.get("log", None) if file_name is not None: log_file = open(file_name, "w") else: log_file = sys.stderr - + scope = kwargs.get("scope", "Cobalt") - - def traceit (frame, event, arg): + + def traceit(frame, event, arg): if event == "line": lineno = frame.f_lineno filename = frame.f_globals["__file__"] @@ -197,10 +197,10 @@ def trace_process (**kwargs): line = linecache.getline(filename, lineno) print >> log_file, "%s:%s: %s" % (name, lineno, line.rstrip()) return traceit - + sys.settrace(traceit) -def log_to_stderr (logger_name, level=logging.INFO): +def log_to_stderr(logger_name, level=logging.INFO): """Set up console logging.""" try: logger = logging.getLogger(logger_name) @@ -212,7 +212,7 @@ def log_to_stderr (logger_name, level=logging.INFO): handler.setFormatter(TermiosFormatter()) # investigate this formatter logger.addHandler(handler) -def log_to_syslog (logger_name, level=logging.INFO, format='%(name)s[%(process)d]: %(message)s'): +def log_to_syslog(logger_name, level=logging.INFO, format='%(name)s[%(process)d]: %(message)s'): """Set up syslog logging.""" try: logger = logging.getLogger(logger_name) diff --git a/src/lib/Options.py b/src/lib/Options.py index b61fea808..1e4ce7aef 100644 --- a/src/lib/Options.py +++ b/src/lib/Options.py @@ -22,6 +22,7 @@ DEFAULT_INSTALL_PREFIX = '/usr' #/usr class Option(object): cfpath = DEFAULT_CONFIG_LOCATION __cfp = False + def getCFP(self): if not self.__cfp: self.__cfp = ConfigParser.ConfigParser() @@ -36,7 +37,7 @@ class Option(object): return self.cook(value) else: return value - + def __init__(self, desc, default, cmd=False, odesc=False, env=False, cf=False, cook=False, long_arg=False): self.desc = desc @@ -121,7 +122,7 @@ class OptionSet(dict): def __init__(self, *args): dict.__init__(self, *args) self.hm = self.buildHelpMessage() - + def buildGetopt(self): return ''.join([opt.buildGetopt() for opt in list(self.values())]) @@ -191,7 +192,7 @@ MDATA_PARANOID = Option('Default ConfigFile paranoid setting', SERVER_REPOSITORY = Option('Server repository path', '/var/lib/bcfg2', cf=('server', 'repository'), cmd='-Q', - odesc='<repository path>' ) + odesc='<repository path>') SERVER_PLUGINS = Option('Server plugin list', cf=('server', 'plugins'), # default server plugins default=[ @@ -299,7 +300,7 @@ LOGGING_FILE_PATH = Option('Set path of file log', default=None, cmd='-o', odesc='<path>', cf=('logging', 'path')) CLIENT_SERVICE_MODE = Option('Set client service mode', default='default', - cmd='-s', odesc='<default|disabled|build>') + cmd='-s', odesc='<default|disabled|build>') class OptionParser(OptionSet): diff --git a/src/lib/Proxy.py b/src/lib/Proxy.py index fc71d212c..ea07fee47 100644 --- a/src/lib/Proxy.py +++ b/src/lib/Proxy.py @@ -160,17 +160,17 @@ class XMLRPCTransport(xmlrpclib.Transport): return u.close() -def ComponentProxy (url, user=None, password=None, key=None, cert=None, ca=None, - allowedServerCNs=None, timeout=90): - +def ComponentProxy(url, user=None, password=None, key=None, cert=None, ca=None, + allowedServerCNs=None, timeout=90): + """Constructs proxies to components. - + Arguments: component_name -- name of the component to connect to - + Additional arguments are passed to the ServerProxy constructor. """ - + if user and password: method, path = urlparse.urlparse(url)[:2] newurl = "%s://%s:%s@%s" % (method, user, password, path) @@ -178,4 +178,3 @@ def ComponentProxy (url, user=None, password=None, key=None, cert=None, ca=None, newurl = url ssl_trans = XMLRPCTransport(key, cert, ca, allowedServerCNs, timeout=timeout) return xmlrpclib.ServerProxy(newurl, allow_none=True, transport=ssl_trans) - diff --git a/src/lib/SSLServer.py b/src/lib/SSLServer.py index 68350d70f..5e5bb6574 100644 --- a/src/lib/SSLServer.py +++ b/src/lib/SSLServer.py @@ -25,7 +25,7 @@ class ForkedChild(Exception): class XMLRPCDispatcher (SimpleXMLRPCServer.SimpleXMLRPCDispatcher): logger = logging.getLogger("Cobalt.Server.XMLRPCDispatcher") - def __init__ (self, allow_none, encoding): + def __init__(self, allow_none, encoding): try: SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self, allow_none, @@ -37,14 +37,14 @@ class XMLRPCDispatcher (SimpleXMLRPCServer.SimpleXMLRPCDispatcher): self.allow_none = allow_none self.encoding = encoding - def _marshaled_dispatch (self, address, data): + def _marshaled_dispatch(self, address, data): method_func = None params, method = xmlrpclib.loads(data) try: if '.' not in method: params = (address, ) + params response = self.instance._dispatch(method, params, self.funcs) - response = (response,) + response = (response, ) raw_response = xmlrpclib.dumps(response, methodresponse=1, allow_none=self.allow_none, encoding=self.encoding) @@ -74,8 +74,8 @@ class SSLServer (SocketServer.TCPServer, object): allow_reuse_address = True logger = logging.getLogger("Cobalt.Server.TCPServer") - def __init__ (self, server_address, RequestHandlerClass, keyfile=None, - certfile=None, reqCert=False, ca=None, timeout=None, protocol='xmlrpc/ssl'): + def __init__(self, server_address, RequestHandlerClass, keyfile=None, + certfile=None, reqCert=False, ca=None, timeout=None, protocol='xmlrpc/ssl'): """Initialize the SSL-TCP server. @@ -134,7 +134,7 @@ class SSLServer (SocketServer.TCPServer, object): ca_certs=self.ca, ssl_version=self.ssl_protocol) return sslsock, sockinfo - def _get_url (self): + def _get_url(self): port = self.socket.getsockname()[1] hostname = socket.gethostname() protocol = "https" @@ -157,7 +157,7 @@ class XMLRPCRequestHandler (SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): """ logger = logging.getLogger("Cobalt.Server.XMLRPCRequestHandler") - def authenticate (self): + def authenticate(self): try: header = self.headers['Authorization'] except KeyError: @@ -175,7 +175,7 @@ class XMLRPCRequestHandler (SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): return self.server.instance.authenticate(cert, username, password, client_address) - def parse_request (self): + def parse_request(self): """Extends parse_request. Optionally check HTTP authentication when parsing.""" @@ -245,11 +245,11 @@ class XMLRPCServer (SocketServer.ThreadingMixIn, SSLServer, credentials -- valid credentials being used for authentication """ - def __init__ (self, server_address, RequestHandlerClass=None, - keyfile=None, certfile=None, ca=None, protocol='xmlrpc/ssl', - timeout=10, - logRequests=False, - register=True, allow_none=True, encoding=None): + def __init__(self, server_address, RequestHandlerClass=None, + keyfile=None, certfile=None, ca=None, protocol='xmlrpc/ssl', + timeout=10, + logRequests=False, + register=True, allow_none=True, encoding=None): """Initialize the XML-RPC server. @@ -283,7 +283,7 @@ class XMLRPCServer (SocketServer.ThreadingMixIn, SSLServer, self.logger.info("service available at %s" % self.url) self.timeout = timeout - def _tasks_thread (self): + def _tasks_thread(self): try: while self.serve: try: @@ -295,26 +295,26 @@ class XMLRPCServer (SocketServer.ThreadingMixIn, SSLServer, except: self.logger.error("tasks_thread failed", exc_info=1) - def server_close (self): + def server_close(self): SSLServer.server_close(self) self.logger.info("server_close()") - def _get_require_auth (self): + def _get_require_auth(self): return getattr(self.RequestHandlerClass, "require_auth", False) - def _set_require_auth (self, value): + def _set_require_auth(self, value): self.RequestHandlerClass.require_auth = value require_auth = property(_get_require_auth, _set_require_auth) - def _get_credentials (self): + def _get_credentials(self): try: return self.RequestHandlerClass.credentials except AttributeError: return dict() - def _set_credentials (self, value): + def _set_credentials(self, value): self.RequestHandlerClass.credentials = value credentials = property(_get_credentials, _set_credentials) - def register_instance (self, instance, *args, **kwargs): + def register_instance(self, instance, *args, **kwargs): XMLRPCDispatcher.register_instance(self, instance, *args, **kwargs) try: name = instance.name @@ -328,7 +328,7 @@ class XMLRPCServer (SocketServer.ThreadingMixIn, SSLServer, self.register_function(fn, name=xmname) self.logger.info("serving %s at %s" % (name, self.url)) - def serve_forever (self): + def serve_forever(self): """Serve single requests until (self.serve == False).""" self.serve = True self.task_thread = threading.Thread(target=self._tasks_thread) @@ -351,14 +351,14 @@ class XMLRPCServer (SocketServer.ThreadingMixIn, SSLServer, finally: self.logger.info("serve_forever() [stop]") - def shutdown (self): + def shutdown(self): """Signal that automatic service should stop.""" self.serve = False - def _handle_shutdown_signal (self, *_): + def _handle_shutdown_signal(self, *_): self.shutdown() - def ping (self, *args): + def ping(self, *args): """Echo response.""" self.logger.info("ping(%s)" % (", ".join([repr(arg) for arg in args]))) return args 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"] diff --git a/src/lib/Statistics.py b/src/lib/Statistics.py index c3fdd4320..b2240db98 100644 --- a/src/lib/Statistics.py +++ b/src/lib/Statistics.py @@ -13,7 +13,7 @@ class Statistic(object): if value > self.max: self.max = value self.count += 1 - self.ave = (((self.ave * (self.count - 1)) + value) / self.count ) + self.ave = (((self.ave * (self.count - 1)) + value) / self.count) def get_value(self): return (self.name, (self.min, self.max, self.ave, self.count)) @@ -30,4 +30,3 @@ class Statistics(object): def display(self): return dict([value.get_value() for value in self.data.values()]) - diff --git a/src/sbin/bcfg2-admin b/src/sbin/bcfg2-admin index c5c03c4cd..2d6ba4f5a 100755 --- a/src/sbin/bcfg2-admin +++ b/src/sbin/bcfg2-admin @@ -4,7 +4,6 @@ from optparse import OptionParser from StringIO import StringIO import logging -import sys import Bcfg2.Server.Core import Bcfg2.Logger import Bcfg2.Options @@ -39,10 +38,13 @@ def create_description(): def main(): Bcfg2.Logger.setup_logging('bcfg2-admin', to_console=True, level=40) - usage="Usage: %prog [options] MODE [args]" + usage = "Usage: %prog [options] MODE [args]" parser = OptionParser(usage=usage) parser.set_defaults(configfile=Bcfg2.Options.CFILE.default) - parser.add_option("-C", "--configfile", dest="configfile", help="Path to bcfg2.conf", metavar="FILE") + parser.add_option("-C", "--configfile", + dest="configfile", + help="Path to bcfg2.conf", + metavar="FILE") parser.disable_interspersed_args() (options, args) = parser.parse_args() diff --git a/src/sbin/bcfg2-info b/src/sbin/bcfg2-info index 31a5ff0f9..676311211 100755 --- a/src/sbin/bcfg2-info +++ b/src/sbin/bcfg2-info @@ -2,10 +2,19 @@ '''This tool loads the Bcfg2 core into an interactive debugger''' __revision__ = '$Revision$' -import copy, logging, lxml.etree, sys, cmd, time, tempfile, profile, pstats -import Bcfg2.Logger, Bcfg2.Server.Core, os -import Bcfg2.Server.Plugins.Metadata, Bcfg2.Server.Plugin +import cmd +import logging +import lxml.etree +import os +import profile +import pstats +import sys +import tempfile +import Bcfg2.Logger import Bcfg2.Options +import Bcfg2.Server.Core +import Bcfg2.Server.Plugins.Metadata +import Bcfg2.Server.Plugin logger = logging.getLogger('bcfg2-info') diff --git a/src/sbin/bcfg2-server b/src/sbin/bcfg2-server index e5ea5c184..06ad53768 100755 --- a/src/sbin/bcfg2-server +++ b/src/sbin/bcfg2-server @@ -5,7 +5,6 @@ __revision__ = '$Revision$' import logging import sys -from xmlrpclib import Fault import Bcfg2.Logger import Bcfg2.Options |