diff options
author | Narayan Desai <desai@mcs.anl.gov> | 2005-12-09 04:37:31 +0000 |
---|---|---|
committer | Narayan Desai <desai@mcs.anl.gov> | 2005-12-09 04:37:31 +0000 |
commit | 68141238ab5c6a5f6232bf91bdedbc791d8e280d (patch) | |
tree | 1565dcd7965dd1f59775a4e3f2bbe5066ae74b31 /src/sbin/Bcfg2Server | |
parent | 6bb9fc6357377882076bfcb135a6d56c47f60bb2 (diff) | |
download | bcfg2-68141238ab5c6a5f6232bf91bdedbc791d8e280d.tar.gz bcfg2-68141238ab5c6a5f6232bf91bdedbc791d8e280d.tar.bz2 bcfg2-68141238ab5c6a5f6232bf91bdedbc791d8e280d.zip |
version bump
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@1618 ce84e21b-d406-0410-9b95-82705330c041
Diffstat (limited to 'src/sbin/Bcfg2Server')
-rw-r--r-- | src/sbin/Bcfg2Server | 193 |
1 files changed, 124 insertions, 69 deletions
diff --git a/src/sbin/Bcfg2Server b/src/sbin/Bcfg2Server index d8e224369..ae878771e 100644 --- a/src/sbin/Bcfg2Server +++ b/src/sbin/Bcfg2Server @@ -17,30 +17,76 @@ from xmlrpclib import Fault from socket import gethostbyaddr, herror from lxml.etree import XML, Element, tostring from M2Crypto.SSL import SSLError -import os, sys -def dgetopt(arglist, opt, vopt): +def critical_error(operation): + '''Print tracebacks in unexpected cases''' + syslog(LOG_ERR, "Traceback information (please include in any bug report):") + (ttype, value, trace) = exc_info() + for line in extract_tb(trace): + syslog(LOG_ERR, "File %s, line %i, in %s\n %s" % (line)) + syslog(LOG_ERR, "%s: %s" % (ttype, value)) + del trace, val, trb + warning_error("An unexpected failure occurred in %s" % (operation) ) + +def fatal_error(message): + '''Signal a fatal error''' + syslog(LOG_ERR, "Fatal error: %s" % (message)) + raise SystemExit, 1 + +def warning_error(message): + '''Warn about a problem but continue''' + syslog(LOG_ERR,"Warning: %s\n" % (message)) + +def usage_error(message, opt, vopt, descs, argDescs): + '''Die because script was called the wrong way''' + print "Usage error: %s" % (message) + print_usage(opt, vopt, descs, argDescs) + raise SystemExit, 2 + +verboseMode = False + +def verbose(message): + '''Conditionally output information in verbose mode''' + global verboseMode + + if(verboseMode == True): + syslog(LOG_INFO, "%s" % (message)) + +def print_usage(opt, vopt, descs, argDescs): + print "Bcfg2Server usage:" + for arg in opt.iteritems(): + print " -%s\t\t\t%s" % (arg[0], descs[arg[0]]) + for arg in vopt.iteritems(): + print " -%s %s\t%s" % (arg[0], argDescs[arg[0]], descs[arg[0]]) + +def dgetopt(arglist, opt, vopt, descs, argDescs): '''parse options into a dictionary''' + global verboseMode + ret = {} for optname in opt.values() + vopt.values(): ret[optname] = False - gstr = "".join(opt.keys()) + "".join([field+':' for field in vopt.keys()]) + + gstr = "".join(opt.keys()) + "".join([optionkey + ':' for optionkey in vopt.keys()]) try: - opts = getopt(arglist, gstr)[0] + ginfo = getopt(arglist, gstr) except GetoptError, gerr: - print gerr - print "bcfg2 Usage:" - for arg in opt.iteritems(): - print " -%s %s" % arg - for arg in vopt.iteritems(): - print " -%s <%s>" % arg - raise SystemExit, 1 - for (gopt, garg) in opts: + usage_error(gerr, opt, vopt, descs, argDescs) + + for (gopt, garg) in ginfo[0]: option = gopt[1:] if opt.has_key(option): ret[opt[option]] = True else: ret[vopt[option]] = garg + + if ret["help"] == True: + print_usage(opt, vopt, descs, argDescs) + raise SystemExit, 0 + + if ret["verbose"] == True: + verboseMode = True + return ret class Bcfg2(Component): @@ -60,10 +106,14 @@ class Bcfg2(Component): self.Core = Core(setup, setup['configfile']) self.CoreLock = Lock() except CoreInitError, msg: - print msg - raise SystemExit, 1 - self.funcs.update({"GetConfig":self.Bcfg2GetConfig, "GetProbes":self.Bcfg2GetProbes, - "RecvProbeData":self.Bcfg2RecvProbeData, "RecvStats":self.Bcfg2RecvStats}) + fatal_error(msg) + + self.funcs.update({ + "GetConfig": self.Bcfg2GetConfig, + "GetProbes": self.Bcfg2GetProbes, + "RecvProbeData": self.Bcfg2RecvProbeData, + "RecvStats": self.Bcfg2RecvStats + }) for plugin in self.Core.plugins.values(): for method in plugin.__rmi__: self.register_function(getattr(self.Core.plugins[plugin.__name__], method), @@ -80,6 +130,7 @@ class Bcfg2(Component): rsockinfo = select([self.socket, famfd], [], [], 15)[0] except selecterror: raise SSLError + if famfd in rsockinfo: self.Core.fam.Service() if self.socket in rsockinfo: @@ -99,19 +150,26 @@ class Bcfg2(Component): def handle_error(self): '''Catch error path for clean exit''' return False + + def resolve_client(self, client): + try: + ret = gethostbyaddr(client)[0] + except herror: + warning = "host resolution error for %s" % (client) + warning_error(warning) + raise Fault, warning def Bcfg2GetProbes(self, address): '''Fetch probes for a particular client''' - peer = address[0] + client = resolve_client(address[0]) resp = Element('probes') - try: - client = gethostbyaddr(peer)[0] - except herror: - raise Fault, "host resolution error" + try: meta = self.Core.metadata.FetchMetadata(client) except MetadataConsistencyError: - raise Fault, 'metadata resolution error' + warning = 'metadata consistency error' + warning_error(warning) + raise Fault, warning for generator in self.Core.generators: for probe in generator.GetProbes(meta): resp.append(probe) @@ -119,36 +177,31 @@ class Bcfg2(Component): def Bcfg2RecvProbeData(self, address, probedata): '''Receive probe data from clients''' - peer = address[0] - try: - client = gethostbyaddr(peer)[0] - except herror: - raise Fault, "host resolution error" + client = resolve_client(address[0]) + for data in probedata: try: [generator] = [gen for gen in self.Core.generators if gen.__name__ == data.get('source')] generator.ReceiveData(client, data) except IndexError: - syslog(LOG_ERR, "Failed to locate plugin %s" % (data.get('source'))) + warning_error("Failed to locate plugin %s" % (data.get('source'))) except: - syslog(LOG_ERR, "Unexpected failure in probe data receipt") + critical_error("probe data receipt") return True def Bcfg2GetConfig(self, address, image=False, profile=False): '''Build config for a client''' - peer = address[0] - try: - client = gethostbyaddr(peer)[0] - except herror: - raise Fault, "host resolution error" + client = resolve_client(address[0]) + if image and profile: try: # if metadata is provided, call FetchMetadata with settings - # it is screwey. i know. + # it is screwy. i know. self.Core.metadata.FetchMetadata(client, image=image, profile=profile) except MetadataConsistencyError: - syslog(LOG_ERR, "Metadata consistency error for client %s" % client) - return Fault, 'metadata error' + warning = 'metadata consistency error' + warning_error(warning) + raise Fault, warning return tostring(self.Core.BuildConfiguration(client)) def Bcfg2RecvStats(self, address, stats): @@ -157,50 +210,52 @@ class Bcfg2(Component): state = sdata.find(".//Statistics") # Versioned stats to prevent tied client/server upgrade if state.get('version') >= '2.0': - try: - client = gethostbyaddr(address[0])[0] - except herror: - return Fault, 'host resolution error' - + client = resolve_client(address[0]) + # Update statistics self.Core.stats.updateStats(sdata, client) - syslog(LOG_INFO, "Client %s reported state %s"%(client, state.attrib['state'])) + verbose("Client %s reported state %s" % + (client, state.attrib['state'])) return "<ok/>" if __name__ == '__main__': openlog("Bcfg2", 0, LOG_LOCAL0) - options = {'v':'verbose', 'd':'debug'} - doptions = {'D':'daemon', 'c':'configfile', 'C':'client'} - ssetup = dgetopt(argv[1:], options, doptions) + options = { + 'v':'verbose', + 'd':'debug', + 'h':'help' + } + doptions = { + 'D':'daemon', + 'c':'configfile', + 'C':'client' + } + + descriptions = { + 'v': "enable verbose output", + 'd': "enable debugging output", + 'D': "daemonise the server, storing PID", + 'c': "set the server's config file", + 'C': "always return the given client's config (debug only)", + 'h': "display this usage information" + } + + argDescriptions = { + 'D': "<PID file> ", + 'c': "<config file>", + 'C': "<client hostname>" + } + + ssetup = dgetopt(argv[1:], options, doptions, + descriptions, argDescriptions) if not ssetup['configfile']: ssetup['configfile'] = '/etc/bcfg2.conf' - if ssetup['daemon']: - if os.fork() != 0: - os._exit(0) - os.setsid() # Create new session - pid = os.fork() - if pid != 0: - pidfile = open(ssetup['daemon'], "w") - pidfile.write("%i" % pid) - pidfile.close() - os._exit(0) - os.chdir("/") - os.umask(0) - null = open("/dev/null", "w+") - os.dup2(null.fileno(), sys.__stdin__.fileno()) - os.dup2(null.fileno(), sys.__stdout__.fileno()) - os.dup2(null.fileno(), sys.__stderr__.fileno()) - s = Bcfg2(ssetup) while not s.shut: try: s.serve_forever() except: - syslog(LOG_ERR, "Unexpected serve loop failure") - (trace, val, trb)=exc_info() - for line in extract_tb(trb): - syslog(LOG_ERR, ' File "%s", line %i, in %s\n %s\n'%line) - syslog(LOG_ERR, "%s: %s\n"%(trace, val)) - del trace, val, trb + critical_error("service loop") + syslog(LOG_INFO, "Shutting down") |