summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNarayan Desai <desai@mcs.anl.gov>2007-07-13 18:16:04 +0000
committerNarayan Desai <desai@mcs.anl.gov>2007-07-13 18:16:04 +0000
commit3377f174bdd0bcf3f6212038dbc51cdb922e5481 (patch)
treef6454b237c2b4b67788f9273bead3027fce67404 /src
parentbef026fd845d90b4b347f18ee0282302dbcb0e72 (diff)
downloadbcfg2-3377f174bdd0bcf3f6212038dbc51cdb922e5481.tar.gz
bcfg2-3377f174bdd0bcf3f6212038dbc51cdb922e5481.tar.bz2
bcfg2-3377f174bdd0bcf3f6212038dbc51cdb922e5481.zip
Add checker support to Component
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@3441 ce84e21b-d406-0410-9b95-82705330c041
Diffstat (limited to 'src')
-rw-r--r--src/lib/Client/Frame.py6
-rw-r--r--src/lib/Component.py6
-rw-r--r--src/lib/Server/Component.py280
-rwxr-xr-xsrc/lib/Server/Reports/importscript.py15
4 files changed, 21 insertions, 286 deletions
diff --git a/src/lib/Client/Frame.py b/src/lib/Client/Frame.py
index f685e7491..a2682d023 100644
--- a/src/lib/Client/Frame.py
+++ b/src/lib/Client/Frame.py
@@ -1,7 +1,7 @@
'''Frame is the Client Framework that verifies and installs entries, and generates statistics'''
__revision__ = '$Revision$'
-import logging, time
+import binascii, logging, time
import Bcfg2.Client.Tools
def cmpent(ent1, ent2):
@@ -326,6 +326,10 @@ class Frame:
for item in data:
item.set('qtext', '')
container.append(item)
+ if item.get('current_diff', False):
+ item.set('current_bdiff',
+ binascii.a2b_base64(item.get('current_diff')))
+ item.set('current_diff', '')
timeinfo = Bcfg2.Client.XML.Element("OpStamps")
feedback.append(stats)
diff --git a/src/lib/Component.py b/src/lib/Component.py
index 34dfbddc2..71df6d68b 100644
--- a/src/lib/Component.py
+++ b/src/lib/Component.py
@@ -60,11 +60,12 @@ class CobaltXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
class TLSServer(Bcfg2.tlslite.api.TLSSocketServerMixIn,
BaseHTTPServer.HTTPServer):
'''This class is an tlslite-using SSLServer'''
- def __init__(self, address, keyfile, handler):
+ def __init__(self, address, keyfile, handler, checker=None):
self.sc = Bcfg2.tlslite.api.SessionCache()
x509 = Bcfg2.tlslite.api.X509()
s = open(keyfile).read()
x509.parse(s)
+ self.checker = checker
try:
self.key = Bcfg2.tlslite.api.parsePEMKey(s, private=True)
except:
@@ -83,7 +84,8 @@ class TLSServer(Bcfg2.tlslite.api.TLSSocketServerMixIn,
try:
tlsConnection.handshakeServer(certChain=self.chain,
privateKey=self.key,
- sessionCache=self.sc)
+ sessionCache=self.sc,
+ checher=self.checker)
tlsConnection.ignoreAbruptClose = True
return True
except Bcfg2.tlslite.errors.TLSError, error:
diff --git a/src/lib/Server/Component.py b/src/lib/Server/Component.py
deleted file mode 100644
index 34dfbddc2..000000000
--- a/src/lib/Server/Component.py
+++ /dev/null
@@ -1,280 +0,0 @@
-'''Cobalt component base classes'''
-__revision__ = '$Revision$'
-
-import atexit, logging, select, signal, socket, sys, time, urlparse, xmlrpclib, cPickle, ConfigParser
-import BaseHTTPServer, SimpleXMLRPCServer, SocketServer
-import Bcfg2.tlslite.errors
-import Bcfg2.tlslite.api
-
-import Bcfg2.Client.Proxy as Proxy
-from Bcfg2.tlslite.TLSConnection import TLSConnection
-
-log = logging.getLogger('Component')
-
-class ComponentInitError(Exception):
- '''Raised in case of component initialization failure'''
- pass
-
-class ComponentKeyError(Exception):
- '''raised in case of key parse fails'''
- pass
-
-class CobaltXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
- '''CobaltXMLRPCRequestHandler takes care of ssl xmlrpc requests'''
- def finish(self):
- '''Finish HTTPS connections properly'''
- self.request.close()
-
- def do_POST(self):
- '''Overload do_POST to pass through client address information'''
- try:
- # get arguments
- data = self.rfile.read(int(self.headers["content-length"]))
- response = self.server._cobalt_marshalled_dispatch(data, self.client_address)
- except: # This should only happen if the module is buggy
- # internal error, report as HTTP server error
- log.error("Unexcepted handler failure in do_POST", exc_info=1)
- self.send_response(500)
- self.end_headers()
- else:
- # got a valid XML RPC response
- try:
- self.send_response(200)
- self.send_header("Content-type", "text/xml")
- self.send_header("Content-length", str(len(response)))
- self.end_headers()
- self.wfile.write(response)
-
- # shut down the connection
- self.wfile.flush()
- #self.connection.shutdown()
- except socket.error:
- pass
-
- def setup(self):
- '''Setup a working connection'''
- self.connection = self.request
- self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
- self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
-
-class TLSServer(Bcfg2.tlslite.api.TLSSocketServerMixIn,
- BaseHTTPServer.HTTPServer):
- '''This class is an tlslite-using SSLServer'''
- def __init__(self, address, keyfile, handler):
- self.sc = Bcfg2.tlslite.api.SessionCache()
- x509 = Bcfg2.tlslite.api.X509()
- s = open(keyfile).read()
- x509.parse(s)
- try:
- self.key = Bcfg2.tlslite.api.parsePEMKey(s, private=True)
- except:
- raise ComponentKeyError
- self.chain = Bcfg2.tlslite.api.X509CertChain([x509])
- BaseHTTPServer.HTTPServer.__init__(self, address, handler)
-
- def finish_request(self, sock, client_address):
- sock.settimeout(90)
- tlsConnection = TLSConnection(sock)
- if self.handshake(tlsConnection) == True:
- self.RequestHandlerClass(tlsConnection, client_address, self)
- tlsConnection.close()
-
- def handshake(self, tlsConnection):
- try:
- tlsConnection.handshakeServer(certChain=self.chain,
- privateKey=self.key,
- sessionCache=self.sc)
- tlsConnection.ignoreAbruptClose = True
- return True
- except Bcfg2.tlslite.errors.TLSError, error:
- return False
- except socket.error:
- return False
-
-class Component(TLSServer,
- SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
- """Cobalt component providing XML-RPC access"""
- __name__ = 'Component'
- __implementation__ = 'Generic'
- __statefields__ = []
- async_funcs = ['assert_location']
-
- def __init__(self, setup):
- # need to get addr
- self.setup = setup
- self.shut = False
- signal.signal(signal.SIGINT, self.start_shutdown)
- signal.signal(signal.SIGTERM, self.start_shutdown)
- self.logger = logging.getLogger('Component')
- self.cfile = ConfigParser.ConfigParser()
- if setup['configfile']:
- cfilename = setup['configfile']
- else:
- cfilename = '/etc/bcfg2.conf'
- self.cfile.read([cfilename])
- if not self.cfile.has_section('communication'):
- print "Configfile missing communication section"
- raise SystemExit, 1
- self.static = False
- if not self.cfile.has_section('components'):
- print "Configfile missing components section"
- raise SystemExit, 1
- if self.cfile._sections['components'].has_key(self.__name__):
- self.static = True
- location = urlparse.urlparse(self.cfile.get('components', self.__name__))[1].split(':')
- location = (location[0], int(location[1]))
- else:
- location = (socket.gethostname(), 0)
- try:
- keyfile = self.cfile.get('communication', 'key')
- #keyfile = '/tmp/keys/server.pkey'
- except ConfigParser.NoOptionError:
- print "No key specified in cobalt.conf"
- raise SystemExit, 1
-
- self.password = self.cfile.get('communication', 'password')
-
- try:
- TLSServer.__init__(self, location, keyfile, CobaltXMLRPCRequestHandler)
- except socket.error:
- self.logger.error("Failed to bind to socket")
- raise ComponentInitError
- except ComponentKeyError:
- self.logger.error("Failed to parse key" % (keyfile))
- raise ComponentInitError
- except:
- self.logger.error("Failed to load ssl key %s" % (keyfile), exc_info=1)
- raise ComponentInitError
- try:
- SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
- except TypeError:
- SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self, False, None)
- self.logRequests = 0
- self.port = self.socket.getsockname()[1]
- self.url = "https://%s:%s" % (socket.gethostname(), self.port)
- self.logger.info("Bound to port %s" % self.port)
- self.funcs.update({'system.listMethods':self.addr_system_listMethods})
- self.atime = 0
- self.assert_location()
- atexit.register(self.deassert_location)
-
- def _cobalt_marshalled_dispatch(self, data, address):
- """Decode and dispatch XMLRPC requests. Overloaded to pass through
- client address information
- """
- try:
- rawparams, method = xmlrpclib.loads(data)
- except:
- self.logger.error("Failed to parse request from %s" \
- % (address[0]))
- #open('/tmp/badreq', 'w').write(data)
- return xmlrpclib.dumps(xmlrpclib.Fault(4, "Bad Request"))
- if len(rawparams) < 2:
- self.logger.error("No authentication included with request from %s" % address[0])
- return xmlrpclib.dumps(xmlrpclib.Fault(2, "No Authentication Info"))
- user = rawparams[0]
- password = rawparams[1]
- params = rawparams[2:]
- # check authentication
- if not self._authenticate_connection(method, user, password, address):
- return xmlrpclib.dumps(xmlrpclib.Fault(3, "Authentication Failure"))
- # generate response
- try:
- # all handlers must take address as the first argument
- response = self._dispatch(method, (address, ) + params)
- # wrap response in a singleton tuple
- response = (response,)
- response = xmlrpclib.dumps(response, methodresponse=1)
- except xmlrpclib.Fault, fault:
- response = xmlrpclib.dumps(fault)
- except TypeError, terror:
- self.logger.error("Client %s called function %s with wrong argument count" %
- (address[0], method), exc_info=1)
- response = xmlrpclib.dumps(xmlrpclib.Fault(4, terror.args[0]))
- except:
- self.logger.error("Unexpected handler failure", exc_info=1)
- # report exception back to server
- response = xmlrpclib.dumps(xmlrpclib.Fault(1,
- "%s:%s" % (sys.exc_type, sys.exc_value)))
- return response
-
- def _authenticate_connection(self, method, user, password, address):
- '''Authenticate new connection'''
- (user, address, method)
- return password == self.password
-
- def save_state(self):
- '''Save fields defined in __statefields__ in /var/spool/cobalt/__implementation__'''
- if self.__statefields__:
- savedata = tuple([getattr(self, field) for field in self.__statefields__])
- try:
- statefile = open("/var/spool/cobalt/%s" % self.__implementation__, 'w')
- # need to flock here
- statefile.write(cPickle.dumps(savedata))
- except:
- self.logger.info("Statefile save failed; data persistence disabled")
- self.__statefields__ = []
-
- def load_state(self):
- '''Load fields defined in __statefields__ from /var/spool/cobalt/__implementation__'''
- if self.__statefields__:
- try:
- loaddata = cPickle.loads(open("/var/spool/cobalt/%s" % self.__implementation__).read())
- except:
- self.logger.info("Statefile load failed")
- return
- for field in self.__statefields__:
- setattr(self, field, loaddata[self.__statefields__.index(field)])
-
- def addr_system_listMethods(self, address):
- """get rid of the address argument and call the underlying dispatcher method"""
- return SimpleXMLRPCServer.SimpleXMLRPCDispatcher.system_listMethods(self)
-
- def get_request(self):
- '''We need to do work between requests, so select with timeout instead of blocking in accept'''
- rsockinfo = []
- while self.socket not in rsockinfo:
- if self.shut:
- raise socket.error
- for funcname in self.async_funcs:
- func = getattr(self, funcname, False)
- if callable(func):
- func()
- else:
- self.logger.error("Cannot call uncallable method %s" % (funcname))
- try:
- rsockinfo = select.select([self.socket], [], [], 10)[0]
- except select.error:
- continue
- if self.socket in rsockinfo:
- return self.socket.accept()
-
- def assert_location(self):
- '''Assert component location with slp'''
- if self.__name__ == 'service-location' or self.static:
- return
- if (time.time() - self.atime) > 240:
- slp = Proxy.service_location()
- slp.AssertService({'tag':'location', 'name':self.__name__, 'url':self.url})
- self.atime = time.time()
-
- def deassert_location(self):
- '''remove registration from slp'''
- if self.__name__ == 'service-location' or self.static:
- return
- slp = Proxy.service_location()
- try:
- slp.DeassertService([{'tag':'location', 'name':self.__name__, 'url':self.url}])
- except xmlrpclib.Fault, fault:
- if fault.faultCode == 11:
- self.logger.error("Failed to deregister self; no matching component")
-
- def serve_forever(self):
- """Handle one request at a time until doomsday."""
- while not self.shut:
- self.handle_request()
-
- def start_shutdown(self, signum, frame):
- '''Shutdown on unexpected signals'''
- self.shut = True
-
diff --git a/src/lib/Server/Reports/importscript.py b/src/lib/Server/Reports/importscript.py
index 39e4ea77b..be7f59da6 100755
--- a/src/lib/Server/Reports/importscript.py
+++ b/src/lib/Server/Reports/importscript.py
@@ -2,7 +2,7 @@
'''Imports statistics.xml and clients.xml files in to database backend for new statistics engine'''
__revision__ = '$Revision$'
-import os, sys
+import os, sys, binascii
try:
import settings
except ImportError:
@@ -146,6 +146,10 @@ if __name__ == '__main__':
for r in statsdata.findall('.//Bad/*')+statsdata.findall('.//Extra/*')+statsdata.findall('.//Modified/*'):
+ if r.get('current_bdiff', False):
+ rc_diff = binascii.b2a_base64(r.get('current_bdiff'))
+ else:
+ rc_diff = r.get('current_diff', '')
arguments = [r.get('owner', default=""), r.get('current_owner', default=""),
r.get('group', default=""), r.get('current_group', default=""),
r.get('perms', default=""), r.get('current_perms', default=""),
@@ -153,7 +157,7 @@ if __name__ == '__main__':
r.get('to', default=""), r.get('current_to', default=""),
r.get('version', default=""), r.get('current_version', default=""),
(r.get('current_exists', default="True").capitalize()=="True"),
- r.get('current_diff', default="")]
+ rc_diff]
if reasons_hash.has_key(tuple(arguments)):
current_reason_id = reasons_hash[tuple(arguments)]
if verbose:
@@ -199,6 +203,11 @@ if __name__ == '__main__':
('Extra/*', extra_hash, 'reports_extra'),
('Modified/*', modified_hash, 'reports_modified')]:
for x in statistics.findall(xpath):
+ if x.get('current_bdiff', False):
+ xc_diff = binascii.b2a_base64(x.get('current_bdiff'))
+ else:
+ xc_diff = x.get('current_diff', '')
+
arguments = [x.get('owner', default=""), x.get('current_owner', default=""),
x.get('group', default=""), x.get('current_group', default=""),
x.get('perms', default=""), x.get('current_perms', default=""),
@@ -206,7 +215,7 @@ if __name__ == '__main__':
x.get('to', default=""), x.get('current_to', default=""),
x.get('version', default=""), x.get('current_version', default=""),
(x.get('current_exists', default="True").capitalize()=="True"),
- x.get('current_diff', default="")]
+ xc_diff]
if not hashname.has_key((x.get('name'), x.tag, reasons_hash[tuple(arguments)])):
cursor.execute("INSERT INTO "+tablename+" VALUES (NULL, %s, %s, %s, %s);",