from __future__ import with_statement

from config import *
from util import *
import service

import basic

class Apache(service.Service):
    """An Apache2 server.  The base configuration for this server is
    taken from SRCDIR/src/bench/apache2 and stored in DESTDIR/apache2
    on the target host.  The caller must register some subclass of
    ApacheMPMSetting in the directory to provide the MPM and MPM
    settings to use.  Additional parts from the
    SRCDIR/src/bench/apache2/parts directory can also be loaded into
    the configuration."""

    __config__ = ["parts"]

    def __init__(self, host, parts = None):
        if parts == None:
            parts = []
        self.parts = parts
        service.Service.__init__(self, "apache.%s" % host, host)

    def addPart(self, name):
        """Add the named part from the parts configuration directory
        to this Apache's configuration.  This must be called before
        setup."""

        self.parts.append(name)

    def link(self, d):
        self.__ls = d[basic.LogSetting]
        self.__mpm = d[ApacheMPMSetting]

    def setup(self):
        # Copy Apache configuration.  This also deletes the logs and
        # the generated configuration files.
        self.host.sendSrcFiles("src/bench/apache2", delete = True)

        # Create environment variables
        user = Cmd("whoami").ssh(self.host).runRead()
        groups = Cmd("groups").ssh(self.host).runRead()
        envs = [
            # apache2ctl variables
            ("APACHE_HTTPD",
             "/usr/lib/apache2/mpm-%s/apache2" % self.__mpm.mpm),
            ("APACHE_LOCK_DIR", os.path.join(DESTDIR, "apache2")),
            ("APACHE_ARGUMENTS", "-d %s -f apache2/apache2.conf" % DESTDIR),
            # apache2.conf environment
            ("APACHE_PID_FILE", "/var/run/apache2.pid"),
            ("APACHE_RUN_USER", user.strip()),
            ("APACHE_RUN_GROUP", groups.strip().split()[0]),
            # Misc
            ("LANG", "C"),
            ]
        envpath = os.path.join(DESTDIR, "apache2", "envvars")
        self.host.writeFile(envpath, "".join("export %s='%s'\n" % (k,v)
                                             for k,v in envs))

        # Create benchmark configuration
        benchpath = os.path.join(DESTDIR, "apache2", "bench.conf")
        bench = (self.__mpm.getApacheConfig() + "\n" +
                 "".join("Include apache2/parts/%s\n" % p
                         for p in self.parts))
        self.host.writeFile(benchpath, bench)

        # We can't reliably tear down Apache, so make sure it's not
        # running before we try to do anything.  Of course, we had to
        # configure it before we could do this so it can find itself.
        self.__stop()

    def __apache2ctl(self, op):
        (Cmd("apache2ctl", op)
         .envs(APACHE_ENVVARS = os.path.join(DESTDIR, "apache2", "envvars"))
         .sudo().ssh(self.host)).run()

    def start(self):
        # XXX We can sort of run Apache under nonohup using
        #   APACHE_HTTPD=~/sandbox/txcache/src/bench/nonohup
        #   APACHE_ARGUMENTS="/usr/sbin/apache2 -DNO_DETACH"
        #   apache2ctl start

        with Progress("Starting %s" % self.name):
            self.__apache2ctl("start")

    def __stop(self):
        with Progress("Stopping %s" % self.name):
            self.__apache2ctl("stop")

    def stop(self):
        self.__stop()

        # Save a copy of the configuration directory, including the
        # error and access logs.
        self.host.getFile(os.path.join(DESTDIR, "apache2/"),
                          os.path.join(self.__ls.logdir, self.name))

class ApacheMPMSetting(service.Setting):
    __config__ = ["mpm"]

    def __init__(self, mpm, args, defaults):
        self.mpm = mpm

        self.__keys = defaults.keys()
        for k, v in defaults.items():
            if k in args:
                setattr(self, k, args.pop(k))
            else:
                setattr(self, k, v)

        def abortIfArgs():
            pass
        abortIfArgs(**args)

    def getApacheConfig(self):
        return "".join("%-19s %3d\n" % (k, getattr(self, k))
                       for k in self.__keys)

class ApachePreforkSettting(ApacheMPMSetting):
    __defaults = {"StartServers": 5,
                  "MinSpareServers": 5, "MaxSpareServers": 10,
                  "MaxClients": 150,"MaxRequestsPerChild": 0}
    __config__ = __defaults.keys()

    def __init__(self, **kwargs):
        ApacheMPMSetting.__init__(self, "prefork", kwargs, self.__defaults)

class ApacheWorkerSettting(ApacheMPMSetting):
    __defaults = {"StartServers": 2,
                  "MinSpareThreads": 25, "MaxSpareThreads": 75,
                  "ThreadLimit": 64, "ThreadsPerChild": 25,
                  "MaxClients": 150, "MaxRequestsPerChild": 0}
    __config__ = __defaults.keys()

    def __init__(self, **kwargs):
        ApacheMPMSetting.__init__(self, "worker", kwargs, self.__defaults)

class ApacheEventSettting(ApacheMPMSetting):
    __defaults = {"StartServers": 2,
                  "MinSpareThreads": 25, "MaxSpareThreads": 75,
                  "ThreadLimit": 64, "ThreadsPerChild": 25,
                  "MaxClients": 150, "MaxRequestsPerChild": 0}
    __config__ = __defaults.keys()

    def __init__(self, **kwargs):
        ApacheMPMSetting.__init__(self, "event", kwargs, self.__defaults)
