#508 drop mod_python support
Merged 4 years ago by mikem. Opened 4 years ago by tkopecek.
tkopecek/koji issue466  into  master

@@ -583,10 +583,6 @@ 

  Koji Hub

  ========

  

- .. note::

-     Koji 1.7 and greater uses mod_wsgi.  Any mod_python configurations will

-     need to be migrated.

- 

  Koji-hub is the center of all Koji operations. It is an XML-RPC server running

  under mod_wsgi in the Apache httpd. koji-hub is passive in that it only

  receives XML-RPC calls and relies upon the build daemons and other components
@@ -833,10 +829,6 @@ 

  Koji Web - Interface for the Masses

  ===================================

  

- .. note::

-     Koji 1.7 and greater uses mod_wsgi.  Any mod_python configurations will

-     need to be migrated.

- 

  Koji-web is a set of scripts that run in mod_wsgi and use the Cheetah

  templating engine to provide an web interface to Koji. koji-web exposes a lot

  of information and also provides a means for certain operations, such as
@@ -874,11 +866,6 @@ 

  it based on your authentication type. Instructions are contained within the

  file and should be simple to follow.

  

- .. note::

-     RHEL 5's mod_python publisher does not support non-basic auth, so Kerberos

-     authentication does not currently work in EPEL 5's Koji-web. See

-     `BZ #682319 <https://bugzilla.redhat.com/682319>`_.

- 

  /etc/httpd/conf.d/ssl.conf

  ^^^^^^^^^^^^^^^^^^^^^^^^^^

  

file modified
-11
@@ -19,17 +19,6 @@ 

      </IfVersion>

  </Directory>

  

- # Support for mod_python is DEPRECATED. If you still need mod_python support,

- # then use the following directory settings instead:

- #

- # <Directory "/usr/share/koji-hub">

- #         SetHandler mod_python

- #         PythonHandler kojixmlrpc

- #         PythonOption ConfigFile /etc/koji-hub/hub.conf

- #         PythonDebug Off

- #         PythonAutoReload Off

- # </Directory>

- 

  # Also serve /mnt/koji

  Alias /kojifiles "/mnt/koji/"

  

file modified
+12 -46
@@ -31,7 +31,6 @@ 

  import resource

  import xmlrpclib

  from xmlrpclib import getparser, dumps, Fault

- from koji.server import WSGIWrapper

  

  import koji

  import koji.auth
@@ -203,7 +202,7 @@ 

  

  

  class ModXMLRPCRequestHandler(object):

-     """Simple XML-RPC handler for mod_python environment"""

+     """Simple XML-RPC handler for mod_wsgi environment"""

  

      def __init__(self, handlers):

          self.traceback = False
