from __future__ import print_function, division, absolute_import import os import sys import shutil import subprocess import optparse import math import signal import threading import atexit import imp import pwd import grp try: import Queue as queue except ImportError: import queue from . import apxs_config _py_version = '%s%s' % sys.version_info[:2] _py_soabi = '' _py_soext = '.so' try: import imp import sysconfig _py_soabi = sysconfig.get_config_var('SOABI') _py_soext = sysconfig.get_config_var('SO') except ImportError: pass MOD_WSGI_SO = 'mod_wsgi-py%s%s' % (_py_version, _py_soext) MOD_WSGI_SO = os.path.join(os.path.dirname(__file__), MOD_WSGI_SO) if not os.path.exists(MOD_WSGI_SO) and _py_soabi: MOD_WSGI_SO = 'mod_wsgi-py%s.%s%s' % (_py_version, _py_soabi, _py_soext) MOD_WSGI_SO = os.path.join(os.path.dirname(__file__), MOD_WSGI_SO) def where(): return MOD_WSGI_SO def default_run_user(): return pwd.getpwuid(os.getuid()).pw_name def default_run_group(): return grp.getgrgid(pwd.getpwuid(os.getuid()).pw_gid).gr_name def find_program(names, default=None, paths=[]): for name in names: for path in os.environ['PATH'].split(':') + paths: program = os.path.join(path, name) if os.path.exists(program): return program return default def find_mimetypes(): import mimetypes for name in mimetypes.knownfiles: if os.path.exists(name): return name break else: return name APACHE_GENERAL_CONFIG = """ LoadModule version_module '%(modules_directory)s/mod_version.so' ServerName %(host)s ServerRoot '%(server_root)s' PidFile '%(pid_file)s' = 2.4> DefaultRuntimeDir '%(server_root)s' ServerSignature Off User ${WSGI_RUN_USER} Group ${WSGI_RUN_GROUP} Listen %(host)s:%(port)s Listen %(port)s LockFile '%(server_root)s/accept.lock' = 2.4> LoadModule mpm_prefork_module '%(modules_directory)s/mod_mpm_prefork.so' = 2.4> LoadModule mpm_event_module '%(modules_directory)s/mod_mpm_event.so' LoadModule mpm_worker_module '%(modules_directory)s/mod_mpm_worker.so' LoadModule mpm_prefork_module '%(modules_directory)s/mod_mpm_prefork.so' = 2.4> LoadModule access_compat_module '%(modules_directory)s/mod_access_compat.so' LoadModule unixd_module '%(modules_directory)s/mod_unixd.so' LoadModule authn_core_module '%(modules_directory)s/mod_authn_core.so' LoadModule authz_core_module '%(modules_directory)s/mod_authz_core.so' LoadModule authz_host_module '%(modules_directory)s/mod_authz_host.so' LoadModule mime_module '%(modules_directory)s/mod_mime.so' LoadModule rewrite_module '%(modules_directory)s/mod_rewrite.so' LoadModule alias_module '%(modules_directory)s/mod_alias.so' LoadModule dir_module '%(modules_directory)s/mod_dir.so' LoadModule env_module '%(modules_directory)s/mod_env.so' LoadModule deflate_module '%(modules_directory)s/mod_deflate.so' LoadModule auth_basic_module '%(modules_directory)s/mod_auth_basic.so' LoadModule auth_digest_module '%(modules_directory)s/mod_auth_digest.so' LoadModule authz_user_module '%(modules_directory)s/mod_authz_user.so' Loadmodule php5_module '%(modules_directory)s/libphp5.so' AddHandler application/x-httpd-php .php LoadModule wsgi_module '%(mod_wsgi_so)s' LoadModule status_module '%(modules_directory)s/mod_status.so' DefaultType text/plain TypesConfig '%(mime_types)s' HostnameLookups Off MaxMemFree 64 Timeout %(socket_timeout)s ListenBacklog %(server_backlog)s LimitRequestBody %(limit_request_body)s AllowOverride None Order deny,allow Deny from all WSGIPythonHome '%(python_home)s' WSGIRestrictEmbedded On WSGISocketPrefix %(server_root)s/wsgi WSGIDaemonProcess %(host)s:%(port)s \\ display-name='%(process_name)s' \\ home='%(working_directory)s' \\ processes=%(processes)s \\ threads=%(threads)s \\ maximum-requests=%(maximum_requests)s \\ python-eggs='%(python_eggs)s' \\ lang='%(lang)s' \\ locale='%(locale)s' \\ listen-backlog=%(daemon_backlog)s \\ queue-timeout=%(queue_timeout)s \\ socket-timeout=%(socket_timeout)s \\ connect-timeout=%(connect_timeout)s \\ request-timeout=%(request_timeout)s \\ inactivity-timeout=%(inactivity_timeout)s \\ deadlock-timeout=%(deadlock_timeout)s \\ graceful-timeout=%(graceful_timeout)s \\ shutdown-timeout=%(shutdown_timeout)s \\ send-buffer-size=%(send_buffer_size)s \\ receive-buffer-size=%(receive_buffer_size)s \\ header-buffer-size=%(header_buffer_size)s \\ server-metrics=%(daemon_server_metrics_flag)s WSGIDaemonProcess %(host)s:%(port)s \\ display-name='%(process_name)s' \\ home='%(working_directory)s' \\ threads=%(threads)s \\ maximum-requests=%(maximum_requests)s \\ python-eggs='%(python_eggs)s' \\ lang='%(lang)s' \\ locale='%(locale)s' \\ listen-backlog=%(daemon_backlog)s \\ queue-timeout=%(queue_timeout)s \\ socket-timeout=%(socket_timeout)s \\ connect-timeout=%(connect_timeout)s \\ request-timeout=%(request_timeout)s \\ inactivity-timeout=%(inactivity_timeout)s \\ deadlock-timeout=%(deadlock_timeout)s \\ graceful-timeout=%(graceful_timeout)s \\ shutdown-timeout=%(shutdown_timeout)s \\ send-buffer-size=%(send_buffer_size)s \\ receive-buffer-size=%(receive_buffer_size)s \\ header-buffer-size=%(header_buffer_size)s \\ server-metrics=%(daemon_server_metrics_flag)s WSGICallableObject '%(callable_object)s' WSGIPassAuthorization On WSGIMapHEADToGET %(map_head_to_get)s WSGIRestrictStdin Off ExtendedStatus On SetHandler server-status Order deny,allow Deny from all Allow from localhost KeepAlive On KeepAliveTimeout %(keep_alive_timeout)s KeepAlive Off AddOutputFilterByType DEFLATE text/plain AddOutputFilterByType DEFLATE text/html AddOutputFilterByType DEFLATE text/xml AddOutputFilterByType DEFLATE text/css AddOutputFilterByType DEFLATE text/javascript AddOutputFilterByType DEFLATE application/xhtml+xml AddOutputFilterByType DEFLATE application/javascript ErrorLog "|%(rotatelogs_executable)s \\ %(error_log)s.%%Y-%%m-%%d-%%H_%%M_%%S %(max_log_size)sM" ErrorLog '%(error_log)s' LogLevel %(log_level)s LoadModule log_config_module %(modules_directory)s/mod_log_config.so LogFormat "%%h %%l %%u %%t \\"%%r\\" %%>s %%b" common CustomLog "|%(rotatelogs_executable)s \\ %(log_directory)s/access_log.%%Y-%%m-%%d-%%H_%%M_%%S %(max_log_size)sM" common CustomLog "%(log_directory)s/access_log" common LoadModule ssl_module %(modules_directory)s/mod_ssl.so ServerLimit %(prefork_server_limit)s StartServers %(prefork_start_servers)s MaxClients %(prefork_max_clients)s MinSpareServers %(prefork_min_spare_servers)s MaxSpareServers %(prefork_max_spare_servers)s ServerLimit 1 StartServers 1 MaxClients 1 MinSpareServers 1 MaxSpareServers 1 MaxRequestsPerChild 0 ServerLimit %(worker_server_limit)s ThreadLimit %(worker_thread_limit)s StartServers %(worker_start_servers)s MaxClients %(worker_max_clients)s MinSpareThreads %(worker_min_spare_threads)s MaxSpareThreads %(worker_max_spare_threads)s ThreadsPerChild %(worker_threads_per_child)s ServerLimit 1 ThreadLimit 1 StartServers 1 MaxClients 1 MinSpareThreads 1 MaxSpareThreads 1 ThreadsPerChild 1 MaxRequestsPerChild 0 ThreadStackSize 262144 ServerLimit %(worker_server_limit)s ThreadLimit %(worker_thread_limit)s StartServers %(worker_start_servers)s MaxClients %(worker_max_clients)s MinSpareThreads %(worker_min_spare_threads)s MaxSpareThreads %(worker_max_spare_threads)s ThreadsPerChild %(worker_threads_per_child)s ServerLimit 1 ThreadLimit 1 StartServers 1 MaxClients 1 MinSpareThreads 1 MaxSpareThreads 1 ThreadsPerChild 1 MaxRequestsPerChild 0 ThreadStackSize 262144 NameVirtualHost *:%(port)s Order deny,allow Deny from all Allow from localhost ServerName %(server_name)s ServerAlias %(server_aliases)s ServerName %(parent_domain)s Redirect permanent / http://%(server_name)s:%(port)s/ ServerName %(server_name)s ServerAlias %(server_aliases)s RewriteEngine On RewriteCond %%{HTTPS} off RewriteRule (.*) https://%%{HTTP_HOST}%%{REQUEST_URI} ServerName %(parent_domain)s RewriteEngine On RewriteCond %%{HTTPS} off RewriteRule (.*) https://%%{HTTP_HOST}%%{REQUEST_URI} Listen %(host)s:%(ssl_port)s Listen %(ssl_port)s NameVirtualHost *:%(ssl_port)s Order deny,allow Deny from all Allow from localhost SSLEngine On SSLCertificateFile %(ssl_certificate)s.crt SSLCertificateKeyFile %(ssl_certificate)s.key ServerName %(server_name)s ServerAlias %(server_aliases)s SSLEngine On SSLCertificateFile %(ssl_certificate)s.crt SSLCertificateKeyFile %(ssl_certificate)s.key ServerName %(parent_domain)s Redirect permanent / https://%(server_name)s:%(ssl_port)s/ SSLEngine On SSLCertificateFile %(ssl_certificate)s.crt SSLCertificateKeyFile %(ssl_certificate)s.key DocumentRoot '%(document_root)s' Order allow,deny Allow from all DirectoryIndex %(directory_index)s RewriteEngine On RewriteCond %%{REQUEST_FILENAME} !-f RewriteCond %%{REQUEST_FILENAME} !-d RewriteCond %%{REQUEST_URI} !/server-status RewriteRule .* - [H=wsgi-handler] Order allow,deny Allow from all WSGIErrorOverride On AuthType %(auth_type)s AuthName '%(host)s:%(port)s' Auth%(auth_type)sProvider wsgi WSGIAuthUserScript '%(auth_user_script)s' WSGIAuthGroupScript '%(auth_group_script)s' Require valid-user Require wsgi-group '%(auth_group)s' = 2.4> Require valid-user Require wsgi-group '%(auth_group)s' WSGIHandlerScript wsgi-handler '%(server_root)s/handler.wsgi' \\ process-group='%(host)s:%(port)s' application-group=%%{GLOBAL} WSGIImportScript '%(server_root)s/handler.wsgi' \\ process-group='%(host)s:%(port)s' application-group=%%{GLOBAL} WSGIHandlerScript wsgi-handler '%(server_root)s/handler.wsgi' \\ process-group='%%{GLOBAL}' application-group=%%{GLOBAL} WSGIImportScript '%(server_root)s/handler.wsgi' \\ process-group='%%{GLOBAL}' application-group=%%{GLOBAL} """ APACHE_ALIAS_DIRECTORY_CONFIG = """ Alias '%(mount_point)s' '%(directory)s' Order allow,deny Allow from all """ APACHE_ALIAS_FILENAME_CONFIG = """ Alias '%(mount_point)s' '%(directory)s/%(filename)s' Order allow,deny Allow from all """ APACHE_ALIAS_DOCUMENTATION = """ Alias /__wsgi__/docs '%(documentation_directory)s' Alias /__wsgi__/images '%(images_directory)s' DirectoryIndex index.html Order allow,deny Allow from all Order allow,deny Allow from all """ APACHE_ERROR_DOCUMENT_CONFIG = """ ErrorDocument '%(status)s' '%(document)s' """ APACHE_SETENV_CONFIG = """ SetEnv '%(name)s' '%(value)s' """ APACHE_PASSENV_CONFIG = """ PassEnv '%(name)s' """ APACHE_INCLUDE_CONFIG = """ Include '%(filename)s' """ APACHE_TOOLS_CONFIG = """ WSGIDaemonProcess express display-name=%%{GROUP} threads=1 server-metrics=On """ APACHE_METRICS_CONFIG = """ WSGIImportScript '%(server_root)s/server-metrics.py' \\ process-group=express application-group=server-metrics """ APACHE_WDB_CONFIG = """ WSGIImportScript '%(server_root)s/wdb-server.py' \\ process-group=express application-group=wdb-server """ def generate_apache_config(options): with open(options['httpd_conf'], 'w') as fp: print(APACHE_GENERAL_CONFIG % options, file=fp) if options['url_aliases']: for mount_point, target in sorted(options['url_aliases'], reverse=True): target = os.path.abspath(target) if os.path.isdir(target): directory = target print(APACHE_ALIAS_DIRECTORY_CONFIG % dict( mount_point=mount_point, directory=directory), file=fp) else: directory = os.path.dirname(target) filename = os.path.basename(target) print(APACHE_ALIAS_FILENAME_CONFIG % dict( mount_point=mount_point, directory=directory, filename=filename), file=fp) if options['enable_docs']: print(APACHE_ALIAS_DOCUMENTATION % options, file=fp) if options['error_documents']: for status, document in options['error_documents']: print(APACHE_ERROR_DOCUMENT_CONFIG % dict(status=status, document=document.replace("'", "\\'")), file=fp) if options['setenv_variables']: for name, value in options['setenv_variables']: print(APACHE_SETENV_CONFIG % dict(name=name, value=value), file=fp) if options['passenv_variables']: for name in options['passenv_variables']: print(APACHE_PASSENV_CONFIG % dict(name=name), file=fp) if options['include_files']: for filename in options['include_files']: filename = os.path.abspath(filename) print(APACHE_INCLUDE_CONFIG % dict(filename=filename), file=fp) if options['with_newrelic_platform'] or options['with_wdb']: print(APACHE_TOOLS_CONFIG % options, file=fp) if options['with_newrelic_platform']: print(APACHE_METRICS_CONFIG % options, file=fp) if options['with_wdb']: print(APACHE_WDB_CONFIG % options, file=fp) _interval = 1.0 _times = {} _files = [] _running = False _queue = queue.Queue() _lock = threading.Lock() def _restart(path): _queue.put(True) prefix = 'monitor (pid=%d):' % os.getpid() print('%s Change detected to "%s".' % (prefix, path), file=sys.stderr) print('%s Triggering process restart.' % prefix, file=sys.stderr) os.kill(os.getpid(), signal.SIGINT) def _modified(path): try: # If path doesn't denote a file and were previously # tracking it, then it has been removed or the file type # has changed so force a restart. If not previously # tracking the file then we can ignore it as probably # pseudo reference such as when file extracted from a # collection of modules contained in a zip file. if not os.path.isfile(path): return path in _times # Check for when file last modified. mtime = os.stat(path).st_mtime if path not in _times: _times[path] = mtime # Force restart when modification time has changed, even # if time now older, as that could indicate older file # has been restored. if mtime != _times[path]: return True except Exception: # If any exception occured, likely that file has been # been removed just before stat(), so force a restart. return True return False def _monitor(): global _files while True: # Check modification times on all files in sys.modules. for module in list(sys.modules.values()): if not hasattr(module, '__file__'): continue path = getattr(module, '__file__') if not path: continue if os.path.splitext(path)[1] in ['.pyc', '.pyo', '.pyd']: path = path[:-1] if _modified(path): return _restart(path) # Check modification times on files which have # specifically been registered for monitoring. for path in _files: if _modified(path): return _restart(path) # Go to sleep for specified interval. try: return _queue.get(timeout=_interval) except queue.Empty: pass _thread = threading.Thread(target=_monitor) _thread.setDaemon(True) def _exiting(): try: _queue.put(True) except Exception: pass _thread.join() def track_changes(path): if not path in _files: _files.append(path) def start_reloader(interval=1.0): global _interval if interval < _interval: _interval = interval global _running _lock.acquire() if not _running: prefix = 'monitor (pid=%d):' % os.getpid() print('%s Starting change monitor.' % prefix, file=sys.stderr) _running = True _thread.start() atexit.register(_exiting) _lock.release() class ApplicationHandler(object): def __init__(self, entry_point, application_type='script', callable_object='application', mount_point='/', with_newrelic=False, with_wdb=False, debug_mode=False): self.entry_point = entry_point self.application_type = application_type self.callable_object = callable_object self.mount_point = mount_point if application_type == 'module': __import__(entry_point) self.module = sys.modules[entry_point] self.application = getattr(self.module, callable_object) self.target = self.module.__file__ parts = os.path.splitext(self.target)[-1] if parts[-1].lower() in ('.pyc', '.pyd', '.pyd'): self.target = parts[0] + '.py' elif application_type == 'paste': from paste.deploy import loadapp self.application = loadapp('config:%s' % entry_point) self.target = entry_point else: self.module = imp.new_module('__wsgi__') self.module.__file__ = entry_point with open(entry_point, 'r') as fp: code = compile(fp.read(), entry_point, 'exec', dont_inherit=True) exec(code, self.module.__dict__) sys.modules['__wsgi__'] = self.module self.application = getattr(self.module, callable_object) self.target = entry_point try: self.mtime = os.path.getmtime(self.target) except Exception: self.mtime = None if with_newrelic: self.setup_newrelic() if with_wdb: self.setup_wdb() self.debug_mode = debug_mode def setup_newrelic(self): import newrelic.agent config_file = os.environ.get('NEW_RELIC_CONFIG_FILE') environment = os.environ.get('NEW_RELIC_ENVIRONMENT') global_settings = newrelic.agent.global_settings() if global_settings.log_file is None: global_settings.log_file = 'stderr' newrelic.agent.initialize(config_file, environment) newrelic.agent.register_application() self.application = newrelic.agent.WSGIApplicationWrapper( self.application) def setup_wdb(self): from wdb.ext import WdbMiddleware self.application = WdbMiddleware(self.application) def reload_required(self, environ): if self.debug_mode: return False try: mtime = os.path.getmtime(self.target) except Exception: mtime = None return mtime != self.mtime def handle_request(self, environ, start_response): # Strip out the leading component due to internal redirect in # Apache when using web application as fallback resource. script_name = environ.get('SCRIPT_NAME') path_info = environ.get('PATH_INFO') environ['SCRIPT_NAME'] = '' environ['PATH_INFO'] = script_name + path_info if self.mount_point != '/': if environ['PATH_INFO'].startswith(self.mount_point): environ['SCRIPT_NAME'] = self.mount_point environ['PATH_INFO'] = environ['PATH_INFO'][len(self.mount_point):] return self.application(environ, start_response) def __call__(self, environ, start_response): return self.handle_request(environ, start_response) WSGI_HANDLER_SCRIPT = """ import mod_wsgi.server entry_point = '%(entry_point)s' application_type = '%(application_type)s' callable_object = '%(callable_object)s' mount_point = '%(mount_point)s' with_newrelic = %(with_newrelic_agent)s with_wdb = %(with_wdb)s reload_on_changes = %(reload_on_changes)s debug_mode = %(debug_mode)s handler = mod_wsgi.server.ApplicationHandler(entry_point, application_type=application_type, callable_object=callable_object, mount_point=mount_point, with_newrelic=with_newrelic, with_wdb=with_wdb, debug_mode=debug_mode) reload_required = handler.reload_required handle_request = handler.handle_request if reload_on_changes and not debug_mode: mod_wsgi.server.start_reloader() """ WSGI_DEFAULT_SCRIPT = """ CONTENT = b''' My web site runs on Malt Whiskey
My web site
runs on
Malt Whiskey

