# Authors: # Jason Gerard DeRose # # Copyright (C) 2008 Red Hat # see file 'COPYING' for use and warranty information # # 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; version 2 only # # 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 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 """ Various utility functions. """ import os import imp import logging import time import socket import re from types import NoneType from ipalib import errors from ipapython import dnsclient def json_serialize(obj): if isinstance(obj, (list, tuple)): return [json_serialize(o) for o in obj] if isinstance(obj, dict): return dict((k, json_serialize(v)) for (k, v) in obj.iteritems()) if isinstance(obj, (bool, float, int, unicode, NoneType)): return obj if isinstance(obj, str): return obj.decode('utf-8') if not callable(getattr(obj, '__json__', None)): # raise TypeError('%r is not JSON serializable') return '' return json_serialize(obj.__json__()) def get_current_principal(): try: # krbV isn't necessarily available on client machines, fail gracefully import krbV return unicode(krbV.default_context().default_ccache().principal().name) except ImportError: raise RuntimeError('python-krbV is not available.') except krbV.Krb5Error: #TODO: do a kinit? raise errors.CCacheError() def get_fqdn(): fqdn = "" try: fqdn = socket.getfqdn() except: try: fqdn = socket.gethostname() except: fqdn = "" return fqdn # FIXME: This function has no unit test def find_modules_in_dir(src_dir): """ Iterate through module names found in ``src_dir``. """ if not (os.path.abspath(src_dir) == src_dir and os.path.isdir(src_dir)): return if os.path.islink(src_dir): return suffix = '.py' for name in sorted(os.listdir(src_dir)): if not name.endswith(suffix): continue pyfile = os.path.join(src_dir, name) if os.path.islink(pyfile) or not os.path.isfile(pyfile): continue module = name[:-len(suffix)] if module == '__init__': continue yield (module, pyfile) # FIXME: This function has no unit test def load_plugins_in_dir(src_dir): """ Import each Python module found in ``src_dir``. """ for module in find_modules_in_dir(src_dir): imp.load_module(module, *imp.find_module(module, [src_dir])) # FIXME: This function has no unit test def import_plugins_subpackage(name): """ Import everythig in ``plugins`` sub-package of package named ``name``. """ try: plugins = __import__(name + '.plugins').plugins except ImportError: return src_dir = os.path.dirname(os.path.abspath(plugins.__file__)) for name in find_modules_in_dir(src_dir): full_name = '%s.%s' % (plugins.__name__, name) __import__(full_name) class LogFormatter(logging.Formatter): """ Log formatter that uses UTC for all timestamps. """ converter = time.gmtime def make_repr(name, *args, **kw): """ Construct a standard representation of a class instance. """ args = [repr(a) for a in args] kw = ['%s=%r' % (k, kw[k]) for k in sorted(kw)] return '%s(%s)' % (name, ', '.join(args + kw)) def realm_to_suffix(realm_name): s = realm_name.split(".") terms = ["dc=" + x.lower() for x in s] return ",".join(terms) def validate_host_dns(log, fqdn): """ See if the hostname has a DNS A record. """ rs = dnsclient.query(fqdn + '.', dnsclient.DNS_C_IN, dnsclient.DNS_T_A) if len(rs) == 0: log.debug( 'IPA: DNS A record lookup failed for %s' % fqdn ) raise errors.DNSNotARecordError() else: log.debug( 'IPA: found %d records for %s' % (len(rs), fqdn) ) def isvalid_base64(data): """ Validate the incoming data as valid base64 data or not. The character set must only include of a-z, A-Z, 0-9, + or / and be padded with = to be a length divisible by 4 (so only 0-2 =s are allowed). Its length must be divisible by 4. White space is not significant so it is removed. This doesn't guarantee we have a base64-encoded value, just that it fits the base64 requirements. """ data = ''.join(data.split()) if len(data) % 4 > 0 or \ re.match('^[a-zA-Z0-9\+\/]+\={0,2}$', data) is None: return False else: return True