@@ -394,21 +393,8 @@ 

      """

      logger = logging.getLogger("koji")

      #get our config file(s)

-     if 'modpy.opts' in environ:

-         modpy_opts = environ.get('modpy.opts')

-         cf = modpy_opts.get('ConfigFile', None)

-         # to aid in the transition from PythonOptions to hub.conf, we only load

-         # the configfile if it is explicitly configured

-         if cf == '/etc/koji-hub/hub.conf':

-             cfdir = modpy_opts.get('ConfigDir', '/etc/koji-hub/hub.conf.d')

-         else:

-             cfdir = modpy_opts.get('ConfigDir', None)

-         if not cf and not cfdir:

-             logger.warn('Warning: configuring Koji via PythonOptions is deprecated. Use hub.conf')

-     else:

-         cf = environ.get('koji.hub.ConfigFile', '/etc/koji-hub/hub.conf')

-         cfdir = environ.get('koji.hub.ConfigDir', '/etc/koji-hub/hub.conf.d')

-         modpy_opts = {}

+     cf = environ.get('koji.hub.ConfigFile', '/etc/koji-hub/hub.conf')

+     cfdir = environ.get('koji.hub.ConfigDir', '/etc/koji-hub/hub.conf.d')

      if cfdir:

          configs = koji.config_directory_contents(cfdir)

      else:
@@ -482,27 +468,16 @@ 

      ]

      opts = {}

      for name, dtype, default in cfgmap:

-         if config:

-             key = ('hub', name)

-             if config.has_option(*key):

-                 if dtype == 'integer':

-                     opts[name] = config.getint(*key)

-                 elif dtype == 'boolean':

-                     opts[name] = config.getboolean(*key)

-                 else:

-                     opts[name] = config.get(*key)

-             else:

-                 opts[name] = default

-         else:

-             if modpy_opts.get(name, None) is not None:

-                 if dtype == 'integer':

-                     opts[name] = int(modpy_opts.get(name))

-                 elif dtype == 'boolean':

-                     opts[name] = modpy_opts.get(name).lower() in ('yes', 'on', 'true', '1')

-                 else:

-                     opts[name] = modpy_opts.get(name)

+         key = ('hub', name)

+         if config and config.has_option(*key):

+             if dtype == 'integer':

+                 opts[name] = config.getint(*key)

+             elif dtype == 'boolean':

+                 opts[name] = config.getboolean(*key)

              else:

-                 opts[name] = default

+                 opts[name] = config.get(*key)

+             continue

+         opts[name] = default

      if opts['DBHost'] is None:

          opts['DBHost'] = opts['DBhost']

      # load policies
@@ -679,15 +654,6 @@ 

      import kojihub

  

  

- #

- # mod_python handler

- #

- 

- def handler(req):

-     wrapper = WSGIWrapper(req)

-     return wrapper.run(application)

- 

- 

  def get_memory_usage():

      pagesize = resource.getpagesize()

      statm = [pagesize*int(y)/1024 for y in "".join(open("/proc/self/statm").readlines()).strip().split()]

file modified
-1
@@ -81,7 +81,6 @@ 

  - streamlined cli options

  - marker files for many things on disk

  - more history data

- - drop modpython support

  - policy code

    - more robust syntax

      - test negation

file modified
-162
@@ -19,170 +19,8 @@ 

  # Authors:

  #       Mike McLean <mikem@redhat.com>

  

- import sys

- import traceback

- from koji.util import LazyDict

- 

- try:

-     from mod_python import apache

- except ImportError:  # pragma: no cover

-     apache = None

- 

- 

  class ServerError(Exception):

      """Base class for our server-side-only exceptions"""

  

  class ServerRedirect(ServerError):

      """Used to handle redirects"""

- 

- 

- class WSGIWrapper(object):

-     """A very thin wsgi compat layer for mod_python

- 

-     This class is highly specific to koji and is not fit for general use.

-     It does not support the full wsgi spec

-     """

- 

-     def __init__(self, req):

-         self.req = req

-         self._env = None

-         host, port = req.connection.remote_addr

-         environ = {

-             'REMOTE_ADDR': req.connection.remote_ip,

-             # or remote_addr[0]?

-             # or req.get_remote_host(apache.REMOTE_NOLOOKUP)?

-             'REMOTE_PORT': str(req.connection.remote_addr[1]),

-             'REMOTE_USER': req.user,

-             'REQUEST_METHOD': req.method,

-             'REQUEST_URI': req.uri,

-             'PATH_INFO': req.path_info,

-             'SCRIPT_FILENAME': req.filename,

-             'QUERY_STRING': req.args or '',

-             'SERVER_NAME': req.hostname,

-             'SERVER_PORT': str(req.connection.local_addr[1]),

-             'wsgi.version': (1, 0),

-             'wsgi.input': InputWrapper(req),

-             'wsgi.errors': sys.stderr,

-             #TODO - file_wrapper support

-         }

-         environ = LazyDict(environ)

-         environ.lazyset('wsgi.url_scheme', self.get_scheme, [])

-         environ.lazyset('modpy.env', self.env, [])

-         environ.lazyset('modpy.opts', req.get_options, [])

-         environ.lazyset('modpy.conf', req.get_config, [])

-         environ.lazyset('SCRIPT_NAME', self.script_name, [], cache=True)

-         env_keys = ['SSL_CLIENT_VERIFY', 'HTTPS', 'SSL_CLIENT_S_DN']

-         for key in env_keys:

-             environ.lazyset(key, self.envget, [key])

-         # The component of the DN used for the username is usually the CN,

-         # but it is configurable.

-         # Allow retrieval of some common DN components from the environment.

-         for comp in ['C', 'ST', 'L', 'O', 'OU', 'CN', 'Email']:

-             key = 'SSL_CLIENT_S_DN_' + comp

-             environ.lazyset(key, self.envget, [key])

-         #gather the headers we care about

-         for key in req.headers_in:

-             k2 = key.upper()

-             k2 = k2.replace('-', '_')

-             if k2 not in ['CONTENT_TYPE', 'CONTENT_LENGTH']:

-                 k2 = 'HTTP_' + k2

-             environ[k2] = req.headers_in[key]

-         self.environ = environ

-         self.set_headers = False

- 

-     def env(self):

-         if self._env is None:

-             self.req.add_common_vars()

-             self._env = self.req.subprocess_env

-         return self._env

- 

-     def envget(self, *args):

-         return self.env().get(*args)

- 

-     def script_name(self):

-         uri = self.req.uri

-         path_info = self.req.path_info

-         if uri.endswith(path_info):

-             uri = uri[:-len(path_info)]

-             uri = uri.rstrip('/')

-         return uri

- 

-     def get_scheme(self):

-         if self.envget('HTTPS') in ('yes', 'on', '1'):

-             return 'https'

-         else:

-             return 'http'

- 

-     def no_write(self, string):

-         """a fake write() callable returned by start_response

