summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xMakefile4
-rw-r--r--etc/certmaster.conf (renamed from certs/certmaster.conf)0
-rw-r--r--func.spec19
-rw-r--r--func/CommonErrors.py62
-rw-r--r--func/SSLCommon.py122
-rw-r--r--func/SSLConnection.py161
-rwxr-xr-xfunc/certmaster.py (renamed from certs/certmaster.py)16
-rwxr-xr-xinit-scripts/certmaster82
-rw-r--r--minion/AuthedXMLRPCServer.py144
-rw-r--r--minion/__init__.py (renamed from client/__init__.py)0
-rwxr-xr-xminion/codes.py (renamed from server/codes.py)0
-rwxr-xr-xminion/config_data.py (renamed from server/config_data.py)4
-rwxr-xr-xminion/logger.py (renamed from server/logger.py)0
-rwxr-xr-xminion/module_loader.py (renamed from server/module_loader.py)21
-rwxr-xr-xminion/server.py (renamed from server/server.py)0
-rw-r--r--minion/sub_process.py (renamed from server/sub_process.py)0
-rwxr-xr-xminion/utils.py (renamed from server/utils.py)0
-rw-r--r--modules/pkt.py92
-rw-r--r--overlord/__init__.py (renamed from server/__init__.py)0
-rwxr-xr-xoverlord/dumb_client.py (renamed from client/dumb_client.py)0
-rw-r--r--overlord/sslclient.py44
-rw-r--r--overlord/test_func.py (renamed from client/test_func.py)0
-rwxr-xr-xscripts/certmaster12
-rwxr-xr-xscripts/funcd2
-rw-r--r--settings6
-rw-r--r--setup.py23
-rw-r--r--version2
27 files changed, 773 insertions, 43 deletions
diff --git a/Makefile b/Makefile
index b831591..30029a5 100755
--- a/Makefile
+++ b/Makefile
@@ -20,8 +20,8 @@ clean:
# python tests/tests.py
# -rm -rf /tmp/_cobbler-*
-messages: server/*.py
- xgettext -k_ -kN_ -o $(MESSAGESPOT) server/*.py
+messages: minion/*.py
+ xgettext -k_ -kN_ -o $(MESSAGESPOT) minion/*.py
sed -i'~' -e 's/SOME DESCRIPTIVE TITLE/func/g' -e 's/YEAR THE PACKAGE'"'"'S COPYRIGHT HOLDER/2007 Red Hat, inc. /g' -e 's/FIRST AUTHOR <EMAIL@ADDRESS>, YEAR/Adrian Likins <alikins@redhat.com>, 2007/g' -e 's/PACKAGE VERSION/func $(VERSION)-$(RELEASE)/g' -e 's/PACKAGE/func/g' $(MESSAGESPOT)
diff --git a/certs/certmaster.conf b/etc/certmaster.conf
index 6e424d1..6e424d1 100644
--- a/certs/certmaster.conf
+++ b/etc/certmaster.conf
diff --git a/func.spec b/func.spec
index 71c2dcf..52ec37a 100644
--- a/func.spec
+++ b/func.spec
@@ -35,16 +35,18 @@ rm -fr $RPM_BUILD_ROOT
%files
%{_bindir}/funcd
+%{_bindir}/certmaster
/etc/init.d/funcd
+/etc/init.d/certmaster
%config(noreplace) /etc/func/settings
%dir %{python_sitelib}/func
-%dir %{python_sitelib}/func/server
-%dir %{python_sitelib}/func/client
-%{python_sitelib}/func/server/*.py*
-%{python_sitelib}/func/client/*.py*
-
-%dir %{python_sitelib}/func/server/modules
-%{python_sitelib}/func/server/modules/*.py*
+%dir %{python_sitelib}/func/minion
+%dir %{python_sitelib}/func/overlord
+%{python_sitelib}/func/minion/*.py*
+%{python_sitelib}/func/overlord/*.py*
+%{python_sitelib}/func/*.py*
+%dir %{python_sitelib}/func/minion/modules
+%{python_sitelib}/func/minion/modules/*.py*
%dir /var/log/func
%post
@@ -59,6 +61,9 @@ fi
%changelog
+* Tue Sep 25 2007 Robin Norwood <rnorwood@redhat.com> - 0.0.11-3
+- Change server -> minion and client -> overlord
+
* Thu Sep 20 2007 James Bowes <jbowes@redhat.com> - 0.0.11-2
- Clean up some speclint warnings
diff --git a/func/CommonErrors.py b/func/CommonErrors.py
new file mode 100644
index 0000000..13ef505
--- /dev/null
+++ b/func/CommonErrors.py
@@ -0,0 +1,62 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Copyright 2005 Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+
+import socket
+
+
+def canIgnoreSSLError(e):
+ """
+ Identify common network errors that mean we cannot connect to the server
+ """
+
+ # This is a bit complicated by the fact that different versions of
+ # M2Crypto & OpenSSL seem to return different error codes for the
+ # same type of error
+ s = "%s" % e
+ if e[0] == 104: # Connection refused
+ return True
+ elif e[0] == 111: # Connection reset by peer
+ return True
+ elif e[0] == 61: # Connection refused
+ return True
+ elif e[0] == 54: # Connection reset by peer
+ return True
+ elif s == "no certificate returned":
+ return True
+ elif s == "wrong version number":
+ return True
+ elif s == "unexpected eof":
+ return True
+
+ return False
+
+
+def canIgnoreSocketError(e):
+ """
+ Identify common network errors that mean we cannot connect to the server
+ """
+
+ try:
+ if e[0] == 111: # Connection refused
+ return True
+ elif e[0] == 104: # Connection reset by peer
+ return True
+ elif e[0] == 61: # Connection refused
+ return True
+ except IndexError:
+ return True
+
+ return False
diff --git a/func/SSLCommon.py b/func/SSLCommon.py
new file mode 100644
index 0000000..bdfd719
--- /dev/null
+++ b/func/SSLCommon.py
@@ -0,0 +1,122 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Copyright 2005 Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+
+import os, sys
+import CommonErrors
+from OpenSSL import SSL
+import SSLConnection
+import httplib
+import socket
+import SocketServer
+
+def our_verify(connection, x509, errNum, errDepth, preverifyOK):
+ # print "Verify: errNum = %s, errDepth = %s, preverifyOK = %s" % (errNum, errDepth, preverifyOK)
+
+ # preverifyOK should tell us whether or not the client's certificate
+ # correctly authenticates against the CA chain
+ return preverifyOK
+
+
+def CreateSSLContext(pkey, cert, ca_cert):
+ for f in pkey, cert, ca_cert:
+ if f and not os.access(f, os.R_OK):
+ print "%s does not exist or is not readable." % f
+ os._exit(1)
+
+ ctx = SSL.Context(SSL.SSLv3_METHOD) # SSLv3 only
+ ctx.use_certificate_file(cert)
+ ctx.use_privatekey_file(pkey)
+ ctx.load_client_ca(ca_cert)
+ ctx.load_verify_locations(ca_cert)
+ verify = SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT
+ ctx.set_verify(verify, our_verify)
+ ctx.set_verify_depth(10)
+ ctx.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_TLSv1)
+ return ctx
+
+
+
+class BaseServer(SocketServer.TCPServer):
+ allow_reuse_address = 1
+
+ def __init__(self, server_addr, req_handler):
+ self._quit = False
+ self.allow_reuse_address = 1
+ SocketServer.TCPServer.__init__(self, server_addr, req_handler)
+
+ def stop(self):
+ self._quit = True
+
+ def serve_forever(self):
+ while not self._quit:
+ self.handle_request()
+ self.server_close()
+
+
+class BaseSSLServer(BaseServer):
+ """ SSL-enabled variant """
+
+ def __init__(self, server_address, req_handler, pkey, cert, ca_cert, timeout=None):
+ self._timeout = timeout
+ self.ssl_ctx = CreateSSLContext(pkey, cert, ca_cert)
+
+ BaseServer.__init__(self, server_address, req_handler)
+
+ sock = socket.socket(self.address_family, self.socket_type)
+ con = SSL.Connection(self.ssl_ctx, sock)
+ self.socket = SSLConnection.SSLConnection(con)
+ if sys.version_info[:3] >= (2, 3, 0):
+ self.socket.settimeout(self._timeout)
+ self.server_bind()
+ self.server_activate()
+
+ host, port = self.socket.getsockname()[:2]
+ self.server_name = socket.getfqdn(host)
+ self.server_port = port
+
+
+class HTTPSConnection(httplib.HTTPConnection):
+ "This class allows communication via SSL."
+
+ response_class = httplib.HTTPResponse
+
+ def __init__(self, host, port=None, ssl_context=None, strict=None, timeout=None):
+ httplib.HTTPConnection.__init__(self, host, port, strict)
+ self.ssl_ctx = ssl_context
+ self._timeout = timeout
+
+ def connect(self):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ con = SSL.Connection(self.ssl_ctx, sock)
+ self.sock = SSLConnection.SSLConnection(con)
+ if sys.version_info[:3] >= (2, 3, 0):
+ self.sock.settimeout(self._timeout)
+ self.sock.connect((self.host, self.port))
+
+
+class HTTPS(httplib.HTTP):
+ """Compatibility with 1.5 httplib interface
+
+ Python 1.5.2 did not have an HTTPS class, but it defined an
+ interface for sending http requests that is also useful for
+ https.
+ """
+
+ _connection_class = HTTPSConnection
+
+ def __init__(self, host='', port=None, ssl_context=None, strict=None, timeout=None):
+ self._setup(self._connection_class(host, port, ssl_context, strict, timeout))
+
diff --git a/func/SSLConnection.py b/func/SSLConnection.py
new file mode 100644
index 0000000..47529b4
--- /dev/null
+++ b/func/SSLConnection.py
@@ -0,0 +1,161 @@
+#!/usr/bin/python
+#
+# Higher-level SSL objects used by rpclib
+#
+# Copyright (c) 2002 Red Hat, Inc.
+#
+# Author: Mihai Ibanescu <misa@redhat.com>
+# Modifications by Dan Williams <dcbw@redhat.com>
+
+
+from OpenSSL import SSL, crypto
+import os, string, time, socket, select
+
+
+class SSLConnection:
+ """
+ This whole class exists just to filter out a parameter
+ passed in to the shutdown() method in SimpleXMLRPC.doPOST()
+ """
+
+ DEFAULT_TIMEOUT = 20
+
+ def __init__(self, conn):
+ """
+ Connection is not yet a new-style class,
+ so I'm making a proxy instead of subclassing.
+ """
+ self.__dict__["conn"] = conn
+ self.__dict__["close_refcount"] = 0
+ self.__dict__["closed"] = False
+ self.__dict__["timeout"] = self.DEFAULT_TIMEOUT
+
+ def __del__(self):
+ self.__dict__["conn"].close()
+
+ def __getattr__(self,name):
+ return getattr(self.__dict__["conn"], name)
+
+ def __setattr__(self,name, value):
+ setattr(self.__dict__["conn"], name, value)
+
+ def settimeout(self, timeout):
+ if timeout == None:
+ self.__dict__["timeout"] = self.DEFAULT_TIMEOUT
+ else:
+ self.__dict__["timeout"] = timeout
+ self.__dict__["conn"].settimeout(timeout)
+
+ def shutdown(self, how=1):
+ """
+ SimpleXMLRpcServer.doPOST calls shutdown(1),
+ and Connection.shutdown() doesn't take
+ an argument. So we just discard the argument.
+ """
+ self.__dict__["conn"].shutdown()
+
+ def accept(self):
+ """
+ This is the other part of the shutdown() workaround.
+ Since servers create new sockets, we have to infect
+ them with our magic. :)
+ """
+ c, a = self.__dict__["conn"].accept()
+ return (SSLConnection(c), a)
+
+ def makefile(self, mode, bufsize):
+ """
+ We need to use socket._fileobject Because SSL.Connection
+ doesn't have a 'dup'. Not exactly sure WHY this is, but
+ this is backed up by comments in socket.py and SSL/connection.c
+
+ Since httplib.HTTPSResponse/HTTPConnection depend on the
+ socket being duplicated when they close it, we refcount the
+ socket object and don't actually close until its count is 0.
+ """
+ self.__dict__["close_refcount"] = self.__dict__["close_refcount"] + 1
+ return PlgFileObject(self, mode, bufsize)
+
+ def close(self):
+ if self.__dict__["closed"]:
+ return
+ self.__dict__["close_refcount"] = self.__dict__["close_refcount"] - 1
+ if self.__dict__["close_refcount"] == 0:
+ self.shutdown()
+ self.__dict__["conn"].close()
+ self.__dict__["closed"] = True
+
+ def sendall(self, data, flags=0):
+ """
+ - Use select() to simulate a socket timeout without setting the socket
+ to non-blocking mode.
+ - Don't use pyOpenSSL's sendall() either, since it just loops on WantRead
+ or WantWrite, consuming 100% CPU, and never times out.
+ """
+ timeout = self.__dict__["timeout"]
+ con = self.__dict__["conn"]
+ (read, write, excpt) = select.select([], [con], [], timeout)
+ if not con in write:
+ raise socket.timeout((110, "Operation timed out."))
+
+ starttime = time.time()
+ origlen = len(data)
+ sent = -1
+ while len(data):
+ curtime = time.time()
+ if curtime - starttime > timeout:
+ raise socket.timeout((110, "Operation timed out."))
+
+ try:
+ sent = con.send(data, flags)
+ except SSL.SysCallError, e:
+ if e[0] == 32: # Broken Pipe
+ self.close()
+ sent = 0
+ else:
+ raise socket.error(e)
+ except (SSL.WantWriteError, SSL.WantReadError):
+ time.sleep(0.2)
+ continue
+
+ data = data[sent:]
+ return origlen - len(data)
+
+ def recv(self, bufsize, flags=0):
+ """
+ Use select() to simulate a socket timeout without setting the socket
+ to non-blocking mode
+ """
+ timeout = self.__dict__["timeout"]
+ con = self.__dict__["conn"]
+ (read, write, excpt) = select.select([con], [], [], timeout)
+ if not con in read:
+ raise socket.timeout((110, "Operation timed out."))
+
+ starttime = time.time()
+ while True:
+ curtime = time.time()
+ if curtime - starttime > timeout:
+ raise socket.timeout((110, "Operation timed out."))
+
+ try:
+ return con.recv(bufsize, flags)
+ except SSL.ZeroReturnError:
+ return None
+ except SSL.WantReadError:
+ time.sleep(0.2)
+ return None
+
+class PlgFileObject(socket._fileobject):
+ def close(self):
+ """
+ socket._fileobject doesn't actually _close_ the socket,
+ which we want it to do, so we have to override.
+ """
+ try:
+ if self._sock:
+ self.flush()
+ self._sock.close()
+ finally:
+ self._sock = None
+
diff --git a/certs/certmaster.py b/func/certmaster.py
index 2fbfb57..02c8013 100755
--- a/certs/certmaster.py
+++ b/func/certmaster.py
@@ -159,13 +159,13 @@ class CertMaster(object):
return False, '', ''
+def serve(xmlrpcinstance):
+ """
+ Code for starting the XMLRPC service.
+ """
-
-cm = CertMaster('/etc/func/certmaster.conf')
-server = SimpleXMLRPCServer.SimpleXMLRPCServer((cm.cfg.listen_addr, int(cm.cfg.listen_port)))
-server.logRequests = 0
-server.register_instance(cm)
-server.serve_forever()
-
-
+ server =FuncXMLRPCServer((xmlrpcinstance.listen_addr, xmlrpcinstance.list_port))
+ server.logRequests = 0 # don't print stuff to console
+ server.register_instance(xmlrpcinstance)
+ server.serve_forever()
diff --git a/init-scripts/certmaster b/init-scripts/certmaster
new file mode 100755
index 0000000..71d5d8a
--- /dev/null
+++ b/init-scripts/certmaster
@@ -0,0 +1,82 @@
+#!/bin/sh
+#
+# certmaster certmaster
+###################################
+
+# LSB header
+
+### BEGIN INIT INFO
+# Provides: certmaster
+# Required-Start: network
+# Default-Start: 3 4 5
+# Short-Description: certificate master for Fedora Unified Network Control 'master server only'
+# Description: certificate master to sign/manage ca/cert infrastructure for func
+### END INIT INFO
+
+# chkconfig header
+
+# chkconfig: 345 98 99
+# description: certificate master to sign/manage ca/cert infrastructure for func
+#
+# processname: /usr/bin/certmaster
+
+# Sanity checks.
+[ -x /usr/bin/certmaster ] || exit 0
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+SERVICE=certmaster
+PROCESS=certmaster
+CONFIG_ARGS=" "
+
+RETVAL=0
+
+start() {
+ echo -n $"Starting certmaster daemon: "
+ daemon --check $SERVICE $PROCESS --daemon $CONFIG_ARGS
+ RETVAL=$?
+ echo
+ [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SERVICE
+ return $RETVAL
+}
+
+stop() {
+ echo -n $"Stopping certmaster daemon: "
+ killproc $PROCESS
+ RETVAL=$?
+ echo
+ if [ $RETVAL -eq 0 ]; then
+ rm -f /var/lock/subsys/$SERVICE
+ rm -f /var/run/$SERVICE.pid
+ fi
+}
+
+restart() {
+ stop
+ start
+}
+
+# See how we were called.
+case "$1" in
+ start|stop|restart)
+ $1
+ ;;
+ status)
+ status $PROCESS
+ RETVAL=$?
+ ;;
+ condrestart)
+ [ -f /var/lock/subsys/$SERVICE ] && restart || :
+ ;;
+ reload)
+ echo "can't reload configuration, you have to restart it"
+ RETVAL=$?
+ ;;
+ *)
+ echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}"
+ exit 1
+ ;;
+esac
+exit $RETVAL
+
diff --git a/minion/AuthedXMLRPCServer.py b/minion/AuthedXMLRPCServer.py
new file mode 100644
index 0000000..490b57a
--- /dev/null
+++ b/minion/AuthedXMLRPCServer.py
@@ -0,0 +1,144 @@
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Library General Public License for more details.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Copyright 2005 Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+# Modifications by Seth Vidal - 2007
+
+import os, sys
+import socket
+import time
+import SocketServer
+import xmlrpclib
+import SimpleXMLRPCServer
+from func import SSLCommon
+import OpenSSL
+
+
+
+class AuthedSimpleXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
+
+ # For some reason, httplib closes the connection right after headers
+ # have been sent if the connection is _not_ HTTP/1.1, which results in
+ # a "Bad file descriptor" error when the client tries to read from the socket
+ protocol_version = "HTTP/1.1"
+
+ def setup(self):
+ """
+ We need to use socket._fileobject Because SSL.Connection
+ doesn't have a 'dup'. Not exactly sure WHY this is, but
+ this is backed up by comments in socket.py and SSL/connection.c
+ """
+ self.connection = self.request # for doPOST
+ self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
+ self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
+
+ def do_POST(self):
+ self.server._this_request = (self.request, self.client_address)
+ try:
+ SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
+ except socket.timeout:
+ pass
+ except (socket.error, OpenSSL.SSL.SysCallError), e:
+ print "Error (%s): socket error - '%s'" % (self.client_address, e)
+
+
+class BaseAuthedXMLRPCServer:
+ def __init__(self, address, authinfo_callback=None):
+ self.allow_reuse_address = 1
+ self.logRequests = 1
+ self.authinfo_callback = authinfo_callback
+
+ self.funcs = {}
+ self.instance = None
+
+ def get_authinfo(self, request, client_address):
+ print 'down here'
+ if self.authinfo_callback:
+ return self.authinfo_callback(request, client_address)
+ return None
+
+
+class AuthedSSLXMLRPCServer(BaseAuthedXMLRPCServer, SSLCommon.BaseSSLServer, SimpleXMLRPCServer.SimpleXMLRPCServer):
+ """ Extension to allow more fine-tuned SSL handling """
+
+ def __init__(self, address, pkey, cert, ca_cert, authinfo_callback=None, timeout=None):
+ BaseAuthedXMLRPCServer.__init__(self, address, authinfo_callback)
+ SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, address, AuthedSimpleXMLRPCRequestHandler)
+ SSLCommon.BaseSSLServer.__init__(self, address, AuthedSimpleXMLRPCRequestHandler, pkey, cert, ca_cert, timeout=timeout)
+
+
+
+class AuthedXMLRPCServer(BaseAuthedXMLRPCServer, SSLCommon.BaseServer, SimpleXMLRPCServer.SimpleXMLRPCServer):
+
+ def __init__(self, address, authinfo_callback=None):
+ BaseAuthedXMLRPCServer.__init__(self, address, authinfo_callback)
+ SSLCommon.BaseServer.__init__(self, address, AuthedSimpleXMLRPCRequestHandler)
+
+
+###########################################################
+# Testing stuff
+###########################################################
+
+class ReqHandler:
+ def ping(self, callerid, trynum):
+ print 'clearly not'
+ print callerid
+ print trynum
+ return "pong %d / %d" % (callerid, trynum)
+
+class TestServer(AuthedSSLXMLRPCServer):
+ """
+ SSL XMLRPC server that authenticates clients based on their certificate.
+ """
+
+ def __init__(self, address, pkey, cert, ca_cert):
+ AuthedSSLXMLRPCServer.__init__(self, address, pkey, cert, ca_cert, self.auth_cb)
+
+ def _dispatch(self, method, params):
+ if method == 'trait_names' or method == '_getAttributeNames':
+ return dir(self)
+ # if we have _this_request then we get the peer cert from it
+ # handling all the authZ checks in _dispatch() means we don't even call the method
+ # for whatever it wants to do and we have the method name.
+
+ if hasattr(self, '_this_request'):
+ r,a = self._this_request
+ p = r.get_peer_certificate()
+ print dir(p)
+ print p.get_subject()
+ else:
+ print 'no cert'
+
+ return "your mom"
+
+ def auth_cb(self, request, client_address):
+ peer_cert = request.get_peer_certificate()
+ return peer_cert.get_subject().CN
+
+
+if __name__ == '__main__':
+ if len(sys.argv) < 4:
+ print "Usage: python AuthdXMLRPCServer.py key cert ca_cert"
+ sys.exit(1)
+
+ pkey = sys.argv[1]
+ cert = sys.argv[2]
+ ca_cert = sys.argv[3]
+
+ print "Starting the server."
+ server = TestServer(('localhost', 51234), pkey, cert, ca_cert)
+ h = ReqHandler()
+ server.register_instance(h)
+ server.serve_forever()
+
diff --git a/client/__init__.py b/minion/__init__.py
index e69de29..e69de29 100644
--- a/client/__init__.py
+++ b/minion/__init__.py
diff --git a/server/codes.py b/minion/codes.py
index c549709..c549709 100755
--- a/server/codes.py
+++ b/minion/codes.py
diff --git a/server/config_data.py b/minion/config_data.py
index ed12383..021a52d 100755
--- a/server/config_data.py
+++ b/minion/config_data.py
@@ -41,9 +41,9 @@ class Config:
cp.read([CONFIG_FILE])
- self.ds["is_master"] = int(cp.get("general","is_master"))
+ self.ds["is_overlord"] = int(cp.get("general","is_overlord"))
self.ds["is_minion"] = int(cp.get("general","is_minion"))
- self.ds["master_server"] = cp.get("general","master_server")
+ self.ds["overlord_server"] = cp.get("general","overlord_server")
def get(self):
return self.ds
diff --git a/server/logger.py b/minion/logger.py
index 1e60dc0..1e60dc0 100755
--- a/server/logger.py
+++ b/minion/logger.py
diff --git a/server/module_loader.py b/minion/module_loader.py
index 6fb69f7..7cfcd26 100755
--- a/server/module_loader.py
+++ b/minion/module_loader.py
@@ -31,7 +31,7 @@ def module_walker(topdir):
# we don't really care about __init__ files, though we do requure them
if filename[:8] == "__init__":
continue
- # the normpath is important, since we
+ # the normpath is important, since we (since we what?! -RN)
module_files.append(os.path.normpath("%s/%s" % (root, filename)))
@@ -39,8 +39,8 @@ def module_walker(topdir):
def load_modules(blacklist=None):
- module_file_path="%s/func/server/modules/" % distutils.sysconfig.get_python_lib()
- mod_path="%s/func/server/" % distutils.sysconfig.get_python_lib()
+ module_file_path="%s/func/minion/modules/" % distutils.sysconfig.get_python_lib()
+ mod_path="%s/func/minion/" % distutils.sysconfig.get_python_lib()
sys.path.insert(0, mod_path)
mods = {}
@@ -52,7 +52,7 @@ def load_modules(blacklist=None):
# aka, everything after the module_file_path
module_name_part = fn[len(module_file_path):]
dirname, basename = os.path.split(module_name_part)
-
+
if basename == "__init__.py":
continue
if basename[-3:] == ".py":
@@ -63,9 +63,13 @@ def load_modules(blacklist=None):
pathname = modname
if dirname != "":
pathname = "%s/%s" % (dirname, modname)
-
+
mod_imp_name = pathname.replace("/", ".")
+ if mods.has_key(mod_imp_name):
+ # If we've already imported mod_imp_name, don't import it again
+ continue
+
try:
blip = __import__("modules.%s" % ( mod_imp_name), globals(), locals(), [mod_imp_name])
if not hasattr(blip, "register_rpc"):
@@ -75,14 +79,17 @@ def load_modules(blacklist=None):
mods[mod_imp_name] = blip
except ImportError, e:
# A module that raises an ImportError is (for now) simply not loaded.
- print e
+ errmsg = _("Could not load %s module: %s")
+ print errmsg % (mod_imp_name, e)
+
+ continue
return mods
if __name__ == "__main__":
- module_file_path = "/usr/lib/python2.5/site-packages/func/server/modules/"
+ module_file_path = "/usr/lib/python2.5/site-packages/func/minion/modules/"
bar = module_walker(module_file_path)
print bar
for f in bar:
diff --git a/server/server.py b/minion/server.py
index cd3c9e7..cd3c9e7 100755
--- a/server/server.py
+++ b/minion/server.py
diff --git a/server/sub_process.py b/minion/sub_process.py
index 7c229dc..7c229dc 100644
--- a/server/sub_process.py
+++ b/minion/sub_process.py
diff --git a/server/utils.py b/minion/utils.py
index 724c847..724c847 100755
--- a/server/utils.py
+++ b/minion/utils.py
diff --git a/modules/pkt.py b/modules/pkt.py
new file mode 100644
index 0000000..60091c9
--- /dev/null
+++ b/modules/pkt.py
@@ -0,0 +1,92 @@
+#!/usr/bin/python
+
+## func module for PackageKit
+##
+## Copyright 2007, Red Hat, Inc
+## Robin Norwood <rnorwood@redhat.com>
+##
+## 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.
+##
+##
+
+
+from codes import *
+from modules import func_module
+
+from packagekit import PackageKit
+
+import StringIO
+
+class PackageKitInterface(PackageKit):
+
+ def __init__(self):
+ PackageKit.__init__(self)
+ self.packages = []
+
+ def Percentage(self, progress):
+ pass
+
+ def JobStatus(self, type):
+ pass
+
+ def Package(self, package_name, package_summary):
+ self.packages.append( {
+ "name" : "%s" % package_name,
+ "summary" : "%s" % package_summary,
+ } )
+
+ def Description(self, package_name, package_group, package_description, package_url):
+ self.packages.append( {
+ "name" : "%s" % package_name,
+ "group" : "%s" % package_group,
+ "description" : "%s" % package_description,
+ "url" : "%s" % package_url,
+ } )
+
+class PackageKitController(func_module.FuncModule):
+
+ def __init__(self):
+ try:
+ self.pkt_interface = PackageKitInterface()
+ except PackageKitNotStarted:
+ func_module.FuncModule.__init__(self)
+ return
+
+ self.methods = {
+ "SearchName" : self.SearchName,
+ "GetDescription" : self.GetDescription,
+ "RefreshCache" : self.RefreshCache,
+ }
+ func_module.FuncModule.__init__(self)
+
+ def SearchName(self, pattern):
+ if len(pattern)==0:
+ return
+
+ self.pkt_interface.job = self.pkt_interface.SearchName(pattern)
+ self.pkt_interface.run()
+
+ return self.pkt_interface.packages
+
+ def GetDescription(self, packageName):
+ if len(packageName) == 0:
+ return
+
+ self.pkt_interface.job = self.pkt_interface.GetDescription(packageName)
+ self.pkt_interface.run()
+
+ return self.pkt_interface.packages
+
+ def RefreshCache(self):
+ self.pkt_interface.job = self.pkt_interface.RefreshCache()
+ self.pkt_interface.run()
+
+ return "Done"
+
+methods = PackageKitController()
+register_rpc = methods.register_rpc
diff --git a/server/__init__.py b/overlord/__init__.py
index e69de29..e69de29 100644
--- a/server/__init__.py
+++ b/overlord/__init__.py
diff --git a/client/dumb_client.py b/overlord/dumb_client.py
index c6a31ed..c6a31ed 100755
--- a/client/dumb_client.py
+++ b/overlord/dumb_client.py
diff --git a/overlord/sslclient.py b/overlord/sslclient.py
new file mode 100644
index 0000000..9439c4a
--- /dev/null
+++ b/overlord/sslclient.py
@@ -0,0 +1,44 @@
+#!/usr/bin/python
+
+import os
+import sys
+import xmlrpclib
+import urllib
+
+from func import SSLCommon
+
+
+class SSL_Transport(xmlrpclib.Transport):
+
+ user_agent = "pyOpenSSL_XMLRPC/%s - %s" % ('0.1', xmlrpclib.Transport.user_agent)
+
+ def __init__(self, ssl_context, timeout=None, use_datetime=0):
+ if sys.version_info[:3] >= (2, 5, 0):
+ xmlrpclib.Transport.__init__(self, use_datetime)
+ self.ssl_ctx=ssl_context
+ self._timeout = timeout
+
+ def make_connection(self, host):
+ # Handle username and password.
+ try:
+ host, extra_headers, x509 = self.get_host_info(host)
+ except AttributeError:
+ # Yay for Python 2.2
+ pass
+ _host, _port = urllib.splitport(host)
+ return SSLCommon.HTTPS(_host, int(_port), ssl_context=self.ssl_ctx, timeout=self._timeout)
+
+
+class SSLXMLRPCServerProxy(xmlrpclib.ServerProxy):
+ def __init__(self, uri, pkey_file, cert_file, ca_cert_file, timeout=None):
+ self.ctx = SSLCommon.CreateSSLContext(pkey_file, cert_file, ca_cert_file)
+ xmlrpclib.ServerProxy.__init__(self, uri, SSL_Transport(ssl_context=self.ctx, timeout=timeout))
+
+
+
+if __name__ == "__main__":
+ s = SSLXMLRPCServerProxy('https://localhost:51234/', '/etc/pki/func/slave.pem', '/etc/pki/func/slave.crt', '/etc/pki/func/ca/funcmaster.crt')
+ f = s.ping(1, 2)
+ print f
+
+ \ No newline at end of file
diff --git a/client/test_func.py b/overlord/test_func.py
index bcce45d..bcce45d 100644
--- a/client/test_func.py
+++ b/overlord/test_func.py
diff --git a/scripts/certmaster b/scripts/certmaster
new file mode 100755
index 0000000..3b212b4
--- /dev/null
+++ b/scripts/certmaster
@@ -0,0 +1,12 @@
+#!/usr/bin/python
+
+import sys
+import distutils.sysconfig
+
+sys.path.append("%s/func" % distutils.sysconfig.get_python_lib())
+
+import certmaster
+
+cm = certmaster.CertMaster('/etc/func/certmaster.conf')
+server = certmaster.serve(cm)
+
diff --git a/scripts/funcd b/scripts/funcd
index 165dd68..2301acf 100755
--- a/scripts/funcd
+++ b/scripts/funcd
@@ -6,7 +6,7 @@ import distutils.sysconfig
sys.path.append("%s/func" % distutils.sysconfig.get_python_lib())
-from server import server
+from minion import server
if __name__ == "__main__":
server.main(sys.argv)
diff --git a/settings b/settings
index 8344dee..8177535 100644
--- a/settings
+++ b/settings
@@ -1,7 +1,7 @@
-# configuration for master servers
+# configuration for overlord servers
[general]
-is_master = 0
+is_overlord = 0
is_minion = 1
-master_server = funcmaster
+overlord_server = funcmaster
log_level = DEBUG
diff --git a/setup.py b/setup.py
index b91f1c6..d487a1a 100644
--- a/setup.py
+++ b/setup.py
@@ -10,7 +10,7 @@ NAME = "func"
VERSION = open("version", "r+").read().split()[0]
SHORT_DESC = "%s remote configuration and management api" % NAME
LONG_DESC = """
-A small pluggabe xml-rpc daemon used by %s to implement various web services hooks
+A small pluggable xml-rpc daemon used by %s to implement various web services hooks
""" % NAME
@@ -36,23 +36,22 @@ if __name__ == "__main__":
name="%s" % NAME,
version = VERSION,
author = "Lots",
- author_email = "et-mgmt-tools@redhat.com",
+ author_email = "func-list@redhat.com",
url = "https://hosted.fedoraproject.org/projects/func/",
license = "GPL",
- scripts = ["scripts/funcd",
- ],
+ scripts = ["scripts/funcd", "scripts/certmaster"],
# package_data = { '' : ['*.*'] },
- package_dir = {"%s" % NAME: "",
- "%s/server" % NAME: "server",
- "%s/server/modules" % NAME: "modules/",
- "%s/client" % NAME: "client"
+ package_dir = {"%s" % NAME: "%s" % NAME,
+ "%s/minion" % NAME: "minion/",
+ "%s/minion/modules" % NAME: "modules/",
+ "%s/overlord" % NAME: "overlord/"
},
packages = ["%s" % NAME,
- "%s/server" % NAME,
- "%s/client" % NAME,
- "%s/server/modules" % NAME
+ "%s/minion" % NAME,
+ "%s/overlord" % NAME,
+ "%s/minion/modules" % NAME
],
- data_files = [(initpath, ["init-scripts/funcd"]),
+ data_files = [(initpath, ["init-scripts/funcd", "init-scripts/certmaster"]),
(etcpath, ["settings",]),
(etcpathdb, []),
(logpath, []),
diff --git a/version b/version
index 2311023..01c3668 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-0.11 2
+0.11 3