summaryrefslogtreecommitdiffstats
path: root/func/minion/server.py
diff options
context:
space:
mode:
Diffstat (limited to 'func/minion/server.py')
-rwxr-xr-xfunc/minion/server.py232
1 files changed, 232 insertions, 0 deletions
diff --git a/func/minion/server.py b/func/minion/server.py
new file mode 100755
index 0000000..f155dba
--- /dev/null
+++ b/func/minion/server.py
@@ -0,0 +1,232 @@
+#!/usr/bin/python
+
+"""
+func
+
+Copyright 2007, Red Hat, Inc
+see AUTHORS
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+# standard modules
+import SimpleXMLRPCServer
+import string
+import sys
+import traceback
+import socket
+
+from gettext import textdomain
+I18N_DOMAIN = "func"
+
+
+from func.config import read_config
+from func.commonconfig import FuncdConfig
+from func import logger
+
+# our modules
+import AuthedXMLRPCServer
+import codes
+import module_loader
+import utils
+
+
+
+class XmlRpcInterface(object):
+
+ def __init__(self):
+
+ """
+ Constructor.
+ """
+
+ config_file = '/etc/func/minion.conf'
+ self.config = read_config(config_file, FuncdConfig)
+ self.logger = logger.Logger().logger
+ self.audit_logger = logger.AuditLogger()
+ self.__setup_handlers()
+
+ # need a reference so we can log ip's, certs, etc
+# self.server = server
+
+ def __setup_handlers(self):
+
+ """
+ Add RPC functions from each class to the global list so they can be called.
+ """
+
+ self.handlers = {}
+ for x in self.modules.keys():
+ try:
+ self.modules[x].register_rpc(self.handlers, x)
+ self.logger.debug("adding %s" % x)
+ except AttributeError, e:
+ self.logger.warning("module %s not loaded, missing register_rpc method" % self.modules[x])
+
+
+ # internal methods that we do instead of spreading internal goo
+ # all over the modules. For now, at lest -akl
+
+
+ # system.listMethods os a quasi stanard xmlrpc method, so
+ # thats why it has a odd looking name
+ self.handlers["system.listMethods"] = self.list_methods
+ self.handlers["system.list_modules"] = self.list_modules
+
+ def list_modules(self):
+ return self.modules.keys()
+
+ def list_methods(self):
+ return self.handlers.keys()
+
+ def get_dispatch_method(self, method):
+
+ if method in self.handlers:
+ return FuncApiMethod(self.logger, method, self.handlers[method])
+
+ else:
+ self.logger.info("Unhandled method call for method: %s " % method)
+ raise codes.InvalidMethodException
+
+
+
+
+class FuncApiMethod:
+
+ """
+ Used to hold a reference to all of the registered functions.
+ """
+
+ def __init__(self, logger, name, method):
+
+ self.logger = logger
+ self.__method = method
+ self.__name = name
+
+ def __log_exc(self):
+
+ """
+ Log an exception.
+ """
+
+ (t, v, tb) = sys.exc_info()
+ self.logger.info("Exception occured: %s" % t )
+ self.logger.info("Exception value: %s" % v)
+ self.logger.info("Exception Info:\n%s" % string.join(traceback.format_list(traceback.extract_tb(tb))))
+
+ def __call__(self, *args):
+
+ self.logger.debug("(X) -------------------------------------------")
+
+ try:
+ rc = self.__method(*args)
+ except codes.FuncException, e:
+ self.__log_exc()
+ rc = e
+ except:
+ self.logger.debug("Not a Func-specific exception")
+ self.__log_exc()
+ raise
+ self.logger.debug("Return code for %s: %s" % (self.__name, rc))
+
+ return rc
+
+
+
+def serve():
+
+ """
+ Code for starting the XMLRPC service.
+ """
+ server =FuncSSLXMLRPCServer(('', 51234))
+ server.logRequests = 0 # don't print stuff to console
+ server.serve_forever()
+
+
+
+class FuncXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer, XmlRpcInterface):
+
+ def __init__(self, args):
+
+ self.allow_reuse_address = True
+
+ self.modules = module_loader.load_modules()
+ SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, args)
+ XmlRpcInterface.__init__(self)
+
+
+class FuncSSLXMLRPCServer(AuthedXMLRPCServer.AuthedSSLXMLRPCServer,
+ XmlRpcInterface):
+ def __init__(self, args):
+ self.allow_reuse_address = True
+ self.modules = module_loader.load_modules()
+
+ XmlRpcInterface.__init__(self)
+ hn = socket.getfqdn()
+ self.key = "%s/%s.pem" % (self.config.cert_dir, hn)
+ self.cert = "%s/%s.cert" % (self.config.cert_dir, hn)
+ self.ca = "%s/ca.cert" % self.config.cert_dir
+
+ AuthedXMLRPCServer.AuthedSSLXMLRPCServer.__init__(self, ("", 51234),
+ self.key, self.cert,
+ self.ca)
+
+ def _dispatch(self, method, params):
+
+ """
+ the SimpleXMLRPCServer class will call _dispatch if it doesn't
+ find a handler method
+ """
+
+ # Recognize ipython's tab completion calls
+ if method == 'trait_names' or method == '_getAttributeNames':
+ return self.handlers.keys()
+
+ if hasattr(self, '_this_request'):
+ r,a = self._this_request
+ p = r.get_peer_certificate()
+ ip = a[0]
+ cn = p.get_subject().CN
+ sub_hash = p.subject_name_hash()
+ else:
+ print 'no cert'
+
+ # XXX FIXME - need to figure out how to dig into the server base classes
+ # so we can get client ip, and eventually cert id info -akl
+ self.audit_logger.log_call(ip, cn, sub_hash, method, params)
+
+ return self.get_dispatch_method(method)(*params)
+
+ def auth_cb(self, request, client_address):
+ peer_cert = request.get_peer_certificate()
+ return peer_cert.get_subject().CN
+
+
+def main(argv):
+
+ """
+ Start things up.
+ """
+
+ if "daemon" in sys.argv or "--daemon" in sys.argv:
+ utils.daemonize("/var/run/funcd.pid")
+ else:
+ print "serving...\n"
+
+ try:
+ utils.create_minion_keys()
+ serve()
+ except codes.FuncException, e:
+ print >> sys.stderr, 'error: %s' % e
+ sys.exit(1)
+
+# ======================================================================================
+
+if __name__ == "__main__":
+ textdomain(I18N_DOMAIN)
+ main(sys.argv)