- 

-         we don't use the write() callable in koji, so it will raise an error if called

-         """

-         raise RuntimeError("wsgi write() callable not supported")

- 

-     def start_response(self, status, headers, exc_info=None):

-         #XXX we don't deal with exc_info

-         if self.set_headers:

-             raise RuntimeError("start_response() already called")

-         self.req.status = int(status[:3])

-         for key, val in headers:

-             if key.lower() == 'content-length':

-                 self.req.set_content_length(int(val))

-             elif key.lower() == 'content-type':

-                 self.req.content_type = val

-             else:

-                 self.req.headers_out.add(key, val)

-         self.set_headers = True

-         return self.no_write

- 

-     def run(self, handler):

-         try:

-             result = handler(self.environ, self.start_response)

-             self.write_result(result)

-             return apache.OK

-         except:

-             sys.stderr.write(''.join(traceback.format_exception(*sys.exc_info())))

-             sys.stderr.flush()

-             raise apache.SERVER_RETURN(apache.HTTP_INTERNAL_SERVER_ERROR)

- 

-     def write_result(self, result):

-         """called by run() to handle the application's result value"""

-         req = self.req

-         write = req.write

-         if self.set_headers:

-             for chunk in result:

-                 write(chunk)

-         else:

-             #slower version -- need to check for set_headers

-             for chunk in result:

-                 if chunk and not self.set_headers:

-                     raise RuntimeError("write() called before start_response()")

-                 write(chunk)

-         if not req.bytes_sent:

-             #application sent nothing back

-             req.set_content_length(0)

- 

- 

- 

- class InputWrapper(object):

- 

-     def __init__(self, req):

-         self.req = req

- 

-     def close(self):

-         pass

- 

-     def read(self, size=-1):

-         return self.req.read(size)

- 

-     def readline(self):

-         return self.req.readline()

- 

-     def readlines(self, hint=-1):

-         return self.req.readlines(hint)

- 

-     def __iter__(self):

-         line = self.readline()

-         while line:

-             yield line

-             line = self.readline()

file modified
-16
@@ -17,22 +17,6 @@ 

      </IfVersion>

  </Directory>

  

- # Support for mod_python is DEPRECATED. If you still need mod_python support,

- # then use the following directory settings instead:

- #

- # <Directory "/usr/share/koji-web/scripts/">

- #     # Config for the publisher handler

- #     SetHandler mod_python

- #     # Use kojiweb's publisher (provides wsgi compat layer)

- #     # mod_python's publisher is no longer supported

- #     PythonHandler wsgi_publisher

- #     PythonOption koji.web.ConfigFile /etc/kojiweb/web.conf

- #     PythonAutoReload Off

- #     # Configuration via PythonOptions is DEPRECATED. Use /etc/kojiweb/web.conf

- #     Order allow,deny

- #     Allow from all

- # </Directory>

