diff options
| author | Adrian Likins <alikins@redhat.com> | 2008-07-24 12:32:50 -0400 |
|---|---|---|
| committer | Adrian Likins <alikins@redhat.com> | 2008-07-24 12:32:50 -0400 |
| commit | 826fdd377c5a7f49e6ca707838d6bee2dbff731e (patch) | |
| tree | bf7ad884b59ec388dfea674fb1d4c2f03f6859a4 | |
| parent | 27133ae4811dd5bb7d86683714a637ca2fdca053 (diff) | |
| download | func-826fdd377c5a7f49e6ca707838d6bee2dbff731e.tar.gz func-826fdd377c5a7f49e6ca707838d6bee2dbff731e.tar.xz func-826fdd377c5a7f49e6ca707838d6bee2dbff731e.zip | |
remove func/certs.py, func/config.py, and func/minion/utils.py
| -rw-r--r-- | func/certs.py | 139 | ||||
| -rw-r--r-- | func/config.py | 478 | ||||
| -rwxr-xr-x | func/minion/utils.py | 95 |
3 files changed, 0 insertions, 712 deletions
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/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/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) |
