diff options
| author | Adrian Likins <alikins@redhat.com> | 2008-07-24 16:17:47 -0400 |
|---|---|---|
| committer | Adrian Likins <alikins@redhat.com> | 2008-07-24 16:17:47 -0400 |
| commit | cedd9198d92ed606fe47bb64cfbe8e0a4aa07ec8 (patch) | |
| tree | e8df842dd72404a2ff7f1ac5974d098af6cbe1db /func | |
| parent | 01f597a670b3554e96cb3f27b68ad4655d66a50b (diff) | |
| parent | 2cf553e9375110f7c15b1785bc95b37c07592750 (diff) | |
Merge branch 'unduping_code'
Diffstat (limited to 'func')
| -rw-r--r-- | func/SSLCommon.py | 121 | ||||
| -rw-r--r-- | func/SSLConnection.py | 165 | ||||
| -rw-r--r-- | func/certs.py | 139 | ||||
| -rwxr-xr-x | func/codes.py | 1 | ||||
| -rw-r--r-- | func/commonconfig.py | 2 | ||||
| -rw-r--r-- | func/config.py | 478 | ||||
| -rw-r--r-- | func/minion/AuthedXMLRPCServer.py | 2 | ||||
| -rwxr-xr-x | func/minion/server.py | 12 | ||||
| -rwxr-xr-x | func/minion/utils.py | 95 | ||||
| -rwxr-xr-x | func/overlord/client.py | 2 | ||||
| -rwxr-xr-x | func/utils.py | 43 |
11 files changed, 9 insertions, 1051 deletions
diff --git a/func/SSLCommon.py b/func/SSLCommon.py deleted file mode 100644 index 6959749..0000000 --- a/func/SSLCommon.py +++ /dev/null @@ -1,121 +0,0 @@ -# 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 -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 deleted file mode 100644 index 98ed8a0..0000000 --- a/func/SSLConnection.py +++ /dev/null @@ -1,165 +0,0 @@ -# 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 -import time, socket, select -from func.CommonErrors import canIgnoreSSLError - - -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) - except Exception, e: - if canIgnoreSSLError(e): - return None - else: - raise e - 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/func/certs.py b/func/certs.py deleted file mode 100644 index 4d6bf15..0000000 --- a/func/certs.py +++ /dev/null @@ -1,139 +0,0 @@ -# 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 (c) 2007 Red Hat, inc -#- Written by Seth Vidal skvidal @ fedoraproject.org - -from OpenSSL import crypto -import socket -import os -import utils - -def_country = 'UN' -def_state = 'FC' -def_local = 'Func-ytown' -def_org = 'func' -def_ou = 'slave-key' - - -def make_keypair(dest=None): - pkey = crypto.PKey() - pkey.generate_key(crypto.TYPE_RSA, 2048) - if dest: - destfd = os.open(dest, os.O_RDWR|os.O_CREAT, 0600) - os.write(destfd, (crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))) - os.close(destfd) - - return pkey - - -def make_csr(pkey, dest=None, cn=None): - req = crypto.X509Req() - req.get_subject() - subj = req.get_subject() - subj.C = def_country - subj.ST = def_state - subj.L = def_local - subj.O = def_org - subj.OU = def_ou - if cn: - subj.CN = cn - else: - subj.CN = utils.get_hostname() - subj.emailAddress = 'root@%s' % subj.CN - - req.set_pubkey(pkey) - req.sign(pkey, 'md5') - if dest: - destfd = os.open(dest, os.O_RDWR|os.O_CREAT, 0644) - os.write(destfd, crypto.dump_certificate_request(crypto.FILETYPE_PEM, req)) - os.close(destfd) - - return req - - -def retrieve_key_from_file(keyfile): - fo = open(keyfile, 'r') - buf = fo.read() - keypair = crypto.load_privatekey(crypto.FILETYPE_PEM, buf) - return keypair - - -def retrieve_csr_from_file(csrfile): - fo = open(csrfile, 'r') - buf = fo.read() - csrreq = crypto.load_certificate_request(crypto.FILETYPE_PEM, buf) - return csrreq - - -def retrieve_cert_from_file(certfile): - fo = open(certfile, 'r') - buf = fo.read() - cert = crypto.load_certificate(crypto.FILETYPE_PEM, buf) - return cert - - -def create_ca(CN="Func Certificate Authority", ca_key_file=None, ca_cert_file=None): - cakey = make_keypair(dest=ca_key_file) - careq = make_csr(cakey, cn=CN) - cacert = crypto.X509() - cacert.set_serial_number(0) - cacert.gmtime_adj_notBefore(0) - cacert.gmtime_adj_notAfter(60*60*24*365*10) # 10 yrs - hard to beat this kind of cert! - cacert.set_issuer(careq.get_subject()) - cacert.set_subject(careq.get_subject()) - cacert.set_pubkey(careq.get_pubkey()) - cacert.sign(cakey, 'md5') - if ca_cert_file: - destfo = open(ca_cert_file, 'w') - destfo.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cacert)) - destfo.close() - - -def _get_serial_number(cadir): - serial = '%s/serial.txt' % cadir - i = 1 - if os.path.exists(serial): - f = open(serial, 'r').read() - f = f.replace('\n','') - try: - i = int(f) - i+=1 - except ValueError, e: - i = 1 - - _set_serial_number(cadir, i) - return i - - -def _set_serial_number(cadir, last): - serial = '%s/serial.txt' % cadir - f = open(serial, 'w') - f.write(str(last) + '\n') - f.close() - - -def create_slave_certificate(csr, cakey, cacert, cadir, slave_cert_file=None): - cert = crypto.X509() - cert.set_serial_number(_get_serial_number(cadir)) - cert.gmtime_adj_notBefore(0) - cert.gmtime_adj_notAfter(60*60*24*365*10) # 10 yrs - hard to beat this kind of cert! - cert.set_issuer(cacert.get_subject()) - cert.set_subject(csr.get_subject()) - cert.set_pubkey(csr.get_pubkey()) - cert.sign(cakey, 'md5') - if slave_cert_file: - destfo = open(slave_cert_file, 'w') - destfo.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) - destfo.close() - return cert diff --git a/func/codes.py b/func/codes.py index c6bcb61..ac61ffe 100755 --- a/func/codes.py +++ b/func/codes.py @@ -1,3 +1,4 @@ +#!/usr/bin/python """ func diff --git a/func/commonconfig.py b/func/commonconfig.py index 0f5ea55..9eaaa88 100644 --- a/func/commonconfig.py +++ b/func/commonconfig.py @@ -14,7 +14,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. """ -from config import BaseConfig, BoolOption, Option +from certmaster.config import BaseConfig, BoolOption, Option class FuncdConfig(BaseConfig): diff --git a/func/config.py b/func/config.py deleted file mode 100644 index e859f4a..0000000 --- a/func/config.py +++ /dev/null @@ -1,478 +0,0 @@ -# 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 2002 Duke University -# filched from yum - menno smits wrote this - he rocks - - -import os -import sys -import warnings -import copy -import urlparse -from ConfigParser import NoSectionError, NoOptionError, ConfigParser -from ConfigParser import ParsingError -import exceptions - -CONFIG_FILE = "/etc/certmaster/certmaster.conf" - -class ConfigError(exceptions.Exception): - def __init__(self, value=None): - exceptions.Exception.__init__(self) - self.value = value - def __str__(self): - return "%s" %(self.value,) - - -class Option(object): - ''' - This class handles a single Yum configuration file option. Create - subclasses for each type of supported configuration option. - - Python descriptor foo (__get__ and __set__) is used to make option - definition easy and consise. - ''' - - def __init__(self, default=None): - self._setattrname() - self.inherit = False - self.default = default - - def _setattrname(self): - '''Calculate the internal attribute name used to store option state in - configuration instances. - ''' - self._attrname = '__opt%d' % id(self) - - def __get__(self, obj, objtype): - '''Called when the option is read (via the descriptor protocol). - - @param obj: The configuration instance to modify. - @param objtype: The type of the config instance (not used). - @return: The parsed option value or the default value if the value - wasn't set in the configuration file. - ''' - if obj is None: - return self - - return getattr(obj, self._attrname, None) - - def __set__(self, obj, value): - '''Called when the option is set (via the descriptor protocol). - - @param obj: The configuration instance to modify. - @param value: The value to set the option to. - @return: Nothing. - ''' - # Only try to parse if its a string - if isinstance(value, basestring): - try: - value = self.parse(value) - except ValueError, e: - # Add the field name onto the error - raise ValueError('Error parsing %r: %s' % (value, str(e))) - - setattr(obj, self._attrname, value) - - def setup(self, obj, name): - '''Initialise the option for a config instance. - This must be called before the option can be set or retrieved. - - @param obj: BaseConfig (or subclass) instance. - @param name: Name of the option. - ''' - setattr(obj, self._attrname, copy.copy(self.default)) - - def clone(self): - '''Return a safe copy of this Option instance - ''' - new = copy.copy(self) - new._setattrname() - return new - - def parse(self, s): - '''Parse the string value to the Option's native value. - - @param s: Raw string value to parse. - @return: Validated native value. - - Will raise ValueError if there was a problem parsing the string. - Subclasses should override this. - ''' - return s - - def tostring(self, value): - '''Convert the Option's native value to a string value. - - @param value: Native option value. - @return: String representation of input. - - This does the opposite of the parse() method above. - Subclasses should override this. - ''' - return str(value) - - -def Inherit(option_obj): - '''Clone an Option instance for the purposes of inheritance. The returned - instance has all the same properties as the input Option and shares items - such as the default value. Use this to avoid redefinition of reused - options. - - @param option_obj: Option instance to inherit. - @return: New Option instance inherited from the input. - ''' - new_option = option_obj.clone() - new_option.inherit = True - return new_option - - -class ListOption(Option): - - def __init__(self, default=None): - if default is None: - default = [] - super(ListOption, self).__init__(default) - - def parse(self, s): - """Converts a string from the config file to a workable list - - Commas and spaces are used as separators for the list - """ - # we need to allow for the '\n[whitespace]' continuation - easier - # to sub the \n with a space and then read the lines - s = s.replace('\n', ' ') - s = s.replace(',', ' ') - return s.split() - - def tostring(self, value): - return '\n '.join(value) - - -class UrlOption(Option): - ''' - This option handles lists of URLs with validation of the URL scheme. - ''' - - def __init__(self, default=None, schemes=('http', 'ftp', 'file', 'https'), - allow_none=False): - super(UrlOption, self).__init__(default) - self.schemes = schemes - self.allow_none = allow_none - - def parse(self, url): - url = url.strip() - - # Handle the "_none_" special case - if url.lower() == '_none_': - if self.allow_none: - return None - else: - raise ValueError('"_none_" is not a valid value') - - # Check that scheme is valid - (s,b,p,q,f,o) = urlparse.urlparse(url) - if s not in self.schemes: - raise ValueError('URL must be %s not "%s"' % (self._schemelist(), s)) - - return url - - def _schemelist(self): - '''Return a user friendly list of the allowed schemes - ''' - if len(self.schemes) < 1: - return 'empty' - elif len(self.schemes) == 1: - return self.schemes[0] - else: - return '%s or %s' % (', '.join(self.schemes[:-1]), self.schemes[-1]) - - -class UrlListOption(ListOption): - ''' - Option for handling lists of URLs with validation of the URL scheme. - ''' - - def __init__(self, default=None, schemes=('http', 'ftp', 'file', 'https')): - super(UrlListOption, self).__init__(default) - - # Hold a UrlOption instance to assist with parsing - self._urloption = UrlOption(schemes=schemes) - - def parse(self, s): - out = [] - for url in super(UrlListOption, self).parse(s): - out.append(self._urloption.parse(url)) - return out - - -class IntOption(Option): - def parse(self, s): - try: - return int(s) - except (ValueError, TypeError), e: - raise ValueError('invalid integer value') - - -class BoolOption(Option): - def parse(self, s): - s = s.lower() - if s in ('0', 'no', 'false'): - return False - elif s in ('1', 'yes', 'true'): - return True - else: - raise ValueError('invalid boolean value') - - def tostring(self, value): - if value: - return "1" - else: - return "0" - - -class FloatOption(Option): - def parse(self, s): - try: - return float(s.strip()) - except (ValueError, TypeError): - raise ValueError('invalid float value') - - -class SelectionOption(Option): - '''Handles string values where only specific values are allowed - ''' - def __init__(self, default=None, allowed=()): - super(SelectionOption, self).__init__(default) - self._allowed = allowed - - def parse(self, s): - if s not in self._allowed: - raise ValueError('"%s" is not an allowed value' % s) - return s - -class BytesOption(Option): - - # Multipliers for unit symbols - MULTS = { - 'k': 1024, - 'm': 1024*1024, - 'g': 1024*1024*1024, - } - - def parse(self, s): - """Parse a friendly bandwidth option to bytes - - The input should be a string containing a (possibly floating point) - number followed by an optional single character unit. Valid units are - 'k', 'M', 'G'. Case is ignored. - - Valid inputs: 100, 123M, 45.6k, 12.4G, 100K, 786.3, 0 - Invalid inputs: -10, -0.1, 45.6L, 123Mb - - Return value will always be an integer - - 1k = 1024 bytes. - - ValueError will be raised if the option couldn't be parsed. - """ - if len(s) < 1: - raise ValueError("no value specified") - - if s[-1].isalpha(): - n = s[:-1] - unit = s[-1].lower() - mult = self.MULTS.get(unit, None) - if not mult: - raise ValueError("unknown unit '%s'" % unit) - else: - n = s - mult = 1 - - try: - n = float(n) - except ValueError: - raise ValueError("couldn't convert '%s' to number" % n) - - if n < 0: - raise ValueError("bytes value may not be negative") - - return int(n * mult) - - -class ThrottleOption(BytesOption): - - def parse(self, s): - """Get a throttle option. - - Input may either be a percentage or a "friendly bandwidth value" as - accepted by the BytesOption. - - Valid inputs: 100, 50%, 80.5%, 123M, 45.6k, 12.4G, 100K, 786.0, 0 - Invalid inputs: 100.1%, -4%, -500 - - Return value will be a int if a bandwidth value was specified or a - float if a percentage was given. - - ValueError will be raised if input couldn't be parsed. - """ - if len(s) < 1: - raise ValueError("no value specified") - - if s[-1] == '%': - n = s[:-1] - try: - n = float(n) - except ValueError: - raise ValueError("couldn't convert '%s' to number" % n) - if n < 0 or n > 100: - raise ValueError("percentage is out of range") - return n / 100.0 - else: - return BytesOption.parse(self, s) - - -class BaseConfig(object): - ''' - Base class for storing configuration definitions. Subclass when creating - your own definitons. - ''' - - def __init__(self): - self._section = None - - for name in self.iterkeys(): - option = self.optionobj(name) - option.setup(self, name) - - def __str__(self): - out = [] - out.append('[%s]' % self._section) - for name, value in self.iteritems(): - out.append('%s: %r' % (name, value)) - return '\n'.join(out) - - def populate(self, parser, section, parent=None): - '''Set option values from a INI file section. - - @param parser: ConfParser instance (or subclass) - @param section: INI file section to read use. - @param parent: Optional parent BaseConfig (or subclass) instance to use - when doing option value inheritance. - ''' - self.cfg = parser - self._section = section - - for name in self.iterkeys(): - option = self.optionobj(name) - value = None - try: - value = parser.get(section, name) - except (NoSectionError, NoOptionError): - # No matching option in this section, try inheriting - if parent and option.inherit: - value = getattr(parent, name) - - if value is not None: - setattr(self, name, value) - - def optionobj(cls, name): - '''Return the Option instance for the given name - ''' - obj = getattr(cls, name, None) - if isinstance(obj, Option): - return obj - else: - raise KeyError - optionobj = classmethod(optionobj) - - def isoption(cls, name): - '''Return True if the given name refers to a defined option - ''' - try: - cls.optionobj(name) - return True - except KeyError: - return False - isoption = classmethod(isoption) - - def iterkeys(self): - '''Yield the names of all defined options in the instance. - ''' - for name, item in self.iteritems(): - yield name - - def iteritems(self): - '''Yield (name, value) pairs for every option in the instance. - - The value returned is the parsed, validated option value. - ''' - # Use dir() so that we see inherited options too - for name in dir(self): - if self.isoption(name): - yield (name, getattr(self, name)) - - def write(self, fileobj, section=None, always=()): - '''Write out the configuration to a file-like object - - @param fileobj: File-like object to write to - @param section: Section name to use. If not-specified the section name - used during parsing will be used. - @param always: A sequence of option names to always write out. - Options not listed here will only be written out if they are at - non-default values. Set to None to dump out all options. - ''' - # Write section heading - if section is None: - if self._section is None: - raise ValueError("not populated, don't know section") - section = self._section - - # Updated the ConfigParser with the changed values - cfgOptions = self.cfg.options(section) - for name,value in self.iteritems(): - option = self.optionobj(name) - if always is None or name in always or option.default != value or name in cfgOptions : - self.cfg.set(section,name, option.tostring(value)) - # write the updated ConfigParser to the fileobj. - self.cfg.write(fileobj) - - def getConfigOption(self, option, default=None): - warnings.warn('getConfigOption() will go away in a future version of Yum.\n' - 'Please access option values as attributes or using getattr().', - DeprecationWarning) - if hasattr(self, option): - return getattr(self, option) - return default - - def setConfigOption(self, option, value): - warnings.warn('setConfigOption() will go away in a future version of Yum.\n' - 'Please set option values as attributes or using setattr().', - DeprecationWarning) - if hasattr(self, option): - setattr(self, option, value) - else: - raise ConfigError, 'No such option %s' % option - - -def read_config(config_file, BaseConfigDerived): - confparser = ConfigParser() - opts = BaseConfigDerived() - if os.path.exists(config_file): - try: - confparser.read(config_file) - except ParsingError, e: - print >> sys.stderr, "Error reading config file: %s" % e - sys.exit(1) - opts.populate(confparser, 'main') - return opts diff --git a/func/minion/AuthedXMLRPCServer.py b/func/minion/AuthedXMLRPCServer.py index 8545d15..dc5d23e 100644 --- a/func/minion/AuthedXMLRPCServer.py +++ b/func/minion/AuthedXMLRPCServer.py @@ -18,7 +18,7 @@ import sys import socket import SimpleXMLRPCServer -from func import SSLCommon +from certmaster import SSLCommon import OpenSSL import SocketServer diff --git a/func/minion/server.py b/func/minion/server.py index 2750afc..36f3262 100755 --- a/func/minion/server.py +++ b/func/minion/server.py @@ -27,15 +27,13 @@ from func.config import read_config from func.commonconfig import FuncdConfig from certmaster.commonconfig import CMConfig from func import logger -from func import certs +from certmaster import certs import func.jobthing as jobthing # our modules import AuthedXMLRPCServer import codes import module_loader -import func.utils as futils -import func.minion.utils as fmutils import func.minion.acls as acls_mod from certmaster import utils @@ -139,11 +137,11 @@ class FuncApiMethod: except codes.FuncException, e: self.__log_exc() (t, v, tb) = sys.exc_info() - rc = futils.nice_exception(t,v,tb) + rc = utils.nice_exception(t,v,tb) except: self.__log_exc() (t, v, tb) = sys.exc_info() - rc = futils.nice_exception(t,v,tb) + rc = utils.nice_exception(t,v,tb) self.logger.debug("Return code for %s: %s" % (self.__name, rc)) return rc @@ -235,7 +233,7 @@ class FuncSSLXMLRPCServer(AuthedXMLRPCServer.AuthedSSLXMLRPCServer, return jobthing.minion_async_run(self.get_dispatch_method, method, params) except: (t, v, tb) = sys.exc_info() - rc = futils.nice_exception(t, v, tb) + rc = utils.nice_exception(t, v, tb) return rc def auth_cb(self, request, client_address): @@ -250,7 +248,7 @@ def main(argv): """ if "daemon" in sys.argv or "--daemon" in sys.argv: - futils.daemonize("/var/run/funcd.pid") + utils.daemonize("/var/run/funcd.pid") else: print "serving...\n" diff --git a/func/minion/utils.py b/func/minion/utils.py deleted file mode 100755 index e8d1b39..0000000 --- a/func/minion/utils.py +++ /dev/null @@ -1,95 +0,0 @@ -""" -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. -""" - -import os -import socket -import string -import sys -import time -import traceback -import xmlrpclib -import glob - -import codes -from func import certs -from func.config import read_config -from certmaster.commonconfig import MinionConfig -from func import logger - -# "localhost" is a lame hostname to use for a key, so try to get -# a more meaningful hostname. We do this by connecting to the certmaster -# and seeing what interface/ip it uses to make that connection, and looking -# up the hostname for that. -def get_hostname(): - - # FIXME: this code ignores http proxies (which granted, we don't - # support elsewhere either. It also hardcodes the port number - # for the certmaster for now - hostname = None - hostname = socket.gethostname() - try: - ip = socket.gethostbyname(hostname) - except: - return hostname - if ip != "127.0.0.1": - return hostname - - - config_file = '/etc/certmaster/minion.conf' - minion_config = read_config(config_file, MinionConfig) - - server = minion_config.certmaster - port = 51235 - - try: - s = socket.socket() - s.settimeout(5) - s.connect((server, port)) - (intf, port) = s.getsockname() - hostname = socket.gethostbyaddr(intf)[0] - s.close() - except: - s.close() - raise - - return hostname - - - -# this is kind of handy, so keep it around for now -# but we really need to fix out server side logging and error -# reporting so we don't need it -def trace_me(): - x = traceback.extract_stack() - bar = string.join(traceback.format_list(x)) - return bar - - -def daemonize(pidfile=None): - """ - Daemonize this process with the UNIX double-fork trick. - Writes the new PID to the provided file name if not None. - """ - - print pidfile - pid = os.fork() - if pid > 0: - sys.exit(0) - os.setsid() - os.umask(0) - pid = os.fork() - - - if pid > 0: - if pidfile is not None: - open(pidfile, "w").write(str(pid)) - sys.exit(0) diff --git a/func/overlord/client.py b/func/overlord/client.py index 4cb8216..79ead06 100755 --- a/func/overlord/client.py +++ b/func/overlord/client.py @@ -19,6 +19,7 @@ import os import func.yaml as yaml from certmaster.commonconfig import CMConfig +from certmaster import utils from func.config import read_config, CONFIG_FILE import sslclient @@ -28,7 +29,6 @@ import groups import delegation_tools as dtools import func.forkbomb as forkbomb import func.jobthing as jobthing -import func.utils as utils from func.CommonErrors import * # =================================== diff --git a/func/utils.py b/func/utils.py index 9577bd9..0e4b4d5 100755 --- a/func/utils.py +++ b/func/utils.py @@ -18,49 +18,6 @@ import socket REMOTE_ERROR = "REMOTE_ERROR" -def trace_me(): - x = traceback.extract_stack() - bar = string.join(traceback.format_list(x)) - return bar - -def daemonize(pidfile=None): - """ - Daemonize this process with the UNIX double-fork trick. - Writes the new PID to the provided file name if not None. - """ - - print pidfile - pid = os.fork() - if pid > 0: - sys.exit(0) - os.setsid() - os.umask(0) - pid = os.fork() - - if pid > 0: - if pidfile is not None: - open(pidfile, "w").write(str(pid)) - sys.exit(0) - -def nice_exception(etype, evalue, etb): - etype = str(etype) - try: - lefti = etype.index("'") + 1 - righti = etype.rindex("'") - nicetype = etype[lefti:righti] - except: - nicetype = etype - nicestack = string.join(traceback.format_list(traceback.extract_tb(etb))) - return [ REMOTE_ERROR, nicetype, str(evalue), nicestack ] - -def get_hostname(): - fqdn = socket.getfqdn() - host = socket.gethostname() - if fqdn.find(host) != -1: - return fqdn - else: - return host - def is_error(result): if type(result) != list: |