- 

  # uncomment this to enable authentication via Kerberos

  # <Location /koji/login>

  #     AuthType Kerberos

file modified
+14 -46
@@ -30,7 +30,7 @@ 

  import traceback

  

  from ConfigParser import RawConfigParser

- from koji.server import WSGIWrapper, ServerError, ServerRedirect

+ from koji.server import ServerError, ServerRedirect

  from koji.util import dslice

  

  
@@ -122,17 +122,8 @@ 

              - all PythonOptions (except koji.web.ConfigFile) are now deprecated and

                support for them will disappear in a future version of Koji

          """

-         modpy_opts = environ.get('modpy.opts', {})

-         if 'modpy.opts' in environ:

-             cf = modpy_opts.get('koji.web.ConfigFile', None)

-             cfdir =  modpy_opts.get('koji.web.ConfigDir', None)

-             # to aid in the transition from PythonOptions to web.conf, we do

-             # not check the config file by default, it must be configured

-             if not cf and not cfdir:

-                 self.logger.warn('Warning: configuring Koji via PythonOptions is deprecated. Use web.conf')

-         else:

-             cf = environ.get('koji.web.ConfigFile', '/etc/kojiweb/web.conf')

-             cfdir = environ.get('koji.web.ConfigDir', '/etc/kojiweb/web.conf.d')

+         cf = environ.get('koji.web.ConfigFile', '/etc/kojiweb/web.conf')

+         cfdir = environ.get('koji.web.ConfigDir', '/etc/kojiweb/web.conf.d')

          if cfdir:

              configs = koji.config_directory_contents(cfdir)

          else:
@@ -142,40 +133,23 @@ 

          if configs:

              config = RawConfigParser()

              config.read(configs)

-         elif modpy_opts:

-             # presumably we are configured by modpy options

-             config = None

          else:

              raise koji.GenericError("Configuration missing")

  

          opts = {}

          for name, dtype, default in self.cfgmap:

-             if config:

-                 key = ('web', name)

-                 if config.has_option(*key):

-                     if dtype == 'integer':

-                         opts[name] = config.getint(*key)

-                     elif dtype == 'boolean':

-                         opts[name] = config.getboolean(*key)

-                     elif dtype == 'list':

-                         opts[name] = [x.strip() for x in config.get(*key).split(',')]

-                     else:

-                         opts[name] = config.get(*key)

+             key = ('web', name)

+             if config and config.has_option(*key):

+                 if dtype == 'integer':

+                     opts[name] = config.getint(*key)

+                 elif dtype == 'boolean':

+                     opts[name] = config.getboolean(*key)

+                 elif dtype == 'list':

+                     opts[name] = [x.strip() for x in config.get(*key).split(',')]

                  else:

-                     opts[name] = default

+                     opts[name] = config.get(*key)

              else:

-                 if modpy_opts.get(name, None) is not None:

-                     if dtype == 'integer':

-                         opts[name] = int(modpy_opts.get(name))

-                     elif dtype == 'boolean':

-                         opts[name] = modpy_opts.get(name).lower() in ('yes', 'on', 'true', '1')

-                     else:

-                         opts[name] = modpy_opts.get(name)

-                 else:

-                     opts[name] = default

-         if 'modpy.conf' in environ:

-             debug = environ['modpy.conf'].get('PythonDebug', '0').lower()

-             opts['PythonDebug'] = (debug in ['yes', 'on', 'true', '1'])

+                 opts[name] = default

          opts['Secret'] = koji.util.HiddenValue(opts['Secret'])

          self.options = opts

          return opts
@@ -432,11 +406,6 @@ 

              result = [result]

          return result

  

-     def handler(self, req):

-         """mod_python handler"""

-         wrapper = WSGIWrapper(req)

-         return wrapper.run(self.application)

- 

      def application(self, environ, start_response):

          """wsgi handler"""

          if self.formatter:
@@ -483,7 +452,6 @@ 

          return logging.Formatter.format(self, record)

  

  

- # provide necessary global handlers for mod_wsgi and mod_python

+ # provide necessary global handlers for mod_wsgi

  dispatcher = Dispatcher()

- handler = dispatcher.handler

  application = dispatcher.application