For further information on configuring mod_wsgi,
see the documentation.
''' def application(environ, start_response): status = '200 OK' output = CONTENT response_headers = [('Content-type', 'text/html'), ('Content-Length', str(len(output)))] start_response(status, response_headers) return [output] """ def generate_wsgi_handler_script(options): path = os.path.join(options['server_root'], 'handler.wsgi') with open(path, 'w') as fp: print(WSGI_HANDLER_SCRIPT % options, file=fp) path = os.path.join(options['server_root'], 'default.wsgi') with open(path, 'w') as fp: print(WSGI_DEFAULT_SCRIPT % options, file=fp) SERVER_METRICS_SCRIPT = """ import logging logging.basicConfig(level=logging.INFO, format='%%(name)s (pid=%%(process)d, level=%%(levelname)s): %%(message)s') _logger = logging.getLogger(__name__) try: from mod_wsgi.metrics.newrelic import Agent agent = Agent() agent.start() except ImportError: _logger.fatal('The module mod_wsgi.metrics.newrelic is not available. ' 'The New Relic platform plugin has been disabled. Install the ' '"mod_wsgi-metrics" package.') """ def generate_server_metrics_script(options): path = os.path.join(options['server_root'], 'server-metrics.py') with open(path, 'w') as fp: print(SERVER_METRICS_SCRIPT % options, file=fp) WDB_SERVER_SCRIPT = """ from wdb_server import server try: from wdb_server.sockets import handle_connection except ImportError: from wdb_server.streams import handle_connection from tornado.ioloop import IOLoop from tornado.options import options from tornado.netutil import bind_sockets, add_accept_handler from threading import Thread def run_server(): ioloop = IOLoop.instance() sockets = bind_sockets(options.socket_port) for socket in sockets: add_accept_handler(socket, handle_connection, ioloop) server.listen(options.server_port) ioloop.start() thread = Thread(target=run_server) thread.setDaemon(True) thread.start() """ def generate_wdb_server_script(options): path = os.path.join(options['server_root'], 'wdb-server.py') with open(path, 'w') as fp: print(WDB_SERVER_SCRIPT, file=fp) WSGI_CONTROL_SCRIPT = """ #!/bin/sh # %(sys_argv)s HTTPD="%(httpd_executable)s %(httpd_arguments)s" WSGI_RUN_USER="${WSGI_RUN_USER:-%(user)s}" WSGI_RUN_GROUP="${WSGI_RUN_GROUP:-%(group)s}" export WSGI_RUN_USER export WSGI_RUN_GROUP LANG='%(lang)s' LC_ALL='%(locale)s' export LANG export LOCALE ACMD="$1" ARGV="$@" if test -f %(server_root)s/envvars; then . %(server_root)s/envvars fi STATUSURL="http://%(host)s:%(port)s/server-status" if [ "x$ARGV" = "x" ] ; then ARGV="-h" fi case $ACMD in start|stop|restart|graceful|graceful-stop) exec $HTTPD -k $ARGV ;; configtest) exec $HTTPD -t ;; status) exec %(python_executable)s -m webbrowser -t $STATUSURL ;; *) exec $HTTPD $ARGV esac """ APACHE_ENVVARS_FILE = """ . %(envvars_script)s """ def generate_control_scripts(options): path = os.path.join(options['server_root'], 'apachectl') with open(path, 'w') as fp: print(WSGI_CONTROL_SCRIPT.lstrip() % options, file=fp) os.chmod(path, 0o755) path = os.path.join(options['server_root'], 'envvars') if options['envvars_script']: with open(path, 'w') as fp: if options['envvars_script']: print(APACHE_ENVVARS_FILE.lstrip() % options, file=fp) elif not os.path.isfile(path): with open(path, 'w') as fp: pass def check_percentage(option, opt_str, value, parser): if value is not None and value < 0 or value > 1: raise optparse.OptionValueError('%s option value needs to be within ' 'the range 0 to 1.' % opt_str) setattr(parser.values, option.dest, value) option_list = ( optparse.make_option('--application-type', default='script', metavar='TYPE', help='The type of WSGI application entry point ' 'that was provided. Defaults to \'script\', indicating the ' 'traditional mod_wsgi style WSGI script file specified by a ' 'filesystem path. Alternatively one can supply \'module\', ' 'indicating that the provided entry point is a Python module ' 'which should be imported using the standard Python import ' 'mechanism, or \'paste\' indicating that the provided entry ' 'point is a Paste deployment configuration file.'), optparse.make_option('--host', default=None, metavar='IP-ADDRESS', help='The specific host (IP address) interface on which ' 'requests are to be accepted. Defaults to listening on ' 'all host interfaces.'), optparse.make_option('--port', default=8000, type='int', metavar='NUMBER', help='The specific port to bind to and ' 'on which requests are to be accepted. Defaults to port 8000.'), optparse.make_option('--ssl-port', type='int', metavar='NUMBER', help='The specific port to bind to and on which requests are ' 'to be accepted for SSL connections.'), optparse.make_option('--ssl-certificate', default=None, metavar='FILE-PATH', help='Specify the path to the SSL ' 'certificate files. It is expected that the files have \'.crt\' ' 'and \'.key\' extensions. This option should refer to the ' 'common part of the names for both files which appears before ' 'the extension.'), optparse.make_option('--https-only', action='store_true', default=False, help='Flag indicating whether any requests ' 'made using a HTTP request over the non SSL connection should ' 'be redirected automatically to use a HTTPS request over the ' 'SSL connection.'), optparse.make_option('--server-name', default=None, metavar='HOSTNAME', help='The primary host name of the web server. If this name ' 'starts with \'www.\' then an automatic redirection from the ' 'parent domain name to the \'www.\' server name will created.'), optparse.make_option('--server-alias', action='append', dest='server_aliases', metavar='HOSTNAME', help='A secondary ' 'host name for the web server. May include wilcard patterns.'), optparse.make_option('--allow-localhost', action='store_true', default=False, help='Flag indicating whether access via ' 'localhost should still be allowed when a server name has been ' 'specified and a name based virtual host has been configured.'), optparse.make_option('--processes', type='int', metavar='NUMBER', help='The number of worker processes (instances of the WSGI ' 'application) to be started up and which will handle requests ' 'concurrently. Defaults to a single process.'), optparse.make_option('--threads', type='int', default=5, metavar='NUMBER', help='The number of threads in the request thread pool of ' 'each process for handling requests. Defaults to 5 in each ' 'process.'), optparse.make_option('--max-clients', type='int', default=None, metavar='NUMBER', help='The maximum number of simultaneous ' 'client connections that will be accepted. This will default ' 'to being 1.5 times the total number of threads in the ' 'request thread pools across all process handling requests.'), optparse.make_option('--initial-workers', type='float', default=None, metavar='NUMBER', action='callback', callback=check_percentage, help='The initial number of workers to create on startup ' 'expressed as a percentage of the maximum number of clients. ' 'The value provided should be between 0 and 1. The default is ' 'dependent on the type of MPM being used.'), optparse.make_option('--minimum-spare-workers', type='float', default=None, metavar='NUMBER', action='callback', callback=check_percentage, help='The minimum number of spare ' 'workers to maintain expressed as a percentage of the maximum ' 'number of clients. The value provided should be between 0 and ' '1. The default is dependent on the type of MPM being used.'), optparse.make_option('--maximum-spare-workers', type='float', default=None, metavar='NUMBER', action='callback', callback=check_percentage, help='The maximum number of spare ' 'workers to maintain expressed as a percentage of the maximum ' 'number of clients. The value provided should be between 0 and ' '1. The default is dependent on the type of MPM being used.'), optparse.make_option('--limit-request-body', type='int', default=10485760, metavar='NUMBER', help='The maximum number of bytes which are ' 'allowed in a request body. Defaults to 10485760 (10MB).'), optparse.make_option('--maximum-requests', type='int', default=0, metavar='NUMBER', help='The number of requests after which ' 'any one worker process will be restarted and the WSGI ' 'application reloaded. Defaults to 0, indicating that the ' 'worker process should never be restarted based on the number ' 'of requests received.'), optparse.make_option('--shutdown-timeout', type='int', default=5, metavar='SECONDS', help='Maximum number of seconds allowed ' 'to pass when waiting for a worker process to shutdown as a ' 'result of the maximum number of requests or inactivity timeout ' 'being reached, or when a user initiated SIGINT signal is sent ' 'to a worker process. When this timeout has been reached the ' 'worker process will be forced to exit even if there are ' 'still active requests or it is still running Python exit ' 'functions. Defaults to 5 seconds.'), optparse.make_option('--graceful-timeout', type='int', default=15, metavar='SECONDS', help='Grace period for requests to complete ' 'normally, without accepting new requests, when worker processes ' 'are being shutdown and restarted due to maximum requests being ' 'reached or due to graceful restart signal. Defaults to 15 ' 'seconds.'), optparse.make_option('--deadlock-timeout', type='int', default=60, metavar='SECONDS', help='Maximum number of seconds allowed ' 'to pass before the worker process is forcibly shutdown and ' 'restarted after a potential deadlock on the Python GIL has ' 'been detected. Defaults to 60 seconds.'), optparse.make_option('--inactivity-timeout', type='int', default=0, metavar='SECONDS', help='Maximum number of seconds allowed ' 'to pass before the worker process is shutdown and restarted ' 'when the worker process has entered an idle state and is no ' 'longer receiving new requests. Not enabled by default.'), optparse.make_option('--request-timeout', type='int', default=60, metavar='SECONDS', help='Maximum number of seconds allowed ' 'to pass before the worker process is forcibly shutdown and ' 'restarted when a request does not complete in the expected ' 'time. In a multi threaded worker, the request time is ' 'calculated as an average across all request threads. Defaults ' 'to 60 seconds.'), optparse.make_option('--connect-timeout', type='int', default=15, metavar='SECONDS', help='Maximum number of seconds allowed ' 'to pass before giving up on attempting to get a connection ' 'to the worker process from the Apache child process which ' 'accepted the request. This comes into play when the worker ' 'listener backlog limit is exceeded. Defaults to 15 seconds.'), optparse.make_option('--socket-timeout', type='int', default=60, metavar='SECONDS', help='Maximum number of seconds allowed ' 'to pass before timing out on a read or write operation on ' 'a socket and aborting the request. Defaults to 60 seconds.'), optparse.make_option('--queue-timeout', type='int', default=30, metavar='SECONDS', help='Maximum number of seconds allowed ' 'for a request to be accepted by a worker process to be ' 'handled, taken from the time when the Apache child process ' 'originally accepted the request. Defaults to 30 seconds.'), optparse.make_option('--server-backlog', type='int', default=500, metavar='NUMBER', help='Depth of server socket listener ' 'backlog for Apache child processes. Defaults to 500.'), optparse.make_option('--daemon-backlog', type='int', default=100, metavar='NUMBER', help='Depth of server socket listener ' 'backlog for daemon processes. Defaults to 100.'), optparse.make_option('--send-buffer-size', type='int', default=0, metavar='NUMBER', help='Size of socket buffer for sending ' 'data to daemon processes. Defaults to 0, indicating ' 'the system default socket buffer size is used.'), optparse.make_option('--receive-buffer-size', type='int', default=0, metavar='NUMBER', help='Size of socket buffer for receiving ' 'data from daemon processes. Defaults to 0, indicating ' 'the system default socket buffer size is used.'), optparse.make_option('--header-buffer-size', type='int', default=0, metavar='NUMBER', help='Size of buffer used for reading ' 'response headers from daemon processes. Defaults to 0, ' 'indicating internal default of 32768 bytes is used.'), optparse.make_option('--reload-on-changes', action='store_true', default=False, help='Flag indicating whether worker processes ' 'should be automatically restarted when any Python code file ' 'loaded by the WSGI application has been modified. Defaults to ' 'being disabled. When reloading on any code changes is disabled, ' 'the worker processes will still though be reloaded if the ' 'WSGI script file itself is modified.'), optparse.make_option('--user', default=default_run_user(), metavar='NAME', help='When being run by the root user, the user that the WSGI ' 'application should be run as.'), optparse.make_option('--group', default=default_run_group(), metavar='NAME', help='When being run by the root user, the group ' 'that the WSGI application should be run as.'), optparse.make_option('--callable-object', default='application', metavar='NAME', help='The name of the entry point for the WSGI ' 'application within the WSGI script file. Defaults to ' 'the name \'application\'.'), optparse.make_option('--map-head-to-get', default='Auto', metavar='OFF|ON|AUTO', help='Flag indicating whether HEAD ' 'requests should be mapped to a GET request. By default a HEAD ' 'request will be automatically mapped to a GET request when an ' 'Apache output filter is detected that may want to see the ' 'entire response in order to set up response headers correctly ' 'for a HEAD request. This can be disable by setting to \'Off\'.'), optparse.make_option('--document-root', metavar='DIRECTORY-PATH', help='The directory which should be used as the document root ' 'and which contains any static files.'), optparse.make_option('--directory-index', metavar='FILE-NAME', help='The name of a directory index resource to be found in the ' 'document root directory. Requests mapping to the directory ' 'will be mapped to this resource rather than being passed ' 'through to the WSGI application.'), optparse.make_option('--mount-point', metavar='URL-PATH', default='/', help='The URL path at which the WSGI application will be ' 'mounted. Defaults to being mounted at the root URL of the ' 'site.'), optparse.make_option('--url-alias', action='append', nargs=2, dest='url_aliases', metavar='URL-PATH FILE-PATH|DIRECTORY-PATH', help='Map a single static file or a directory of static files ' 'to a sub URL.'), optparse.make_option('--error-document', action='append', nargs=2, dest='error_documents', metavar='STATUS URL-PATH', help='Map ' 'a specific sub URL as the handler for HTTP errors generated ' 'by the web server.'), optparse.make_option('--error-override', action='store_true', default=False, help='Flag indicating whether Apache error ' 'documents will override application error responses.'), optparse.make_option('--keep-alive-timeout', type='int', default=0, metavar='SECONDS', help='The number of seconds which a client ' 'connection will be kept alive to allow subsequent requests ' 'to be made over the same connection. Defaults to 0, indicating ' 'that keep alive connections are disabled.'), optparse.make_option('--compress-responses', action='store_true', default=False, help='Flag indicating whether responses for ' 'common text based responses, such as plain text, HTML, XML, ' 'CSS and Javascript should be compressed.'), optparse.make_option('--server-metrics', action='store_true', default=False, help='Flag indicating whether internal server ' 'metrics will be available within the WSGI application. ' 'Defaults to being disabled.'), optparse.make_option('--server-status', action='store_true', default=False, help='Flag indicating whether web server status ' 'will be available at the /server-status sub URL. Defaults to ' 'being disabled.'), optparse.make_option('--auth-user-script', metavar='SCRIPT-PATH', default=None, help='Specify a Python script file for ' 'performing user authentication.'), optparse.make_option('--auth-type', metavar='TYPE', default='Basic', help='Specify the type of authentication ' 'scheme used when authenticating users. Defaults to using ' '\'Basic\'. Alternate schemes available are \'Digest\'.'), optparse.make_option('--auth-group-script', metavar='SCRIPT-PATH', default=None, help='Specify a Python script file for ' 'performing group based authorization in conjunction with ' 'a user authentication script.'), optparse.make_option('--auth-group', metavar='SCRIPT-PATH', default='wsgi', help='Specify the group which users should ' 'be a member of when using a group based authorization script. ' 'Defaults to \'wsgi\' as a place holder but should be ' 'overridden to be the actual group you use rather than ' 'making your group name match the default.'), optparse.make_option('--include-file', action='append', dest='include_files', metavar='FILE-PATH', help='Specify the ' 'path to an additional web server configuration file to be ' 'included at the end of the generated web server configuration ' 'file.'), optparse.make_option('--envvars-script', metavar='FILE-PATH', help='Specify an alternate script file for user defined web ' 'server environment variables. Defaults to using the ' '\'envvars\' stored under the server root directory.'), optparse.make_option('--lang', default='en_US.UTF-8', metavar='NAME', help='Specify the default language locale as normally defined ' 'by the LANG environment variable. Defaults to \'en_US.UTF-8\'.'), optparse.make_option('--locale', default='en_US.UTF-8', metavar='NAME', help='Specify the default natural language formatting style ' 'as normally defined by the LC_ALL environment variable. ' 'Defaults to \'en_US.UTF-8\'.'), optparse.make_option('--setenv', action='append', nargs=2, dest='setenv_variables', metavar='KEY VALUE', help='Specify ' 'a name/value pairs to be added to the per request WSGI environ ' 'dictionary'), optparse.make_option('--passenv', action='append', dest='passenv_variables', metavar='KEY', help='Specify the ' 'names of any process level environment variables which should ' 'be passed as a name/value pair in the per request WSGI ' 'environ dictionary.'), optparse.make_option('--working-directory', metavar='DIRECTORY-PATH', help='Specify the directory which should be used as the ' 'current working directory of the WSGI application. This ' 'directory will be searched when importing Python modules ' 'so long as the WSGI application doesn\'t subsequently ' 'change the current working directory. Defaults to the ' 'directory this script is run from.'), optparse.make_option('--pid-file', metavar='FILE-PATH', help='Specify an alternate file to be used to store the ' 'process ID for the root process of the web server.'), optparse.make_option('--server-root', metavar='DIRECTORY-PATH', help='Specify an alternate directory for where the generated ' 'web server configuration, startup files and logs will be ' 'stored. Defaults to a sub directory of /tmp.'), optparse.make_option('--log-directory', metavar='DIRECTORY-PATH', help='Specify an alternate directory for where the log files ' 'will be stored. Defaults to the server root directory.'), optparse.make_option('--log-level', default='info', metavar='NAME', help='Specify the log level for logging. Defaults to \'info\'.'), optparse.make_option('--access-log', action='store_true', default=False, help='Flag indicating whether the web server access log ' 'should be enabled. Defaults to being disabled.'), optparse.make_option('--startup-log', action='store_true', default=False, help='Flag indicating whether the web server startup log should ' 'be enabled. Defaults to being disabled.'), optparse.make_option('--rotate-logs', action='store_true', default=False, help='Flag indicating whether log rotation should be performed.'), optparse.make_option('--max-log-size', default=5, type='int', metavar='MB', help='The maximum size in MB the log file should ' 'be allowed to reach before log file rotation is performed.'), optparse.make_option('--rotatelogs-executable', default=apxs_config.ROTATELOGS, metavar='FILE-PATH', help='Override the path to the rotatelogs executable.'), optparse.make_option('--python-eggs', metavar='DIRECTORY-PATH', help='Specify an alternate directory which should be used for ' 'unpacking of Python eggs. Defaults to a sub directory of ' 'the server root directory.'), optparse.make_option('--httpd-executable', default=apxs_config.HTTPD, metavar='FILE-PATH', help='Override the path to the Apache web ' 'server executable.'), optparse.make_option('--modules-directory', default=apxs_config.LIBEXECDIR, metavar='DIRECTORY-PATH', help='Override the path to the Apache ' 'web server modules directory.'), optparse.make_option('--mime-types', default=find_mimetypes(), metavar='FILE-PATH', help='Override the path to the mime types ' 'file used by the web server.'), optparse.make_option('--with-newrelic', action='store_true', default=False, help='Flag indicating whether all New Relic ' 'performance monitoring features should be enabled.'), optparse.make_option('--with-newrelic-agent', action='store_true', default=False, help='Flag indicating whether the New Relic ' 'Python agent should be enabled for reporting application server ' 'metrics.'), optparse.make_option('--with-newrelic-platform', action='store_true', default=False, help='Flag indicating whether the New Relic ' 'platform plugin should be enabled for reporting server level ' 'metrics.'), optparse.make_option('--with-wdb', action='store_true', default=False, help='Flag indicating whether the wdb interactive debugger ' 'should be enabled for the WSGI application.'), optparse.make_option('--with-php5', action='store_true', default=False, help='Flag indicating whether PHP 5 support should be enabled.'), optparse.make_option('--enable-docs', action='store_true', default=False, help='Flag indicating whether the mod_wsgi documentation should ' 'be made available at the /__wsgi__/docs sub URL.'), optparse.make_option('--debug-mode', action='store_true', default=False, help='Flag indicating whether to run in single process mode ' 'to allow the running of an interactive Python debugger. This ' 'will override all options related to processes, threads and ' 'communication with workers. All forms of source code reloading ' 'will also be disabled. Both stdin and stdout will be attached ' 'to the console to allow interaction with the Python debugger.'), optparse.make_option('--setup-only', action='store_true', default=False, help='Flag indicating that after the configuration files have ' 'been setup, that the command should then exit and not go on ' 'to actually run up the Apache server. This is to allow for ' 'the generation of the configuration with Apache then later ' 'being started separately using the generated \'apachectl\' ' 'script.'), ) def cmd_setup_server(params): formatter = optparse.IndentedHelpFormatter() formatter.set_long_opt_delimiter(' ') usage = '%prog setup-server script [options]' parser = optparse.OptionParser(usage=usage, option_list=option_list, formatter=formatter) (options, args) = parser.parse_args(params) _cmd_setup_server('setup-server', args, vars(options)) def _mpm_module_defines(modules_directory): result = [] workers = ['event', 'worker', 'prefork'] found = False for name in workers: if os.path.exists(os.path.join(modules_directory, 'mod_mpm_%s.so' % name)): if not found: result.append('-DWSGI_MPM_ENABLE_%s_MODULE' % name.upper()) found = True result.append('-DWSGI_MPM_EXISTS_%s_MODULE' % name.upper()) return result def _cmd_setup_server(command, args, options): options['sys_argv'] = repr(sys.argv) options['mod_wsgi_so'] = where() options['working_directory'] = options['working_directory'] or os.getcwd() if not options['host']: options['listener_host'] = None options['host'] = 'localhost' else: options['listener_host'] = options['host'] options['process_name'] = '(wsgi:%s:%s:%s)' % (options['host'], options['port'], os.getuid()) if not options['server_root']: options['server_root'] = '/tmp/mod_wsgi-%s:%s:%s' % (options['host'], options['port'], os.getuid()) try: os.mkdir(options['server_root']) except Exception: pass if options['ssl_certificate']: options['ssl_certificate'] = os.path.abspath( options['ssl_certificate']) if not args: options['entry_point'] = os.path.join(options['server_root'], 'default.wsgi') options['application_type'] = 'script' options['enable_docs'] = True elif options['application_type'] in ('script', 'paste'): options['entry_point'] = os.path.abspath(args[0]) else: options['entry_point'] = args[0] if options['auth_user_script']: options['auth_user_script'] = os.path.abspath( options['auth_user_script']) if options['auth_group_script']: options['auth_group_script'] = os.path.abspath( options['auth_group_script']) options['documentation_directory'] = os.path.join(os.path.dirname( os.path.dirname(__file__)), 'docs') options['images_directory'] = os.path.join(os.path.dirname( os.path.dirname(__file__)), 'images') if os.path.exists(os.path.join(options['documentation_directory'], 'index.html')): options['documentation_url'] = '/__wsgi__/docs/' else: options['documentation_url'] = 'http://www.modwsgi.org/' if not os.path.isabs(options['server_root']): options['server_root'] = os.path.abspath(options['server_root']) if not options['document_root']: options['document_root'] = os.path.join(options['server_root'], 'htdocs') try: os.mkdir(options['document_root']) except Exception: pass if not options['mount_point'].startswith('/'): options['mount_point'] = os.path.normpath('/' + options['mount_point']) if options['mount_point'] != '/': parts = options['mount_point'].rstrip('/').split('/')[1:] subdir = options['document_root'] try: for part in parts: subdir = os.path.join(subdir, part) if not os.path.exists(subdir): os.mkdir(subdir) except Exception: raise if not os.path.isabs(options['document_root']): options['document_root'] = os.path.abspath(options['document_root']) if not options['log_directory']: options['log_directory'] = options['server_root'] try: os.mkdir(options['log_directory']) except Exception: pass if not os.path.isabs(options['log_directory']): options['log_directory'] = os.path.abspath(options['log_directory']) options['error_log'] = os.path.join(options['log_directory'], 'error_log') options['pid_file'] = ((options['pid_file'] and os.path.abspath( options['pid_file'])) or os.path.join(options['server_root'], 'httpd.pid')) options['python_eggs'] = (os.path.abspath(options['python_eggs']) if options['python_eggs'] is not None else None) if options['python_eggs'] is None: options['python_eggs'] = os.path.join(options['server_root'], 'python-eggs') try: os.mkdir(options['python_eggs']) except Exception: pass options['multiprocess'] = options['processes'] is not None options['processes'] = options['processes'] or 1 options['python_home'] = sys.prefix options['keep_alive'] = options['keep_alive_timeout'] != 0 if options['server_metrics']: options['daemon_server_metrics_flag'] = 'On' else: options['daemon_server_metrics_flag'] = 'Off' if options['with_newrelic']: options['with_newrelic_agent'] = True options['with_newrelic_platform'] = True if options['with_newrelic_platform']: options['server_metrics'] = True generate_wsgi_handler_script(options) if options['with_newrelic_platform']: generate_server_metrics_script(options) if options['with_wdb']: generate_wdb_server_script(options) max_clients = options['processes'] * options['threads'] if options['max_clients'] is not None: max_clients = max(options['max_clients'], max_clients) else: max_clients = int(1.5 * max_clients) initial_workers = options['initial_workers'] min_spare_workers = options['minimum_spare_workers'] max_spare_workers = options['maximum_spare_workers'] if initial_workers is None: prefork_initial_workers = 0.02 else: prefork_initial_workers = initial_workers if min_spare_workers is None: prefork_min_spare_workers = prefork_initial_workers else: prefork_min_spare_workers = min_spare_workers if max_spare_workers is None: prefork_max_spare_workers = 0.05 else: prefork_max_spare_workers = max_spare_workers options['prefork_max_clients'] = max_clients options['prefork_server_limit'] = max_clients options['prefork_start_servers'] = max(1, int( prefork_initial_workers * max_clients)) options['prefork_min_spare_servers'] = max(1, int( prefork_min_spare_workers * max_clients)) options['prefork_max_spare_servers'] = max(1, int( prefork_max_spare_workers * max_clients)) if initial_workers is None: worker_initial_workers = 0.2 else: worker_initial_workers = initial_workers if min_spare_workers is None: worker_min_spare_workers = worker_initial_workers else: worker_min_spare_workers = min_spare_workers if max_spare_workers is None: worker_max_spare_workers = 0.6 else: worker_max_spare_workers = max_spare_workers options['worker_max_clients'] = max_clients if max_clients > 25: options['worker_threads_per_child'] = int(max_clients / (int(max_clients / 25) + 1)) else: options['worker_threads_per_child'] = max_clients options['worker_thread_limit'] = options['worker_threads_per_child'] count = max_clients / options['worker_threads_per_child'] options['worker_server_limit'] = int(math.floor(count)) if options['worker_server_limit'] != count: options['worker_server_limit'] += 1 options['worker_max_clients'] = (options['worker_server_limit'] * options['worker_threads_per_child']) options['worker_start_servers'] = max(1, int(worker_initial_workers * options['worker_server_limit'])) options['worker_min_spare_threads'] = max( options['worker_threads_per_child'], int(worker_min_spare_workers * options['worker_server_limit']) * options['worker_threads_per_child']) options['worker_max_spare_threads'] = max( options['worker_threads_per_child'], int(worker_max_spare_workers * options['worker_server_limit']) * options['worker_threads_per_child']) options['httpd_conf'] = os.path.join(options['server_root'], 'httpd.conf') options['httpd_executable'] = os.environ.get('HTTPD', options['httpd_executable']) if not os.path.isabs(options['httpd_executable']): options['httpd_executable'] = find_program( [options['httpd_executable']], 'httpd', ['/usr/sbin']) options['envvars_script'] = (os.path.abspath( options['envvars_script']) if options['envvars_script'] is not None else None) options['httpd_arguments_list'] = [] if options['startup_log']: options['startup_log_filename']= os.path.join( options['log_directory'], 'startup.log') options['httpd_arguments_list'].append('-E') options['httpd_arguments_list'].append( options['startup_log_filename']) if options['server_name']: host = options['server_name'] else: host = options['host'] if options['port'] == 80: options['url'] = 'http://%s/' % host else: options['url'] = 'http://%s:%s/' % (host, options['port']) if options['ssl_port'] == 443: options['ssl_url'] = 'https://%s/' % host elif options['ssl_port'] is not None: options['ssl_url'] = 'https://%s:%s/' % (host, options['ssl_port']) else: options['ssl_url'] = None if options['debug_mode']: options['httpd_arguments_list'].append('-DONE_PROCESS') options['parent_domain'] = 'unspecified' if options['server_name']: options['httpd_arguments_list'].append('-DWSGI_VIRTUAL_HOST') if options['server_name'].lower().startswith('www.'): options['httpd_arguments_list'].append('-DWSGI_REDIRECT_WWW') options['parent_domain'] = options['server_name'][4:] if options['ssl_port'] and options['ssl_certificate']: options['httpd_arguments_list'].append('-DWSGI_WITH_SSL') if options['https_only']: options['httpd_arguments_list'].append('-DWSGI_HTTPS_ONLY') if options['server_aliases']: options['httpd_arguments_list'].append('-DWSGI_SERVER_ALIAS') options['server_aliases'] = ' '.join(options['server_aliases']) if options['allow_localhost']: options['httpd_arguments_list'].append('-DWSGI_ALLOW_LOCALHOST') if options['server_metrics']: options['httpd_arguments_list'].append('-DWSGI_SERVER_METRICS') if options['server_status']: options['httpd_arguments_list'].append('-DWSGI_SERVER_METRICS') options['httpd_arguments_list'].append('-DWSGI_SERVER_STATUS') if options['directory_index']: options['httpd_arguments_list'].append('-DWSGI_DIRECTORY_INDEX') if options['access_log']: options['httpd_arguments_list'].append('-DWSGI_ACCESS_LOG') if options['rotate_logs']: options['httpd_arguments_list'].append('-DWSGI_ROTATE_LOGS') if options['keep_alive'] != 0: options['httpd_arguments_list'].append('-DWSGI_KEEP_ALIVE') if options['compress_responses'] != 0: options['httpd_arguments_list'].append('-DWSGI_COMPRESS_RESPONSES') if options['multiprocess']: options['httpd_arguments_list'].append('-DWSGI_MULTIPROCESS') if options['listener_host']: options['httpd_arguments_list'].append('-DWSGI_LISTENER_HOST') if options['error_override']: options['httpd_arguments_list'].append('-DWSGI_ERROR_OVERRIDE') if options['auth_user_script']: options['httpd_arguments_list'].append('-DWSGI_AUTH_USER') if options['auth_group_script']: options['httpd_arguments_list'].append('-DWSGI_AUTH_GROUP') if options['with_php5']: options['httpd_arguments_list'].append('-DWSGI_WITH_PHP5') options['httpd_arguments_list'].extend( _mpm_module_defines(options['modules_directory'])) options['httpd_arguments'] = '-f %s %s' % (options['httpd_conf'], ' '.join(options['httpd_arguments_list'])) options['python_executable'] = sys.executable generate_apache_config(options) generate_control_scripts(options) print('Server URL :', options['url']) if options['ssl_url']: print('Server URL (SSL) :', options['ssl_url']) if options['server_status']: print('Server Status :', '%sserver-status' % options['url']) print('Server Root :', options['server_root']) print('Server Conf :', options['httpd_conf']) print('Error Log File :', options['error_log']) if options['access_log']: print('Access Log File :', os.path.join(options['log_directory'], 'access_log')) if options['envvars_script']: print('Environ Variables :', options['envvars_script']) if command == 'setup-server' or options['setup_only']: if not options['envvars_script']: print('Environ Variables :', options['server_root'] + '/envvars') print('Control Script :', options['server_root'] + '/apachectl') return options def cmd_start_server(params): formatter = optparse.IndentedHelpFormatter() formatter.set_long_opt_delimiter(' ') usage = '%prog start-server script [options]' parser = optparse.OptionParser(usage=usage, option_list=option_list, formatter=formatter) (options, args) = parser.parse_args(params) config = _cmd_setup_server('start-server', args, vars(options)) if config['setup_only']: return executable = os.path.join(config['server_root'], 'apachectl') name = executable.ljust(len(config['process_name'])) os.execl(executable, name, 'start', '-DNO_DETACH') def cmd_install_module(params): formatter = optparse.IndentedHelpFormatter() formatter.set_long_opt_delimiter(' ') usage = '%prog install-module [options]' parser = optparse.OptionParser(usage=usage, formatter=formatter) parser.add_option('--modules-directory', metavar='DIRECTORY', default=apxs_config.LIBEXECDIR) (options, args) = parser.parse_args(params) if len(args) != 0: parser.error('Incorrect number of arguments.') target = os.path.abspath(os.path.join(options.modules_directory, MOD_WSGI_SO)) shutil.copyfile(where(), target) print('LoadModule wsgi_module %s' % target) def cmd_module_location(params): formatter = optparse.IndentedHelpFormatter() formatter.set_long_opt_delimiter(' ') usage = '%prog module-location' parser = optparse.OptionParser(usage=usage, formatter=formatter) (options, args) = parser.parse_args(params) if len(args) != 0: parser.error('Incorrect number of arguments.') print(where()) main_usage=""" %prog command [params] Commands: install-module module-location setup-server start-server """ def main(): parser = optparse.OptionParser(main_usage.strip()) args = sys.argv[1:] if not args: parser.error('No command was specified.') command = args.pop(0) args = [os.path.expandvars(arg) for arg in args] if command == 'install-module': cmd_install_module(args) elif command == 'module-location': cmd_module_location(args) elif command == 'setup-server': cmd_setup_server(args) elif command == 'start-server': cmd_start_server(args) else: parser.error('Invalid command was specified.') if __name__ == '__main__': main()