#!/usr/bin/env python2
"""
    Test tomcat for hangproblems
    I think that this script is not in use anymore

    Copyright  Afrihost.com (PTY) Ltd 2003
    Original file by: Ed Pascoe <ed@pascoe.co.za>
    $Id: tomcattest,v 1.2 2004/02/09 11:02:32 elp Exp $
"""
__author__  = "Ed Pascoe <ed@pascoe.co.za>"
__date__    = "$Date: 2004/02/09 11:02:32 $ "
__version__ = "$Revision: 1.2 $"
__credits__ = "Afrihost.com -- The best webhosting. Ever."

from xml.dom.ext.reader import PyExpat
import xml.dom.ext
import xml.xpath
import os, os.path,sys, errno, shutil
import StringIO
from xml.dom import EMPTY_NAMESPACE
import time
exedir=os.path.dirname(os.path.realpath(sys.argv[0]))
dom=None

from optparse import OptionParser

import dircache
import time

class TomcatError(Exception): pass
class TomcatPasswordError(TomcatError): pass
class TomcatConfigError(TomcatError): pass
    
class Tomcat:
    tomcatconf="/etc/tomcatusers.xml"
    dom="The xml data tree"
    sitelist="Array of sites in the config file"
    #Where to get find default copies of missing files
    tomcatbase="/usr/local/jakarta/tomcat"
    #{{{ def __init__(self,conffile=""):
    def __init__(self,conffile=""):
        """Pass the location of the config file if you need to"""
        if conffile: self.tomcatconf=conffile
        reader = PyExpat.Reader()
        f=open(os.path.join(exedir,self.tomcatconf),"r")
        self.dom = reader.fromStream(f)
        f.close()
        self.sitelist=self.__sites()
    #}}} 
    #{{{ def __sites(self):
    def __sites(self):
        """Return a list of sites that use tomcat"""
        sitelist=[]
        for node in xml.xpath.Evaluate(r"/tomcat-users/site/info", self.dom.documentElement):
               sitelist.append(node.getAttributeNS(EMPTY_NAMESPACE, u'site'))
        return sitelist
    #}}}
    #{{{ def __mkdirs(self,newdir,mode=0777):
    def __mkdirs(self,newdir,mode=0777):
        """Like shell command: mkdir -p"""
        try: os.makedirs(newdir,mode)
        except OSError, err:
        #Rereaise if not already existing directory
            if err.errno != errno.EEXIST or not os.path.isdir(newdir): raise
    #}}}
    #{{{ def getnode(self,site):
    def getnode(self,site):
        """Returns the dom node for the given site"""
        nodes=xml.xpath.Evaluate(r"/tomcat-users/site/info[@site='%s']" % (site) , self.dom.documentElement)
        if not nodes: return None
        return nodes[0] #Find the first site that matches
    #}}}
    #{{{ def tomcatuserxml_str(self,node):
    def tomcatuserxml_str(self,node):
        """Return a config string  suitable for tomcatusers.xml"""
        config={}
        config["site"]=node.getAttributeNS(EMPTY_NAMESPACE, u'site')
        config["password"]=node.getAttributeNS(EMPTY_NAMESPACE, u'password')
        config["url"]="http://"+config["site"]+"/manager"

        data=r"""<?xml version='1.0' encoding='utf-8'?>
<!-- ************************************************************************ -->
<!-- tomcat-users.xml                                                         -->
<!-- This file controls the usernames and passwords for the tomcat manager    -->
<!-- found at %(url)-63s -->
<!--                                                                          -->
<!-- If you make changes and get confused. Just delete this file and it will  -->
<!-- be recreated with the defaults as soon as you restart tomcat             -->
<!-- ************************************************************************ -->
<tomcat-users>
    <role rolename="tomcat"/>
    <role rolename="role1"/>
    <role rolename="standard"/>
    <role rolename="admin"/>
    <role rolename="manager"/>
    <user username="%(site)s" password="%(password)s" roles="standard,manager,tomcat,role1,admin"/>
</tomcat-users>

        """ % (config)
        return data
    #}}}
    #{{{ def serverxml_str(self,node):
    def serverxml_str(self,node):
        """Return a config string  suitable for server.xml"""
        config={}
        config["user"]=node.getAttributeNS(EMPTY_NAMESPACE, u'user')
        config["site"]=node.getAttributeNS(EMPTY_NAMESPACE, u'site')
        config["tomcatdir"]=node.getAttributeNS(EMPTY_NAMESPACE, u'tomcatdir')
        config["port"]=node.getAttributeNS(EMPTY_NAMESPACE, u'port')
        config["shutdownport"]=node.getAttributeNS(EMPTY_NAMESPACE, u'shutdown_port')

        data=r"""<!-- ************************************************************************ -->
<!-- Server.xml. Please be careful modifying this file.                       -->
<!-- DO NOT CHANGE THE PORT NUMBERS. If you do your site WILL STOP WORKING!!  -->
<!--                                                                          -->
<!-- If you make changes and get confused. Just delete this file and it will  -->
<!-- be recreated with the defaults as soon as you restart tomcat             -->
<!-- ************************************************************************ -->

<Server port="%(shutdownport)s" shutdown="SHUTDOWN" debug="0">
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"
            debug="0"/>
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"
            debug="0"/>
  <GlobalNamingResources>
    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
       description="User database that can be updated and saved">
    </Resource>
    <ResourceParams name="UserDatabase">
      <parameter>
        <name>factory</name>
        <value>org.apache.catalina.users.MemoryUserDatabaseFactory</value>
      </parameter>
      <parameter>
        <name>pathname</name>
        <value>conf/tomcat-users.xml</value>
      </parameter>
    </ResourceParams>
  </GlobalNamingResources>

  <Service name="Catalina">
    <Connector port="%(port)s"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" redirectPort="8443" acceptCount="100"
               connectionTimeout="20000"
               disableUploadTimeout="true" debug="0" />

    <Engine name="Catalina" defaultHost="www.computerguys.co.za" debug="0">
      <Logger className="org.apache.catalina.logger.FileLogger"
              directory="%(tomcatdir)s/logs" prefix="log." suffix=".txt"
              timestamp="true"/>

      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                 debug="0" resourceName="UserDatabase"/>

      <Host name="www.%(site)s" appBase="%(tomcatdir)s/../public_html" debug="3" reloadable="true"
            unpackWARs="true" autoDeploy="true" >
               <Alias>%(site)s</Alias>
               <Context path="" docBase="." swallowOutput="true" reloadable="true" />
               <Context path="/manager" debug="0" privileged="true"
                 docBase="/usr/local/jakarta/tomcat/server/webapps/manager" />
       </Host>
    </Engine>
  </Service>
</Server>

        """ % (config)
        return data
    #}}}
    #{{{ def checksitepassword(self,site,password):
    def checksitepassword(self,site,password):
        """Make sure that password is valid for given site"""
        for node in xml.xpath.Evaluate(r"/tomcat-users/site/info[@site='%s']" % site, self.dom.documentElement):
            csite = node.getAttributeNS(EMPTY_NAMESPACE, u'site')
            cpassword = node.getAttributeNS(EMPTY_NAMESPACE, u'password')
            if cpassword != password:
                raise TomcatPasswordError,"Bad Password"
            return 1
        
        raise TomcatPasswordError,"Unknown site"
    #}}}
    #{{{ def mktomcatconf(self,node):
    def mktomcatconf(self,node):
        """Make sure that all required conf files for tomcat have been created"""
        site          = node.getAttributeNS(EMPTY_NAMESPACE, u'site')
        port          = node.getAttributeNS(EMPTY_NAMESPACE, u'port')
        shutdown_port = node.getAttributeNS(EMPTY_NAMESPACE, u'shutdown_port')
        heap          = node.getAttributeNS(EMPTY_NAMESPACE, u'heap')
        user          = node.getAttributeNS(EMPTY_NAMESPACE, u'user')
        password      = node.getAttributeNS(EMPTY_NAMESPACE, u'password')
        tomcatdir     = node.getAttributeNS(EMPTY_NAMESPACE, u'tomcatdir')

        if not user: raise TomcatConfigError, "user attribute missing from config"

        #{{{ Create needed directories
        for f in ["conf","logs","temp","work"]:
            self.__mkdirs(os.path.join(tomcatdir,f))
        confdir=os.path.join(tomcatdir,"conf")
        #}}} 
        #{{{ Create linked directories
        for f in ["bin","server"]:
            src=os.path.join(self.tomcatbase,f)
            dst=os.path.join(tomcatdir,f)
            if not os.path.exists(dst): 
                print "Linking '%s' to '%s'" % (src,dst)
                os.symlink(src,dst)
        #}}}
        #{{{ do a cp -a on required directories
        for f in ["common","shared"]:
            src=os.path.join(self.tomcatbase,f)
            dst=os.path.join(tomcatdir,f)
            if not os.path.exists(dst): 
                print "Copying directory %s from base tomcat" % (f)
                os.system("cp -a '%s' '%s'" % (src,dst))
        #}}}
        #{{{ copy required config files
        for f in ["catalina.policy","catalina.properties","web.xml"]:
            dst=os.path.join(confdir,f)
            if not os.path.exists(dst):
               src=os.path.join(self.tomcatbase,"conf",f)
               print "Installing %s to %s" % (src,dst)
               shutil.copy2(src,dst) 
        #}}}
        #{{{ create server.xml and tomcat-users.xml
        serverxml=os.path.join(confdir,"server.xml")
        if not os.path.exists(serverxml):
            print "Installing a default server.xml"
            s=StringIO.StringIO(self.serverxml_str(node))
            d=open(serverxml,"w")
            shutil.copyfileobj(s,d)
            s.close()
            d.close()
        os.system("chown -R %s.%s '%s'" % (user,user,tomcatdir)) #Make sure ownership of files is correct
            
        tomuser = os.path.join(confdir,"tomcat-users.xml")

        if not os.path.exists(tomuser):
            print "Installing a default tomcat-users.xml"
            s=StringIO.StringIO(self.tomcatuserxml_str(node))
            d=open(tomuser,"w")
            shutil.copyfileobj(s,d)
            s.close()
            d.close()
        #}}}
        os.system("chown -R %s.%s '%s'" % (user,user,tomcatdir)) #Make sure ownership of files is correct

    #}}}
    #{{{ def javaSetEnv(self,node):
    def javaSetEnv(self,node):
        """Set all required environment variables for tomcat"""
        site      = node.getAttributeNS(EMPTY_NAMESPACE, u'site')
        user      = node.getAttributeNS(EMPTY_NAMESPACE, u'user')
        tomcatdir = node.getAttributeNS(EMPTY_NAMESPACE, u'tomcatdir')
        tempdir   = os.path.join(tomcatdir,"temp")
        logdir    = os.path.join(tomcatdir,"logs")
        os.chdir(tomcatdir)

        os.environ["PATH"]="/usr/local/jdk/bin:/usr/local/bin:/sbin:/bin:/usr/bin:/usr/X11R6/bin"
        os.environ["JAVA_HOME"]="/usr/local/jdk"
        os.environ["XML"]="/usr/local/jdk/lib"
        os.environ["SSL"]="/usr/local/jdk/lib"
        os.environ["JAVAMYSQL"]="/usr/local/jdk/lib"
        os.environ["CLASSPATH"]=".:/usr/local/jdk/lib/classes.zip:/usr/local/jdk/lib/tools.jar:%s/bin/bootstrap.jar:%s/bin/commons-logging-api.jar" % (tomcatdir,tomcatdir)
        os.environ["JAKARTA_HOME"]="/usr/local/jakarta"
        os.environ["TOMCAT_HOME"]  =tomcatdir
        os.environ["CATALINA_HOME"]=tomcatdir
        os.environ["CATALINA_BASE"]=tomcatdir
        os.environ["CATALINA_TMPDIR"]=tempdir

        cmd="/usr/local/jdk/bin/java -classpath '%s' " % os.environ["CLASSPATH"]
        cmd=cmd+ "-Dcatalina.base='%s' " % (os.environ["CATALINA_BASE"])
        cmd=cmd+ "-Dcatalina.home='%s' " % (os.environ["CATALINA_HOME"])
        cmd=cmd+ "-Dcatalina.tmpdir='%s' " % (tempdir)
        return cmd
    #}}}
    #{{{ def starttomcat(self,site):
    def starttomcat(self,site):
        node=self.getnode(site)
        user      = node.getAttributeNS(EMPTY_NAMESPACE, u'user')
        port      = node.getAttributeNS(EMPTY_NAMESPACE, u'port')
        tomcatdir = node.getAttributeNS(EMPTY_NAMESPACE, u'tomcatdir')
        logdir    = os.path.join(tomcatdir,"logs")
        if not user: raise TomcatConfigError, "user attribute missing from config"
        self.mktomcatconf(node)

        print "starting %s on port %s " % (site,port)
        su="su -l %s -s/bin/sh -c" %user
        java= self.javaSetEnv(node)+" org.apache.catalina.startup.Bootstrap start > %s 2>&1" % (os.path.join(logdir,"catalina.out"))
        cmd="exec %s \"exec %s \" & " % (su,java)
        os.system(cmd)
    #}}}
    #{{{ def stoptomcat(self,site):
    def stoptomcat(self,site):

        node          = self.getnode(site)
        port          = node.getAttributeNS(EMPTY_NAMESPACE, u'port')
        shutdown_port = node.getAttributeNS(EMPTY_NAMESPACE, u'shutdown_port')
        heap          = node.getAttributeNS(EMPTY_NAMESPACE, u'heap')
        user          = node.getAttributeNS(EMPTY_NAMESPACE, u'user')
        tomcatdir     = node.getAttributeNS(EMPTY_NAMESPACE, u'tomcatdir')
        logdir        = os.path.join(tomcatdir,"logs")

        if not user: raise TomcatConfigError, "user attribute missing from config"

        logdir=os.path.join(tomcatdir,"logs")

        os.chdir(tomcatdir)
        if not os.path.exists(logdir):
            os.mkdir(logdir)
            os.chmod(logdir,0777)
        print "stopping  %s on port %s " % (site,port)
        su="su -l %s -s/bin/sh -c" %user
        java= self.javaSetEnv(node)+" org.apache.catalina.startup.Bootstrap stop > %s 2>&1" % (os.path.join(logdir,"catalina.out"))
        cmd="exec %s \"exec %s \" & " % (su,java)
        #print cmd
        os.system(cmd)

        time.sleep(3)
        if not port: return #Only kill if we know its port number
        #Kill anything left behind
        os.system(r"kill -9 `/usr/sbin/lsof -i TCP:%s | grep java | awk '{print $2}'` 2> /dev/null " % (port))
    #}}}
            
if __name__=='__main__': 
    parser = OptionParser()
    parser.add_option("-f", "--file", dest="configfile", help="Config file to use (optional) ", metavar="FILE", default="/etc/tomcatusers.xml")
    parser.add_option("-s","--site",dest="site",help="tomcat site to work with" )
    parser.add_option("-p","--password","--passwd",dest="password",help="Site password")
    (options, args) = parser.parse_args()

    t=Tomcat()

    if options.password: t.checksitepassword(options.site,options.password)
        
    for action in args: #Step through the possible actions for the sites
        if action=="start":
            t.starttomcat(options.site)
            continue
        if action=="stop":
            t.stoptomcat(options.site)
            continue
        if action=="restart":
            t.stoptomcat(options.site)
            t.starttomcat(options.site)
            continue
"""
    <site>
        <info
            site="computerguys.co.za"
            port="8081"
            shutdown_port="8082"
            heap="20"
            user="computer"
            password="paranoid"
            tomcatdir="/home/computer/tomcat"
        />
    </site>

"""
#    vim600: sw=4 fdm=marker expandtab sm ts=3
