diff options
author | Alexander Bokovoy <abokovoy@redhat.com> | 2011-08-30 17:13:12 +0300 |
---|---|---|
committer | Alexander Bokovoy <abokovoy@redhat.com> | 2011-08-30 17:13:12 +0300 |
commit | 40b1bba03ea8da78ad19a1d187baf7ffeea9c351 (patch) | |
tree | 58534f1fd8d6ff93032f02b223f9fa75f1db06df | |
parent | ce72af8079e8ba54eb67cacfcf674d4cca36a0da (diff) | |
download | freeipa-40b1bba03ea8da78ad19a1d187baf7ffeea9c351.tar.gz freeipa-40b1bba03ea8da78ad19a1d187baf7ffeea9c351.tar.xz freeipa-40b1bba03ea8da78ad19a1d187baf7ffeea9c351.zip |
Move system-specific code to ipapython/platform, use it via ipapython/services.py
-rw-r--r-- | ipapython/ipautil.py | 69 | ||||
-rw-r--r-- | ipapython/platform/redhat.py | 163 | ||||
-rw-r--r-- | ipapython/services.py.in | 182 | ||||
-rw-r--r-- | ipapython/sysrestore.py | 5 |
4 files changed, 294 insertions, 125 deletions
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py index 0e2532dc9..81a079285 100644 --- a/ipapython/ipautil.py +++ b/ipapython/ipautil.py @@ -1,5 +1,4 @@ # Authors: Simo Sorce <ssorce@redhat.com> -# Alexander Bokovoy <abokovoy@redhat.com> # # Copyright (C) 2007-2011 Red Hat # see file 'COPYING' for use and warranty information @@ -1128,71 +1127,3 @@ def bind_port_responder(port, socket_stream=True, socket_timeout=None, responder finally: s.close() -class AuthConfig: - """ - AuthConfig class implements system-independent interface to configure - system authentication resources. In Red Hat systems this is done with - authconfig(8) utility. - - AuthConfig class is nothing more than a tool to gather configuration options - and execute their processing. These options then converted by an actual implementation - to series of a system calls to appropriate utilities performing real configuration. - - Actual implementation should be done in ipapython/platform/<platform>.py by inheriting from ipautil.AuthConfig - and redefining __build_args() and execute() methods. - .... - class PlatformAuthConfig(ipautil.AuthConfig): - def __build_args(): - ... - - def execute(): - ... - - authconfig = PlatformAuthConfig - .... - - See ipapython/platform/redhat.py for a sample implementation that uses authconfig(8) as its backend. - - From IPA perspective, the authentication configuration should be done with use of ipapython.services.authconfig: - - auth_config = ipapython.services.authconfig() - auth_config.disable("ldap").\ - disable("krb5").\ - disable("sssd").\ - disable("sssdauth").\ - disable("mkhomedir").\ - add_option("update").\ - enable("nis").\ - add_parameter("nisdomain","foobar") - auth_config.execute() - """ - - def __init__(self): - self.parameters = {} - - def enable(self, option): - self.parameters[option] = True - return self - - def disable(self, option): - self.parameters[option] = False - return self - - def add_option(self, option): - self.parameters[option] = None - return self - - def add_parameter(self, option, value): - self.parameters[option] = [value] - return self - - def __build_args(self): - # do nothing - return None - - def execute(self): - # do nothing - return None - - - diff --git a/ipapython/platform/redhat.py b/ipapython/platform/redhat.py index c6d2631cd..de97b5be8 100644 --- a/ipapython/platform/redhat.py +++ b/ipapython/platform/redhat.py @@ -18,80 +18,83 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -from ipapython import ipautil +import tempfile +import re +import os +import stat +import sys +from ipapython import ipautil, sysrestore +from ipapython import services as ipaservices -SERVICE_PORTMAP = "portmap" -SERVICE_RPCBIND = "rpcbind" -SERVICE_CERTMONGER = "certmonger" -SERVICE_NSCD = "nscd" -SERVICE_NLSCD = "nlscd" +# All what we allow exporting directly from this module +# Everything else is made available through these symbols when they directly imported into ipapython.services: +# authconfig -- class reference for platform-specific implementation of authconfig(8) +# service -- class reference for platform-specific implementation of a PlatformService class +# knownservices -- factory instance to access named services IPA cares about, names are ipapython.services.wellknownservices +# backup_and_replace_hostname -- platform-specific way to set hostname and make it persistent over reboots +# restore_context -- platform-sepcific way to restore security context, if applicable +__all__ = ['authconfig', 'service', 'knownservices', 'backup_and_replace_hostname', 'restore_context'] -def service_stop(service_name, instance_name="", capture_output=True): - ipautil.run(["/sbin/service", service_name, "stop", instance_name], - capture_output=capture_output) +class RedHatService(ipaservices.PlatformService): + def stop(self, instance_name="", capture_output=True): + ipautil.run(["/sbin/service", self.service_name, "stop", instance_name], capture_output=capture_output) -def service_start(service_name, instance_name="", capture_output=True): - ipautil.run(["/sbin/service", service_name, "start", instance_name], - capture_output=capture_output) + def start(self, instance_name="", capture_output=True): + ipautil.run(["/sbin/service", self.service_name, "start", instance_name], capture_output=capture_output) -def service_restart(service_name, instance_name="", capture_output=True): - ipautil.run(["/sbin/service", service_name, "restart", instance_name], - capture_output=capture_output) + def restart(self, instance_name="", capture_output=True): + ipautil.run(["/sbin/service", self.service_name, "restart", instance_name], capture_output=capture_output) -def service_is_running(service_name, instance_name=""): - ret = True - try: - ipautil.run(["/sbin/service", service_name, "status", instance_name]) - except ipautil.CalledProcessError: - ret = False - return ret + def is_running(self, instance_name=""): + ret = True + try: + (sout,serr,rcode) = ipautil.run(["/sbin/service", self.service_name, "status", instance_name]) + if sout.find("is stopped") >= 0: + ret = False + except ipautil.CalledProcessError: + ret = False + return ret -def service_is_installed(service_name): - installed = True - try: - ipautil.run(["/sbin/service", service_name, "status"]) - except ipautil.CalledProcessError, e: - if e.returncode == 1: - # service is not installed or there is other serious issue - installed = False - return installed + def is_installed(self): + installed = True + try: + ipautil.run(["/sbin/service", self.service_name, "status"]) + except ipautil.CalledProcessError, e: + if e.returncode == 1: + # service is not installed or there is other serious issue + installed = False + return installed -def service_is_enabled(service_name): - (stdout, stderr, returncode) = ipautil.run(["/sbin/chkconfig", service_name], raiseonerr=False) - return (returncode == 0) + def is_enabled(self): + (stdout, stderr, returncode) = ipautil.run(["/sbin/chkconfig", self.service_name],raiseonerr=False) + return (returncode == 0) -def service_on(service_name): - ipautil.run(["/sbin/chkconfig", service_name, "on"]) + def enable(self): + ipautil.run(["/sbin/chkconfig", self.service_name, "on"]) -def service_off(service_name): - ipautil.run(["/sbin/chkconfig", service_name, "off"]) + def disable(self): + ipautil.run(["/sbin/chkconfig", self.service_name, "off"]) -def service_add(service_name): - ipautil.run(["/sbin/chkconfig", "--add", service_name]) + def install(self): + ipautil.run(["/sbin/chkconfig", "--add", self.service_name]) -def service_del(service_name): - ipautil.run(["/sbin/chkconfig", "--del", service_name]) + def remove(self): + ipautil.run(["/sbin/chkconfig", "--del", self.service_name]) -def restore_context(dirname): +def restore_context(filepath): """ - restore security context on the directory - SE Linux equivalent is /sbin/restorecon <dirname> + restore security context on the file path + SE Linux equivalent is /sbin/restorecon <filepath> """ - ipautil.run(["/sbin/restorecon", dirname]) + ipautil.run(["/sbin/restorecon", filepath]) -class RedHatAuthConfig(ipautil.AuthConfig): +class RedHatAuthConfig(ipaservices.AuthConfig): """ AuthConfig class implements system-independent interface to configure system authentication resources. In Red Hat-produced systems this is done with authconfig(8) utility. """ - S_SHADOW = "shadow" - S_MD5 = "md5" - S_NIS = "nis" - S_LDAP = "ldap" - S_SSSD = "sssd" - def __build_args(self): args = [] for (option, value) in self.parameters.items(): @@ -113,4 +116,58 @@ class RedHatAuthConfig(ipautil.AuthConfig): args = self.__build_args() ipautil.run(["/usr/sbin/authconfig"]+args) +def backup_and_replace_hostname(fstore, statestore, hostname): + network_filename = "/etc/sysconfig/network" + # Backup original /etc/sysconfig/network + fstore.backup_file(network_filename) + hostname_pattern = re.compile(''' +(^ + \s* + (?P<option> [^\#;]+?) + (\s*=\s*) + (?P<value> .+?)? + (\s*((\#|;).*)?)? +$)''', re.VERBOSE) + temp_filename = None + with tempfile.NamedTemporaryFile(delete=False) as new_config: + temp_filename = new_config.name + with open(network_filename, 'r') as f: + for line in f: + new_line = line + m = hostname_pattern.match(line) + if m: + option, value = m.group('option', 'value') + if option is not None and option == 'HOSTNAME': + if value is not None and hostname != value: + new_line = u"HOSTNAME=%s\n" % (hostname) + statestore.backup_state('network', 'hostname', value) + new_config.write(new_line) + new_config.flush() + # Make sure the resulting file is readable by others before installing it + os.fchmod(new_config.fileno(), stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) + os.fchown(new_config.fileno(), 0, 0) + + # At this point new_config is closed but not removed due to 'delete=False' above + # Now, install the temporary file as configuration and ensure old version is available as .orig + # While .orig file is not used during uninstall, it is left there for administrator. + ipautil.install_file(temp_filename, network_filename) + try: + ipautil.run(['/bin/hostname', hostname]) + except ipautil.CalledProcessError, e: + print >>sys.stderr, "Failed to set this machine hostname to %s (%s)." % (hostname, str(e)) + + # For SE Linux environments it is important to reset SE labels to the expected ones + try: + restore_context(network_filename) + except ipautil.CalledProcessError, e: + print >>sys.stderr, "Failed to set permissions for %s (%s)." % (network_filename, str(e)) + +class RedHatServices(ipaservices.KnownServices): + def __init__(self): + for s in ipaservices.wellknownservices: + self.__services__ += RedHatService(s) + authconfig = RedHatAuthConfig +service = RedHatService +knownservices = RedHatServices() + diff --git a/ipapython/services.py.in b/ipapython/services.py.in index 040ab562e..f6099a7dc 100644 --- a/ipapython/services.py.in +++ b/ipapython/services.py.in @@ -1,2 +1,182 @@ -from ipapython.platform.SUPPORTED_PLATFORM import * +# Authors: Alexander Bokovoy <abokovoy@redhat.com> +# Authors: Simo Sorce <ssorce@redhat.com> +# +# Copyright (C) 2011 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, either version 3 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +# Canonical names of services as IPA wants to see them. As we need to have *some* naming, +# set them as in Red Hat distributions. Actual implementation should make them available +# through knownservices.<name> and take care of remapping internally, if needed +wellknownservices = ['certmonger', 'dirsrv', 'httpd', 'ipa', 'krb5kdc', 'messagebus', + 'nlscd', 'nscd', 'ntpd', 'portmap', 'rpcbind'] + +# authconfig is an entry point to platform-provided AuthConfig implementation +authconfig = None + +# knownservices is an entry point to known platform services (instance of KnownServices) +knownservices = None + +class AuthConfig(object): + """ + AuthConfig class implements system-independent interface to configure + system authentication resources. In Red Hat systems this is done with + authconfig(8) utility. + + AuthConfig class is nothing more than a tool to gather configuration options + and execute their processing. These options then converted by an actual implementation + to series of a system calls to appropriate utilities performing real configuration. + + IPA *expects* names of AuthConfig's options to follow authconfig(8) naming scheme! + + Actual implementation should be done in ipapython/platform/<platform>.py by inheriting from ipapython.services.AuthConfig + and redefining __build_args() and execute() methods. + + class PlatformAuthConfig(ipautil.AuthConfig): + def __build_args(): + ... + + def execute(): + ... + + authconfig = PlatformAuthConfig + .... + + See ipapython/platform/redhat.py for a sample implementation that uses authconfig(8) as its backend. + + From IPA perspective, the authentication configuration should be done with use of ipapython.services.authconfig: + + auth_config = ipapython.services.authconfig() + auth_config.disable("ldap").\ + disable("krb5").\ + disable("sssd").\ + disable("sssdauth").\ + disable("mkhomedir").\ + add_option("update").\ + enable("nis").\ + add_parameter("nisdomain","foobar") + auth_config.execute() + + If you need to re-use existing AuthConfig instance for multiple runs, make sure to + call 'AuthConfig.reset()' between the runs. + """ + + def __init__(self): + self.parameters = {} + + def enable(self, option): + self.parameters[option] = True + return self + + def disable(self, option): + self.parameters[option] = False + return self + + def add_option(self, option): + self.parameters[option] = None + return self + + def add_parameter(self, option, value): + self.parameters[option] = [value] + return self + + def __build_args(self): + # do nothing + return None + + def execute(self): + # do nothing + return None + def reset(self): + self.parameters = {} + return self + +class PlatformService(object): + """ + PlatformService abstracts out external process running on the system which is possible + to administer (start, stop, check status, etc). + + """ + + def __init__(self, service_name): + self.service_name = service_name + + def start(self, instance_name="", capture_output=True): + return + + def stop(self, instance_name="", capture_output=True): + return + + def restart(self, instance_name="", capture_output=True): + return + + def is_running(self): + return False + + def is_installed(self): + return False + + def is_enabled(self): + return False + + def enable(self): + return + + def disable(self): + return + + def install(self): + return + + def remove(self): + return + +class KnownServices(object): + """ + KnownServices is an abstract class factory that produces instances of well-known + platform services. Actual implementation must create these instances on first access + and cache them. + """ + + def __init__(self): + self.__services__ = {} + + def __getattr__(self, name): + if name in self.__services__: + object.__setattr__(self, name, self.__services__[name]) + return self.__services__[name] + return None + +# restore context default implementation that does nothing +def restore_context_default(filepath): + return + +# Restore security context for a path +# If the platform has security features where context is important, implement your own +# version in platform services +restore_context = restore_context_default + +# Default implementation of backup and replace hostname that does nothing +def backup_and_replace_hostname_default(fstore, statestore, hostname): + return + +# Backup and replace system's hostname +# Since many platforms have their own way how to store system's hostname, this method must be +# implemented in platform services +backup_and_replace_hostname = backup_and_replace_hostname_default + +from ipapython.platform.SUPPORTED_PLATFORM import * diff --git a/ipapython/sysrestore.py b/ipapython/sysrestore.py index 1025449c2..9b0e39fcb 100644 --- a/ipapython/sysrestore.py +++ b/ipapython/sysrestore.py @@ -32,6 +32,7 @@ import random import string from ipapython import ipautil +from ipapython import services as ipaservices SYSRESTORE_PATH = "/tmp" SYSRESTORE_INDEXFILE = "sysrestore.index" @@ -165,7 +166,7 @@ class FileStore: os.chown(path, int(uid), int(gid)) os.chmod(path, int(mode)) - ipautil.run(["/sbin/restorecon", path]) + ipaservices.restore_context(path) del self.files[filename] self.save() @@ -196,7 +197,7 @@ class FileStore: os.chown(path, int(uid), int(gid)) os.chmod(path, int(mode)) - ipautil.run(["/sbin/restorecon", path]) + ipaservices.restore_context(path) #force file to be deleted self.files = {} |