#!/usr/bin/python
#
# @package      hubzero-cli
# @file         hzcms
# @author       David Benham <dbenham@purdue.edu>
# @author       Nicholas J. Kisseberth <nkissebe@purdue.edu>
# @copyright    Copyright (c) 2013-2015 HUBzero Foundation, LLC.
# @license      http://opensource.org/licenses/MIT MIT
#
# Copyright (c) 2013-2015 HUBzero Foundation, LLC.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# HUBzero is a registered trademark of HUBzero Foundation, LLC.
#

import sys
import os

dist_packages = "/usr/lib/python%d.%d/dist-packages" % (sys.version_info[0], sys.version_info[1])

if os.path.isdir(dist_packages):
    sys.path.insert(1,dist_packages)

import argparse
import ConfigParser
import errno
import hubzero.data.db
import hubzero.utilities.misc
import hubzero.utilities.user
import hubzero.config.webconfig
import random
import re
import string
import distutils.dir_util
import grp
import pwd
import stat
import shutil
import platform
import subprocess
import time
import MySQLdb
import socket
import tempfile
import _mysql_exceptions
from distutils.version import LooseVersion, StrictVersion

sourceFilesDir = "usr/lib/hubzero/cms"
hubzeroConfigFilePath = "/etc/hubzero.conf"
hubzero.utilities.misc.JOOMLA_25 = False
HUBZERO_CMS_DIR = "/usr/share/hubzero-cms"

# distribution constants
DIST_DEB = 1
DIST_RH = 2

# default password length for autogenerated passwords
autoGenPWLength = 14

# set some global versioning and distribution variables
if os.path.exists("/usr/share/hubzero-cms-2.1.0/cms/index.php"):
    HUBZERO_CMS_DIR = "/usr/share/hubzero-cms-2.1.0"
    hubzero.utilities.misc.JOOMLA_25 = True
elif os.path.exists("/usr/share/hubzero-cms-2.0.0/cms/index.php"):
    HUBZERO_CMS_DIR = "/usr/share/hubzero-cms-2.0.0"
    hubzero.utilities.misc.JOOMLA_25 = True
elif os.path.exists("/usr/share/hubzero-cms-1.3.1/cms/index.php"):
    HUBZERO_CMS_DIR = "/usr/share/hubzero-cms-1.3.1"
    hubzero.utilities.misc.JOOMLA_25 = True
elif os.path.exists("/usr/share/hubzero-cms-1.3.0/cms/index.php"):
    HUBZERO_CMS_DIR = "/usr/share/hubzero-cms-1.3.0"
    hubzero.utilities.misc.JOOMLA_25 = True
elif os.path.exists("/usr/share/hubzero-cms-1.2.2/cms/index.php"):
    HUBZERO_CMS_DIR = "/usr/share/hubzero-cms-1.2.2"
    hubzero.utilities.misc.JOOMLA_25 = True
elif os.path.exists("/usr/share/hubzero-cms-1.2.1/cms/index.php"):
    HUBZERO_CMS_DIR = "/usr/share/hubzero-cms-1.2.1"
    hubzero.utilities.misc.JOOMLA_25 = True
elif os.path.exists("/usr/share/hubzero-cms-1.2.0/cms/index.php"):
    HUBZERO_CMS_DIR = "/usr/share/hubzero-cms-1.2.0"
    hubzero.utilities.misc.JOOMLA_25 = True
elif os.path.exists("/usr/share/hubzero-cms-1.1.0/cms/index.php"):
    HUBZERO_CMS_DIR = "/usr/share/hubzero-cms-1.1.0"
elif os.path.exists("/usr/share/hubzero-cms/cms/index.php"):
    HUBZERO_CMS_DIR = "/usr/share/hubzero-cms"

# I know, shame on me, using a global
if hubzero.utilities.misc.isRHEL():
	dist = DIST_RH
elif hubzero.utilities.misc.isDebian():
	dist = DIST_DEB
else:
	print "unknown distribution"
	exit(1)

def blockTillMySQLStopped(connAttemptsMax = 32, sleepInterval = 2):
    waitLoop = False
    connAttempt = 1

    while(1):
        if connAttempt > connAttemptsMax:
            print ""
            # if we try too many times, we throw an exception    
            raise Exception("timed out testing for MySQL stopped check")
        try:
            connAttempt+=1
            time.sleep(sleepInterval)

            # we're just looking to see if the MySQL is running, a failed login attempt
            # while mysql is running will return a 1045 error, 2002 if it isn't running
            db = MySQLdb.connect(host="localhost", user="XX~XX", passwd="XX~XX",  db="XX~XX")

        except MySQLdb.OperationalError as e:
            if e.args[0] == 2002: # can't connect to server
                break

        sys.stdout.write('.')
        sys.stdout.flush()
        waitLoop = True

    if waitLoop : print ""


def blockTillMySQLRunning(connAttemptsMax = 10, sleepInterval = 1):
    waitLoop = False
    connAttempt = 1

    while(1):
        if connAttempt > connAttemptsMax:
            print ""
            # if we wait too long, we throw an exception    
            raise Exception("timed out testing for MySQL running check")
        try:
            connAttempt+=1
            time.sleep(sleepInterval)

            # we're just looking to see if the MySQL is running, a failed login attempt
            # will return a different error and we don't care about it
            db = MySQLdb.connect(host="localhost", user="XX~XX", passwd="XX~XX",  db="XX~XX")

        except MySQLdb.OperationalError as e:
            if e.args[0] == 2002: # when mysql is not running
                sys.stdout.write('.')
                sys.stdout.flush()
                waitLoop = True
                continue
        break

    if waitLoop : print ""


def restartWebServer():
# figure we do this enough for a function
	if hubzero.utilities.misc.isRHEL():
		serviceInit('httpd','restart')
	elif hubzero.utilities.misc.isDebian():
		serviceInit('apache2','restart')

# return the user and group for the web user
def webGroup():
    if hubzero.utilities.misc.isRHEL():
        return "apache"
    elif hubzero.utilities.misc.isDebian():
        return "www-data"

# return the user and group for the web user
def webUser():
    if hubzero.utilities.misc.isRHEL():
        return "apache"
    elif hubzero.utilities.misc.isDebian():
        return "www-data"

# return the apache config directory 
def apacheConfigDir():
    if hubzero.utilities.misc.isRHEL():
        return "/etc/httpd/"
    elif hubzero.utilities.misc.isDebian():
        return "/etc/apache2/"


def checkforroot():
    uid = os.geteuid()
    if uid != 0:
        print 'Script must be run with root privileges'
        exit(1)


def serviceInit(service, action = 'start'):

    serviceScript = '/etc/init.d/' + service

    print "checking " + serviceScript

    if not os.path.exists(serviceScript):
        print "missing " + serviceScript

    print serviceScript + " " + action

    try:
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand([serviceScript, action])
    except:
        print serviceScript + " " + action + " failed"
        return -1
    
    if rc : print procStdErr
    
    return rc


def generateAlphaNumPassword(length):
    random.seed(time.time())
    # we removed I, i, L, l, O, o, and 1 and 0 to avoid ambiguity in generated passwords
    pw = ''.join(random.choice("ABCDEFGHJKMNPQRSTUVWXYZ" + "abcdefghjkmnpqrstuvwxyz" + "23456789") for x in range(length-1)) + (random.choice("23456789"));	
    return pw


def createHubzeroSecretsFile(joomlaAdminPW, mySQLRootUserName, mySQLRootPW):

    secretsFilename = "/etc/hubzero.secrets"

    # grab what we can when its stored, everything else is stored as hash and needs to be passed in
    hubdbpw = hubzero.config.webconfig.getWebConfigDBPassword()
    ldapadminpw = hubzero.config.webconfig.getComponentParam("com_system", "ldap_managerpw")

    f = open(secretsFilename, "w")
    f.write("[DEFAULT]\n")
    #f.write("LDAP-ADMIN=" + ldapadminpw + "\n")
    #f.write("HUBREPO=" + hubrepopw + "\n")
    f.write("HUBDB=" + hubdbpw  + "\n")
    f.write("JOOMLA-ADMIN=" + joomlaAdminPW  + "\n")
    f.write("MYSQL-ROOT=" + mySQLRootPW  + "\n")
    f.write("MYSQL-ROOT-USER=" + mySQLRootUserName  + "\n")
    f.close()

    hubzero.utilities.misc.exShellCommand(['chmod', "0600", secretsFilename])


def createHubzeroConfigurationFile(hubname, docroot, uri = "", dbname = ""):
    print "creating " + hubzeroConfigFilePath

    # For some reason, default section of the ini files can only be created via the constructor
    defaults = {'site':hubname}
    config = ConfigParser.ConfigParser(defaults)
    config.optionxform = str

    config.add_section(hubname)
    config.set(hubname, "HubName", hubname)
    config.set(hubname, "documentroot", docroot)

    if uri: config.set(hubname, "uri", uri)
    if dbname: config.set(hubname, "dbname", dbname)

    cfgfile = open(hubzeroConfigFilePath, 'w')
    config.write(cfgfile)

    hubzero.utilities.misc.exShellCommand(['chown', '/etc/hubzero.conf', '0640'])


def deleteHubFromHubconfigFile(hubname):
    parser = ConfigParser.ConfigParser()
    parser.optionxform = str
    parser.read(hubzeroConfigFilePath)

    if parser.has_option(hubname, "documentroot"):

        parser.remove_section(hubname)

        # if this was the only hub, remove the file. If the removed hub was the default, reset the default hub
        if len(parser.sections()) < 1:
            os.remove(hubzeroConfigFilePath)
        else:

            #print (parser.sections())
            if parser.get("DEFAULT", "site") == hubname:
                newDefault = parser.sections()[0]
                parser.set("DEFAULT", "site", newDefault)

            cfgfile = open(hubzeroConfigFilePath, 'w')
            parser.write(cfgfile)


def insertHubIntoHubConfigFile(hubname, docroot, uri, dbname, makeSiteDefault = False):
    """
    config file /etc/hubzero.conf, a machine wide listing of hubs with the idea
    of supporting multiple hubs someday
    """

    changed = False

    print "checking " + hubzeroConfigFilePath

    if not os.path.exists(hubzeroConfigFilePath):
        createHubzeroConfigurationFile(hubname, docroot, uri, dbname)
    else:		
        parser = ConfigParser.RawConfigParser()
        parser.optionxform = str

        parser.read(hubzeroConfigFilePath)

        if not parser.has_section(hubname):
            changed = True
            parser.add_section(hubname)

        if not parser.has_option(hubname,'HubName') or parser.get(hubname,'HubName') != hubname:
            changed = True
            parser.set(hubname, "HubName", hubname)
        
        if not parser.has_option(hubname,'documentroot') or parser.get(hubname,'documentroot') != docroot:
            changed = True
            parser.set(hubname, "documentroot", docroot)

        if uri: 
            if not parser.has_option(hubname,'uri') or parser.get(hubname,'uri') != uri:
                changed = True
                parser.set(hubname, "uri", uri)

        if dbname: 
            if not parser.has_option(hubname,'dbname') or parser.get(hubname,'dbname') != dbname:
                changed = True
                parser.set(hubname, "dbname", dbname)

        if makeSiteDefault:
            if not parser.has_option("DEFAULT", 'site') or parser.get("DEFAULT",'site') != hubname:
                changed = True
                parser.set("DEFAULT", "site", hubname)

        if changed:
            print "updating " + hubzeroConfigFilePath
            cfgfile = open(hubzeroConfigFilePath, 'w')
            parser.write(cfgfile)


def modifyHubConfigFile(sectionName, fieldName, fieldValue):
    """
    Change a config value in the /etc/hubzero-cms/{hubname}.conf file for the specified section and field
    """
    hubname = hubzero.config.webconfig.getDefaultSite()

    configFilename = "/etc/hubzero-cms/" + hubname + ".conf"
    parser = ConfigParser.RawConfigParser()
    parser.optionxform = str

    parser.read(configFilename)

    # make sure section exists, if not add it
    if not parser.has_section(sectionName):
        parser.add_section(sectionName)

    if (fieldValue != None):
        parser.set(sectionName, fieldName, fieldValue)	
    else:
        parser.remove_option(sectionName, fieldName)

    cfgfile = open(configFilename, 'w')
    parser.write(cfgfile)


def copyCMSFiles(src, dest, fileOwner, fileGroup):
    print "copy_tree " + src + " " +  dest

    if os.path.isdir(src + "/core"):

        cmd = [ "/usr/bin/rsync", "-dptgox", src + "/", dest ]

        process = subprocess.Popen(cmd,
            stdout= subprocess.PIPE,
            stderr= subprocess.PIPE,
            shell = False)

        (stdout, stderr) = process.communicate()
    
        if process.returncode != 0:
            print "failed to copy  top level cms files"
            return 1

        cmd = [ "/usr/bin/rsync", "-rptgox", src + "/administrator", dest ]

        process = subprocess.Popen(cmd,
            stdout= subprocess.PIPE,
            stderr= subprocess.PIPE,
            shell = False)

        (stdout, stderr) = process.communicate()
    
        if process.returncode != 0:
            print "failed to copy administrator cms files"
            return 2

        cmd = [ "/usr/bin/rsync", "-rptgox", src + "/api", dest ]

        process = subprocess.Popen(cmd,
            stdout= subprocess.PIPE,
            stderr= subprocess.PIPE,
            shell = False)

        (stdout, stderr) = process.communicate()
    
        if process.returncode != 0:
            print "failed to copy api cms files"
            return 3

        cmd = [ "/usr/bin/rsync", "-rptgox", src + "/app", dest ]

        process = subprocess.Popen(cmd,
            stdout= subprocess.PIPE,
            stderr= subprocess.PIPE,
            shell = False)

        (stdout, stderr) = process.communicate()
    
        if process.returncode != 0:
            print "failed to copy app cms files"
            return 4

        cmd = [ "/usr/bin/rsync", "-rptgox", "--delete", src + "/core", dest ]

        process = subprocess.Popen(cmd,
            stdout= subprocess.PIPE,
            stderr= subprocess.PIPE,
            shell = False)

        (stdout, stderr) = process.communicate()
    
        if process.returncode != 0:
            print "failed to copy core cms files"
            return 5

    else:
        distutils.dir_util.copy_tree(src, dest)


    # recursive set permissions
    hubzero.utilities.misc.exShellCommand(['chown', '-R', fileOwner + '.' + fileGroup, dest])
    hubzero.utilities.misc.exShellCommand(['chmod', '-R', 'g+rw', dest])



def _setMySQLPW(args):
    setMySQLPW(args.username, args.pw)


def setMySQLPW(username, pw):
    print "setting MYSQL pw for user: " + username

    if os.path.exists('/etc/init.d/mysql'):
            mysql_service = "/etc/init.d/mysql"
    else:
            mysql_service = "/etc/init.d/mysqld"

    if os.path.exists('/var/run/mysqld/mysqld.pid'):
        os.system(mysql_service + " stop")

        # wait for mysql to stop
        blockTillMySQLStopped()
    else:
        # this could be first mysql start, if so we need a normal start to create the mysql database
        os.system(mysql_service + " start")
        blockTillMySQLRunning()

        # wait for mysql to stop
        os.system(mysql_service + " stop")
        blockTillMySQLStopped()

    # use subprocess to keep process around after it starts, use mysqld_safe to bypass security checks,
    # allows for password changes (especially for root) without having to know root's password
    subprocess.Popen(["/usr/bin/mysqld_safe", "--skip-grant-tables" , "--skip-networking"])

    # wait for mysql server to restart
    print "waiting for mysql to restart"
    blockTillMySQLRunning()

    # change password
    print "changing mysql password for " + username

    sql =  'use mysql; '
    sql += 'update user set password=PASSWORD("' + pw + '") where User="' + username + ' "; ';
    sql += 'flush privileges; '
    os.system('mysql -u root -e ' + "'" + sql + "'")

    # restart normal mysql server
    os.system(mysql_service + " stop")
    blockTillMySQLStopped()
    os.system(mysql_service + " start")
    blockTillMySQLRunning()




def createHubconfigurationPHPfile():
    """ Legacy, I know, but some things still use it """

    fileText = """<?php
class HubConfig {
 var $hubLDAPMasterHost = 'ldap://127.0.0.1';
 var $hubLDAPSlaveHosts = '';
 var $hubLDAPBaseDN = '%$hubLDAPBaseDN%';
 var $hubLDAPNegotiateTLS = '0';
 var $hubLDAPSearchUserDN = '%hubLDAPSearchUserDN%';
 var $hubLDAPSearchUserPW = '%hubLDAPSearchUserPW%';
 var $hubLDAPAcctMgrDN = '%hubLDAPAcctMgrDN%';
 var $hubLDAPAcctMgrPW = '%hubLDAPAcctMgrPW%';
 var $ipDBDriver = 'mysql';
 var $ipDBHost = '';
 var $ipDBPort = '';
 var $ipDBUsername = '';
 var $ipDBPassword = '';
 var $ipDBDatabase = '';
 var $ipDBPrefix = '';
 var $hubShortName = '%HUBNAME%';
 var $forgeName = '%HUBNAME% Forge';
 var $forgeURL = 'https://%HOSTNAME%';
 var $forgeRepoURL = 'https://%HOSTNAME%';
 var $svn_user = 'hubrepo';
 var $svn_password = '%FORGEPW%';
 var $hubzero_ipgeo_url = 'http://hubzero.org/ipinfo/v1';
 var $hubzero_ipgeo_key = '_HUBZERO_OPNSRC_V1_';
}
?>"""


    hubname = hubzero.config.webconfig.getDefaultSite()
    docroot = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")
    
    filePath = docroot + "/hubconfiguration.php"

    print "creating: " + filePath

    # get hubrepo password from hubzero.secrets file, if file is not there, it's blank
    hubzeroSecretsFilename = "/etc/hubzero.secrets"
    if os.path.exists(hubzeroSecretsFilename):
        secretsConfig = ConfigParser.ConfigParser()
        secretsConfig.optionxform = str
        f1 = open(hubzeroSecretsFilename, "r")
        secretsConfig.readfp(f1)
        f1.close()

        if secretsConfig.has_option("DEFAULT", "HUBREPO"):
            forgePW = secretsConfig.get("DEFAULT", "HUBREPO")
        else:
            forgePW = ""
    else:
        forgePW = ""

    hubLDAPAcctMgrDN = hubzero.config.webconfig.getComponentParam("com_system", "ldap_managerdn")
    hubLDAPAcctMgrPW = hubzero.config.webconfig.getComponentParam("com_system", "ldap_managerpw")
    hubLDAPBaseDN = hubzero.config.webconfig.getComponentParam("com_system", "ldap_basedn")	
    hubLDAPSearchUserDN = hubzero.config.webconfig.getComponentParam("com_system", "ldap_searchdn")	
    hubLDAPSearchUserPW = hubzero.config.webconfig.getComponentParam("com_system", "ldap_searchpw")	

    hostname = gethostname()

    fileText = fileText.replace("%$hubLDAPBaseDN%", hubLDAPBaseDN)
    fileText = fileText.replace("%hubLDAPAcctMgrDN%", hubLDAPAcctMgrDN)
    fileText = fileText.replace("%hubLDAPAcctMgrPW%", hubLDAPAcctMgrPW)
    fileText = fileText.replace("%HOSTNAME%", hostname)
    fileText = fileText.replace("%FORGEPW%", forgePW)
    fileText = fileText.replace("%HUBNAME%", hubname)
    fileText = fileText.replace("%hubLDAPSearchUserDN%", hubLDAPSearchUserDN)
    fileText = fileText.replace("%hubLDAPSearchUserPW%", hubLDAPSearchUserPW)

    f1 = open(filePath, "w")
    f1.write(fileText)

    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chown", webUser() + ":" + webGroup(), filePath])	
    if rc: print procStdErr

    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chmod", "0644", filePath])	
    if rc: print procStdErr



def createHubConfigFile(hubname):
    """home
    config file /etc/hubzero-cms/{hubname}.conf 
    """

    print "creating /etc/hubzero-cms/" + args.hubname + ".conf"

    createDir("/etc/hubzero-cms/", "0755", "root", "root", resetattrs=True)
    createDir("/etc/hubzero-cms/" + hubname + "/", "0755", "root", "root", resetattrs=True)

    # For some reason, DEFAULT section of the ini files can only be created via the constructor
    defaults = {}
    config = ConfigParser.ConfigParser(defaults)
    config.optionxform = str

    config.add_section("global")
    config.set("global", "name", hubname)

    config.add_section("apache-config")
    config.set("apache-config", "document_root", "/var/www/" + hubname)
    config.set("apache-config", "force_canon", "false")
    config.set("apache-config", "enable_webdav", "false")
    config.set("apache-config", "enable_filexfer", "false")
    config.set("apache-config", "enable_subversion", "false")
    config.set("apache-config", "enable_trac", "false")
    config.set("apache-config", "enable_vncproxy", "false")

    config.add_section("mw")
    config.add_section("package-config")

    filename = "/etc/hubzero-cms/" + hubname + ".conf"
    cfgfile = open(filename, 'w')
    config.write(cfgfile)

    hubzero.utilities.misc.exShellCommand(['chmod', filename, '0644'])


def deleteHubConfigFile(hubname):
    pass


def createFile(filename, mode=-1, owner=-1, group=-1, resetattrs=False, verbose=True):
    try:
        ownerUid = int(owner,0)
        if ownerUid == -1:
            owner = "-1"
        else:
            owner = pwd.getpwuid(ownerUid).pw_name
    except ValueError:
        ownerUid = pwd.getpwnam(owner).pw_uid

    try:
        ownerGid = int(group,0)
        if ownerGid == -1:
            group = "-1"
        else:
            group = grp.getgrid(ownerGid).gr_name
    except ValueError:
        ownerGid = grp.getgrnam(group).gr_gid

    if isinstance(mode,basestring):
        if mode.startswith('0'):

            nmode = int(mode,0)
        else:
            nmode = int(mode,8)
    else:
        nmode = mode

    if verbose:
        print "checking " + filename

    if not os.path.exists(filename):
        if verbose:
           print "creating " + filename
        open(filename,"a").close()
        resetattrs = True

    if (resetattrs):
        st = os.stat(filename)

        if ownerGid != -1 and ownerUid != -1 and ownerGid != st.st_gid and ownerUid != st.st_uid:
            if verbose:
                print "chown " +  owner + ":" + group + " " + filename
            os.chown(filename, ownerUid, ownerGid)
        elif ownerUid != -1 and ownerUid != st.st_uid:
            if verbose:
                print "chown " +  owner + " " + filename
            os.chown(filename, ownerUid, -1)
        elif ownerGid != -1 and ownerGid != st.st_gid:
            if verbose:
                print "chown " + ":" + group + " " + filename
            os.chown(filename, -1, ownerGid)

        if nmode != -1 and stat.S_IMODE(st.st_mode) != nmode:
            if verbose:
                print "chmod %#o" % nmode + " " + filename
            os.chmod(filename, nmode)


def createDir(dirName, mode=-1, owner=-1, group=-1, resetattrs=False, verbose=True):
    try:
        if isinstance(owner, (int,long)):
            ownerUid = owner
        else:
            ownerUid = int(owner,0)
        if ownerUid == -1:
            owner = "-1"
        else:
            owner = pwd.getpwuid(ownerUid).pw_name
    except ValueError:
        ownerUid = pwd.getpwnam(owner).pw_uid

    try:
        if isinstance(group, (int,long)):
            ownerGid = group
        else:
            ownerGid = int(group,0)
        if ownerGid == -1:
            group = "-1"
        else:
            group = grp.getgrgid(ownerGid).gr_name
    except ValueError:
        ownerGid = grp.getgrnam(group).gr_gid

    if isinstance(mode,basestring):
        if mode.startswith('0'):
            nmode = int(mode,0)
        else:
            nmode = int(mode,8)
    else:
        nmode = mode

    if verbose:
        print "checking " + dirName

    if not os.path.exists(dirName):
        if verbose:
           print "mkdir " + dirName
        os.mkdir(dirName)
        resetattrs = True
    
    if (resetattrs):
        st = os.stat(dirName)

        if ownerGid != -1 and ownerUid != -1 and ownerGid != st.st_gid and ownerUid != st.st_uid:
            if verbose:
                print "chown " +  owner + ":" + group + " " + dirName
            os.chown(dirName, ownerUid, ownerGid)
        elif ownerUid != -1 and ownerUid != st.st_uid:
            if verbose:
                print "chown " +  owner + " " + dirName
            os.chown(dirName, ownerUid, -1)
        elif ownerGid != -1 and ownerGid != st.st_gid:
            if verbose:
                print "chown " + ":" + group + " " + dirName
            os.chown(dirName, -1, ownerGid)

        if nmode != -1 and stat.S_IMODE(st.st_mode) != nmode:
            if verbose:
                print "chmod %#o" % nmode + " " + dirName
            os.chmod(dirName, nmode)


def fixPhpBinary():

    print "checking for alternate php binary"

    if os.path.exists('/opt/rh/php54/root/usr/bin/php'):
        if not os.path.exists('/usr/bin/php'):
            print "ln -s /opt/rh/php54/root/usr/bin/php /usr/bin/php"
            os.symlink('/opt/rh/php54/root/usr/bin/php', '/usr/bin/php')


def initPhpErrorLog(logfile = '/var/log/php/error.log', forceChange = False):

    if os.path.exists('/etc/php5/apache2/php.ini'):
        filename = '/etc/php5/apache2/php.ini'
    elif os.path.exists('/opt/rh/php54/root/etc/php.ini'):
        filename = '/opt/rh/php54/root/etc/php.ini'
    elif os.path.exists('/etc/php.ini'):
        filename = '/etc/php.ini'

    configtxt = ''

    if os.path.exists(filename):
        fh = open(filename, 'r+')
        configtxt = fh.read()
    else:
        return True

    if (not forceChange):
        m = re.search(r'(?im)^\s*error_log\s*=\s*(.*)\s*$', configtxt)

        if (m != None):
            logfile = m.group(1)

    (txt, n) = re.subn(r'(?im)^\s*error_log\s*=\s*(.*)\s*$', 'error_log = ' + logfile + "\n", configtxt)

    if (n == 0):
        (txt, n) = re.subn(r'(?im)^\s*;\s*error_log\s*=\s*(.*)\s*$', 'error_log = ' + logfile + "\n", configtxt, 1)

    if (n == 0):
        txt = configtxt.rstrip() + "\n" + "error_log = " + logfile + "\n"

    if (txt != configtxt):
        fh.seek(0)
        fh.write(txt)
        fh.truncate()
        print "patched " + filename
        serviceInit('apache2','restart')

    fh.close()

    createDir(os.path.dirname(logfile), "0750", "root", webGroup(), resetattrs=True)
    createFile(logfile, "0750", webUser(), webGroup(), resetattrs=True)

    return True

def checkDirectories(docroot, webServerUser, webServerGroup):
    createDir("/etc/hubzero-cms/", "0775", "root", "root", resetattrs=True)

    createDir("/var/log/hubzero", "02750", webServerUser, webServerGroup, resetattrs=True)
    createDir("/var/log/hubzero/daily", "0750", webServerUser, webServerGroup, resetattrs=True)
    createDir("/var/log/hubzero/imported", "02750", webServerUser, webServerGroup, resetattrs=True)
    createDir("/var/log/hubzero/archive", "0750", webServerUser, webServerGroup, resetattrs=True)

    createDir("/var/log/hubzero-cms", "0775", "root", webServerGroup, resetattrs=True)
    createDir("/var/log/hubzero-cms/daily", "0770", "root", webServerGroup, resetattrs=True)
    createDir("/var/log/hubzero-cms/daily/imported", "0770", "root", webServerGroup, resetattrs=True)
    createDir("/var/log/hubzero-cms/archive", "0770", "root", webServerGroup, resetattrs=True)

    if os.path.exists('/usr/sbin/apache2'):
        createDir("/var/log/apache2", "0750", "root", "adm", resetattrs=True)
        createDir("/var/log/apache2/daily", "0750", "root", "adm", resetattrs=True)
        createDir("/var/log/apache2/imported", "0750", "root", "adm", resetattrs=True)
        createDir("/var/log/apache2/archive", "0750", "root", "adm", resetattrs=True)

    if os.path.exists('/usr/sbin/httpd'):
        createDir("/var/log/httpd", "0750", "root", "adm", resetattrs=True)
        createDir("/var/log/httpd/daily", "0750", "root", "adm", resetattrs=True)
        createDir("/var/log/httpd/imported", "0750", "root", "adm", resetattrs=True)
        createDir("/var/log/httpd/archive", "0750", "root", "adm", resetattrs=True)

    createDir(docroot, "0775", webServerUser, webServerGroup, resetattrs=True)

def checkConfigurationPhp(docroot, verbose=True):

    filename = docroot + "/configuration.php"

    if verbose:
        print "checking " + filename

    st = os.stat(filename)

    if (st.st_mode & stat.S_IROTH):
        if verbose:
            print "chmod %#o" % (st.st_mode & ~stat.S_IROTH) + " " + filename

        os.chmod(filename,st.st_mode&~stat.S_IROTH)


def m4Processing(inputFileName, outputFileName, m4ArgsArray, mode=-1, owner=-1, group=-1, resetattrs=False, verbose=True):
    rc = False

    try:
        ownerUid = int(owner)
        if ownerUid == -1:
            owner = "-1"
        else:
            owner = pwd.getpwuid(ownerUid).pw_name
    except ValueError:
        ownerUid = pwd.getpwnam(owner).pw_uid

    try:
        groupGid = int(group)
        if groupGid == -1:
            group = "-1"
        else: 
            group = grp.getgrgid(groupGid).gr_name
    except ValueError:
        ownerGid = grp.getgrnam(group).gr_gid

    if isinstance(mode,basestring):
        if mode.startswith('0'):
            nmode = int(mode,0)
        else:
            nmode = int(mode,8)
    else:
        nmode = mode

    filename = outputFileName

    if verbose:
        print "checking " + outputFileName

    commandArgsArray = ["m4"] + m4ArgsArray + [inputFileName]
    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(commandArgsArray)

    configtxt = ''

    if os.path.exists(filename):
        f = open(filename, 'r')
        configtxt = f.read()
        f.close()
    else:
        resetattrs = True

    if (configtxt != procStdOut):
	
        if (verbose):
            print "m4 " + inputFileName
        f = open(filename, 'w')
        f.write(procStdOut)
        f.close()
        rc = True

    if (resetattrs):
        st = os.stat(filename)

        if ownerGid != -1 and ownerUid != -1 and ownerGid != st.st_gid and ownerUid != st.st_uid:
            if verbose:
                print "chown " +  owner + ":" + group + " " + filename
            os.chown(filename, ownerUid, ownerGid)
        elif ownerUid != -1 and ownerUid != st.st_uid:
            if verbose:
                print "chown " +  owner + " " + filename
            os.chown(filename, ownerUid, -1)
        elif ownerGid != -1 and ownerGid != st.st_gid:
            if verbose:
                print "chown " + ":" + group + " " + filename
            os.chown(filename, -1, ownerGid)

        if nmode != -1 and stat.S_IMODE(st.st_mode) != nmode:
            if verbose:
                print "chmod %#o" % nmode + " " + filename
            os.chmod(filename, nmode)

    return rc


def _mySQLDatabaseSetup(args):

    dbPW, mysqlRootPW = mySQLDatabaseSetup(args.dbname, 'localhost', dist)

    loadSQLSchema(args.dbname, "localhost", args.dbname, args.dbname, dbPW, "jos_")
    loadSQLTableData(args.dbname, "localhost", args.dbname, args.dbname, dbPW, "jos_")


def mySQLDatabaseSetup(dbName, host, dist, dbPW = '', dbRootPW=''):
    """
    dbName - name of new database
    host - database host
    dbRootPW - pw for the DB root user
    Dist - distribution - Deb/RH

    """
    if not dbPW:
        dbPW = generateAlphaNumPassword(14)

    print "creating mySQL databases"

    if dist == DIST_DEB:

        # Creating primary database
        print "creating database: " + dbName
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(
            ["/usr/bin/mysql",
            "--defaults-file=/etc/mysql/debian.cnf",
            "-e", "CREATE DATABASE " + dbName])

        if procStdOut: print procStdOut.strip()
        if rc : print procStdErr

        # metrics database
        print "creating database: " + dbName + "-metrics"
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(
            ["/usr/bin/mysql",
            "--defaults-file=/etc/mysql/debian.cnf",
            "-e", "CREATE DATABASE " + dbName + "_metrics"])

        if procStdOut: print procStdOut.strip()
        if rc : print procStdErr

        # Create user with full permissions
        print "creating database user: " + dbName
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(
            ["/usr/bin/mysql",
            "--defaults-file=/etc/mysql/debian.cnf",
            "-e", "GRANT ALL PRIVILEGES ON " + dbName + ".* TO " + dbName + "@localhost"])

        if procStdOut: print procStdOut.strip()
        if rc : print procStdErr

        # Set that user's password
        print "setting database password for user: " + dbName
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(
            ["/usr/bin/mysql",
            "--defaults-file=/etc/mysql/debian.cnf",
            "-e", "SET PASSWORD FOR " + dbName + "@localhost = PASSWORD('" + dbPW + "'); flush privileges;"])

        if procStdOut: print procStdOut.strip()
        if rc : print procStdErr

    elif dist == DIST_RH:

        # create hub database
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(
            ["/usr/bin/mysql",
            "-u", "root", "-p" + dbRootPW,
            "-e", "CREATE DATABASE " + dbName])

        if procStdOut: print procStdOut.strip()
        if rc : print procStdErr

        # metrics database
        print "creating database: " + dbName + "-metrics"
        if dist == DIST_DEB:
            rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(
                ["/usr/bin/mysql",
                "-u", "root", "-p" + dbRootPW,
                "-e", "CREATE DATABASE " + dbName + "_metrics"])

        if procStdOut: print procStdOut.strip()
        if rc : print procStdErr

        # Create db user with full permissions over the new database
        # Note: user name matches database name
        print "creating database user: " + dbName
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand([
            "/usr/bin/mysql",
            "-u", "root", "-p" + dbRootPW,
            "-e", "GRANT ALL PRIVILEGES ON " + dbName + ".* TO " + dbName + "@localhost"])

        if procStdOut: print procStdOut.strip()
        if rc : print procStdErr

        # Set that user's password
        print "setting database password for user: " + dbName
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(
            ["/usr/bin/mysql",
            "-u", "root", "-p" + dbRootPW,
            "-e", "SET PASSWORD FOR " + dbName + "@localhost = PASSWORD('" + dbPW + "'); flush privileges;"])

        if procStdOut: print procStdOut.strip()
        if rc : print procStdErr

    else:
        raise Exception("mySQLDatabaseSetup error, unknown dist: " + dist)

    return dbPW


def generateLogrotateFiles(hubname):

    m4ConfigOptions = []

    try:
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(
            ["/usr/bin/strings", "/usr/sbin/logrotate" ] )

        if rc : print procStdErr
    except:
	raise

    if 'because parent directory has insecure' in procStdOut:
        m4ConfigOptions.append("-DUSE_SU")

    m4ConfigOptions.append("-DHUBNAME=" + hubname)

    sfilename = HUBZERO_CMS_DIR + "/conf/logrotate-cmsdebug.m4"

    if os.path.exists(sfilename):
        tfilename = "/etc/logrotate.d/" + hubname + "-cmsdebug"
        m4Processing(sfilename, tfilename, m4ConfigOptions, 0644, "root", "root", resetattrs=True, verbose=True)	

    sfilename = HUBZERO_CMS_DIR + "/conf/logrotate-cmsauth.m4"

    if os.path.exists(sfilename):
        tfilename = "/etc/logrotate.d/" + hubname + "-cmsauth"
        m4Processing(sfilename, tfilename, m4ConfigOptions, 0644, "root", "root", resetattrs=True, verbose=True)	

    sfilename = HUBZERO_CMS_DIR + "/conf/logrotate-cmsprofile.m4"

    if os.path.exists(sfilename):
        tfilename = "/etc/logrotate.d/" + hubname + "-cmsprofile"
        m4Processing(sfilename, tfilename, m4ConfigOptions, 0644, "root", "root", resetattrs=True, verbose=True)	

    sfilename = HUBZERO_CMS_DIR + "/conf/logrotate-hub-access.m4"

    if os.path.exists(sfilename):
        tfilename = "/etc/logrotate.d/" + hubname + "-access"
        m4Processing(sfilename, tfilename, m4ConfigOptions, 0644, "root", "root", resetattrs=True, verbose=True)	

    sfilename = HUBZERO_CMS_DIR + "/conf/logrotate-hub-error.m4"

    if os.path.exists(sfilename):
        tfilename = "/etc/logrotate.d/" + hubname + "-error"
        m4Processing(sfilename, tfilename, ["-DHUBNAME=" + hubname], 0644, "root", "root", resetattrs=True, verbose=True)	

    if os.path.exists('/etc/logrotate.d/apache2'):
        try:
            pattern1 = r'(?im)^\s*/var/log/apache2/\*.log\s+{\s*$'
            repl1 = r'/var/log/apache2/access.log /var/log/apache2/ssl_access.log /var/log/apache2/error.log /var/log/apache2/other_vhosts_access.log {'

            apache2lr = "/etc/logrotate.d/apache2"
            print "checking " + apache2lr
            apache2lrfh = open(apache2lr,'r+')
            apache2lrtxt = apache2lrfh.read()
            txt = re.sub(pattern1, repl1, apache2lrtxt)
            if (txt != apache2lrtxt):
                apache2lrfh.seek(0)
                apache2lrfh.write(txt)
                apache2lrfh.truncate()
                print "patched " + apache2lr
            apache2lrfh.close()
        except:
            print "Failed to patch file " + apache2lr
            pass

    if os.path.exists('/etc/logrotate.d/httpd'):
        try:
            pattern1 = r'(?im)^\s*/var/log/httpd/\*log\s+{\s*$'
            repl1 = r'/var/log/httpd/access_log /var/log/httpd/ssl_access_log /var/log/httpd/error_log /var/log/httpd/ssl_error_log /var/log/httpd/ssl_request_log {'

            apache2lr = "/etc/logrotate.d/httpd"
            print "checking " + apache2lr
            apache2lrfh = open(apache2lr,'r+')
            apache2lrtxt = apache2lrfh.read()
            txt = re.sub(pattern1, repl1, apache2lrtxt)
            if (txt != apache2lrtxt):
                apache2lrfh.seek(0)
                apache2lrfh.write(txt)
                apache2lrfh.truncate()
                print "patched " + apache2lr
            apache2lrfh.close()
        except:
            print "Failed to patch file " + apache2lr
            pass


def generateApacheConfFiles(hubname, dist):

    m4dir = apacheConfigDir() + "sites-m4/"
    print "m4 processing to " + m4dir

    if not os.path.exists(m4dir):
            print "creating " + m4dir
            createDir(m4dir, "0755", "root", "root")

    print "cp /usr/share/hubzero-cms/conf/hub.m4 " + m4dir + hubname + ".m4"
    hubzero.utilities.misc.exShellCommand(["cp", HUBZERO_CMS_DIR + "/conf/hub.m4", m4dir + hubname + ".m4"])
    hubzero.utilities.misc.exShellCommand(['chmod', "'", m4dir + hubname + ".m4"])
    hubzero.utilities.misc.exShellCommand(['chown', "root.root", m4dir + hubname + ".m4"])

    print "cp /usr/share/hubzero-cms/conf/hub-ssl.m4 " + m4dir + hubname + "-ssl.m4"
    hubzero.utilities.misc.exShellCommand(["cp", HUBZERO_CMS_DIR + "/conf/hub-ssl.m4", m4dir + hubname + "-ssl.m4"])
    hubzero.utilities.misc.exShellCommand(['chmod', "0644", m4dir + hubname + "-ssl.m4"])
    hubzero.utilities.misc.exShellCommand(['chown', "root.root", m4dir + hubname + "-ssl.m4"])

    # do the M4 processing
    generateApacheM4config(hubname)

    if dist == DIST_RH and os.path.exists("/etc/httpd/conf.d/ssl.conf"):
        os.remove("/etc/httpd/conf.d/ssl.conf")


def generateApacheM4config(hubname):

    generatedM4File = False

    # Read the options from the /etc/hubzero-cms/{HUBNAME}.conf file to see what to enable in our apache config
    hubzeroCMSConfig = ConfigParser.ConfigParser()
    hubzeroCMSConfig.optionxform = str
    hubzeroCMSConfig.readfp(open("/etc/hubzero-cms/" + hubname + ".conf"))

    m4ApacheConfigOptions = []

    fqdn = gethostname()
    m4ApacheConfigOptions.append("-DFQDN=" + fqdn)

    m4ApacheConfigOptions.append("-DHUBNAME=" + hubname)

    if hubzeroCMSConfig.get("apache-config", "force_canon").lower() == "true":
        m4ApacheConfigOptions.append("-DUSE_CANONICAL_HOSTNAME")

    if hubzeroCMSConfig.get("apache-config", "enable_webdav").lower() == "true":
        m4ApacheConfigOptions.append("-DUSE_WEBDAV")

    if hubzeroCMSConfig.get("apache-config", "enable_filexfer").lower() == "true":
        m4ApacheConfigOptions.append("-DUSE_FILEXFER")

    if hubzeroCMSConfig.get("apache-config", "enable_subversion").lower() == "true":
        m4ApacheConfigOptions.append("-DUSE_SUBVERSION")

    if hubzeroCMSConfig.get("apache-config", "enable_trac").lower() == "true":
        m4ApacheConfigOptions.append("-DUSE_TRAC")

    if hubzeroCMSConfig.get("apache-config", "enable_vncproxy").lower() == "true":

        dbPW = hubzero.config.webconfig.getWebConfigDBPassword()
        dbUserName = hubzero.config.webconfig.getWebConfigDBUsername()
        dbName = hubzero.config.webconfig.getWebConfigDBName()
        dbHost = hubzero.config.webconfig.getWebConfigOption("host")

        if dbHost: m4ApacheConfigOptions.append("-DDBHOST=" + dbHost)
        if dbUserName: m4ApacheConfigOptions.append("-DDBUSER=" + dbUserName)
        if dbPW: m4ApacheConfigOptions.append("-DDBPASS=" + dbPW)
        if dbName: m4ApacheConfigOptions.append("-DDBNAME=" + dbName)

        m4ApacheConfigOptions.append("-DUSE_VNCPROXY")

    basedn = hubLDAPBaseDN = hubzero.config.webconfig.getComponentParam("com_system", "ldap_basedn")
    if basedn: m4ApacheConfigOptions.append("-DBASEDN=" + basedn)

    ldap_searchdn = hubLDAPBaseDN = hubzero.config.webconfig.getComponentParam("com_system", "ldap_searchdn")
    if ldap_searchdn : m4ApacheConfigOptions.append("-DSEARCHDN=" + ldap_searchdn)

    ldap_searchpw = hubLDAPBaseDN = hubzero.config.webconfig.getComponentParam("com_system", "ldap_searchpw")
    if ldap_searchpw: m4ApacheConfigOptions.append("-DSEARCHPW=" + ldap_searchpw)

    if hubzero.utilities.misc.isDebian():

        # log file location in debian
        m4ApacheConfigOptions.append("-DWEBLOGFILEROOT=${APACHE_LOG_DIR}")

        m4ApacheConfigOptions.append("-DSSLCERTFILE=/etc/ssl/certs/ssl-cert-snakeoil.pem")
        m4ApacheConfigOptions.append("-DSSLCERTKEYFILE=/etc/ssl/private/ssl-cert-snakeoil.key")
        m4ApacheConfigOptions.append("-DTRACROOT=/usr/share/pyshared/")
        m4ApacheConfigOptions.append("-DAPACHE_HOME=apache2")
        m4ApacheConfigOptions.append("-DDISTDEB=1")

        if not os.path.exists(apacheConfigDir() + "/sites-m4"):
            print apacheConfigDir() + "/sites-m4 doesn't exist, skipping m4 reconfiguration"
        else:
            #print "processing " + apacheConfigDir() + "/sites-m4/" + hubname + ".m4 to " + apacheConfigDir() + "/sites-available/" + hubname
            m4Processing(apacheConfigDir() + "/sites-m4/" + hubname + ".m4",
                         apacheConfigDir() + "/sites-available/" + hubname,
                         m4ApacheConfigOptions,
                         0644, "root", "root")

            #print "processing " + apacheConfigDir() + "/sites-m4/" + hubname + "-ssl.m4 to " + apacheConfigDir() + "/sites-available/" + hubname + "-ssl"
            m4Processing(apacheConfigDir() + "/sites-m4/" + hubname + "-ssl.m4",
                         apacheConfigDir() + "/sites-available/" + hubname + "-ssl",
                         m4ApacheConfigOptions,
                         0644, "root", "root")

            generatedM4File = True

    elif hubzero.utilities.misc.isRHEL():

        # log file location in rh, logs is a symbolic link to /var/log/httpd
        m4ApacheConfigOptions.append("-DWEBLOGFILEROOT=logs")

        m4ApacheConfigOptions.append("-DSSLCERTFILE=/etc/ssl/certs/ssl-cert-snakeoil.pem")
        m4ApacheConfigOptions.append("-DSSLCERTKEYFILE=/etc/ssl/certs/private/ssl-cert-snakeoil.key")
        m4ApacheConfigOptions.append("-DTRACROOT=/usr/lib/python%d.%d/site-packages/" % (sys.version_info[0], sys.version_info[1]))
        m4ApacheConfigOptions.append("-DAPACHE_HOME=httpd")
        m4ApacheConfigOptions.append("-DDISTRH=1")

        if not os.path.exists("/etc/httpd/sites-m4"):
            print "/etc/httpd/sites-m4 doesn't exist, skipping m4 reconfiguration"
        else:
            #print "processing /etc/httpd/sites-m4/" + hubname + ".m4 to /etc/httpd/conf.d/" + hubname + ".conf"
            m4Processing("/etc/httpd/sites-m4/" + hubname + ".m4",
                         "/etc/httpd/conf.d/" + hubname + ".conf",
                         m4ApacheConfigOptions,
                         0644, "root", "root")

            #print "processing /etc/httpd/sites-m4/" + hubname + "-ssl.m4 to /etc/httpd/conf.d/" + hubname + "-ssl.conf"
            m4Processing("/etc/httpd/sites-m4/" + hubname + "-ssl.m4",
                         "/etc/httpd/conf.d/" + hubname + "-ssl.conf",
                         m4ApacheConfigOptions,
                         0644, "root", "root")

            generatedM4File = True

    else:
        print "generateApacheM4config error, unrecognized Linux distribution "

    return generatedM4File


def replacePrefix(sql, prefix = '#__', tablePrefix = 'jos_'):
    # Initialize variables.
    escaped = False
    startPos = 0
    quoteChar = ''
    literal = ''

    sql = sql.strip()
    n = len(sql)

    while (startPos < n):
        ip = sql.find(prefix, startPos)

        if (ip == -1):
            break
    
        j = sql.find("'", startPos)

        k = sql.find('"', startPos)

        if ((k != -1) and ((k < j) or (j == -1))):
            quoteChar = '"'
            j = k
        else:
            quoteChar = "'"

        if (j == -1):
            j = n

        sub = sql[startPos:j]

        literal += sub.replace(prefix, tablePrefix)

        startPos = j

        j = startPos + 1

        if (j >= n):
            break

        # quote comes first, find end of quote
        while (True):
            k = sql.find(quoteChar, j)

            escaped = False

            if (k == -1):
                break

            l = k - 1

            while (l >= 0 and sql[l] == '\\'):
                l = l - 1
                escaped = not escaped

            if (escaped):
                j = k + 1
                continue

            break

        if (k == -1):
            # error in the query - no end quote; ignore it
            break

        sub = sql[startPos:(k+1)]
        literal += sub
        startPos = k + 1

    if (startPos < n):
        sub = sql[startPos:n]
        literal += sub
    
    return literal

def loadSQLSchema(hubname, dbHost, dbName, dbUserName, dbPW, dbTablePrefix = 'jos_'):
    """
    Load the hubzero schema sql and execute. Logic parses the file into individual statements
    """

    if hubzero.utilities.misc.JOOMLA_25:

        if "hubzero-cms-2.0.0" in HUBZERO_CMS_DIR:
            dbsqlfile = open(HUBZERO_CMS_DIR + "/cms/core/bootstrap/install/sql/mysql/joomla.sql", "r")
        elif "hubzero-cms-2.1.0" in HUBZERO_CMS_DIR:
            dbsqlfile = open(HUBZERO_CMS_DIR + "/cms/core/bootstrap/install/sql/mysql/joomla.sql", "r")
        else:
            dbsqlfile = open(HUBZERO_CMS_DIR + "/cms/installation/sql/mysql/joomla.sql", "r")

        dbsql = dbsqlfile.read()

        # split file into individual statementsstatements
        dbsql = re.sub("\n\#[^\n]*", "", "\n" + dbsql)

        sqlSplitter = re.compile("\n\n", re.MULTILINE)
        sqlStatements = sqlSplitter.split(dbsql)

        # execute each statement separately
        db = hubzero.data.db.MySQLConnection(dbHost, dbName, dbUserName, dbPW)
        for sqlStatement in sqlStatements:
            if sqlStatement.strip() != "" :
                #sqlStatement = string.replace(sqlStatement, "#__", dbTablePrefix)
                sqlStatement = replacePrefix(sqlStatement, "#__", dbTablePrefix)
                db.query_rowcount(sqlStatement, None)


    if "hubzero-cms-2.0.0" in HUBZERO_CMS_DIR:
        dbsqlfile = open(HUBZERO_CMS_DIR + "/cms/core/bootstrap/install/sql/mysql/hubzero.sql", "r")
    elif "hubzero-cms-2.1.0" in HUBZERO_CMS_DIR:
        dbsqlfile = open(HUBZERO_CMS_DIR + "/cms/core/bootstrap/install/sql/mysql/hubzero.sql", "r")
    else:
        dbsqlfile = open(HUBZERO_CMS_DIR + "/cms/installation/sql/mysql/hubzero.sql", "r")

    dbsql = dbsqlfile.read()

    # split file into individual statementsstatements
    dbsql = re.sub("\n\#[^\n]*", "", "\n" + dbsql)

    sqlSplitter = re.compile("\n\n", re.MULTILINE)
    sqlStatements = sqlSplitter.split(dbsql)

    # execute each statement separately
    db = hubzero.data.db.MySQLConnection(dbHost, dbName, dbUserName, dbPW)
    for sqlStatement in sqlStatements:

        try:
                if sqlStatement.strip() != "" :
                    #sqlStatement = string.replace(sqlStatement, "#__", dbTablePrefix)
                    sqlStatement = replacePrefix(sqlStatement, "#__", dbTablePrefix)
                    db.query_rowcount(sqlStatement, None)
        except Exception as e:
                # print out the problem, but don't stop
                print "SQL schema import exception" + str(e)


def loadSQLTableData(hubname, dbHost, dbName, dbUserName, dbPW, dbTablePrefix = 'jos_'):
    """
    Load the hubzero sample data
    """

    if "hubzero-cms-2.0.0" in HUBZERO_CMS_DIR:
        dbsqlfile = open(HUBZERO_CMS_DIR + "/cms/core/bootstrap/install/sql/mysql/hz_sample_data.sql", "r")
    elif "hubzero-cms-2.1.0" in HUBZERO_CMS_DIR:
        dbsqlfile = open(HUBZERO_CMS_DIR + "/cms/core/bootstrap/install/sql/mysql/hz_sample_data.sql", "r")
    else:
        dbsqlfile = open(HUBZERO_CMS_DIR + "/cms/installation/sql/mysql/hz_sample_data.sql", "r")

    dbsql = dbsqlfile.read()

    # split file into individual statementsstatements
    dbsql = re.sub("\n\#[^\n]*", "", "\n" + dbsql)

    sqlSplitter = re.compile("\n\n", re.MULTILINE)
    sqlStatements = sqlSplitter.split(dbsql)

    # execute each statement separately
    db = hubzero.data.db.MySQLConnection(dbHost, dbName, dbUserName, dbPW)	
    for sqlStatement in sqlStatements:
        if sqlStatement.strip() != "" :
            #sqlStatement = string.replace(sqlStatement, "#__", dbTablePrefix)
            sqlStatement = replacePrefix(sqlStatement, "#__", dbTablePrefix)
            db.query_rowcount(sqlStatement, None)



def createPHPConfigurationFile(hubname, docroot, dbName, dbPW, dbTablePrefix, siteAdminEmail, siteAdminName, mailFrom, installKey, fileOwner, fileGroup):
    """
    Take the template and do all the needed replacements and write file to disk

    TODO: The template file moved in 2.0, and 2.0 uses an entirely different config file setup.
    Technically, we should rewrite this whole function to produce the 2.0 config files
    but 2.0 automatically checks for the old config file and generates the new onces for us

    """

    if "hubzero-cms-2.0.0" in HUBZERO_CMS_DIR:
        configfilepath = HUBZERO_CMS_DIR + "/cms/core/bootstrap/tmpl/configuration.html"
    elif "hubzero-cms-2.1.0" in HUBZERO_CMS_DIR:
        configfilepath = HUBZERO_CMS_DIR + "/cms/core/bootstrap/tmpl/configuration.html"
    else:
        configfilepath = HUBZERO_CMS_DIR + "/cms/installation/template/tmpl/configuration.html"

    print configfilepath

    if not os.path.exists(configfilepath):
        print "cannot find " + configfilepath
        return 1

    configfile = open(configfilepath, "r")
    configfileText =  configfile.read()
    configfile.close()

    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(['php','-r','@print(date_default_timezone_get());'])

    if rc: 
        print procStdErr
        print "failed to detect current timezone"
        sys.exit(1)

    timezone = procStdOut.strip()

    # do all the replacements and substitutions
    configfileText = re.sub(re.compile("<jtmpl:comment>.*</jtmpl:comment>\n\n", re.MULTILINE | re.DOTALL), "", configfileText)
    configfileText = configfileText.replace('<jtmpl:tmpl name="configuration">', '')	
    configfileText = configfileText.replace('</jtmpl:tmpl>', "")	

    configfileText = configfileText.replace("{VAR_OFFLINE|addslashes}", "This site is down for maintenance. Please check back again soon.")
    configfileText = configfileText.replace("{VAR_SITENAME|addslashes}", hubname) # note this currently does TWO separate replacements
    configfileText = configfileText.replace("{VAR_DBTYPE|addslashes}", "mysql")
    configfileText = configfileText.replace("{VAR_DBHOSTNAME|addslashes}", "localhost")
    configfileText = configfileText.replace("{VAR_DBPASSWORD|addslashes}", dbPW)
    configfileText = configfileText.replace("{VAR_DBNAME|addslashes}", dbName)
    configfileText = configfileText.replace("{VAR_DBUSERNAME|addslashes}", hubname)
    configfileText = configfileText.replace("{VAR_DBPREFIX|addslashes}", dbTablePrefix)
    configfileText = configfileText.replace("{VAR_SECRET|addslashes}", generateAlphaNumPassword(10))
    configfileText = configfileText.replace("{VAR_HELPURL|addslashes}", "http://www.hubzero.org")
    configfileText = configfileText.replace("{VAR_FTPHOST|addslashes}", "127.0.0.1")
    configfileText = configfileText.replace("{VAR_FTPPORT|addslashes}", "21")
    configfileText = configfileText.replace("{VAR_FTPUSER|addslashes}", "")
    configfileText = configfileText.replace("{VAR_FTPPASSWORD|addslashes}", "")
    configfileText = configfileText.replace("{VAR_FTPROOT|addslashes}", "")
    configfileText = configfileText.replace("{VAR_FTPENABLE|intval}", "0")
    configfileText = configfileText.replace("{VAR_ADMINEMAIL|addslashes}", mailFrom)
    configfileText = configfileText.replace("{VAR_METADESC|addslashes}", "Hubzero - Platform for Scientific Collaboration")
    configfileText = configfileText.replace("{VAR_METAKEYS|addslashes}", "hubzero,Hubzero,HUBzero")
    configfileText = configfileText.replace("{VAR_LOG_PATH|addslashes}", docroot + "/logs")
    configfileText = configfileText.replace("{VAR_TMP_PATH|addslashes}", docroot + "/tmp")
    configfileText = configfileText.replace("{VAR_ENV|addslashes}", "production")
    configfileText = configfileText.replace("'UTC'", "'" + timezone + "'")

    configFilePath = docroot + "/configuration.php"

    print "creating " + configFilePath

    configfile = open(configFilePath, 'w')
    configfile.write(configfileText)
    configfile.close()

    hubzero.utilities.misc.exShellCommand(['chmod', "0660", configFilePath])
    hubzero.utilities.misc.exShellCommand(['chown', fileOwner + "." + fileGroup, configFilePath])	


def reconfigureHub(args):
    print "Reconfigure " + args.hubname
    generateApacheM4config(args.hubname)
    generateLogrotateFiles(args.hubname)

def generateDefaultSnakeoilCert(args):

    if args.force_overwrite:
        createSSLCerts(True)
    else:
        createSSLCerts(False)

def createSSLCerts(overwrite = False):

    # create the private subdir of the certs directory
    if os.path.exists("/etc/ssl/private"):
        keypath = "/etc/ssl/private"
        certpath = "/etc/ssl/certs"
    elif os.path.exists("/etc/ssl/certs/private"):
        keypath = "/etc/ssl/certs/private"
        certpath = "/etc/ssl/certs"
    else:
        certpath = "/etc/ssl/certs"
        keypath = "/etc/ssl/certs/private"
        if not os.path.exists("/etc/ssl"):
            os.makedirs("/etc/ssl")
            os.chown("/etc/ssl",0,0)
            os.chmod("/etc/ssl",0755)
        if not os.path.exists("/etc/ssl/certs"):
            os.makedirs("/etc/ssl/certs")
            os.chown("/etc/ssl/certs",0,0)
            os.chmod("/etc/ssl/certs",0755)
        if not os.path.exists("/etc/ssl/certs/private"):
            os.makedirs("/etc/ssl/certs/private")
            os.chown("/etc/ssl/certs/private",0,0)
            os.chmod("/etc/ssl/certs/private",0755)

    if not overwrite and os.path.exists(keypath + "/ssl-cert-snakeoil.key"):
        print keypath + "/ssl-cert-snakeoil.key already exists"
        return 0

    conffile  = "RANDFILE = /dev/urandom\n"
    conffile += "[req]\n"
    conffile += "default_bits = 2048\n"
    conffile += "distinguished_name = req_distinguished_name\n"
    conffile += "prompt = no\n"
    conffile += "policy = policy_anything\n"
    conffile += "req_extensions = v3_req\n"
    conffile += "x509_extensions = v3_req\n"
    conffile += "[ req_distinguished_name ]\n"
    conffile += "commonName = " + socket.getfqdn() + "\n"
    conffile += "[ v3_req ]\n"
    conffile += "basicConstraints = CA:FALSE\n"

    (fd, tmpfile) = tempfile.mkstemp(dir = "/tmp")

    try:
        with os.fdopen(fd, 'w') as tmp:
            tmp.write(conffile)

        proc = subprocess.Popen(["/usr/bin/openssl",
            "req", "-config", tmpfile, "-newkey", "rsa:2048",
            "-keyout", keypath + "/ssl-cert-snakeoil.key",
            "-nodes", "-x509", "-days", "3650",
            "-out", certpath + "/ssl-cert-snakeoil.pem"], shell=False,
            stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        procStdOut, procStdErr = proc.communicate()

        rc = proc.returncode

    except Exception, ex:
        print ex
        raise
        #raise Exception('exShellCommand error ' + str(argArray) + ' ' + str(ex) + "\n" + traceback.format_exc())

    finally:
        os.remove(tmpfile)

    os.chown(certpath + "/ssl-cert-snakeoil.pem",0,0)
    os.chmod(certpath + "/ssl-cert-snakeoil.pem",0644)
    os.chown(keypath + "/ssl-cert-snakeoil.key",0,0)
    os.chmod(keypath + "/ssl-cert-snakeoil.key",0640)

    # hash symlink
    # cd /etc/ssl/certs/
    # ln -sf ssl-cert-snakeoil.pem $(openssl x509 -hash -noout -in ssl-cert-snakeoil.pem)

    #for line in p.stdout:
    #    print line

    #for line in p.stderr:
    #    print line


def deleteHub(args):

    hubname = args.hubname

    parser = ConfigParser.ConfigParser()
    parser.optionxform = str
    parser.read(hubzeroConfigFilePath)
    if parser.has_option(hubname, "documentroot"):
        docroot = parser.get(hubname, "documentroot")
    else:
        print "no documentroot in /etc/hubzero.conf for " + args.hubname
        exit()

    # get root pw
    if os.path.exists("/root/.my.cnf"):
        config = ConfigParser.RawConfigParser()
        config.read("/root/.my.cnf")
        newRootPW = config.get("client", "password")
        rootmysqlpw = config.get("client", "password")
        rootmysqlrootusername = config.get("client", "user")
    else:
        # just blow it away
        newRootPW = generateAlphaNumPassword(10)
        rootmysqlrootusername = 'root'
        setMySQLPW('root', newRootPW)

        with open('/root/.my.cnf', 'w') as f:
            f.write("[client]\nuser=root\npassword=" + newRootPW + "\n")
        
    # delete the database
    print "deleting database " + hubname
    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand([
        "/usr/bin/mysql",
         "-u", rootmysqlrootusername, 
         "-p" + newRootPW,
         "-e", "DROP DATABASE " + hubname])

    # delete the web root
    print "removing " + docroot
    if os.path.isdir(docroot):
        distutils.dir_util.remove_tree(docroot)

    # delete /etc/hubzero.secrets
    try:
        os.remove("/etc/hubzero.secrets")
    except OSError as e:
        if e.errno != errno.ENOENT:
            raise


def availableCMSVersions():
    files = glob.glob("/usr/share/hubzero-cms-*/cms")

    versions = []

    for file in files:
        file = file.strip()

        if not os.path.isdir(file):
            continue

        m = re.match(r'^/usr/share/hubzero-cms-(\d.*)/cms$', file)

        if m:
            versions.append([m.group(1),file])

    if os.path.isdir("/usr/share/hubzero-cms/cms/libraries/Hubzero/Oauth"):
        versions.append(["1.1.0","/usr/share/hubzero-cms"])
    elif os.path.isdir("/usr/share/hubzero-cms/cms/libraries/Hubzero/Session"):
        versions.append(["1.0.0","/usr/share/hubzero-cms"])
    elif os.path.isdir("/usr/share/hubzero-cms/cms/libraries/Hubzero"):
        versions.append(["0.8.0","/usr/share/hubzero-cms"])

    return versions


def installHub(args):

    # Debian or RH?
    if hubzero.utilities.misc.isDebian():
        print "Debian install"
        return installHubDebian(args)
    elif hubzero.utilities.misc.isRHEL():
        print "RHEL install"
        return installHubRH(args)
    else:
	print "Error: unknown distribution"
        return 1

def a2enmod(name):
    print "enabling apache mod '" + name + "'"
    rc, stdOut, stdErr = hubzero.utilities.misc.exShellCommand(["a2enmod", name])
    for s in stdOut.split("\n"):
	if "Enabling module" in s:
            continue
        if "to activate new configuration" in s:
            continue
        if "on how to configure SSL" in s:
            continue
        if "already enabled" in s:
            continue
        if "To activate the new configuration" in s:
            continue
        if "service apache2 restart" in s:
            continue
        if s.strip() == "":
            continue

        print s.strip()
    if rc: print stdErr

def installHubDebian(args):

    if validateArgs(args) != 0:
        return 1

    wwwOwner = webUser()
    wwwGroup = webGroup()

    hubname = args.hubname
    hostname = gethostname()

    # docroot is where the www directory will go
    if not os.path.exists(args.docroot):
        print "ERROR - top level document root (" + args.docroot + ") does not exist"
        return 1

    docroot = args.docroot + "/" + hubname

    if os.path.exists(docroot):
        print "ERROR - install location (" + docroot + ") already exists"
        return 1

    # if install key was provided, validate
    if args.installkey:
        p = re.compile("^[a-zA-Z0-9]+$")
        m = p.match(args.installkey)

        if not m:
            print "install key invalid - must be alphanumeric"
            return(1)
        else:
            if len(args.installkey) < 8 :
                print "installkey must have length of at least 8"
                return(1)
            else:
                print "installkey key ok"

    fixPhpBinary()

    initPhpErrorLog()

    # Todo, offer upgrade functionality, for now, exit the install if the secrets file alread exists
    if os.path.exists('/etc/hubzero.secrets'):
        print 'looks like this is not a fresh install, /etc/hubzero.secrets file present'
        return(1)

    copyCMSFiles(HUBZERO_CMS_DIR + "/cms/", docroot, wwwOwner, wwwGroup)

    print "creating /etc/hubzero.conf entry"
    if (args.uri == None):
        uri = "http://" + hostname
    else:
        uri = args.uri

    if (args.dbname == None):
        dbname = hubname
    else:
        dbname = args.dbname

    insertHubIntoHubConfigFile(hubname, docroot, uri, dbname, True)

    # check various installation directories and create if necessary
    checkDirectories(docroot, wwwOwner, wwwGroup)

    # do substitutions for the configuraiton.php file from the template and write out
    print "creating: configuration.php"
    dbPW = generateAlphaNumPassword(14)
    installKey = generateAlphaNumPassword(14)

    if args.mailfrom == "":
        args.mailfrom = "webmaster@" + hostname

    # setup the databases
    print "setting up the databases"
    dbName = hubname
    dbUserName = hubname
    mySQLDatabaseSetup(hubname, "localhost", dist, dbPW)

    createPHPConfigurationFile(
        hubname, 
        docroot, 
        hubname, 
        dbPW, 
        args.dbprefix, 
        args.siteadminemail, 
        args.siteadminfirstname + ' ' + args.siteadminlastname,
        args.mailfrom,
        installKey,
        webUser(),
        webGroup())	

    createHubConfigFile(hubname)

    generateLogrotateFiles(hubname)

    print "creating database schema"
    loadSQLSchema(hubname, "localhost", dbName, dbUserName, dbPW, args.dbprefix)

    print "loading default data into database"
    loadSQLTableData(hubname, "localhost", dbName, dbUserName, dbPW, args.dbprefix)	

    a2enmod("rewrite")
    a2enmod("ssl")
   
    # generate the apache web config files
    if not apacheOgreManaged():
        generateApacheConfFiles(hubname, DIST_DEB)

    # add joomla admin user
    if not args.promptsiteadminpw:
        if os.path.exists("/etc/hubzero-adminpw"):
            with open('/etc/hubzero-adminpw') as f:
                adminpw = f.read()
        else:
            adminpw = generateAlphaNumPassword(autoGenPWLength)
    else:
        adminpw = pw = raw_input("Enter an password for your website admin user")


    if not os.path.exists("/root/.my.cnf"):
        rootmysqlpw = generateAlphaNumPassword(autoGenPWLength)
        rootmysqlrootusername = 'root'
        setMySQLPW('root', rootmysqlpw)

        with open('/root/.my.cnf', 'w') as f:
            f.write("[client]\nuser=root\npassword=" + rootmysqlpw + "\n")
    else:
        config = ConfigParser.RawConfigParser()
        config.read("/root/.my.cnf")
        rootmysqlpw = config.get("client", "password")
        rootmysqlrootusername = config.get("client", "user") 

    updateTimezoneDatabase(True, rootmysqlrootusername, rootmysqlpw)

    # create home directory for the hub
    hubHomeDir = "/home/" + hubname
    if not os.path.exists(hubHomeDir):
        print "creating " + hubHomeDir
        rc, stdOut, stdErr = hubzero.utilities.misc.exShellCommand(["mkdir", hubHomeDir])
        if stdOut: print stdOut.strip()
        if rc: print stdErr

    # create apache conf.d directory for the hub
    if not apacheOgreManaged():
        confDir = apacheConfigDir() + hubname + ".conf.d"
        print "creating " + confDir
        if not os.path.exists(confDir):
            rc, stdOut, stdErr = hubzero.utilities.misc.exShellCommand(["mkdir", confDir])
            if stdOut: print stdOut.strip()
            if rc: print stdErr
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chown", "root:root", confDir])	
        if rc: 
            print procStdErr
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chmod", "0755", confDir])	
        if rc: 
            print procStdErr

    # create hub admin account
    print "adding site admin account"

    hubzero.utilities.user.addhubuser(args.hubname,
                                      'admin', 
                                      'webmaster@' + hostname,
                                      adminpw,
                                      gecos="CMS Manager",
                                      joomlagidNumber=25,
                                      uidNumber=1000, 
                                      skipCreateLDAPUser = True,
                                      createGroup = False)	

    #create /srv/hubname (webUser()+":"+webGroup() 0770)
    createDir("/srv/" + args.hubname, '0770', webUser(), webGroup(), resetattrs=True)

    #create /srv/hubname/projects (webUser()+":"+webGroup() 0770)
    createDir("/srv/" + args.hubname + "/projects", '0770', webUser(), webGroup(), resetattrs=True)	

    #set the webpath parameter in params in the com_projects component entry to '/srv/hubname/projects'	
    hubzero.config.webconfig.addComponentParam('com_projects', 'webpath', '/srv/' + args.hubname + '/projects')

    serviceInit('apache2','restart')

    if args.createsecretsfile:
        createHubzeroSecretsFile(adminpw, rootmysqlrootusername, rootmysqlpw)

    # usr/bin/textifier exists enable textifier
    if os.path.exists("/usr/bin/textifier"):
        textifierConfigure(True)

    # if mailgateway installed, enable mailgateway 
    if os.path.exists("/usr/lib/hubzero/bin/mailproc/mailproc.py"):
        mailgateway(True)

    dataviewerConfigure(True)
    cronEnable()

    version = hubzero.config.webconfig.getCMSversion(docroot)

    museCmd = ""
    if os.path.exists(docroot + "/cli/muse.php"):
        museCmd = docroot + "/cli/muse.php"
    if os.path.exists(docroot + "/muse"):
        museCmd = docroot + "/muse"

    if StrictVersion(version) >= StrictVersion("2.0.0"):
	defaultTemplate = "kimera"
    elif StrictVersion(version) >= StrictVersion("1.3.0"):
        defaultTemplate = "hubbasic2013"
    elif StrictVersion(version) >= StrictVersion("1.2.0"):
        defaultTemplate = "hubbasic2012"
    elif StrictVersion(version) >= StrictVersion("1.1.0"):
        defaultTemplate = "hubbasic2012"
    else:
        defaultTemplate = "hubbasic"

    if StrictVersion(version) >= StrictVersion("1.3.0"):
        if os.path.exists(museCmd):
            if StrictVersion(version) >= StrictVersion("2.0.0"):
                output, err = subprocess.Popen(["/usr/bin/php", museCmd, "scaffolding", "copy", "template", defaultTemplate, "to", "app/mytemplate"],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
            else:
                output, err = subprocess.Popen(["/usr/bin/php", museCmd, "scaffolding", "copy", "template", defaultTemplate, "to", "mytemplate"],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()

            if err:
                print err
            else:
                output, err = subprocess.Popen(["/usr/bin/php", museCmd, "extension", "add", "--name=tpl_mytemplate"],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
                if err:
                    print err
                else:
                    hubzero.config.webconfig.addTemplateParam('welcome', 'template', 'mytemplate')

    # Summary messages at end of install
    print "\nInstallation Complete"
    print "Your web docroot is: " + docroot
    print "Your database name is: " + dbName
    print "Your database username is: " + dbName
    print "Your database password is: " + dbPW
    print "Your installation key is: " + installKey
    print "Your web admin password is " + adminpw

    return(0)


def apacheOgreManaged():
    # gonna assume if ogre owns this file, then it owns all apache
    return OgreManaged("/etc/httpd/conf/httpd.conf")


def installHubRH(args):

    hubname = args.hubname
    wwwOwner = 'apache'
    wwwGroup = 'apache'

    # we'll need the hostname in a couple of spots
    rc, stdOut, StdErr = hubzero.utilities.misc.exShellCommand(["hostname"])
    hostname = stdOut.strip()

    # check the hubname
    p = re.compile("^[a-zA-Z][a-zA-Z0-9]+$")
    m = p.match(hubname)
    if not m:
        print "ERROR - hubname must be alphanumeric and start with a letter"
        return(1)

    docroot = args.docroot + "/" + hubname

    # docroot is where the www directory will go
    if not os.path.exists(args.docroot):
        print "ERROR - docroot " + docroot + " does not exist"
        return 1

    if os.path.exists(docroot):
        print "NOTE - install location " + docroot + " already exists"

    # if install key was provided, validate
    if args.installkey:
        p = re.compile("^[a-zA-Z0-9]+$")
        m = p.match(args.installkey)

        if not m:
            print "install key invalid - must be alphanumeric"
            return(1)
        else:
            if len(args.installkey) < 8 :
                print "installkey must have length of at least 8"
                return(1)
            else:
                print "installkey key ok"

    # Todo, offer upgrade functionality, for now, exit the install if the secrets file alread exists
    if os.path.exists('/etc/hubzero.secrets'):
        print 'looks like this is not a fresh install, /etc/hubzero.secrets file present'
        return(1)

    fixPhpBinary()

    copyCMSFiles(HUBZERO_CMS_DIR + "/cms/", docroot, wwwOwner, wwwGroup)

    print "creating /etc/hubzero.conf entry"
    if (args.uri == None):
        uri = "http://" + hostname
    else:
        uri = args.uri

    if (args.dbname == None):
        dbname = hubname
    else:
        dbname = args.dbname

    insertHubIntoHubConfigFile(hubname, docroot, uri, dbname, True)

    # check various installation directories and create if necessary
    checkDirectories(docroot, wwwOwner, wwwGroup)

    # do substitutions for the configuraiton.php file from the template and write out
    print "creating configuration.php"
    dbPW = generateAlphaNumPassword(autoGenPWLength)
    installKey = generateAlphaNumPassword(autoGenPWLength)

    if args.mailfrom == "":
        args.mailfrom = "webmaster@" + hostname

    createPHPConfigurationFile(hubname,
                               docroot,
                               hubname,
                               dbPW,
                               args.dbprefix,
                               args.siteadminemail,
                               args.siteadminfirstname + ' ' + args.siteadminlastname,
                               args.mailfrom,
                               installKey,
                               webUser(),
                               webGroup())

    createHubConfigFile(hubname)

    generateLogrotateFiles(hubname)

    # get/generate joomla admin user pw for later
    if not args.promptsiteadminpw:
        if os.path.exists("/etc/hubzero-adminpw"):
            with open('/etc/hubzero-adminpw') as f:
               	adminpw = f.read()
	else:
            adminpw = generateAlphaNumPassword(autoGenPWLength)
    else:
	adminpw = pw = raw_input("Enter an password for your website admin user")

    if not os.path.exists("/root/.my.cnf"):
        rootmysqlpw = generateAlphaNumPassword(autoGenPWLength)
        rootmysqlrootusername = 'root'
        setMySQLPW('root', rootmysqlpw)

        with open('/root/.my.cnf', 'w') as f:
            f.write("[client]\nuser=root\npassword=" + rootmysqlpw + "\n")
    else:
        config = ConfigParser.RawConfigParser()
        config.read("/root/.my.cnf")
        rootmysqlpw = config.get("client", "password")
        rootmysqlrootusername = config.get("client", "user")

    updateTimezoneDatabase(True, rootmysqlrootusername, rootmysqlpw)

    # setup the databases, pw of the new database owner is passed back
    print "setting up the databases"
    dbName = hubname
    dbPW = mySQLDatabaseSetup(hubname, "localhost", DIST_RH, dbPW, rootmysqlpw)

    print "creating database schema"
    loadSQLSchema(hubname, "localhost", dbName, dbName, dbPW, args.dbprefix)

    print "loading default data into database"
    loadSQLTableData(hubname, "localhost", dbName, rootmysqlrootusername, rootmysqlpw, args.dbprefix)

    # create home directory for the hub
    hubHomeDir = "/home/" + hubname
    if not os.path.isdir(hubHomeDir):
        rc, stdOut, stdErr = hubzero.utilities.misc.exShellCommand(["mkdir", hubHomeDir])
        if stdOut: print stdOut.strip()
        if rc: print stdErr

    # see if apache orge files are OGRE managed
    if not apacheOgreManaged():
        generateApacheConfFiles(hubname, DIST_RH)

    # create apache conf.d directory for the hub
    # Todo, check to see if conf.d is zero length file, delete if present.
    if not OgreManaged("/etc/httpd/conf/httpd.conf"):
        confDir = "/etc/httpd/" + hubname + ".conf.d";
        print "creating " + confDir
        
        rc, stdOut, stdErr = hubzero.utilities.misc.exShellCommand(["mkdir", confDir])
        if stdOut: 
            print stdOut.strip()
        if rc: 
            print stdErr

        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chown", "root:root", confDir])
        if rc:
    	    print procStdErr
            rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chmod", "0755", confDir])
        if rc:
        	print procStdErr

    # create hub admin account
    print "Adding site admin account"

    hubzero.utilities.user.addhubuser(args.hubname,
                                      'admin',
                                      'webmaster@' + hostname,
                                      adminpw,
                                      gecos="CMS Manager",
                                      joomlagidNumber=25,
                                      uidNumber=1000,
                                      skipCreateLDAPUser = True,
                                      createGroup = False)

    #create /srv/hubname (apache:apache 0770)
    createDir("/srv/" + args.hubname, '0770', 'apache', 'apache')

    #create /srv/hubname/projects (apache:apache 0770)
    createDir("/srv/" + args.hubname + "/projects", '0770', 'apache', 'apache')

    #set the webpath parameter in params in the com_projects component entry to '/srv/hubname/projects'
    hubzero.config.webconfig.addComponentParam('com_projects', 'webpath', '/srv/' + args.hubname + '/projects')

    # create /etc/hubzero.secrets file
    if args.createsecretsfile:
        createHubzeroSecretsFile(adminpw, rootmysqlrootusername, rootmysqlpw)

    # create certs
    print "creating self signed SSL certificates for website"
    createSSLCerts()

    print "restarting web server"
    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/etc/init.d/httpd", "restart"])
    if rc: print procStdErr

    # usr/bin/textifier exists enable textifier
    if os.path.exists("/usr/bin/textifier"):

        print "enabling textifier"
        textifierConfigure(True)

    # if mailgateway installed, enable mailgateway
    if os.path.exists("/usr/lib/hubzero/bin/mailproc/mailproc.py"):
        print "enabling mailgateway"
        mailgateway(True)

    dataviewerConfigure(True)
    cronEnable()

    version = hubzero.config.webconfig.getCMSversion(docroot)

    museCmd = ""
    if os.path.exists(docroot + "/cli/muse.php"):
        museCmd = docroot + "/cli/muse.php"
    if os.path.exists(docroot + "/muse"):
        museCmd = docroot + "/muse"

    if StrictVersion(version) >= StrictVersion("2.0.0"):
	defaultTemplate = "kimera"
    elif StrictVersion(version) >= StrictVersion("1.3.0"):
        defaultTemplate = "hubbasic2013"
    elif StrictVersion(version) >= StrictVersion("1.2.0"):
        defaultTemplate = "hubbasic2012"
    elif StrictVersion(version) >= StrictVersion("1.1.0"):
        defaultTemplate = "hubbasic2012"
    else:
        defaultTemplate = "hubbasic"

    if StrictVersion(version) >= StrictVersion("1.3.0"):
        print "making custom template from " + defaultTemplate + " to 'mytemplate'"
        if os.path.exists(museCmd):
            if StrictVersion(version) >= StrictVersion("2.0.0"):
                print "copying " + defaultTemplate + " to app/templates/mytemplate"
                output, err = subprocess.Popen(["/usr/bin/php", museCmd, "scaffolding", "copy", "template", defaultTemplate, "to", "app/mytemplate"],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
            else:
                print "copying " + defaultTemplate + " to core/templates/mytemplate"
                output, err = subprocess.Popen(["/usr/bin/php", museCmd, "scaffolding", "copy", "template", defaultTemplate, "to", "mytemplate"],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()

            if err:
                print err
            else:
                print "installing 'mytemplate'"
                output, err = subprocess.Popen(["/usr/bin/php", museCmd, "extension", "add", "--name=tpl_mytemplate"],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
                if err:
                    print err
                else:
                    print "setting 'welcome' template to redirect to 'mytemplate'"
                    hubzero.config.webconfig.addTemplateParam('welcome', 'template', 'mytemplate')

    # Summary messages at end of install
    print "\nInstallation Complete"
    print "Your web docroot is: " + docroot
    print "Your database name is: " + dbName
    print "Your database username is: " + dbName
    print "Your database password is: " + dbPW
    print "Your installation key is: " + installKey
    print "Your web admin password is " + adminpw

    return(0)


def OgreManaged(filename):
    if not os.path.exists(filename):
        return False
    else:
        with open(filename, 'r') as f:
            ftxt = f.read()

            if "### WARNING Ogre Managed ###" in ftxt:
                return True
            else:
                return False

def configHubFile(args):
    configFilename = "/etc/hubzero-cms/" + args.hubname + ".conf"

    if not os.path.exists(configFilename):
        print "Cannot find config file " + configFilename
        return(1)

    config = ConfigParser.RawConfigParser()
    config.optionxform = str
    config.read(configFilename)

    # = means we are setting, otherwise we're retrieving 
    if "=" in args.option:
        option, value = args.option.split("=")
        config.set(args.section, option, value)

        with open(configFilename, 'wb') as configfile:
            config.write(configfile)
    else:
        rv = config.get(args.section, args.option)
        print rv


def uninstallHub(args):
    hubname = args.hubname

    # reconcile /etc/hubzero.conf (remove hubname section, reassign default if it was set to value hubname)
    deleteHubFromHubconfigFile(hubname)

    if os.path.exists("/etc/hubzero-cms/" + hubname + ".conf"): os.remove("/etc/hubzero-cms/" + hubname + ".conf")
    if os.path.exists("/etc/logrotate.d/" + hubname + "-cmsauth"): os.remove("/etc/logrotate.d/" + hubname + "-cmsauth")
    if os.path.exists("/etc/logrotate.d/" + hubname + "-cmsdebug"): os.remove("/etc/logrotate.d/" + hubname + "-cmsdebug")
    if os.path.exists("/etc/logrotate.d/" + hubname + "-access"): os.remove("/etc/logrotate.d/" + hubname + "-access")
    if os.path.exists("/etc/logrotate.d/" + hubname + "-error"): os.remove("/etc/logrotate.d/" + hubname + "-error")
    if os.path.exists(apacheConfigDir() + "/sites-m4/" + hubname + ".m4"): os.remove(apacheConfigDir() + "/sites-m4/" + hubname + ".m4") 
    if os.path.exists(apacheConfigDir() + "/sites-available/" + hubname): os.remove(apacheConfigDir()+ "/sites-available/" + hubname) 
    if os.path.exists(apacheConfigDir() + "/sites-m4/" + hubname + "-ssl.m4"): os.remove(apacheConfigDir() + "/sites-m4/" + hubname + "-ssl.m4")
    if os.path.exists(apacheConfigDir() + "/sites-available/" + hubname + "-ssl"): os.remove(apacheConfigDir() + "/sites-available/" + hubname + "-ssl")
    if os.path.exists(apacheConfigDir() + "/sites-enabled/" + hubname + "-ssl"): os.remove(apacheConfigDir() + "/sites-enabled/" + hubname + "-ssl")
    if os.path.exists(apacheConfigDir() + "/sites-enabled/" + hubname): os.remove(apacheConfigDir() + "/sites-enabled/" + hubname)

    print "You must manually delete /var/www/" + hubname
    print "You must manually delete /var/log/hubzero/" + hubname + "-cmsprofile.log"
    print "You must manually delete /var/log/hubzero/" + hubname + "-cmsdebug.log"
    print "You must manually delete /var/log/hubzero/" + hubname + "-cmsauth.log"
    if os.path.exists('/var/log/apache2'):
        print "You must manually delete /var/log/apache2/" + hubname + "-access.log"
        print "You must manually delete /var/log/apache2/" + hubname + "-error.log"
    if os.path.exists('/var/log/httpd'):
        print "You must manually delete /var/log/httpd/" + hubname + "-access.log"
        print "You must manually delete /var/log/httpd/" + hubname + "-error.log"
    print "You must manually delete /home/" + hubname 
    print "You must manually delete " + apacheConfigDir() + hubname + ".conf.d/" 

    # remove database user
    print "Removing database user: " + hubname
    
    if os.path.exists("/etc/mysql/debian.cnf"):
        root_cnf = "/etc/mysql/debian.cnf"
    else:
        root_cnf = "/root/.my.cnf"

    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/bin/mysql", 
                                                                        "--defaults-file=" + root_cnf,
                                                                        "-e", "DROP USER " + hubname + '@localhost'])
    if procStdOut: print procStdOut.strip()
    if rc : print procStdErr

    # remove databases
    print "Removing database: " + hubname
    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/bin/mysql", 
                                                                        "--defaults-file=" + root_cnf,
                                                                        "-e", "DROP DATABASE " + hubname])
    if procStdOut: print procStdOut.strip()
    if rc : print procStdErr

    print "Removing database: " + hubname + "_metrics"
    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/bin/mysql", 
                                                                        "--defaults-file=" + root_cnf,
                                                                        "-e", "DROP DATABASE " + hubname + "_metrics"])		
    print procStdOut
    if procStdOut: print procStdOut.strip()
    if rc : print procStdErr


def serviceInit(service, action = 'start'):

    if service == 'apache2':
        service = 'httpd'

    serviceScript = '/etc/init.d/' + service

    print "checking " + serviceScript

    if not os.path.exists(serviceScript):
        print "missing " + serviceScript

    print serviceScript + " " + action

    try:
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand([serviceScript, action])
    except:
        print serviceScript + " " + action + " failed"
        return -1
    
    if rc : print procStdErr
    
    return rc


def nscdInvalidate(passwords = True, groups = True):

    print "checking /etc/init.d/nscd status"
    try:
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/etc/init.d/nscd", "status"])
    except:
        print "/etc/init.d/nscd status check failed"
        return

    if rc == 0:
        if passwords:
            print "invalidating nscd password cache"
            print "/usr/sbin/nscd -i passwd"
            rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/nscd", "-i", "passwd"])
            if rc : print procStdErr
        if groups:
            print "invalidating nscd group cache"
            print "/usr/sbin/nscd -i group"
            rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/nscd", "-i", "group"])
            if rc : print procStdErr
    else:
        print "nscd not running, can't invalidate cache(s)"
  

def _ldapConfigure(args):
    ldapConfigure(args.enable)

def ldapConfigure(enable):

    if enable:
        print "enabling LDAP support"
        hubzero.config.webconfig.setPluginEnabled('user', 'ldap', True)
        hubzero.utilities.group.syncgroups(verbose=True)
        hubzero.utilities.user.syncusers(verbose=True)

        if dist == DIST_RH:
            print "clearing sssd cache"
            subprocess.call('/etc/init.d/sssd stop', shell=True)
            subprocess.call('/bin/rm /var/lib/sss/db/* -Rf', shell=True)
            subprocess.call('/etc/init.d/sssd start', shell=True)
        else:
            nscdInvalidate()

        pw = pwd.getpwnam('admin')
        if pw:
            createDir(pw.pw_dir, '0750', pw.pw_uid, pw.pw_gid, resetattrs=True)

        modifyHubConfigFile("package-config", 'ldap', 'true')        
    else:
        print "disabling ldap support"

        if dist == DIST_RH:
            print "clearing sssd cache"
            subprocess.call('/etc/init.d/sssd stop', shell=True)
            subprocess.call('/bin/rm /var/lib/sss/db/* -Rf', shell=True)
            subprocess.call('/etc/init.d/sssd start', shell=True)
        else:
            nscdInvalidate()

        hubzero.config.webconfig.setPluginEnabled('user', 'ldap', False)
        modifyHubConfigFile("package-config", 'ldap', 'false')



def _webdavConfigure(args):
    webdavConfigure(args.enable)


def webdavConfigure(enable):

    hubname = hubzero.config.webconfig.getDefaultSite()	
    filename = '/etc/auto.master'
    filename2 =  '/etc/auto.webdav'

    if not os.path.exists("/etc/modules"):
        print "creating /etc/modules file"
        with open('/etc/modules', 'a'):
            os.utime('/etc/modules', None)


    if enable:
        print "enabling WebDAV"
        modifyHubConfigFile('apache-config', 'enable_webdav', 'true')

        print "checking /etc/auto.master"
        print "regenerating /etc/auto.master"
        # add line to /etc/auto.master, remove any pre existing line similar to the one below (commented out or not) and add

        if not os.path.exists(filename):
            f1 = open(filename, 'w')
            f1.write("/webdav/home /etc/auto.webdav --timeout=60\n")
            f1.close()			
        else:
            f1 = open(filename, 'r')
            filetext = f1.read()
            f1.close()
            filetext = re.sub(".*?/webdav/home /etc/auto.webdav --timeout=60.*?\n", "", filetext, re.DOTALL)
            filetext += "/webdav/home /etc/auto.webdav --timeout=60\n"
           
            f1 = open(filename, 'w')
            f1.write(filetext)
            f1.close()	

        print "checking /etc/auto.webdav"
        print "rewriting /etc/auto.webdav"
        f2 = open(filename2, 'w')

        if dist == DIST_DEB:
            f2.write("*  -fstype=usermap,user=www-data,source_user=&,allow_other :/home/" + hubname + "/&")
        else:
            f2.write("*  -fstype=usermap,user=apache,source_user=&,allow_other :/home/" + hubname + "/&")

        f2.close()

        print "checking /etc/modules"
        try:
            modulesfn = "/etc/modules"
            modulesfh = open(modulesfn,"r+")
            modulestxt = modulesfh.read()

            txt = re.sub(r'(?m)^\s*#\s*fuse($|\s+.*$)',r'fuse\1',modulestxt)

            if txt.find('fuse') == -1:
                txt = txt.rstrip() + "\nfuse"

            txt = txt.rstrip() + "\n"
            
            if (txt != modulestxt):
                modulesfh.seek(0)
                modulesfh.write(txt)
                modulesfh.truncate()
                print "patched " + modulesfn
                    
                print "/sbin/modprobe fuse"
                rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/sbin/modprobe", "fuse"])  
                print procStdOut
                if rc: print procStdErr 

            modulesfh.close()

        except:
            print "Failed to patch file " + modulesfn
            pass

        modifyHubConfigFile("package-config", 'webdav', 'true')        

    else:
        print "disabling WebDAV"
        modifyHubConfigFile('apache-config', 'enable_webdav', 'false')

        print "checking /etc/auto.master"
        print "regenerating /etc/auto.master"
        f1 = open(filename, 'r')
        filetext = f1.read()
        f1.close()

        filetext = re.sub('^.*/webdav/home /etc/auto.webdav --timeout=60\n.*$', '', filetext)

        f1 = open(filename, 'w')
        f1.write(filetext)
        f1.close()

        print "checking /etc/auto.webdav"
        if os.path.exists("/etc/auto.webdav"):
            print "removing /etc/auto.webdav"
            os.remove(filename2)

        # This would undo /etc/modules, but we leave it unchanged in case something 
        # other than WebDAV also needs it.
        #
        #print "checking /etc/modules"
        #try:
        #    modulesfn = "/etc/modules"
        #    modulesfh = open(modulesfn,"r+")
        #    modulestxt = modulesfh.read()
        #
        #    txt = re.sub(r'(?m)^\s*fuse($|\s+.*$)',r'#fuse\1',modulestxt)
        #   
        #    if (txt != modulestxt):
        #        modulesfh.seek(0)
        #        modulesfh.write(txt)
        #        modulesfh.truncate()
        #        print "patched " + modulesfn
        #    modulesfh.close()
        #except:
        #    print "Failed to patch file " + modulesfn
        #    pass

                    
    # regenerate the apache config files to use the new option setting
    if generateApacheM4config(hubname):
        restartWebServer()

    serviceInit('autofs','restart')

    modifyHubConfigFile("package-config", 'webdav', 'false')


def _tracConfigure(args):
    tracConfigure(args.enable)


def tracConfigure(enable):
    hubname = hubzero.config.webconfig.getDefaultSite()	

    if enable:
        print "enabling trac"
        modifyHubConfigFile('apache-config', 'enable_trac', 'true')
        createDir("/opt", "0755", "root", "root", resetattrs=True)
        createDir("/opt/trac", "0755",  webUser(),  webGroup(), resetattrs=True)
        createDir("/opt/trac/tools", "0750",  webUser(),  webGroup(), resetattrs=True)		

    else:
        print "disabling trac"
        modifyHubConfigFile('apache-config', 'enable_trac', 'false')

    # regenerate the apache config files to use the new option setting
    if generateApacheM4config(hubname):
        restartWebServer()

def _filexferConfigure(args):
    filexferConfigure(args.enable)


def filexferConfigure(enable):
    hubname = hubzero.config.webconfig.getDefaultSite()	

    if enable:
        print "enabling filexfer"
        modifyHubConfigFile('apache-config', 'enable_filexfer', 'true')
    else:
        print "disabling filexfer"
        modifyHubConfigFile('apache-config', 'enable_filexfer', 'false')

    # regenerate the apache config files to use the new option setting
    if generateApacheM4config(hubname):
        restartWebServer()

def _forcecanonConfigure(args):
    forcecanonConfigure(args.enable)


def forcecanonConfigure(enable):
    hubname = hubzero.config.webconfig.getDefaultSite()	

    if enable:
        print "enabling force_canon"
        modifyHubConfigFile('apache-config', 'force_canon', 'true')
    else:
        print "disabling force_canon"
        modifyHubConfigFile('apache-config', 'force_canon', 'false')

    # regenerate the apache config files to use the new option setting
    if generateApacheM4config(hubname):
        restartWebServer()


def _forgeConfigure(args):
    forgeConfigure(args.enable)

def forgeConfigure(enable):

    hubname = hubzero.config.webconfig.getDefaultSite()	

    if enable:
        print "enabling hubzero-forge"

        print "checking user 'apps'"

        if not hubzero.utilities.user.userExists('apps',hubname):
            print "creating user 'apps'"

            hubzero.utilities.user.addhubuser(hubname,
                                      username = 'apps',
                                      email = 'apps@' + hostname,
                                      grouptype = 0,
                                      pw = '*',
                                      pwdisabled = True,
                                      gecos = 'Applications Manager', 
                                      loginShell = '/bin/bash',
                                      createGroup = False)

        print "checking user 'hubrepo'"

        if not hubzero.utilities.user.userExists('hubrepo',hubname):
            print "creating user 'hubrepo'"

            hubzero.utilities.user.addhubuser(hubname,
                                      username = 'hubrepo', 
                                      email = 'hubrepo@' + hostname,
                                      grouptype = 0,
                                      gecos = 'Repository Manager', 
                                      pw = '*',
                                      loginShell = '/bin/bash',
                                      homeDir = '/home/'+hubname+'/hubrepo',
                                      createGroup = False)

        # add group 'apps'
        print "checking 'apps' group"
        if not hubzero.utilities.group.groupExists("apps"):
            print "adding 'apps' group"
            hubzero.utilities.group.addhubgroup("apps", "apps")

        # apps should be in the apps group
        print "checking 'apps' user in 'apps' group"
        if not hubzero.utilities.group.userInGroup("apps","apps"):
            print "adding 'apps' user to 'apps' group"
            hubzero.utilities.group.addUserToGroup("apps","apps")

        # apps should be in the web user group (!)
        print "checking 'apps' user in '" + webGroup() + "' group"
        group = grp.getgrnam(webGroup())
        if ('apps' not in group.gr_mem):
            print "usermod -a -G %s apps" % webGroup()
            hubzero.utilities.misc.exShellCommand(["usermod","-a","-G",webGroup(),"apps"])

        # admin should be in the apps group
        print "checking 'admin' user in 'apps' group"
        if not hubzero.utilities.group.userInGroup("admin","apps"):
            print "adding 'admin' user to 'apps' group"
            hubzero.utilities.group.addUserToGroup("admin","apps")

        # hubrepo should be in the apps group
        print "checking 'hubrepo' user in 'apps' group"
        if not hubzero.utilities.group.userInGroup("hubrepo","apps"):
            print "adding 'hubrepo' user to 'apps' group"
            hubzero.utilities.group.addUserToGroup("hubrepo","apps")

        # subversion needs to be enabled for this to work
        print "checking hubzero-subversion configuration"
        if hubzero.config.webconfig.getHubSiteConfig(hubname, "apache-config", "enable_subversion").lower() != 'true':
            subversionConfigure(True)

        # trac need to be enabled for this to work
        print "checking hubzero-trac configuration"
        if hubzero.config.webconfig.getHubSiteConfig(hubname, "apache-config", "enable_trac").lower() != 'true':
            tracConfigure(True)

        createDir("/apps", "2775", "apps", "apps", resetattrs=True)

        print "checking /etc/sudoers.d/hubzero-forge"
        filename = "/etc/sudoers.d/hubzero-forge"
        if not os.path.exists(filename):
            if not os.path.exists("/etc/sudoers.d"):
                os.makedirs("/etc/sudoers.d")

            print "creating: /etc/sudoers.d/hubzero-forge"
            f1 = open(filename, 'w')
            f1.write(webUser() + "\tALL=(apps)NOPASSWD:/usr/bin/finalizetool\n")
            f1.write(webUser() + "\tALL=(apps)NOPASSWD:/usr/bin/installtool\n")
            f1.write(webUser() + "\tALL=(apps)NOPASSWD:/usr/bin/licensetool\n")
            if os.path.exists("/etc/init.d/httpd"):
                f1.write(webUser() + "\tALL=(root)NOPASSWD:/usr/sbin/apachectl\n")
                f1.write(webUser() + "\tALL=(root)NOPASSWD:/etc/init.d/httpd\n")
            else:
                f1.write(webUser() + "\tALL=(root)NOPASSWD:/etc/init.d/apache2\n")
            f1.write(webUser() + "\tALL=(root)NOPASSWD:/usr/bin/maxwell_service\n")	
            f1.close()			
        else:
            f1 = open(filename, 'r')
            filetext = f1.read()
            f1.close()

            print "patching: /etc/sudoers.d/hubzero-forge"
            # remove any possibly commented out lines then add the new lines
            filetext = re.sub(".*"+ webUser() +"\\s+ALL=\\(apps\\)NOPASSWD:/usr/bin/finalizetool\n", "", filetext, re.MULTILINE | re.DOTALL)
            filetext += webUser() + "\tALL=(apps)NOPASSWD:/usr/bin/finalizetool\n"

            filetext = re.sub(".*"+ webUser() +"\\s+ALL=\\(apps\\)NOPASSWD:/usr/bin/installtool\n", "", filetext, re.MULTILINE | re.DOTALL)
            filetext += webUser() + "\tALL=(apps)NOPASSWD:/usr/bin/installtool\n"

            filetext = re.sub(".*"+ webUser() +"\\s+ALL=\\(apps\\)NOPASSWD:/usr/bin/licensetool\n", "", filetext, re.MULTILINE | re.DOTALL)
            filetext += webUser() + "\tALL=(apps)NOPASSWD:/usr/bin/licensetool\n"

            if os.path.exists("/etc/init.d/httpd"):
                filetext = re.sub(".*"+ webUser() +"\\s+ALL=\\(root\\)NOPASSWD:/etc/init.d/httpd\n", "", filetext, re.MULTILINE | re.DOTALL)
                filetext += webUser() + "\tALL=(root)NOPASSWD:/etc/init.d/httpd\n"
                filetext = re.sub(".*"+ webUser() +"\\s+ALL=\\(root\\)NOPASSWD:/usr/sbin/apachectl\n", "", filetext, re.MULTILINE | re.DOTALL)
                filetext += webUser() + "\tALL=(root)NOPASSWD:/usr/sbin/apachectl\n"
            else:
                filetext = re.sub(".*"+ webUser() +"\\s+ALL=\\(root\\)NOPASSWD:/etc/init.d/apache2\n", "", filetext, re.MULTILINE | re.DOTALL)
                filetext += webUser() + "\tALL=(root)NOPASSWD:/etc/init.d/apache2\n"

            f1 = open(filename, 'w')
            f1.write(filetext)
            f1.close()	

        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chmod", "0440", "-R", filename])	
        if rc: print procStdErr

        # add hubrepo password to hubzero.secrets file, if file is not there, not sure what to do, just skip for now
        hubzeroSecretsFilename = "/etc/hubzero.secrets"
        repoPW = dbPW = generateAlphaNumPassword(autoGenPWLength)

        if os.path.exists(hubzeroSecretsFilename):
            secretsConfig = ConfigParser.ConfigParser()
            secretsConfig.optionxform = str
            f1 = open(hubzeroSecretsFilename, "rw")
            secretsConfig.readfp(f1)
            secretsConfig.set("DEFAULT", "HUBREPO", repoPW)
            f2 = open(hubzeroSecretsFilename, "w")
            secretsConfig.write(f2)
            f1.close()
            f2.close()

        # update hubrepo user passwords
        if hubzero.utilities.user.userExists('hubrepo'):
            print "changing: user 'hubrepo' password"
            hubzero.utilities.user.updateUserPW('hubrepo', repoPW)
        else:
            print "[ERROR] no hubrepo user present, not changing password"

        # create the hubconfiguration.php file
        createHubconfigurationPHPfile()

        modifyHubConfigFile('apache-config', 'enable_forge', 'true')

    else:
        print "disabling hubzero-forge"
        modifyHubConfigFile('apache-config', 'enable_forge', 'false')

    # TODO	
    # error out if no ldap configured

    # regenerate the apache config files to use the new option setting
    if generateApacheM4config(hubname):
        restartWebServer()


def _subversionConfigure(args):
    subversionConfigure(args.enable)


def subversionConfigure(enable):
    hubname = hubzero.config.webconfig.getDefaultSite()	

    if enable:
        print "enabling subversion"
        modifyHubConfigFile('apache-config', 'enable_subversion', 'true')
        createDir("/opt", "0755", "root", "root", resetattrs=True)
        createDir("/opt/svn", "0755", webUser(), webGroup(), resetattrs=True)
        createDir("/opt/svn/tools", "0750", webUser(), webGroup(), resetattrs=True)
        createDir(apacheConfigDir() + hubname + ".conf.d", "0755", "root", "root", resetattrs=True)
        createDir(apacheConfigDir() + hubname + ".conf.d/svn", "0700", webUser(), webGroup(), resetattrs=True)

    else:
        print "disabling subversion"
        modifyHubConfigFile('apache-config', 'enable_subversion', 'false')

    if os.path.exists(apacheConfigDir() + "/svn.conf"):
        print "Upgrading subversion for hub"
        print "Moving svn.conf to new " + apacheConfigDir + " " + hubname + ".conf.d/svn"
        createDir(apacheConfigDir() + hubname + ".conf.d", "0755", "root", "root", resetattrs=True)
        createDir(apacheConfigDir() + hubname + ".conf.d/svn", "0700", webUser(), webGroup(), resetattrs=True)
        os.rename(apacheConfigDir() + "svn.conf", apacheConfigDir() + hubname + ".conf.d/svn/svn.conf")

    if os.path.exists(apacheConfigDir() + "svn.bak"):
        print "Upgrading subversion for hub"
        print "Moving svn.bak to new " + apacheConfigDir() + hubname + ".conf.d/svn"
        createDir(apacheConfigDir() + hubname + ".conf.d", "0755", "root", "root", resetattrs=True)
        createDir(apacheConfigDir() + hubname + ".conf.d/svn", "0700", webUser(), webGroup(), resetattrs=True)
        os.rename(apacheConfigDir() + "svn.bak", apacheConfigDir() + hubname + ".conf.d/svn/svn.bak")

    # regenerate the apache config files to use the new option setting
    if generateApacheM4config(hubname):
        restartWebServer()
    

def _vncProxyConfigure(args):
    vncProxyConfigure(args.enable)


def vncProxyConfigure(enable):
    hubname = hubzero.config.webconfig.getDefaultSite()	

    if args.enable:
        print "enabling vncproxy"
        print "checking user 'vncproxy'"

        try:
            pwd.getpwnam('vncproxy').pw_uid
        except:
            print "creating: user 'vncproxy'"
            rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/useradd","-r",
                "-d","/var/lib/vncproxy","-g","nobody" if dist== DIST_RH else "nogroup",'-m',"-s","/bin/false","vncproxy"])  
            print procStdOut
            if rc: print procStdErr 
    
        createDir("/var/log/vncproxy", "0750", webUser(), "adm", resetattrs=True)
        createDir("/var/log/vncproxyd", "0750", "vncproxy", "adm", resetattrs=True)
        modifyHubConfigFile('apache-config', 'enable_vncproxy', 'true')

        # add the load module for the vncproxy to the end of the LoadModule lines in /etc/httpd/conf/httpd.conf
        if dist == DIST_RH:
            filename = "/etc/httpd/conf/httpd.conf"
            f = open(filename, "r+")
            configtxt = f.read()
            txt = re.sub(re.compile(r'(LoadModule.*)(\n){2,}'), r'\1\nLoadModule vncproxy_module modules/mod_vncproxy.so\n\n', configtxt)

            if configtxt != txt:
                f.seek(0)
                f.write(txt)
                f.truncate()
                print "patched " + filename
            f.close()

    else:
        print "disabling vncproxy"
        modifyHubConfigFile('apache-config', 'enable_vncproxy', 'false')

        # comment out all vncProxy lines in in /etc/httpd/conf/httpd.conf
        if dist == DIST_RH:
            filename = "/etc/httpd/conf/httpd.conf"
            f = open(filename, "r+")
            configtxt = f.read()
            txt = re.sub(re.compile(r'^(LoadModule vncproxy_module.*)$', re.MULTILINE), r'#\1', configtxt)

            if configtxt != txt:
                f.seek(0)
                f.write(txt)
                f.truncate()
                print "patched " + filename
                f.close()


    # regenerate the apache config files to use the new option setting
    if generateApacheM4config(hubname):
        restartWebServer()

def _hubgraphConfigure(args):
    hubgraphConfigure(args.enable)

def hubgraphConfigure(enable):
    hubname = hubzero.config.webconfig.getDefaultSite() 

    config = ConfigParser.ConfigParser()

    newListen = ''
    
    if config.read("/etc/hubgraph.conf") != []:
        if config.has_section('hubgraph'):
            try:
                if config.has_option('hubgraph','listen'):
                    newListen = config.get('hubgraph','listen')
            except:
                pass
                
    if enable:
        print "enabling hubgraph"

        oldHost = hubzero.config.webconfig.getComponentParam('com_search', 'hubgraph_host', '')

        if (oldHost is None or oldHost.startswith('unix') or oldHost == '' or oldHost == 'localhost' or oldHost == '127.0.0.1') and newListen.startswith('/'):
            hubzero.config.webconfig.addComponentParam('com_search', 'hubgraph_host', 'unix://' + newListen)
            hubzero.config.webconfig.addComponentParam('com_search', 'hubgraph_port', None)

        hubzero.config.webconfig.addComponentParam('com_search', 'engine', 'hubgraph')

    else:
        print "disabling hubgraph"
        hubzero.config.webconfig.addComponentParam('com_search', 'engine', 'basic')


def _dataviewerConfigure(args):
    dataviewerConfigure(args.enable)


def dataviewerConfigure(enable):
    hubname = hubzero.config.webconfig.getDefaultSite()	

    if enable:
        print "enabling dataviewer"

        db_host = hubzero.config.webconfig.getPluginParam("projects","databases","db_host")
        db_user = hubzero.config.webconfig.getPluginParam("projects","databases","db_user")
        db_password = hubzero.config.webconfig.getPluginParam("projects","databases","db_password")
        db_ro_user = hubzero.config.webconfig.getPluginParam("projects","databases","db_ro_user")
        db_ro_password = hubzero.config.webconfig.getPluginParam("projects","databases","db_ro_password")

        if (db_password == 'datawriter_pw') or (db_password == '') or (db_password == None):
          	rwPW = generateAlphaNumPassword(autoGenPWLength)
        else:
            rwPW = db_password

        if (db_ro_password == 'dataviewer_pw') or (db_ro_password == '') or (db_ro_password == None):
            roPW = generateAlphaNumPassword(autoGenPWLength)
        else:
            roPW = db_ro_password

        # TODO SQL native calls for these
        # TODO check to see if database is running

        print "creating database user: dataviewer, password = " + roPW

        if os.path.exists("/etc/mysql/debian.cnf"):
            rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/bin/mysql", 
                                                                        "--defaults-file=/etc/mysql/debian.cnf",
                                                                        "-e", "GRANT SELECT ON `prj\_db\_%`.* TO 'dataviewer'@'localhost' IDENTIFIED BY '" + roPW + "'"])
        else:

            rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(
                ["/usr/bin/mysql",
                "--defaults-file=/root/.my.cnf", 
                "-e", "GRANT SELECT ON `prj\_db\_%`.* TO 'dataviewer'@'localhost' IDENTIFIED BY '" + roPW + "'"])


        if procStdOut: print procStdOut.strip()
        if rc : print procStdErr


        print "creating database user: datawriter, password = " + rwPW

        if os.path.exists("/etc/mysql/debian.cnf"):
            rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/bin/mysql", 
                                                                        "--defaults-file=/etc/mysql/debian.cnf",
                                                                        "-e", "GRANT CREATE,DROP,SELECT,INSERT,UPDATE,DELETE ON `prj\_db\_%`.* TO 'datawriter'@'localhost' IDENTIFIED BY '" + rwPW + "'"])
        else:
            rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/bin/mysql", 
                                                                        "--defaults-file=/root/.my.cnf",
                                                                        "-e", "GRANT CREATE,DROP,SELECT,INSERT,UPDATE,DELETE ON `prj\_db\_%`.* TO 'datawriter'@'localhost' IDENTIFIED BY '" + rwPW + "'"])

        if procStdOut: print procStdOut.strip()
        if rc : print procStdErr

        hubzero.config.webconfig.addPluginParam("projects","databases","db_password",rwPW)
        hubzero.config.webconfig.addPluginParam("projects","databases","db_host","localhost")
        hubzero.config.webconfig.addPluginParam("projects","databases","db_user","datawriter")
        hubzero.config.webconfig.addPluginParam("projects","databases","db_ro_user","dataviewer")
        hubzero.config.webconfig.addPluginParam("projects","databases","db_ro_password",roPW)
    else:
        print "disabling dataviewer [THIS DOESN'T ACTUALLY CHANGE ANYTHING YET]"


def _mwServiceConfigure(args):
    mwServiceConfigure(args.enable)


def mwServiceConfigure(enable):
    hubname = hubzero.config.webconfig.getDefaultSite()	
    enable_mw_service = hubzero.config.webconfig.getHubSiteConfig(hubname, "package-config", "mw-service")
    
    if enable:
            
        if enable_mw_service.lower() != 'true':
            print "enabling mw-service"

        # turn off disk quota
        print "checking /etc/vz/vz.conf"
        vzConfFile = "/etc/vz/vz.conf"	
        if os.path.exists(vzConfFile):
            changed = False
            with open(vzConfFile, "r") as f1:
                vzConfFileText = f1.read()

                # add or replace our needed config option
                if "DISK_QUOTA=yes" in vzConfFileText:
                    vzConfFileText = vzConfFileText.replace("DISK_QUOTA=yes", "DISK_QUOTA=no")
                    changed = True
                else:
                    if not "DISK_QUOTA=no" in vzConfFileText:
                        vzConfFileText += "DISK_QUOTA=no\n"
                        changed = True
            if changed:
                with open(vzConfFile, "w") as f1:
                    print "Turning off disk quota in " + vzConfFile
                    f1.write(vzConfFileText)
        else:
            print vzConfFile + " not found"

        if os.path.exists("/var/lib/vz/template/debian-7.0-amd64-maxwell"):
            ovz_session = "7.0-amd64"
        elif os.path.exists("/var/lib/vz/template/debian-7.0-i386-maxwell"):
            ovz_session = "7.0-i386"
        elif os.path.exists("/var/lib/vz/template/debian-6.0-amd64-maxwell"):
            ovz_session = "6.0-amd64"
        elif os.path.exists("/var/lib/vz/template/debian-6.0-i386-maxwell"):
            ovz_session = "6.0-i386"
        elif os.path.exists("/var/lib/vz/template/debian-5.0-amd64-maxwell"):
            ovz_session = "5.0-amd64"
        elif os.path.exists("/var/lib/vz/template/debian-5.0-i386-maxwell"):
            ovz_session = "5.0-i386"
        elif os.path.exists("/var/lib/vz/template/debian-4.0-amd64-maxwell"):
            ovz_session = "4.0-amd64"
        elif os.path.exists("/var/lib/vz/template/debian-4.0-i386-maxwell"):
            ovz_session = "4.0-i386"

        # generate /etc/mw-service/mw-service.conf	
        # @TODO: set_quotas needs this, it should be rewritten to
        # to loop through user list from database and lookup homedirs
        # per user instead of looping through directory.
        confFileName = "/etc/mw-service/mw-service.conf"

        print "checking " + confFileName

        if not os.path.exists(confFileName):
            maxwellConfFileText = (
                "submit_server = \"" + hostname + "\"\n"
                "hub_name = \"" + hubname + "\"\n"
                "hub_homedir = \"/home/" + hubname + "\"\n" 
                "ovz_session_conf = \"hub-session-" + ovz_session + ".conf\"\n"
                "ovz_session_mount = \"hub-session-" + ovz_session + ".mount\"\n"
                "ovz_session_umount = \"hub-session-" + ovz_session + ".umount\"\n" )

            # write the file
            print "creating " + confFileName
            f3 = open(confFileName, "w")
            f3.write(maxwellConfFileText)
            f3.close()

            rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chown", "root." + webGroup()  , confFileName])	
            if rc: 
                print procStdErr

            rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chmod", "0640", confFileName])	
            if rc: 
                print procStdErr
        else:
            # @TODO Should use a regex check to find these variables more accurately
            changed = False
            with open(confFileName, "r") as f1:
                maxwellConfFileText = f1.read().rstrip()

                if "hub_name" not in maxwellConfFileText:
                    maxwellConfFileText += "\nhub_name = \"" + hubname + "\""
                    changed = True
                if "hub_homedir" not in maxwellConfFileText:
                    maxwellConfFileText += "\nhub_homedir = \"/home/" + hubname + "\""
                    changed = True
                if "ovz_session_conf" not in maxwellConfFileText:
                    maxwellConfFileText += "\novz_session_conf = \"hub-session-" + ovz_session + ".conf\""
                    changed = True
                if "ovz_session_mount" not in maxwellConfFileText:
                    maxwellConfFileText += "\novz_session_mount = \"hub-session-" + ovz_session + ".mount\""
                    changed = True
                if "ovz_session_umount" not in maxwellConfFileText:
                    maxwellConfFileText += "\novz_session_umount = \"hub-session-" + ovz_session + ".umount\""
                    changed = True

            if changed:
                print "updating " + confFileName
                with open(confFileName, "w") as f1:
                    f1.write(maxwellConfFileText+"\n")

        # some db work	
        # @TODO Should probably use proper fqdn rather than localhost
        dbPW = hubzero.config.webconfig.getWebConfigDBPassword()
        dbUserName = hubzero.config.webconfig.getWebConfigDBUsername()
        dbName = hubzero.config.webconfig.getWebConfigDBName()
        db =  hubzero.data.db.MySQLConnection("localhost", dbName, dbUserName, dbPW)		

        sql = "INSERT IGNORE INTO `host` (`hostname`,`provisions`,`status`,`uses`,`portbase`) VALUE ('localhost',14,'down',0,0);"
        db.query_rowcount(sql, None)	

        sql = "UPDATE `host` SET status='up' WHERE hostname='localhost';"
        db.query_rowcount(sql, None)	

        if hubzero.config.webconfig.getPluginEnabled('user','ldap'):
            syncLdap = True
        else:
            syncLdap = False

        # add group 'network'
        print "checking group 'network'"
        if not hubzero.utilities.group.groupExists("network"):
            print "adding group 'network'"
            hubzero.utilities.group.addhubgroup("network", "network")
 
        db.query_rowcount("UPDATE jos_xgroups SET type='0', published='1' WHERE cn='network'", None)
        if syncLdap:
            hubzero.utilities.group.syncgroup('network',verbose=True)

        modifyHubConfigFile("package-config", 'mw-service', 'true')		
    else:
        print "disabling mw-service"
        # some db work	
        # @TODO Should probably use proper fqdn rather than localhost
        dbPW = hubzero.config.webconfig.getWebConfigDBPassword()
        dbUserName = hubzero.config.webconfig.getWebConfigDBUsername()
        dbName = hubzero.config.webconfig.getWebConfigDBName()
        db =  hubzero.data.db.MySQLConnection("localhost", dbName, dbUserName, dbPW)		

        print "Doing mw database configuration"
        sql = "UPDATE `host` SET status='down' WHERE hostname='localhost';"
        db.query_rowcount(sql, None)	
        modifyHubConfigFile("package-config", 'mw-service', 'false')		
        pass


def _mwClientConfigure(args):
    mwClientConfigure(args.enable)

def mwClientConfigure(enable):
    hubname = hubzero.config.webconfig.getDefaultSite()	

    if enable:
        print "enabling mw-client"
        
        modifyHubConfigFile("package-config", 'mw-client', 'true')		

        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["mkdir", "-p", "/root/.ssh"])	
        if rc: print procStdErr

        # put key in root's authorized keys
        # cat /etc/mw-client/maxwell.key.pub >>  /root/.ssh/authorized_keys

        keyfile = "/etc/mw-client/maxwell.key.pub"
        authkeysfile = "/root/.ssh/authorized_keys"

        f1 = open(keyfile, 'r')
        key = f1.read()
        f1.close()

        # add to file
        if os.path.exists(authkeysfile):

            f2 = open(authkeysfile, 'r')
            keyfileTextOriginal = f2.read()
            f2.close()

            if not key in keyfileTextOriginal:
                print "adding /etc/mw-client/maxwell.key.pub to /root/.ssh/authorized_keys"
                keyfile = open("/root/.ssh/authorized_keys", "a")
                keyfile.write(key)
                keyfile.close()
            else:
                print "key already in /root/.ssh/authorized_keys"

        else: # create file
            print "adding /etc/mw-client/maxwell.key.pub to newly created /root/.ssh/authorized_keys file"
            keyfile = open("/root/.ssh/authorized_keys", "w")
            keyfile.write(key)
            keyfile.close()			

        # generate /etc/mw-client/mw-client.conf	
        dbPW = hubzero.config.webconfig.getWebConfigDBPassword()
        dbUserName = hubzero.config.webconfig.getWebConfigDBUsername()
        dbName = hubzero.config.webconfig.getWebConfigDBName()
        db =  hubzero.data.db.MySQLConnection("localhost", dbName, dbUserName, dbPW)

        uri = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "uri")
        if uri == '':
            uri = "http://" + hostname

        # do /etc/mw-client/mw-clienta.conf file replacements
        # get hostname
        hostname = gethostname()

        uri = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "uri")
        if uri == '':
            uri = "http://" + hostname

        try:
            sql = 'select template from `jos_template_styles` where client_id=0 and home=1'
            template = db.query_selectscalar(sql, None)
        except _mysql_exceptions.ProgrammingError as err:
            sql = 'select template from `jos_templates_menu` where menuid = 0 and client_id=0'
            template = db.query_selectscalar(sql, None)

        maxwellConfFileText = (
            "mysql_host = \"localhost\"\n"
            "mysql_user=\"" + dbUserName + "\"\n"
            "mysql_password=\"" + dbPW + "\"\n"
            "mysql_db=\"" + dbName + "\"\n"
            "hub_name=\"" + hubname + "\"\n"
            "hub_url=\"" + uri + "\"\n"
            "hub_homedir=\"/home/" + hubname + "\"\n"
            "hub_template=\"" + template + "\"\n")


        confFileName = "/etc/mw-client/mw-client.conf"
        # write the file
        print "creating " + confFileName
        f3 = open(confFileName, "w")
        f3.write(maxwellConfFileText)
        f3.close()

        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chown", "root:" + webGroup(), confFileName])	
        if rc: 
            print procStdErr

        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chmod", "0640", confFileName])	
        if rc: 
            print procStdErr

	## Todo, permissions on the /etc/mw-client directory needs more open read
        ##rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chmod", "0640", /etc/mw-client/])	
        ##if rc: 
        ##    print procStdErr

        serviceInit('expire-sessions','restart')

    else:
        print "disabling mw for hub"
        modifyHubConfigFile("package-config", 'mw-client', 'false')		


def _textifierConfigure(args):
    textifierConfigure(args.enable)


def textifierConfigure(enable):

    confFileText = """host: localhost
db: %db
user: %user
password: %password
insert: INSERT INTO jos_document_text_data(hash, body) VALUES (%0q,%1q) ON DUPLICATE KEY UPDATE body = %1q
"""	
    if enable:
        print "enabling textifier"
        dbPW = hubzero.config.webconfig.getWebConfigDBPassword()
        dbUserName = hubzero.config.webconfig.getWebConfigDBUsername()
        dbName = hubzero.config.webconfig.getWebConfigDBName()

        confFileText = confFileText.replace("%db", dbName)
        confFileText = confFileText.replace("%user", dbUserName)
        confFileText = confFileText.replace("%password", dbPW)

        # create /etc/textifier.conf
        textifierConfFile = "/etc/textifier.conf"

        file1 = open(textifierConfFile, "w")
        file1.write(confFileText)	
        os.chmod(textifierConfFile, 0640)

        hubzero.utilities.misc.exShellCommand(['chown', webUser() + ":" + webGroup(), textifierConfFile])
    else:
        print "disabling textifier"


def _mwMetrics(args):
    mwMetrics(args.enable)


def mwMetrics(enable, document_root = None):
    if enable:
        # some db work

        dbPW = hubzero.config.webconfig.getWebConfigDBPassword()
        dbUserName = hubzero.config.webconfig.getWebConfigDBUsername()
        dbName = hubzero.config.webconfig.getWebConfigDBName()
        db =  hubzero.data.db.MySQLConnection("localhost", dbName, dbUserName, dbPW)		

        if document_root == None:    
            hubname = hubzero.config.webconfig.getDefaultSite()
            document_root = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")
    
        if not os.path.isdir(document_root):
            print "Can't find document root, cancelling metrics configuration"
            return True

        print "Doing metrics database configuration"
        try:
            sql = 'UPDATE jos_extensions SET enabled = 0 WHERE type = "plugin" AND folder = "usage";'
            db.query_rowcount(sql, None)	
        except _mysql_exceptions.ProgrammingError as err:
            sql = 'UPDATE jos_plugins SET published = 0 WHERE folder = "usage";'
            db.query_rowcount(sql, None)	

        try:
            sql = 'UPDATE jos_extensions SET enabled = 1 WHERE type = "plugin" AND folder = "usage" AND element IN ("overview","maps");'
            db.query_rowcount(sql, None)			
        except _mysql_exceptions.ProgrammingError as err:
            sql = 'UPDATE jos_plugins SET published = 1 WHERE folder = "usage" AND element IN ("overview","maps")'
            db.query_rowcount(sql, None)			

        try:
            sql = 'UPDATE jos_extensions SET params = \'{"period":"14","chart_path":"/site/stats/chart_resources/","map_path":"/site/stats/resource_maps/"}\' WHERE type="plugin" AND folder = "resources" AND element = "usage";'
            db.query_rowcount(sql, None)			
        except _mysql_exceptions.ProgrammingError as err:
            sql = 'UPDATE jos_plugins SET params = "period=14 nchart_path=/site/stats/chart_resources/\nmap_path=/site/stats/resource_maps/" WHERE folder = "resources" AND element = "usage";'
            db.query_rowcount(sql, None)			

        try:
            sql = 'UPDATE jos_resource_types SET params="plg_citations=1\nplg_questions=1\nplg_recommendations=1\nplg_related=1\nplg_reviews=1\nplg_usage=1\nplg_versions=1\nplg_favorite=1\nplg_share=1\nplg_wishlist=1\nplg_supportingdocs=1" WHERE type="Tools"'
            db.query_rowcount(sql, None)
        except _mysql_exceptions.ProgrammingError as err:
            sql = 'UPDATE jos_resource_types SET params="plg_citations=1\nplg_questions=1\nplg_recommendations=1\nplg_related=1\nplg_reviews=1\nplg_usage=1\nplg_versions=1\nplg_favorite=1\nplg_share=1\nplg_wishlist=1\nplg_supportingdocs=1" WHERE type="Tools"'
            db.query_rowcount(sql, None)

        updateDatabaseSchema(document_root, force = True, component = "com_usage")

        # Debian or RH?
        wwwOwner = webUser()
        wwwGroup = webGroup()

        hubname = hubzero.config.webconfig.getDefaultSite()

        createDir("/etc/hubzero-metrics", "2770", webUser(), webGroup(), resetattrs=False)
        createDir("/var/log/hubzero/metrics", "2770", webUser(), webGroup(), resetattrs=False)

    else:
        pass


def _mailgateway(args):
    mailgateway(args.enable)


def mailgateway(enable):

    postfix_main_filename = '/etc/postfix/main.cf'
    postfix_master_filename = '/etc/postfix/master.cf'
    postfix_access_filename = '/etc/postfix/access'

    if enable:
        print "enabling mailgateway"
        pwSalt = generateAlphaNumPassword(16)
        pw = generateAlphaNumPassword(16)
        dbPW = hubzero.config.webconfig.getWebConfigDBPassword()
        dbUserName = hubzero.config.webconfig.getWebConfigDBUsername()
        dbName = hubzero.config.webconfig.getWebConfigDBName()
        confFileName = "/etc/hubmail_gw.conf"
        hubname = hubzero.config.webconfig.getDefaultSite()

        hostname = gethostname()

        fileText = """<?php
class HubmailConfig {
 public $user = '%DBUSER%';
 public $password = '%DBPW%';
 public $db = '%DBNAME%';
 public $host = 'localhost';
 public $fromname = '%HUBNAME% Support Team';
 public $mailfrom = 'support@%HOSTNAME%';
 public $sitename = '%HUBNAME%';
 public $email_token_current_version = '1';
 public $email_token_encryption_info_v1 = '%SALT%,%PW%';
 public $hubShortURL = '%HOSTNAME%';
 public $hubLongURL = 'http://%HOSTNAME%';
}
"""
        fileText = fileText.replace("%DBUSER%", dbUserName)
        fileText = fileText.replace("%DBPW%", dbPW)
        fileText = fileText.replace("%DBNAME%", dbName)
        fileText = fileText.replace("%HUBNAME%", hubname)
        fileText = fileText.replace("%HOSTNAME%", hostname)
        fileText = fileText.replace("%SALT%", pwSalt)
        fileText = fileText.replace("%PW%", pw)

        with open(confFileName, "w") as f1:
            f1.write(fileText)

        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chown", webUser()+":Debian-exim", confFileName])	
        if rc: 
            print procStdErr

        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chmod", "0640", confFileName])	
        if rc: 
            print procStdErr
      
        filename = '/etc/default/spamassassin'
        
        print "checking " + filename
        
        if os.path.exists(filename):
            try:
                fh = open(filename, 'r+')
                configtxt = fh.read()
                (txt, count) = re.subn(r'(?im)^\s*ENABLED\s*=\s*.*$', "ENABLED=1", configtxt)

                txt = txt.rstrip() + "\n"

                if (count == 0):
                    txt = txt + "ENABLED=1\n"                

                if (txt != configtxt):
                    fh.seek(0)
                    fh.write(txt)
                    fh.truncate()
                    print "patched " + filename
                    serviceInit('spamassassin','restart')

                fh.close()
            except:
                print "Failed to patch " + filename
                raise

        else:
            print "/etc/default/spamassassin not found, unable to patch"

        modifyHubConfigFile("package-config", 'mailgateway', 'true')

        if hubzero.utilities.misc.isRHEL():
            checkFileConfigOption(postfix_main_filename,
                'smtpd_recipient_restrictions = check_recipient_access regexp:/etc/postfix/access, permit_mynetworks, reject_unauth_destination',
                'smtpd_recipient_restrictions = check_recipient_access regexp:/etc/postfix/access, permit_mynetworks, reject_unauth_destination',
                True)

            checkFileConfigOption(postfix_master_filename,
                'hubmailgatewayhtc     unix -        n       n       -       -       pipe',
                'hubmailgatewayhtc     unix -        n       n       -       -       pipe',
                True)

            checkFileConfigOption(postfix_master_filename,
                '  flags=Rq user=hubmail argv=/usr/lib/hubzero/bin/mailproc/processticketcomment.py ${sender} ${recipient}',
                '  flags=Rq user=hubmail argv=/usr/lib/hubzero/bin/mailproc/processticketcomment.py \${sender} \${recipient}',
                True)

            checkFileConfigOption(postfix_master_filename,
                'hubmailgatewayhgm     unix -        n       n       -       -       pipe',
                'hubmailgatewayhgm     unix -        n       n       -       -       pipe',
                True)

            checkFileConfigOption(postfix_master_filename,
                '  flags=Rq user=hubmail argv=/usr/lib/hubzero/bin/mailproc/processgroupforumpost.py ${sender} ${recipient}',
                '  flags=Rq user=hubmail argv=/usr/lib/hubzero/bin/mailproc/processgroupforumpost.py \${sender} \${recipient}',
                True)


            # create /etc/postfix/access file, blow away whatever is there
            access_file_txt = """/htc-[0-9]{4}[a-z0-9]{32}@/ FILTER hubmailgatewayhtc:dummy
/hgm-[0-9]{4}[a-z0-9]{32}@/ FILTER hubmailgatewayhgm:dummy"""

            if os.path.exists(postfix_access_filename):
                os.remove(postfix_access_filename)
            with open(postfix_access_filename, "w") as f1:
                f1.write(access_file_txt)

            serviceInit('postfix','restart')


    else:
        print "disabling Mail Gateway"

        # Disable spamassisin, leave on instead in case something else wanted it
        #filename = '/etc/defaults/spamassassin'
        #
        #if os.path.exists(filename):
        #    fh = open(filename, 'r+')
        #    configtxt = fh.read()
        #    (txt, count) = re.subn(r'(?im)^\s*ENABLED\s*=\s*(.*$)', "ENABLED=0", configtxt)
        #
        #    txt = txt.rstrip() + "\n"
        #
        #    if (txt != configtxt):
        #        fh.seek(0)
        #        fh.write(txt)
        #        fh.truncate()
        #        print "patched " + filename
        #
        #    fh.close()

        modifyHubConfigFile("package-config", 'mailgateway', 'false')      
        
        # /etc/postfix/main.cf removals
        if hubzero.utilities.misc.isRHEL():
            checkFileConfigOption(postfix_main_filename,
                'smtpd_recipient_restrictions = check_recipient_access regexp:/etc/postfix/access, permit_mynetworks, reject_unauth_destination',
                'smtpd_recipient_restrictions = check_recipient_access regexp:/etc/postfix/access, permit_mynetworks, reject_unauth_destination',
                False)

            checkFileConfigOption(postfix_master_filename,
                'hubmailgatewayhtc     unix -        n       n       -       -       pipe',
                'hubmailgatewayhtc     unix -        n       n       -       -       pipe',
                False)

            checkFileConfigOption(postfix_master_filename,
                r'  flags=Rq user=hubmail argv=/usr/lib/hubzero/bin/mailproc/processticketcomment.py ${sender} ${recipient}',
                r'  flags=Rq user=hubmail argv=/usr/lib/hubzero/bin/mailproc/processticketcomment.py \${sender} \${recipient}',
                False)

            checkFileConfigOption(postfix_master_filename,
                'hubmailgatewayhgm     unix -        n       n       -       -       pipe',
                'hubmailgatewayhgm     unix -        n       n       -       -       pipe',
                False)

            checkFileConfigOption(postfix_master_filename,
                r'  flags=Rq user=hubmail argv=/usr/lib/hubzero/bin/mailproc/processgroupforumpost.py ${sender} ${recipient}',
                r'  flags=Rq user=hubmail argv=/usr/lib/hubzero/bin/mailproc/processgroupforumpost.py \${sender} \${recipient}',
                False)

            # remove /etc/postfix/access file
            if os.path.exists(postfix_access_filename):
                os.remove(postfix_access_filename)

            serviceInit('postfix','restart')


def checkFileConfigOption(filename, optionLine, optionLineRegex = "", enable = True):

    if os.path.exists(filename):

        with open(filename, 'r') as f:
            ftxt = f.read()

        match = re.search(optionLineRegex, ftxt, re.M)

        if match and not enable:
            # remove line
            with open(filename, 'r+') as f:
                ftxt = f.read()
                ftxt = re.sub(optionLineRegex, '', ftxt, re.M)
                f.seek(0)
                f.write(ftxt.rstrip())
                f.truncate()
        elif not match and enable:
            # append line
            with open(filename, 'a') as f:
                f.write("\n" + optionLine)
    else:
        raise Exception("file " + filename + " not found")



def fixSubmitServer():

    # @TODO should check current version of submit-server package

    ss = "/etc/submit/submit-server.conf"

    if os.path.exists(ss):
        print "checking /etc/submit/submit-server.conf"

        hostname = gethostname()

        pattern1 = r'(?im)(^\s*)mysqlDB(\s*=\s*.*$)'
        repl1 = r'\1mysqlMiddlewareDB\2'

        try:
            ssfh = open(ss,'r+')
            sstxt = ssfh.read()
            txt = re.sub(pattern1,repl1,sstxt)
   
            m = re.search("^\s*emailFrom\s*=\s*.*$", txt, re.MULTILINE)

            if not m:
                txt = txt.rstrip() + "\n\nemailFrom = noreply@%s\n" % (hostname)

            if (txt != sstxt):
                ssfh.seek(0)
                ssfh.write(txt)
                ssfh.truncate()
                print "patched " + ss
            ssfh.close()
        except:
            print "failed to patch " + ss
            pass

def _submitserverConfigure(args):
    submitserverConfigure(args.enable)

def submitserverConfigure(enable):

    confFileName = "/etc/submit/submit-server.conf"

    fileText = """# WARNING: this file is auto-generated.
[server]
listenURIs = tcp://:830

mysqlHost = localhost
mysqlUser = %DBUSERNAME%
mysqlPassword = %DBPW%
mysqlMiddlewareDB = %DBNAME%

ldapHosts = ldap://localhost
ldapBaseDN = %hubLDAPBaseDN%
ldapUserDN = uid=%s,ou=users,%hubLDAPBaseDN%

loadLimit = 510         # cumulative load must not exceed 510
loadHalflife = 3600     # static load is divided in half ever 3600 sec
loadHorizon = 86400     # forget about jobs started earlier than 1 day ago

emailFrom = noreply@%fqdn%

"""

    if enable:
        dbPW = hubzero.config.webconfig.getWebConfigDBPassword()
        dbUserName = hubzero.config.webconfig.getWebConfigDBUsername()
        dbName = hubzero.config.webconfig.getWebConfigDBName()
        hubname = hubzero.config.webconfig.getDefaultSite()
        hubLDAPAcctMgrDN = hubzero.config.webconfig.getComponentParam("com_system", "ldap_managerdn")
        hubLDAPAcctMgrPW = hubzero.config.webconfig.getComponentParam("com_system", "ldap_managerpw")
        hubLDAPBaseDN = hubzero.config.webconfig.getComponentParam("com_system", "ldap_basedn")	
        db =  hubzero.data.db.MySQLConnection("localhost", dbName, dbUserName, dbPW)

        hostname = gethostname()

        if hubzero.config.webconfig.getPluginEnabled('user','ldap'):
            syncLdap = True
        else:
            syncLdap = False

        print "checking group 'submit'"
        if not hubzero.utilities.group.groupExists("submit"):
            print "adding 'submit' group"
            hubzero.utilities.group.addhubgroup("submit", "submit")
        
        db.query_rowcount("UPDATE jos_xgroups SET type='0', published='1' WHERE cn='submit'", None)

        if syncLdap:
            hubzero.utilities.group.syncgroup('submit',verbose=True)

        fileText = fileText.replace("%DBUSERNAME%", dbUserName)
        fileText = fileText.replace("%fqdn%", hostname)
        fileText = fileText.replace("%DBPW%", dbPW)
        fileText = fileText.replace("%DBNAME%", dbName)
        fileText = fileText.replace("%hubLDAPBaseDN%", hubLDAPBaseDN)
        fileText = fileText.replace("%hubLDAPAcctMgrDN%", hubLDAPAcctMgrDN)
        fileText = fileText.replace("%hubLDAPBaseDN%", hubLDAPBaseDN)


        if not os.path.exists("/etc/submit/"):
            os.makedirs("/etc/submit/")
        with open(confFileName, "w") as f1:
            f1.write(fileText)

        #rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chown", "XXX.XXX", confFileName])	
        #if rc: 
        #	print procStdErr

        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chmod", "0640", confFileName])	
        if rc: 
            print procStdErr

        rsyslogText = """local6.* /var/log/submit/distributor/distributor.log
local6.* ~"""

	with open("/etc/rsyslog.d/distributor.conf","w") as f1:
            f1.write(rsyslogText)


def reconfigureSshdConfig(enable_sftp, enable_ssh, enable_mwvirtualssh):

    print "checking /etc/ssh/sshd_config"

    if os.path.exists("/etc/ssh/sshd_config"):
        fh = open("/etc/ssh/sshd_config",'r+')
        configtxt = fh.read()

        pattern1 = r'(?ims)^\n*#\s*hubzero-mw-virtualssh\s*--\s*DO\s*NOT\s*REMOVE\s*THIS\s*LINE\s*\n.*?^#\s*hubzero-mw-virtualssh\s*--\s*DO\s*NOT\s*REMOVE\s*THIS\s*LINE\s*(\n+|$)'
        pattern2 = r'(?ims)^\n*#\s*hubzero-ssh\s*--\s*DO\s*NOT\s*REMOVE\s*THIS\s*LINE\s*\n.*?^#\s*hubzero-ssh\s*--\s*DO\s*NOT\s*REMOVE\s*THIS\s*LINE\s*(\n+|$)'
        pattern3 = r'(?ims)^\n*#\s*hubzero-sftp\s*--\s*DO\s*NOT\s*REMOVE\s*THIS\s*LINE\s*\n.*?^#\s*hubzero-sftp\s*--\s*DO\s*NOT\s*REMOVE\s*THIS\s*LINE\s*(\n+|$)'

        txt = re.sub(pattern1, "", configtxt)
        txt = re.sub(pattern2, "", txt)
        txt = re.sub(pattern3, "", txt)

        #   virtualssh    ssh    sftp
        #       0          0       0    --  GOOD
        #       0          0       1    --  GOOD
        #       0          1       0    --  GOOD
        #       0          1       1    --  GOOD
        #       1          0       0    --  GOOD
        #       1          0       1    --  GOOD
        #       1          1       0    --  GOOD
        #       1          1       1    --  GOOD

        # possibly simpler to just directly define all 8 combinations
        newtxt  = ""
        
        if enable_mwvirtualssh:
            newtxt += "\n"
            newtxt += "# hubzero-mw-virtualssh -- DO NOT REMOVE THIS LINE\n"
            newtxt += "XAuthLocation /usr/share/hubzero-mw-client/xauth-incoming\n"
            newtxt += "\n"

            if enable_ssh:
               newtxt += "Match Group !tunnelers,!root,!staff,!adm,!hnusers,ctusers User *,!www-data\n"
            else:
               newtxt += "Match Group !root,!staff,!adm,ctusers User *,!www-data\n"
            
            newtxt += "    AllowTcpForwarding no\n"
            newtxt += "    ForceCommand /usr/share/hubzero-mw-client/virtualssh\n"

            if enable_ssh:
                newtxt += "\n"
                newtxt += "Match Group tunnelers,!root,!staff,!adm,!hnusers,ctusers User *,!www-data\n"
                newtxt += "    AllowTcpForwarding yes\n"
                newtxt += "    ForceCommand /usr/share/hubzero-mw-client/virtualssh\n"
            elif not enable_sftp:
                newtxt += "\n"
                newtxt += "Match Group *,!root,!staff,!adm User *,!www-data\n"
                newtxt += "    AllowTcpForwarding no\n"
                newtxt += "    ForceCommand /bin/false\n"
            
            newtxt += "# hubzero-mw-virtualssh -- DO NOT REMOVE THIS LINE\n"

        if enable_ssh:
            newtxt += "\n"
            newtxt += "# hubzero-ssh -- DO NOT REMOVE THIS LINE\n"
            if not enable_sftp:
                if enable_mwvirtualssh:
                    newtxt += "Match Group tunnelers,!root,!staff,!adm,!hnusers,!ctusers User *,!www-data\n"
                else:
                    newtxt += "Match Group tunnelers,!root,!staff,!adm,!hnusers User *,!www-data\n"
                newtxt += "    AllowTcpForwarding yes\n"
                newtxt += "    ForceCommand /bin/false\n"
                newtxt += "\n"

                if enable_mwvirtualssh:
                    newtxt += "Match Group *,!tunnelers,!root,!staff,!adm,!hnusers,!ctusers User *,!www-data\n"
                else:
                    newtxt += "Match Group *,!tunnelers,!root,!staff,!adm,!hnusers User *,!www-data\n"
                newtxt += "    AllowTcpForwarding no\n"
                newtxt += "    ForceCommand /bin/false\n"
            newtxt += "# hubzero-ssh -- DO NOT REMOVE THIS LINE\n"

        if enable_sftp:
            newtxt += "\n"
            newtxt += "# hubzero-sftp -- DO NOT REMOVE THIS LINE\n"
            if enable_mwvirtualssh and enable_ssh:
                newtxt += "Match Group *,!tunnelers,!root,!staff,!adm,!hnusers,!ctusers User *,!www-data\n"
            elif enable_ssh:
                newtxt += "Match Group *,!tunnelers,!root,!staff,!adm,!hnusers User *,!www-data\n"
            elif enable_mwvirtualssh:
                newtxt += "Match Group *,!root,!staff,!adm,!ctusers User *,!www-data\n"
            else:
                newtxt += "Match Group *,!root,!staff,!adm User *,!www-data\n"
            newtxt += "    X11Forwarding no\n"
            newtxt += "    AllowTcpForwarding no\n"
            newtxt += "    ForceCommand internal-sftp\n"
            newtxt += "    ChrootDirectory /sftp\n"
            
            if enable_ssh: 
                newtxt += "\n"
                if enable_mwvirtualssh:
                    newtxt += "Match Group tunnelers,!root,!staff,!adm,!hnusers,!ctusers User *,!www-data\n"
                else:
                    newtxt += "Match Group tunnelers,!root,!staff,!adm,!hnusers User *,!www-data\n"
                newtxt += "    X11Forwarding no\n"
                newtxt += "    AllowTcpForwarding yes\n"
                newtxt += "    ForceCommand internal-sftp\n"
                newtxt += "    ChrootDirectory /sftp\n"

            newtxt += "# hubzero-sftp -- DO NOT REMOVE THIS LINE\n"

        txt = txt.rstrip() + "\n" + newtxt

        if (txt != configtxt):
            fh.seek(0)
            fh.write(txt)
            fh.truncate()
            print "patched " + "/etc/ssh/sshd_config"
            serviceInit('ssh','restart')

        fh.close()


def groupExists(name):
    try:
        (name, passwd, gid, mem) = grp.getgrnam(name)
    except:
        return False

    return True


def createSshGroups():
    print "checking hnusers group"
    if not groupExists("hnusers"):
        print "adding 'hnusers' group"
        rc, stdOut, stdErr = hubzero.utilities.misc.exShellCommand(["groupadd", "--system", "hnusers"])

    print "checking tunnelers group"
    if not groupExists("tunnelers"):
        print "adding 'tunnelers' group"
        rc, stdOut, stdErr = hubzero.utilities.misc.exShellCommand(["groupadd", "--system", "tunnelers"])


def reconfigureNslcdConfig(useGroups):

    print "checking /etc/nslcd.conf"

    if os.path.exists("/etc/nslcd.conf"):
        fh = open("/etc/nslcd.conf", 'r+')
        configtxt = fh.read()

        if useGroups:
            # filter shadow (&(objectClass=posixAccount)(host=web))
            # pam_authz_search (&(objectClass=posixAccount)(uid=$username)(host=web))

            pattern1 = r'(?im)(^\s*filter\s+shadow\s+)\(\s*\&\s*(\(\s*objectClass\s*=\s*posixAccount\s*\))\s*\(\s*host\s*=\s*web\s*\s*\)\s*\)(.*$)'
            pattern2 = r'(?im)(^\s*pam_authz_search\s+\(\s*\&\s*\(\s*objectClass\s*=\s*posixAccount\s*\)\s*\(\s*uid\s*=\s*\$username\s*\)\s*)\(\s*host\s*=\s*web\s*\)(\s*\).*$)'
        
            (txt, count) = re.subn(pattern1, r'\1\2\3', configtxt)
            (txt, count) = re.subn(pattern2, r'\1\2', txt)
        else:
            # filter shadow (objectClass=posixAccount)
            # pam_authz_search (&(objectClass=posixAccount)(uid=$username))

            pattern1 = r'(?im)(^\s*filter\s+shadow\s+)(\s*\(objectClass\s*=\s*posixAccount\s*\))(.*$)'
            pattern2 = r'(?im)(^\s*pam_authz_search\s+\(\s*\&\s*\(\s*objectClass\s*=\s*posixAccount\s*\)\s*\(\s*uid\s*=\s*\$username\s*\))(\s*\).*$)'
            (txt, count) = re.subn(pattern1,r'\1(&\2(host=web))\3',configtxt)
            (txt, count) = re.subn(pattern2,r'\1(host=web)\2',txt)

        if txt != "" and txt[-1] != "\n":
            txt = txt + "\n"

        if (txt != configtxt):
            fh.seek(0)
            fh.write(txt)
            fh.truncate()
            print "patched " + "/etc/nslcd.conf"
            serviceInit('nslcd','restart')

        fh.close()

    else:
        print "/etc/nslcd.conf missing, can't reconfigure it"


def _mwVirtualsshConfigure(args):
    mwVirtualsshConfigure(args.enable)


def mwVirtualsshConfigure(enable):

    hubname = hubzero.config.webconfig.getDefaultSite()

    enable_mwvirtualssh = enable
    enable_sftp = hubzero.config.webconfig.getHubSiteConfig(hubname, "package-config", "sftp") == 'true'
    enable_ssh = hubzero.config.webconfig.getHubSiteConfig(hubname, "package-config", "ssh") == 'true'

    if enable:
        createSshGroups()

        print "checking ctusers group"
        if not groupExists("ctusers"):
            print "adding 'ctusers' group"
            rc, stdOut, stdErr = hubzero.utilities.misc.exShellCommand(["groupadd", "--system", "ctusers"])

        reconfigureSshdConfig(enable_sftp, enable_ssh, enable_mwvirtualssh)
        reconfigureNslcdConfig(True if enable_sftp or enable_ssh or enable_mwvirtualssh else False)
        modifyHubConfigFile("package-config", 'mw-virtualssh', 'true')

    else:
        reconfigureNslcdConfig(True if enable_sftp or enable_ssh or enable_mwvirtualssh else False)
        reconfigureSshdConfig(enable_sftp, enable_ssh, enable_mwvirtualssh)
        modifyHubConfigFile("package-config", 'mw-virtualssh', 'false')      

def _sshConfigure(args):
    sshConfigure(args.enable) 

def sshConfigure(enable):

    hubname = hubzero.config.webconfig.getDefaultSite()

    enable_mwvirtualssh = hubzero.config.webconfig.getHubSiteConfig(hubname, "package-config", "mw-virtualssh") == 'true'
    enable_sftp = hubzero.config.webconfig.getHubSiteConfig(hubname, "package-config", "sftp") == 'true'
    enable_ssh = enable

    if enable:
        reconfigureSshdConfig(enable_sftp, enable_ssh, enable_mwvirtualssh)
        reconfigureNslcdConfig(True if enable_sftp or enable_ssh or enable_mwvirtualssh else False)
        modifyHubConfigFile("package-config", 'ssh', 'true')
    else:
        reconfigureNslcdConfig(True if enable_sftp or enable_ssh or enable_mwvirtualssh else False)
        reconfigureSshdConfig(enable_sftp, enable_ssh, enable_mwvirtualssh)
        modifyHubConfigFile("package-config", 'ssh', 'false')


def _sftpConfigure(args):
    if (args.enable):
        sftpEnable()
    else:
        sftpDisable()

def sftpDisable():
    hubname = hubzero.config.webconfig.getDefaultSite()	
    enable_mwvirtualssh = hubzero.config.webconfig.getHubSiteConfig(hubname, "package-config", "mw-virtualssh") == 'true'
    enable_sftp = False
    enable_ssh = hubzero.config.webconfig.getHubSiteConfig(hubname, "package-config", "ssh") == 'true'
    restart_autofs = False

    # @TODO try to delete these directories
    # removeDirIfEmpty("/sftp/home")
    # removeDirIfEmpty("/sftp")
    # maybe try to umount

    filename = '/etc/auto.master'

    if os.path.exists(filename):
        fh = open(filename, 'r+')
        configtxt = fh.read()
        (txt, count) = re.subn(r'(?im)^\n*^.*?/sftp/home\s*/etc/auto.home\n.*(\n+|$)', "", configtxt)

        if txt != "" and txt[-1] != "\n":
            txt = txt + "\n"

        if (txt != configtxt):
            fh.seek(0)
            fh.write(txt)
            fh.truncate()
            print "patched " + filename
            restart_autofs = True

        fh.close()

    filename = '/etc/auto.home'

    if os.path.exists(filename):
        fh = open(filename, 'r+')
        configtxt = fh.read()
        (txt, count) = re.subn(r'(?im)^\n*^.*?' + hubname + r'\s*-rw,hard,bg,tcp\s*:/home/' + hubname + r'.*?(\n+|$)', "", configtxt)

        if txt != '' and txt[-1] != "\n":
            txt = txt + "\n"

        if (txt != configtxt):
            fh.seek(0)
            fh.write(txt)
            fh.truncate()
            print "patched " + filename
            restart_autofs = True

        fh.close()

    reconfigureSshdConfig(enable_sftp, enable_ssh, enable_mwvirtualssh)
    reconfigureNslcdConfig(True if enable_sftp or enable_ssh or enable_mwvirtualssh else False)

    if restart_autofs:
        serviceInit('autofs','restart')

    modifyHubConfigFile("package-config", 'sftp', 'false')
    
def sftpEnable():
    hubname = hubzero.config.webconfig.getDefaultSite()	

    enable_mwvirtualssh = hubzero.config.webconfig.getHubSiteConfig(hubname, "package-config", "mw-virtualssh") == 'true'
    enable_sftp = True
    enable_ssh = hubzero.config.webconfig.getHubSiteConfig(hubname, "package-config", "ssh") == 'true'

    restart_autofs = False

    createSshGroups()

    createDir("/sftp", "0755", "root", "root", resetattrs=True)
    createDir("/sftp/home", "0755", "root", "root", resetattrs=True)

    fileText = "\n/sftp/home		/etc/auto.home\n"
    filename = '/etc/auto.master'

    if not os.path.exists(filename):
        fh = open(filename, 'w')
        configtxt = ''
        txt = fileText
    else:
        fh = open(filename, 'r+')
    
        configtxt = fh.read()
        (txt, count) = re.subn(r'(?im)^\n*^.*?/sftp/home\s*/etc/auto.home\n.*?(\n+|$)', "/sftp/home		/etc/auto.home\n", configtxt)
        if count < 1:
           txt = configtxt.rstrip("\n \t\r") + fileText

    if txt != '' and txt[-1] != "\n":
        txt = txt + "\n"

    if (txt != configtxt):
        fh.seek(0)
        fh.write(txt)
        fh.truncate()
        print "patched " + filename
        restart_autofs = True

    fh.close()

    fileText = "\n" + hubname + "    -rw,hard,bg,tcp    :/home/" + hubname + "\n"
    filename = '/etc/auto.home'

    if not os.path.exists(filename):
        fh = open(filename, 'w')
        configtxt = ''
        txt = fileText
    else:
        fh = open(filename, 'r+')
        configtxt = fh.read()
        (txt, count) = re.subn(r'(?im)^\n*^.*?' + hubname + r'\s*-rw,hard,bg,tcp\s*:/home/' + hubname + '.*?(\n+|$)', fileText, configtxt)
        if count < 1:
            txt = configtxt.rstrip("\n \t\r") + fileText

    if txt != '' and txt[-1] != "\n":
        txt = txt + "\n"

    if (txt != configtxt):
        fh.seek(0)
        fh.write(txt)
        fh.truncate()
        print "patched " + filename
        restart_autofs = True

    fh.close()

    reconfigureNslcdConfig(True if enable_sftp or enable_ssh or enable_mwvirtualssh else False)
    reconfigureSshdConfig(enable_sftp, enable_ssh, enable_mwvirtualssh)

    if restart_autofs:
        serviceInit('autofs','restart')

    modifyHubConfigFile("package-config", 'sftp', 'true')

def _openvzConfigure(args):
    if (args.enable):
        openvzEnable()
    else:
        openvzDisable()

def openvzEnable():

    print "enabling openvz"

    hubname = hubzero.config.webconfig.getDefaultSite() 

    (sysname, nodename, release, version, machine) = os.uname()
    
    if (machine == 'x86_64'):
        arch = 'amd64'
    elif (machine == 'i686'):
        arch = '686'
    else:
        print "hzcms doesn't recognize this machine type: " + machine
        return

    if hubzero.utilities.misc.isRHEL():        
        kernelstring = 'stab'
        print "hzcms doesn't know how to configure openvz on RedHat"
        return

    if not hubzero.utilities.misc.isDebian():
        kernelstring = 'unknown'
        print "hzcms doesn't know how to configure openvz on this unknown Linux distribution"
        return

    (distname, version, id) = platform.linux_distribution('debian','debian')
    
    if version.startswith('6.') or version.startswith('5.'):
        kernelstring = 'openvz'
    elif version.startswith('7.') or version.stratswith('4.'):
        kernelstring = 'stab'
    else:
        print "hzcms doesn't know to configure openvz on this version of Debian GNU/Linux: " + version
        return

    grubfn = "/boot/grub/grub.cfg"
    grubfh = open(grubfn,'r')
    grubtxt = grubfh.read()
    grubfh.close()

    menuentries = re.findall(r'(?m)^.*/boot/vmlinuz-.*\s', grubtxt)
    entry = 0
    vzrelease = ''

    for menuentry in menuentries:
        if menuentry.find(kernelstring) != -1 and menuentry.find(' single') == -1:
            m = re.search(r'vmlinuz-(.*?)\s',menuentry)
            if m:
                vzrelease = m.group(1)
            break
        entry = entry + 1
    
    if entry > len(menuentries):
        print "hzcms didn't find an openvz kernel in the grub menu list."
        return

    print "checking /etc/default/grub"
    try:
        grubfn = "/etc/default/grub"
        grubfh = open(grubfn,'r+')
        grubtxt = grubfh.read()

        txt = re.sub(r'(?m)^\s*GRUB_DEFAULT\s*=.*$','GRUB_DEFAULT='+str(entry),grubtxt)

        if (txt != grubtxt):
            grubfh.seek(0)
            grubfh.write(txt)
            grubfh.truncate()
            print "patched " + grubfn
            print "/usr/sbin/update-grub"
            rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/update-grub"]) 
            if rc: print procStdErr

        grubfh.close()
    except:
        print "Failed to patch file: " + grubfn
        raise
    
    
    if hubzero.utilities.misc.isDebian() and kernelstring == 'stab':
        print "checking /etc/modules"
        try:
            modulesfn = "/etc/modules"
            modulesfh = open(modulesfn,"r+")
            modulestxt = modulesfh.read()

            txt = re.sub(r'(?m)^\s*loop($|\s+.*$)',r'#loop\1',modulestxt)
            if (txt != modulestxt):
                modulesfh.seek(0)
                modulesfh.write(txt)
                modulesfh.truncate()
                print "patched " + modulesfn
            modulesfh.close()
        except:
            print "Failed to patch " + modulesfn
            pass

    print "checking /etc/sysctl.conf"
    try:
        sysctlfn = "/etc/sysctl.conf"
        sysctlfh = open(sysctlfn,"r+")
        sysctltxt = sysctlfh.read()

        txt = re.sub(r'(?m)^\s*#\s*net.ipv4.ip_forward\s*=.*$','net.ipv4.ip_forward=1',sysctltxt)

        if (txt != sysctltxt):
            sysctlfh.seek(0)
            sysctlfh.write(txt)
            print "patched " + sysctlfn
        
        sysctlfh.close()
    except:
        print "Failed to patch " + sysctlfn
        pass

    print "checking /proc/sys/net/ipv4/ip_forward"
    try:
        ipffn = "/proc/sys/net/ipv4/ip_forward"
        ipffh = open(ipffn,"r+")
        ipfftxt = ipffh.read()

        if ipfftxt != '1\n':
            ipffh.seek(0)
            ipffh.write('1\n')
            print "patched " + ipffn
        ipffh.close()
    except:
        print "Failed to patch " + ipffn
        pass

    if release.find(kernelstring) == -1:
        print "\nOpenVZ is configured. Please restart to boot into the OpenVZ kernel"
    else:
        print "\nOpenVZ is configured and running."

    modifyHubConfigFile("package-config", 'openvz', 'true')


def openvzDisable():

    print "disabling OpenVZ kernel"

    hubname = hubzero.config.webconfig.getDefaultSite() 

    (sysname, nodename, release, version, machine) = os.uname()
    
    if (machine == 'x86_64'):
        arch = 'amd64'
    elif (machine == 'i686'):
        arch = '686'
    else:
        print "hzcms doesn't recognize this machine type: " + machine
        return

    if hubzero.utilities.misc.isRHEL():        
        kernelstring = 'stab'
        print "hzcms doesn't know how to unconfigure openvz on RedHat"
        return

    if not hubzero.utilities.misc.isDebian():
        kernelstring = 'unknown'
        print "hzcms doesn't know how to unconfigure openvz on this unknown Linux distribution"
        return

    (distname, version, id) = platform.linux_distribution('debian','debian')
    
    if version.startswith('6.') or version.startswith('5.'):
        kernelstring = 'openvz'
    elif version.startswith('7.'):
        kernelstring = 'stab'
    else:
        print "hzcms doesn't know to unconfigure openvz on this version of Debian GNU/Linux: " + version
        return

    grubfn = "/boot/grub/grub.cfg"
    grubfh = open(grubfn,'r')
    grubtxt = grubfh.read()
    grubfh.close()

    menuentries = re.findall(r'(?m)^.*/boot/vmlinuz-.*\s', grubtxt)
    entry = 0
    vzrelease = ''

    for menuentry in menuentries:
        if menuentry.find(kernelstring) == -1 and menuentry.find(' single') == -1:
            m = re.search(r'vmlinuz-(.*?)\s',menuentry)
            if m:
                vzrelease = m.group(1)
            break
        entry = entry + 1
    
    if entry > len(menuentries):
        print "hzcms didn't find a non-openvz kernel in the grub menu list."
        return

        print "checking /etc/default/grub"
        try:
            grubfn = "/etc/default/grub"
            grubfh = open(grubfn,'r+')
            grubtxt = grubfh.read()

            txt = re.sub(r'(?m)^\s*GRUB_DEFAULT\s*=.*$','GRUB_DEFAULT='+str(entry),grubtxt)
            if (txt != grubtxt):
                grubfh.seek(0)
                grubfh.write(txt)
                grubfh.truncate()
                print "patched " + grubfn
                print "/usr/sbin/update-grub"
                rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/update-grub"]) 
                if rc: print procStdErr
            grubfh.close()
        except:
            print "Failed to patch " + grubfn
            raise
    
    if hubzero.utilities.misc.isDebian() and kernelstring == 'stab':
        print "checking /etc/modules"
        try:
            modulesfn = "/etc/modules"
            modulesfh = open(modulesfn,"r+")
            modulestxt = modulesfh.read()

            txt = re.sub(r'(?m)^\s*#\s*loop($|\s+.*$)',r'loop\1',modulestxt)
            if (txt != modulestxt):
                modulesfh.seek(0)
                modulesfh.write(txt)
                modulesfh.truncate()
                print "patched " + modulesfn
            modulesfh.close()
        except:
            print "Failed to patch " + modulesfn
            pass
              
    print "\nYou may want to turn off ipv4_ipforward in /etc/sysctl.conf"
    print "You may want to disable IP forwarding in /proc/sys/net/ipv4/ip_forward"

    if release.find(kernelstring) != -1:
        print "The OpenVZ kernel is now unconfigured but it still running."
        print "Please reboot into a non-OpenVZ kernel"
    else:
        print "The OpenVZ is unconfigured and not running."

    modifyHubConfigFile("package-config", 'openvz', 'false')

def _telequotadConfigure(args):
    if (args.enable):
        telequotadEnable()
    else:
        telequotadDisable()

def telequotadEnable():
    hubzero.config.webconfig.addComponentParam('com_tools', 'show_storage', '1')
    hubzero.config.webconfig.addModuleParam('My Sessions', 'show_storage', '1')

def telequotadDisable():
    hubzero.config.webconfig.addComponentParam('com_tools', 'show_storage', '0')
    hubzero.config.webconfig.addModuleParam('My Sessions', 'show_storage', '0')


def _cronConfigure(args):
    if (args.enable):
        cronEnable()
    else:
        cronDisable()

def cronEnable():
    hubname = hubzero.config.webconfig.getDefaultSite() 

    createDir("/etc/hubzero-cms/" + hubname + "/", "0755", "root", "root", resetattrs=True)
    createDir("/var/log/hubzero-cms/", 0770, webUser(),  webGroup(), resetattrs=True)
    createDir("/var/log/hubzero-cms/daily", 0770, webUser(),  webGroup(), resetattrs=True)
    createDir("/var/log/hubzero-cms/daily/cron", 0770, webUser(),  webGroup(), resetattrs=True)
    createFile("/var/log/hubzero-cms/" + hubname + "-cmscron.log", 0640, webUser(), webGroup(), resetattrs=True)
    usrfilename = "/usr/share/hubzero-cli/conf/cron-cmscron.m4"
    etcfilename = "/etc/hubzero-cms/" + hubname + "/cron-cmscron.m4"
    cronfilename = "/etc/cron.d/" + hubname + "-cmscron"

    if not os.path.exists(etcfilename):
        # copy over the base template files
        print "copy2 " + usrfilename + " to " + etcfilename
        shutil.copy2(usrfilename,etcfilename)

    m4Processing(etcfilename, cronfilename, ["-DHUBNAME=" + hubname], 0644, "root", "root", resetattrs=True) 

    usrfilename = "/usr/share/hubzero-cli/conf/logrotate-cmscron.m4"
    etcfilename = "/etc/hubzero-cms/" + hubname + "/logrotate-cmscron.m4"
    logrotatefilename = "/etc/logrotate.d/" + hubname + "-cmscron"

    if not os.path.exists(etcfilename):
        # copy over the base template files
        print "copy2 " + usrfilename + " to " + etcfilename
        shutil.copy2(usrfilename, etcfilename)

    m4ConfigOptions = []

    try:
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(
            ["/usr/bin/strings", "/usr/sbin/logrotate" ] )

        if rc : print procStdErr
    except:
        raise

    if 'because parent directory has insecure' in procStdOut:
        m4ConfigOptions.append("-DUSE_SU")

    m4ConfigOptions.append("-DHUBNAME=" + hubname)

    m4Processing(etcfilename, logrotatefilename, m4ConfigOptions, 0644, "root", "root", resetattrs=True)    

    if os.path.exists("/etc/init.d/cron"):
        serviceInit('cron','reload')
    else:
        serviceInit('crond','reload')

def cronDisable():
    hubname = hubzero.config.webconfig.getDefaultSite() 

    cronfilename = "/etc/cron.d/" + hubname + "-cmscron"

    if os.path.exists(cronfilename):
        print "remove " + cronfilename
        os.remove(cronfilename)

    logrotatefilename = "/etc/logrotate.d/" + hubname + "-cmscron"

    if os.path.exists(logrotatefilename):
        print "remove " + logrotatefilename
        os.remove(logrotatefilename)

    serviceInit('cron','reload')


def _createDHCPExitHookFile(args):
    fileName = "/etc/dhcp/dhclient-exit-hooks.d/dhcpleaseupdate"
    fileText = """# our custom change is delimited by #.# ... #.#
# just delete this and replace it every time
sed -i "/\#\.\#/,/\#\.\#/d" /etc/hosts

hn=$(hostname)
fqdn=$(hostname -f)
date=`date`

line="$new_ip_address $fqdn $hn"
t="#.# Do not edit. Auto inserted section by /etc/dhcp/dhclient-exit-hooks.d/dhcpleaseupdate script on $date \\n$line\\n#.#"

sed -i "1i $t" /etc/hosts"""

    if args.enable:
        with open(fileName, "w") as f1:
            f1.write(fileText)

        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chmod", "0644", fileName])	
        if rc: print procStdErr

    else:
        if os.path.exists(fileName):
            os.remove(fileName)

def updateDatabaseSchema(document_root = None, force = False, component = None):

    print "checking database schema"

    if document_root == None:    
        hubname = hubzero.config.webconfig.getDefaultSite()
        document_root = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")
    
    if not os.path.isdir(document_root):
        print "document root does not exist"
        return False

    if "hubzero-cms-2.0.0" in HUBZERO_CMS_DIR:
        schemaUpdateFilename = HUBZERO_CMS_DIR + "/cms/core/bootstrap/install/sql/mysql/updates.sql"
    elif "hubzero-cms-2.1.0" in HUBZERO_CMS_DIR:
        schemaUpdateFilename = HUBZERO_CMS_DIR + "/cms/core/bootstrap/install/sql/mysql/updates.sql"
    else:
        schemaUpdateFilename = HUBZERO_CMS_DIR + "/cms/installation/sql/mysql/updates.sql"

    if os.path.exists(schemaUpdateFilename):
        print "updating database schema"

        dbPW = hubzero.config.webconfig.getWebConfigDBPassword(document_root)
        dbUserName = hubzero.config.webconfig.getWebConfigDBUsername(document_root)
        dbName = hubzero.config.webconfig.getWebConfigDBName(document_root)
        db =  hubzero.data.db.MySQLConnection("localhost", dbName, dbUserName, dbPW)

        #if hubzero.utilities.misc.JOOMLA_25:
        #    sql = """
        #UPDATE `jos_xgroups` SET type=0, published=1 WHERE cn IN ('apps','network','submit');
        #"""
    
        with open(schemaUpdateFilename) as f:
            print "updating database schema by applying " + schemaUpdateFilename
            for line in f:
                if line == "":
                    continue
                try:
                    #print s
                    db.query_rowcount(line, None)
                except Exception as e:
                    #print e
                    pass

    museCmd = ""
    if os.path.exists(document_root + "/cli/muse.php"):
        museCmd = document_root + "/cli/muse.php"
    if os.path.exists(document_root + "/muse"):
        museCmd = document_root + "/muse"

    if os.path.exists(museCmd):
        options = ["/usr/bin/php", museCmd, "migration", "-i"]
        if (component != None):
            options.append('-e=' + component)
        output, err = subprocess.Popen(options,stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
        for s in output.split("\n"):
            if force == True or "Would run" in s:
                options.append('-f')
                if (force == True):
                    options.append('--force')
                print " ".join(options)
                output, err = subprocess.Popen(options,stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
                if err:
                    print err
                for s in output.split("\n"):
                    s = s.strip()

                    if s == '':
                        continue

                    if "Ignoring up()" in s:
                        continue

                    if "Ignore dates: all eligible" in s:
                        continue

                    print s
                break
    elif os.path.exists(document_root + "/bin/migration.php"):
        output, err = subprocess.Popen(["/usr/bin/php", document_root+"/bin/migration.php", "-i"],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
        for s in output.split("\n"):
            if "Would run" in s:
                print "/usr/bin/php " + document_root + "/bin/migration.php -i -f"
                output, err = subprocess.Popen(["/usr/bin/php", document_root+"/bin/migration.php", "-i", "-f"],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
                if err:
                    print err
                for s in output.split("\n"):
                    s = s.strip()

                    if s == '':
                        continue

                    if "Ignoring up()" in s:
                        continue
                    if "Ignore dates: all eligible" in s:
                        continue

                    print s
                break


# To regenerate this file:
#
# git log --summary --reverse | sed -e '/ delete mode ...... /!d;s/ .\{19\}/\.\//' | xargs -I {} sh -c "[ ! -f '{}' ]  && echo '{}'" > deleted-files.txt
#
# since 2.1.0 we change this to exclude the hubzero-cms core directory which we always force replace on update
#
# git log --summary --reverse | sed -e '/ delete mode ...... /!d;s/ .\{19\}/\.\//' | grep -v "^\./core" | xargs -I {} sh -c "[ ! -f '{}' ]  && echo '{}'" > deleted-files.txt
#
# Since development sometimes continues on other branches we also create an orphaned-files.txt which includes files
# that were added to other branches but aren't in the current branch. This list has to be manually created 
# at this time.
#
# When processing this list a script should:
#
# * ignore any line not starting with "./"
# * normalize path to remove any attempts escape the document root
# * ignore any result that does not resolve to a file or symbolic link
# * remove containing directory if empty after removing result
#
# gitcheck = false apply even if document root is "git" controlled
# dryrun = true, print what would be done, but don't do it
# quiet = true, don't print errors
# 

#
# @TODO the detection of when to delete directories is cumbersome and
#       time consuming. do something better.
#

def updateDeletedFiles(document_root = None, gitcheck = True, dryrun = True, quiet = False, verbose = False):

    print "removing deleted code files"

    if document_root == None:    
        hubname = hubzero.config.webconfig.getDefaultSite()
        document_root = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")
    
    if not os.path.isdir(document_root):
        return True

    if os.path.isdir(document_root + "/.git") and gitcheck:
        return True

    deletedFilesFilename = document_root + "/core/bootstrap/install/deleted-files.txt"
    
    if not os.path.exists(deletedFilesFilename):
        deletedFilesFilename = document_root + "/installation/deleted-files.txt"    

    if os.path.exists(deletedFilesFilename):
        with open(deletedFilesFilename, "r") as f:
            for line in f:
                filename = line.strip()

                if filename.startswith("./"):
                    filename = os.path.normpath(filename)
                    if os.path.isfile(document_root + "/" + filename):
                        os.remove(document_root + "/" + filename)
                        #print "rm " + document_root + "/" + filename

                    directory_name = os.path.dirname(document_root + "/" + filename)
                    if os.path.isdir(directory_name):
                        found_files = False
                        for dirpath, dirnames, filenames in os.walk( directory_name ):
                            if filenames != []:
                                found_files = True
                                break

                        if not found_files:
                            shutil.rmtree(directory_name)
                            try:
                                os.removedirs(os.path.dirname(directory_name))
                            except OSError:
                                pass
                            #print "rmtree " + directory_name

                    continue
                elif filename.startswith("#"):
                    continue
                elif filename == "":
                    continue
            
                print "Remove deleted files [skipping invalid filename " + filename + "]"

    if deletedFilesFilename != document_root + "/installation/deleted-files.txt":
        if os.path.exists(document_root + "/cache"):
            shutil.rmtree(document_root + "/cache")
            print "rmtree " + document_root + "/cache"

        try:
            if os.path.exists(document_root + "/media/software"):
                os.rmdir(document_root + "/media/software")
                print "rmdir " + document_root + "/media/software"
            if os.path.exists(document_root + "/media"):
                os.rmdir(document_root + "/media")
                print "rmdir " + document_root + "/media"
        except OSError:
            pass
  
    orphanedFilesFilename = document_root + "/core/bootstrap/install/orphaned-files.txt"

    if not os.path.exists(orphanedFilesFilename):
        orphanedFilesFilename = document_root + "/installation/orphaned-files.txt"    

    if os.path.exists(orphanedFilesFilename):
        with open(orphanedFilesFilename, "r") as f:
            for line in f:
                filename = line.strip()

                if filename.startswith("./"):
                    filename = os.path.normpath(filename)
                    if os.path.isfile(document_root + "/" + filename):
                        os.remove(document_root + "/" + filename)
                        #print "rm " + document_root + "/" + filename

                        directory_name = os.path.dirname(document_root + "/" + filename)

                        if os.path.isdir(directory_name):
                            found_files = False
                            for dirpath, dirnames, filenames in os.walk( directory_name ):
                                if filenames != []:
                                    found_files = True
                                    break

                            if not found_files:
                                shutil.rmtree(directory_name)
                                try:
                                    os.removedirs(os.path.dirname(directory_name))
                                except OSError:
                                    pass
                                #print "rmtree " + directory_name

                    continue
                elif filename.startswith("#"):
                    continue
                elif filename == "":
                    continue
            
                print "Remove orphaned files [skipping invalid filename " + filename + "]"

def moveTemplates(document_root = None, gitcheck = True, dryrun = True, quiet = False, verbose = False):

    if document_root == None:    
        hubname = hubzero.config.webconfig.getDefaultSite()
        document_root = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")
    
    if not os.path.isdir(document_root):
        return True

    if os.path.isdir(document_root + "/.git") and gitcheck:
        return True

    if not os.path.exists(document_root + "/app"):
        return True
    
    directory_name = document_root + "/templates"

    if os.path.exists(directory_name) and not os.path.islink(directory_name):
        print "move custom templates"

        file_list = os.listdir( directory_name )

        for template_dir in file_list:
            if not os.path.exists(document_root + "/app/templates/" + template_dir):
                shutil.move(document_root + "/templates/" + template_dir, document_root + "/app/templates")
                print "move " + document_root + "/templates/" + template_dir + " to " + document_root + "/app/templates/"
       
                if not os.path.exists(document_root + "/app/templates/" + template_dir + "/language"):
                    createDir(document_root + "/app/templates/" + template_dir + "/language", "0750", webUser(), webGroup(), resetattrs=True)

                if not os.path.exists(document_root + "/app/templates/" + template_dir + "/language/en-GB"):
                    createDir(document_root + "/app/templates/" + template_dir + "/language/en-GB", "0750", webUser(), webGroup(), resetattrs=True)

                if os.path.exists(document_root + "/language/en-GB/en-GB.tpl_" + template_dir + ".ini"):
                    shutil.move(document_root + "/language/en-GB/en-GB.tpl_" + template_dir + ".ini", document_root + "/app/templates/" + template_dir + "/language/en-GB")
                    print "move " + document_root + "/language/en-GB/en-GB.tpl_" + template_dir + ".ini" + " to " + document_root + "/app/templates/" + template_dir + "/language/en-GB"
                    langdirectory_name = document_root + "/language"
                    if os.path.isdir(langdirectory_name):
                        found_files = False
                        for dirpath, dirnames, filenames in os.walk( langdirectory_name ):
                            if filenames != []:
                                found_files = True
                                break

                        if not found_files:
                            shutil.rmtree(langdirectory_name)
                            print "rmtree " + langdirectory_name

                fixTemplate(template_dir)

        file_list = os.listdir( directory_name )

        if file_list == []:
            os.removedirs(directory_name)
            print "removedirs " + directory_name


def fixMySQLRootSecret():

    print "checking /etc/hubzero.secrets [MYSQL-ROOT]"

    secretsFileLocation = "/etc/hubzero.secrets"

    file = open(secretsFileLocation)

    fileContents = file.read().rstrip()
    file.close()

    m = re.search("^\s*MYSQL-ROOT\s*=\s*(.*)$", fileContents, re.MULTILINE)
    
    if m:
        return True

    guesses = ['','hubzero2010','hubzero2011','hubzero2012','hubzero2013']

    for guess in guesses:
        try:
            db =  hubzero.data.db.MySQLConnection("localhost", "mysql", "root", guess)
        except MySQLdb.OperationalError as e:
            if e.args[0] == 1045:
                continue
            else:
                raise e

        if db:
            if guess == '':
                guess = generateAlphaNumPassword(10)
                sql = "UPDATE mysql.user SET Password = PASSWORD('%s') WHERE User = 'root' AND Password=''; FLUSH PRIVILEGES;" % (guess)
                count = db.query_rowcount(sql, None)
                print "set mysql root password on %d accounts that previously had no password" % (count)

            fileContents += "\nMYSQL-ROOT = %s\n" % (guess)
            print "patching /etc/hubzero.secrets"
            with open(secretsFileLocation, "w+") as f:
                f.write(fileContents)
            return True

    print "unable to determine root MySQL password, can not continue"
    raise Exception

    return False

def _updateTimezoneDatabase(args):

    rootmysqlpw = None
    rootmysqlrootusername = 'root'    

    if os.path.exists("/root/.my.cnf"):
        config = ConfigParser.RawConfigParser()
        config.read("/root/.my.cnf")
        rootmysqlpw = config.get("client", "password")
        rootmysqlrootusername = config.get("client", "user") 

    updateTimezoneDatabase(True, rootmysqlrootusername, rootmysqlpw, force = args.force)


def updateTimezoneDatabase(restart_on_update = False, rootuser = None, rootpw = None, force = False):
    
    print "checking for timezone database updates"

    my_mtime = 0
    my_filename = None

    for root, dirs, files in os.walk('/usr/share/zoneinfo', topdown=False):
        for name in files:
            name = os.path.join(root,name)
            if os.path.isfile(name):
                file_mtime = os.path.getmtime(name)
                if file_mtime > my_mtime:
                        my_mtime = file_mtime
                        my_filename = name

    createDir("/etc/hubzero", "0755", "root", "root", resetattrs=True)

    with open("/etc/hubzero/timezone.dat", "a+") as f:
        content = f.readlines()
        last_mtime = 0

        if content:
            last_mtime = content[0]

    if (last_mtime >= my_mtime) and not force:
        return False

    if rootpw == None:
        rootpw = hubzero.config.passwords.getMySqlPW()

    if not rootpw:
        print "unable to load timezone data [MySQL root password unknown]"
        return False

    if not rootuser:
        rootuser = 'root'
    
    db =  hubzero.data.db.MySQLConnection("localhost", "mysql", rootuser, rootpw)

    print "/usr/bin/mysql_tzinfo_to_sql /usr/share/zoneinfo"

    output, err = subprocess.Popen(["/usr/bin/mysql_tzinfo_to_sql","/usr/share/zoneinfo"],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()

    for s in err.split("\n"):
        s = s.strip()

        if s == '':
            continue

        if "Riyadh" in s:
            continue

        if "zone.tab" in s:
            continue

        if "iso3166.tab" in s:
            continue

        print "STDERR: " + s

    sql = output.split(';')

    print "executing " + str(len(sql)) + " SQL statements"

    for s in sql:
        s = s.strip()

        if s == '':
            continue

        if 'Local time zone must be set' in s:
            continue

        try:
            #print "string ["+s+"]"
            db.query_rowcount(s, None)
        except Exception as e:
            print s
            print "Got Exception"
            print e
            pass

    
    with open("/etc/hubzero/timezone.dat", "w+") as f:
        f.write(str(my_mtime)+"\n")
        f.write(time.ctime(my_mtime)+"\n")
        f.write(my_filename+"\n")

    if restart_on_update:
        if os.path.exists('/etc/init.d/mysql'):
            serviceInit('mysql','restart')
        else:
            serviceInit('mysqld','restart')

        blockTillMySQLRunning()

    return True

def fixVzTemplateResolvConf():

    # I'm not sure how it ever got in this state, but the distributed VM image had
    # an invalid /etc/resolv.conf in its OpenVZ template file. So we'll go 
    # ahead and check a couple common instances of this and replace the file
    # with the host's version if that seems appropriate. I believe a proper
    # one gets installed when a tool is run, but this default version is used
    # when doing a chroot based package update in the raw image.

    if os.path.exists("/var/lib/vz/template/debian-7.0-amd64-maxwell/etc/resolv.conf"):
        print "checking /var/lib/vz/template/debian-7.0-amd64-maxwell/etc/resolv.conf"
        d7resolvfh = open("/var/lib/vz/template/debian-7.0-amd64-maxwell/etc/resolv.conf",'r')
        d7resolvtxt = d7resolvfh.read()
        d7resolvfh.close()
        pattern = r'^\s*nameserver\s+192\.168\.\d+\.\d+\s*$'
        if re.match(pattern, d7resolvtxt) != None:
            print "cp /etc/resolv.conf /var/lib/vz/template/debian-7.0-amd64-maxwell/etc/resolv.conf"
            shutil.copy2("/etc/resolv.conf", "/var/lib/vz/template/debian-7.0-amd64-maxwell/etc/resolv.conf")


    if os.path.exists("/var/lib/vz/template/debian-6.0-amd64-maxwell/etc/resolv.conf"):
        print "checking /var/lib/vz/template/debian-6.0-amd64-maxwell/etc/resolv.conf"
        d6resolvfh = open("/var/lib/vz/template/debian-6.0-amd64-maxwell/etc/resolv.conf",'r')
        d6resolvtxt = d6resolvfh.read()
        d6resolvfh.close()
        pattern = r'^\s*nameserver\s+192\.168\.\d+\.\d+\s*$'
        if re.match(pattern, d6resolvtxt) != None:
            print "cp /etc/resolv.conf /var/lib/vz/template/debian-6.0-amd64-maxwell/etc/resolv.conf"
            shutil.copy2("/etc/resolv.conf", "/var/lib/vz/template/debian-6.0-amd64-maxwell/etc/resolv.conf")


def fixTemplate(template):

    hubname = hubzero.config.webconfig.getDefaultSite()
    docroot = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")

    if not os.path.isdir(docroot + "/app/templates"):
        return 0

    popen_cmd = [ '/usr/bin/find', docroot + '/app/templates/' + template, 
        '-type', 'f',  '(', '-iname', '*.php', '-o', '-iname', '*.css', '-o',
        '-iname', '*.less', '-o', '-iname', '*.js', ')', '-print' ]

    process = subprocess.Popen(popen_cmd, stdout= subprocess.PIPE, stderr= subprocess.PIPE)

    (filelist, stderr) = process.communicate()

    print "checking template files in [" + docroot + '/app/template/' + template + "]"

    if process.returncode == 0 and filelist != "":
    
        commands = [
            [ '/usr/bin/xargs', 'sed', '-i', 's/\/media\/system\//\/core\/assets\//g' ],
            [ '/usr/bin/xargs', 'sed', '-ri', "s/([\">'])\/modules\//\\1\/core\/modules\//g" ],
            [ '/usr/bin/xargs', 'sed', '-ri', "s/([\">'])\/plugins\//\\1\/core\/plugins\//g" ],
            [ '/usr/bin/xargs', 'sed', '-ri', "s/([\">'])\/components\//\\1\/core\/components\//g" ],
            [ '/usr/bin/xargs', 'sed', '-i', 's/$config\s*->\s*getValue(/$config->get(/g' ],
            [ '/usr/bin/xargs', 'sed', '-i', 's/$config\s*->\s*get(\'config\./$config->get(\'/g' ],
            [ '/usr/bin/xargs', 'sed', '-i', 's/\"\/templates\/' + template + '/\"\/app\/templates\/' + template + '/g' ],
            [ '/usr/bin/xargs', 'sed', '-i', 's/ templates\/' + template + '/ app\/templates\/' + template + '/g' ],
            [ '/usr/bin/xargs', 'sed', '-i', 's/\'\/templates\/' + template + '/\'\/app\/templates\/' + template + '/g' ],
            [ '/usr/bin/xargs', 'sed', '-i', 's/ templates\/kameleon/ app\/templates\/' + template + '/g' ],
            [ '/usr/bin/xargs', 'sed', '-i', 's/JPATH_ROOT . \'\/templates\/\'/JPATH_ROOT . \'\/app\/templates\/\'/g' ],
            [ '/usr/bin/xargs', 'sed', '-i', "s/mod_reportproblems\/mod_reportproblems\.css/mod_reportproblems\/assets\/css\/mod_reportproblems.css/g" ],
            [ '/usr/bin/xargs', 'sed', '-i', "s/mod_reportproblems\/mod_reportproblems\.js/mod_reportproblems\/assets\/js\/mod_reportproblems.js/g" ],
            [ '/usr/bin/xargs', 'sed', '-i', "s/\/plugins\/groups\/announcements\/announcements.css/\/plugins\/groups\/announcements\/assets\/css\/announcements.css/g" ],
            [ '/usr/bin/xargs', 'sed', '-i', "s/com_resources\/assets/com_resources\/site\/assets/g" ]
        ]

        for command in commands:

            process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

            (stdout, stderr) = process.communicate(input=filelist)

            if process.returncode != 0:
                print "failed to run [/usr/bin/xargs sed -i " + command[3] + "]."
    else:
        print "no template files were found in [" + docroot + '/app/template/' + template + "]"


def fixSiteDirectory():

    # Debian or RH?
    wwwOwner = webUser()
    wwwGroup = webGroup()

    hubname = hubzero.config.webconfig.getDefaultSite()
    docroot = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")
    dbname = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "dbname")
    uri = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "uri")

    if os.path.exists(docroot + "/app"):
        sitedir = docroot + "/app/site"
    else:
        sitedir = docroot + "/site"

    print "checking for expected site directories"

    createDir(sitedir, "2775", webUser(), webGroup(), resetattrs=False)
    createDir(sitedir+"/media", "2775", webUser(), webGroup(), resetattrs=False)
    createDir(sitedir+"/stats", "2775", webUser(), webGroup(), resetattrs=False)
    createDir(sitedir+"/stats/maps", "2775", webUser(), webGroup(), resetattrs=False)
    createDir(sitedir+"/stats/plots", "2775", webUser(), webGroup(), resetattrs=False)
    createDir(sitedir+"/stats/chart_resources", "2775", webUser(), webGroup(), resetattrs=False)
    createDir(sitedir+"/protected", "2775", webUser(), webGroup(), resetattrs=False)

def fixLogDirectory():

    # Debian or RH?
    wwwOwner = webUser()
    wwwGroup = webGroup()

    hubname = hubzero.config.webconfig.getDefaultSite()
    docroot = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")
    dbname = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "dbname")
    uri = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "uri")

    if os.path.exists(docroot + "/app"):
        logdir = docroot + "/app/logs"
    else:
        logdir = docroot + "/logs"

    print "checking for expected log directories"

    createDir(logdir, "2775", webUser(), webGroup(), resetattrs=False)

def fixTmpDirectory():

    # Debian or RH?
    wwwOwner = webUser()
    wwwGroup = webGroup()

    hubname = hubzero.config.webconfig.getDefaultSite()
    docroot = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")
    dbname = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "dbname")
    uri = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "uri")

    if os.path.exists(docroot + "/app"):
        tmpdir = docroot + "/app/tmp"
    else:
        tmpdir = docroot + "/tmp"

    print "checking for expected tmp directories"

    createDir(tmpdir, "2770", webUser(), webGroup(), resetattrs=False)



def updateCMS(args):
    # Debian or RH?
    wwwOwner = webUser()
    wwwGroup = webGroup()

    hubname = hubzero.config.webconfig.getDefaultSite()
    docroot = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")
    dbname = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "dbname")
    uri = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "uri")

    hostname = gethostname()

    if uri == None:
        uri = "http://" + hostname

    if dbname == None:
        dbname = hubname

    # Copy fresh code
    if os.path.exists(docroot + "/.git"):
        print "checking " + docroot + " [git]"
    else:
        print "checking " + docroot
        copyCMSFiles(HUBZERO_CMS_DIR+"/cms/", docroot, wwwOwner, wwwGroup)
        updateDeletedFiles()
        moveTemplates()

    #updateDatabaseSchema()


def updateHub(args):

    # Debian or RH?
    wwwOwner = webUser()
    wwwGroup = webGroup()

    hubname = hubzero.config.webconfig.getDefaultSite()
    docroot = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")
    dbname = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "dbname")
    uri = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "uri")

    hostname = gethostname()

    if uri == None:
        uri = "http://" + hostname

    if dbname == None:
        dbname = hubname

    if not fixMySQLRootSecret():
        print ""
        print "Unable to determine MySQL root password. Unable to continue"
        print ""
        print "Please add 'MYSQL-ROOT = <passwd>' to the end of the file /etc/hubzero.secrets"
        print "(replacing <passwd> with the actual MySQL root password)"
        print ""
        print "Then please try this command again."
        print ""
        sys.exit(1)

    fixPhpBinary()

    # Copy fresh code
    if os.path.exists(docroot + "/.git"):
        print "checking " + docroot + " [git]"
    else:
        print "checking " + docroot
        copyCMSFiles(HUBZERO_CMS_DIR+"/cms/", docroot, wwwOwner, wwwGroup)
        updateDeletedFiles()
        moveTemplates()

    rootmysqlpw = None
    rootmysqlrootusername = 'root'    

    if os.path.exists("/root/.my.cnf"):
        config = ConfigParser.RawConfigParser()
        config.read("/root/.my.cnf")
        rootmysqlpw = config.get("client", "password")
        rootmysqlrootusername = config.get("client", "user") 

    updateTimezoneDatabase(True, rootmysqlrootusername, rootmysqlpw)

    updateDatabaseSchema()

    initPhpErrorLog()

    # Fix various problems with apache configuration problems
    if os.path.exists(apacheConfigDir() + "/sites-m4"):

        pattern1 = r'(?im)^(\s*)(AddType\s+text/plain\s+.*\.php(\s+.*\n|\n))((?!^\s*php_admin_value\s+engine\s+Off))'
        repl1 = r'\1\2\1php_admin_value engine Off\n'
        pattern2 = r'(?im)^(\s*)(Include\s+' + apacheConfigDir() + ')(svn.con\[f].*\n)'
        repl2 = r'\1\2HUBNAME.conf.d/svn/\3'
        pattern3 = r'(?im)^(\s*)(Include\s+' + apacheConfigDir() + '/HUBNAME\.conf\.d/)(svn.con\[f].*\n)'
        repl3 = r'\1\2svn/\3'
        pattern4 = r'(?im)^(\s*)(RewriteRule\s+\^filexfer/\(\.\*\)\s+\${)(xlate.*\n)'
        repl4 = r'\1\2filexfer-\3'
  
        # versions prior to 1.2.0 need a security patch to not serve wishlist attachments directly
        svn_line = r'RewriteRule\s+\^\(\.\*/\)\?\(\\\.svn\|\\\.git\|\\\.hg\)/\s+-\s+\[R=404,L\]'
        wl_line  = r'RewriteRule\s+\^/site/wishlist/\(\.\*\)\(\\\.htm\|\\\.html\)\$\s+\-\s+\[R=404,L,NC\]'
        
        pattern5 = r'(?im)(^\s*)(' + svn_line + r')\s*\n+(?!\s*' + wl_line + r'\s*\n)'
        repl5 = r'\1\2\n\1RewriteRule ^/site/wishlist/(.*)(\.htm|\.html)$ - [R=404,L,NC]\n\n'
        
        # versions 1.2.0 and later can have that protection removed
        pattern6 = r'(?im)(^\s*RewriteRule\s+\^\/site\/wishlist\/\(\.\*\)\(\\\.html*\|\\\.html*\)\$\s+-\s+\[R=404,L,NC\]\s*$)'
	repl6 = ''

	# Remove [OR] which was causing the site to redirect to ssl all the time instead of just for Trac pages
        pattern7 = r'(?im)(^\s*RewriteCond\s+%{REQUEST_URI}\s+\^\/tools\/\[\^\/\]\+\(\(\/\(pygments)(.*)(\s*\[OR\]\s*$)'
        repl7 = r'\1\2'

        try:
            hubm4 = apacheConfigDir() + "/sites-m4/" + hubname + ".m4"
            print "checking " + hubm4
            hubm4fh = open(hubm4,'r+')
            hubm4txt = hubm4fh.read()
            txt = re.sub(pattern1, repl1, hubm4txt)
            txt = re.sub(pattern2, repl2, txt)
            txt = re.sub(pattern3, repl3, txt)
            txt = re.sub(pattern4, repl4, txt)
            version = hubzero.config.webconfig.getCMSversion(docroot)
            if StrictVersion(version) < StrictVersion("1.2.0"):
                txt = re.sub(pattern5, repl5, txt)
            else:
                txt = re.sub(pattern6, repl6, txt)
            txt = txt.replace("//FQDN}","//FQDN")
            txt = re.sub(pattern7, repl7, txt)
            if (txt != hubm4txt):
                hubm4fh.seek(0)
                hubm4fh.write(txt)
                hubm4fh.truncate()
                print "patched " + hubm4
            hubm4fh.close()
        except:
            print "failed to patch " + hubm4
            pass

        try:
            hubsslm4 = apacheConfigDir() + "/sites-m4/" + hubname + "-ssl.m4"
            print "checking " + hubsslm4
            hubsslm4fh = open(hubsslm4,'r+')
            hubsslm4txt = hubsslm4fh.read()
            txt = re.sub(pattern1, repl1, hubsslm4txt)
            txt = re.sub(pattern2, repl2, txt)
            txt = re.sub(pattern3, repl3, txt)
            txt = re.sub(pattern4, repl4, txt)
            version = hubzero.config.webconfig.getCMSversion(docroot)
            if StrictVersion(version) < StrictVersion("1.2.0"):
                txt = re.sub(pattern5, repl5, txt)
            else:
                txt = re.sub(pattern6, repl6, txt)
            txt = txt.replace("//FQDN}","//FQDN")
            if (txt != hubsslm4txt):
                hubsslm4fh.seek(0)
                hubsslm4fh.write(txt)
                hubsslm4fh.truncate()
                print "patched " + hubsslm4
            hubsslm4fh.close()
        except:
            print "Failed to patch " + hubsslm4
            pass

    # fix apache access log rotation scripts
    if os.path.exists("/etc/logrotate.d/" + hubname + "-access"):
        print "checking /etc/logrotate.d/" + hubname + "-access"
        pattern1 = r'(?im)^(\s*if\s+)(-f\s*"`\.\s+' + apacheConfigDir() + '/envvars\s*;\s*echo\s+\${APACHE_PID_FILE:-/var/run/apache2\.pid}`")(\s*;\s*then\s*)'
        repl1 = r'\1[ \2 ]\3'
	pattern2 = r'(?im)^(\s*su\s+)(www-data\s+www-data)(\s*.*$)'
        repl2 = r'\1root adm\3'

        try:
            tfilename = "/etc/logrotate.d/" + hubname + "-access"
            tfileh = open(tfilename,'r+')
            tfiletxt = tfileh.read()
            txt = re.sub(pattern1, repl1, tfiletxt)
            txt = re.sub(pattern2, repl2, txt)
            if (txt != tfiletxt):
                tfileh.seek(0)
                tfileh.write(txt)
                tfileh.truncate()
                print "patched " + tfilename
            tfileh.close()
        except Exception, ex:
            print ex
            print "Failed to patch " + tfilename
            pass

    if os.path.exists("/etc/logrotate.d/" + hubname + "-error"):
        print "checking /etc/logrotate.d/" + hubname + "-error"
        pattern1 = r'(?im)^(\s*su\s+)(www-data\s+www-data)(\s*.*$)'
        repl1 = r'\1root adm\3'

        try:
            tfilename = "/etc/logrotate.d/" + hubname + "-error"
            tfileh = open(tfilename,'r+')
            tfiletxt = tfileh.read()
            txt = re.sub(pattern1, repl1, tfiletxt)
            if (txt != tfiletxt):
                tfileh.seek(0)
                tfileh.write(txt)
                tfileh.truncate()
                print "patched " + tfilename
            tfileh.close()
        except:
            print "Failed to patch " + tfilename
            pass

    checkConfigurationPhp(docroot)

    dbPW = hubzero.config.webconfig.getWebConfigDBPassword()
    dbUserName = hubzero.config.webconfig.getWebConfigDBUsername()
    dbName = hubzero.config.webconfig.getWebConfigDBName()
    db =  hubzero.data.db.MySQLConnection("localhost", dbName, dbUserName, dbPW)

    # Add new uri and dbname options to hub configuration file
    insertHubIntoHubConfigFile(hubname, docroot, uri, dbname)

    # check various installation directories and create if necessary
    checkDirectories(docroot, wwwOwner, wwwGroup)

    # fix mw-client.conf
    # if hub_template is set, update it
    print "checking /etc/mw-client/mw-client.conf"
    if os.path.exists("/etc/mw-client/mw-client.conf"):
 
        try:
            sql = 'select template from `jos_template_styles` where client_id=0 and home=1'
            template = db.query_selectscalar(sql, None)
        except _mysql_exceptions.ProgrammingError as err:
            sql = 'select template from `jos_templates_menu` where menuid = 0 and client_id=0'
            template = db.query_selectscalar(sql, None)

        try:
            mwfilename = "/etc/mw-client/mw-client.conf"
            mwfh = open(mwfilename,'r+')
            mwtxt = mwfh.read()
            txt, count = re.subn(r'(?im)(^\s*hub_template\s*=).*$',r'\1'+'"'+template+'"',mwtxt)

            #if count < 1:
            #    txt = txt.rstrip()
            #    txt = txt + "\nhub_template=\"" + template + "\""

            if (txt != mwtxt):
                mwfh.seek(0)
                mwfh.write(txt)
                mwfh.truncate()
                print "patched " + mwfilename

        except:
            print "Failed tp patch " + mwfilename

        mwfh.close()

    # Eventually we need a container template fixer, but it will need to be more
    # flexible then what we have commented out below

    #template = "/var/lib/vz/template/debian-6.0-amd64-maxwell"
    #print "checking " + template
    #if os.path.exists(template):
    #    print "apt-get update " + template
    #    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/chroot", template, "apt-get", "update"]) 
    #    if rc: print procStdErr
    #
    #    print "apt-get install -y hubzero-filexfer " + template
    #    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/chroot", template, "apt-get", "install", "-y", "hubzero-filexfer"]) 
    #    if rc: print procStdErr

    #template = "/var/lib/vz/template/debian-7.0-amd64-maxwell"
    #print "checking " + template
    #if os.path.exists(template):
    #    print "apt-get update " + template
    #    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/chroot", template, "apt-get", "update"]) 
    #    if rc: print procStdErr

    #    print "apt-get install -y hubzero-filexfer " + template
    #    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/chroot", template, "apt-get", "install", "-y", "hubzero-filexfer"]) 
    #    if rc: print procStdErr

    # Update database schema to match commits broguht in since original release
    # @TODO migrations will replace this segment one day

    # Fix trac if it's configured
    if hubzero.config.webconfig.getHubSiteConfig(hubname, "apache-config", "enable_trac").lower() == 'true':
        createDir("/opt", "0755", "root", "root", resetattrs=True)
        createDir("/opt/trac", "0755", webUser(), webGroup(), resetattrs=True)
        createDir("/opt/trac/tools", "0750", webUser(), webGroup(), resetattrs=True)

    # Fix subversion if it's configured
    if hubzero.config.webconfig.getHubSiteConfig(hubname, "apache-config", "enable_subversion").lower() == 'true':
        createDir("/opt", "0755", "root", "root", resetattrs=True)
        createDir("/opt/svn", "0755", webUser(), webGroup(), resetattrs=True)
        createDir("/opt/svn/tools", "0750", webUser(), webGroup(), resetattrs=True)
        createDir(apacheConfigDir() + hubname + ".conf.d", "0755", "root", "root", resetattrs=True)
        createDir(apacheConfigDir() + hubname + ".conf.d/svn", "0700", webUser(), webGroup(), resetattrs=True)

        if os.path.exists(apacheConfigDir() + "/svn.conf"):
            print "rename " + apacheConfigDir() + "/svn.conf " + apacheConfigDir() + hubname + ".conf.d/svn/svn.conf"
            os.rename(apacheConfigDir() + "/svn.conf", apacheConfigDir() + hubname + ".conf.d/svn/svn.conf")

        if os.path.exists(apacheConfigDir() + "/svn.bak"):
            print "rename " + apacheConfigDir() + " /svn.bak " + apacheConfigDir() + hubname + ".conf.d/svn/svn.bak"
            os.rename(apacheConfigDir() + "/svn.bak", apacheConfigDir() + hubname + ".conf.d/svn/svn.bak")

    # Use enable_mw_service and enable_mw_client seperate flags instead of enable_mw
    enable_mw_service = hubzero.config.webconfig.getHubSiteConfig(hubname, "package-config", "mw-service")
    enable_mw_client = hubzero.config.webconfig.getHubSiteConfig(hubname, "package-config", "mw-client")
    enable_mw = hubzero.config.webconfig.getHubSiteConfig(hubname, "mw", "enable_mw")

    if (enable_mw_client == ''):
        enable_mw_client = enable_mw
        if (enable_mw_client != ''):
            modifyHubConfigFile("package-config", 'mw-client', enable_mw_client)
        else:
            modifyHubConfigFile("package-config", 'mw-client', 'false')
            enable_mw_client = 'false'

    if (enable_mw_service == ''):
        enable_mw_service = enable_mw
        if (enable_mw_service != ''):
            modifyHubConfigFile("package-config", 'mw-service', enable_mw_service)		
        else:
            modifyHubConfigFile("package-config", 'mw-service', 'false')
            enable_mw_service = 'false'

    if (enable_mw != ''):
        modifyHubConfigFile('mw', 'enable_mw', None)
        enable_mw = ''

    # Make sure /etc/mw-service/mw-service.conf got written, we missed it originally
    # @TODO It would be slightly better to look for the host entry to determine
    # if this needs to be fixed or left alone.
    if (enable_mw_service.lower() == 'true'):
        mwServiceConfigure(True)

    # Fix permissions on hubname.conf.d
    if os.path.exists(apacheConfigDir() + hubname + ".conf.d"):
        hubzero.utilities.misc.exShellCommand(['chmod', "0755", apacheConfigDir() + hubname + ".conf.d"])
        hubzero.utilities.misc.exShellCommand(['chown', "root:root", apacheConfigDir() + hubname + ".conf.d"])

    # Fix permissions on hubname.conf.d/svn
    if os.path.exists(apacheConfigDir() + hubname + ".conf.d/svn"):
        hubzero.utilities.misc.exShellCommand(['chmod', "0700", apacheConfigDir() + hubname + ".conf.d/svn"])
        hubzero.utilities.misc.exShellCommand(['chown', webUser()+":"+webGroup(), apacheConfigDir() + hubname + ".conf.d/svn"])

    # Fix permissions to /etc/nsswitch.conf which we initially got wrong
    filename = "/etc/nsswitch.conf"
    hubzero.utilities.misc.exShellCommand(['chmod', '0644', filename])
    hubzero.utilities.misc.exShellCommand(['chown', 'root:root', filename])

    # Regenerate logrotate files to fix some issues with original generation
    generateLogrotateFiles(hubname)

    # Fix missing closing brace on hubconfiguration.php file
    print "checking " + docroot + "/hubconfiguration.php"
    if os.path.exists(docroot + "/hubconfiguration.php"):
        f = open(docroot + "/hubconfiguration.php","r+")
        configtxt = f.read()
        txt = re.sub(r'([^\s}])\s*\?>\s*$',r'\1\n}\n?>\n',configtxt)
        if txt.find('hubShortName') == -1:
            txt = re.sub(r'(?im)^(\s*)(var\s*\$forgeName\s*=)',r'\1var $hubShortName = ' + "'" + hubname + "'" + r';\n\1\2',txt)

        if configtxt != txt:
            f.seek(0)
            f.write(txt)
            f.truncate()
            print "patched " + docroot + "/hubconfiguration.php"
        f.close()

    if hubzero.config.webconfig.getPluginEnabled('user','ldap'):
        syncLdap = True
    else:
        syncLdap = False

    # Fix admin user/group
    # At some point hzcms created 'admin' user with a 
    # corresponding 'admin' group instead of using the 'users' group (100).
    # We can check for those conditions and fix the group with a fair
    # confidence we aren't squashing an intentionally created group
    # with the same name
    print "checking user 'admin'"
    cn = db.query_selectscalar("SELECT cn FROM jos_xgroups AS xg, jos_xprofiles AS xp WHERE xg.cn='admin' AND xp.username='admin' AND xp.gidNumber=xg.gidNumber;", None)
    if cn == 'admin':
        print "repairing user 'admin'"
        db.query_rowcount("UPDATE jos_xprofiles SET gidNumber=100 WHERE username='admin' AND gidNumber NOT IN (100,3000)", None)
        print "deleting group 'admin' from database"
        db.query_rowcount("DELETE xgm FROM jos_xgroups_members AS xgm, jos_xgroups AS xg WHERE xgm.gidNumber=xg.gidNumber AND xg.cn='admin';", None)
        db.query_rowcount("DELETE FROM jos_xgroups WHERE cn='admin';", None)
        if syncLdap:
            hubzero.utilities.group.syncgroup('admin',verbose=True)
            hubzero.utilities.user.syncuser('admin',verbose=True)

    # Fix apps user/group
    # At some point hzcms or hubzero-fogrge created 'apps' user with a 
    # primary corresponding 'apps' group instead of using the 'users' 
    # group (100). We can check for those conditions and fix 
    # the group with a fair confidence we aren't squashing an intentional 
    # change.
    print "checking user 'apps'"
    cn = db.query_selectscalar("SELECT cn FROM jos_xgroups AS xg, jos_xprofiles AS xp WHERE xg.cn='apps' AND xp.username='apps' AND xp.gidNumber=xg.gidNumber;", None)
    if cn == 'apps':
        print "repairing user 'apps'"
        db.query_rowcount("UPDATE jos_xprofiles SET gidNumber=100 WHERE username='apps' AND gidNumber NOT IN (100,3000)", None)
        db.query_rowcount("UPDATE jos_xgroups SET type='0', published='1', approved='1', description='apps' WHERE cn='apps'", None)
        if syncLdap:
            hubzero.utilities.user.syncuser('apps',verbose=True)
            hubzero.utilities.group.syncgroup('apps',verbose=True)

    # Fix hubrepo user/group
    # At some point hzcms or hubzero-fogrge created 'hubrepo' user with a 
    # corresponding 'hubrepo' group instead of using the 'users' group (100).
    # We can check for those conditions and fix the group with a fair
    # confidence we aren't squashing an intentionally created group
    # with the same name.
    print "checking user 'hubrepo'"
    cn = db.query_selectscalar("SELECT cn FROM jos_xgroups AS xg, jos_xprofiles AS xp WHERE xg.cn='hubrepo' AND xp.username='hubrepo' AND xp.gidNumber=xg.gidNumber;", None)
    if cn == 'hubrepo':
        print "repairing user 'hubrepo'"
        db.query_rowcount("UPDATE jos_xprofiles SET gidNumber=100 WHERE username='hubrepo' AND gidNumber NOT IN (100,3000)", None)
        print "deleting group 'hubrepo' from database"
        db.query_rowcount("DELETE xgm FROM jos_xgroups_members AS xgm, jos_xgroups AS xg WHERE xgm.gidNumber=xg.gidNumber AND xg.cn='hubrepo';", None)
        db.query_rowcount("DELETE FROM jos_xgroups WHERE cn='hubrepo';", None)
        if syncLdap:
            hubzero.utilities.group.syncgroup('hubrepo',verbose=True)
            hubzero.utilities.user.syncuser('hubrepo',verbose=True)

    # Fix fuse module loading if webdav is configured
    if hubzero.config.webconfig.getHubSiteConfig(hubname, "apache-config", "enable_trac").lower() == 'true':
        print "checking /etc/modules"
        try:
            modulesfn = "/etc/modules"
            modulesfh = open(modulesfn,"r+")
            modulestxt = modulesfh.read()

            txt = re.sub(r'(?m)^\s*#\s*fuse($|\s+.*$)',r'fuse\1',modulestxt)

            if txt.find('fuse') == -1:
                txt = txt.rstrip() + "\nfuse"

            txt = txt.rstrip() + "\n"
            
            if (txt != modulestxt):
                modulesfh.seek(0)
                modulesfh.write(txt)
                modulesfh.truncate()
                print "patched " + modulesfn
                    
                print "/sbin/modprobe fuse"
                rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/sbin/modprobe", "fuse"])  
                if rc: print procStdErr 

                serviceInit("autofs","restart")

            modulesfh.close()

        except:
            print "Failed to patch file " + modulesfn
            pass

    # Fix admin in apps group if forge is configured
    if hubzero.config.webconfig.getHubSiteConfig(hubname, "apache-config", "enable_forge").lower() == 'true':
        if hubzero.utilities.group.groupExists("apps"):
            print "checking 'admin' user in 'apps' group"
            if not hubzero.utilities.group.userInGroup("admin","apps"):
                print "adding 'admin' user to 'apps' group"
                hubzero.utilities.group.addUserToGroup("admin","apps")

    # Fix apps user in webGroup() group if forge is configured (so it can read configuration.php)
    if hubzero.config.webconfig.getHubSiteConfig(hubname, "apache-config", "enable_forge").lower() == 'true':
        print "checking 'apps' user in '" + webGroup() + "' group"
        group = grp.getgrnam(webGroup())
        if ('apps' not in group.gr_mem):
            print "usermod -a -G %s apps" % webGroup()
            hubzero.utilities.misc.exShellCommand(["usermod","-a","-G",webGroup(),"apps"])

    # Fix default home directory parameter
    # @FIXME: effectively disables having /home as your home directory
    # location. This will be fixed one day by putting home directory
    # in a global config file and resetting this accordingly
    # @FIXME: should also remove hubHomeDir parameter, but it should be harmless

    print "checking default home directory prefix"
    changedHomeDirs = False
    try:
        id = db.query_selectscalar("SELECT extension_id FROM jos_extensions WHERE type='component' AND (params LIKE BINARY '%\"homedir\":\"/home\"%' OR params LIKE BINARY '%\"homedir\":\"/\"%') AND `element`='com_members';",None)
    except:
        id = db.query_selectscalar("SELECT id FROM jos_components WHERE (params LIKE BINARY '%homedir=/home\n%' OR params LIKE BINARY '%homedir=\n%') AND `option`='com_members' AND parent=0;",None)

    if (id > 0):
        print "setting default home directory prefix to /home/" + hubname
        try:
            sql = "UPDATE jos_extensions SET `params` = REPLACE(`params`,'\"homedir\":\"/home\"','\"homedir\":\"/home/' + hubname + '\"') WHERE `element` = 'com_members'"
            db.query_rowcount(sql, None)
            sql = "UPDATE jos_extensions SET `params` = REPLACE(`params`,'\"homedir\":\"/\"','\"homedir\":\"/home/' + hubname + '\"') WHERE `element` = 'com_members'"
            db.query_rowcount(sql, None)
        except:
            sql = "UPDATE jos_components SET `params` = REPLACE(`params`,'homedir=/home\n','homedir=/home/" + hubname + "\n') WHERE `option` = 'com_members'"
            db.query_rowcount(sql, None)
            sql = "UPDATE jos_components SET `params` = REPLACE(`params`,'homedir=\n','homedir=/home/" + hubname + "\n') WHERE `option` = 'com_members'"
            db.query_rowcount(sql, None)

    # Fix user home directories that were incorrectly set due to the above

        print "checking user home directory prefixes"

        # grab all users from db with invalid home directory prefix
        sql = "SELECT username from jos_xprofiles WHERE homeDirectory=CONCAT('/home/',username)"

        usersFromDB = {}
        for duser in db.query(sql, None):
            usersFromDB[duser.username] = 1
            #print duser.username + " has invalid home directory prefix"

        for user in usersFromDB:
            print "fixing home directory prefix for user " + user
            sql = "UPDATE jos_xprofiles SET homeDirectory=CONCAT('/home/"+hubname+"/"+"',username) WHERE username='" + user + "'"
            if db.query_rowcount(sql,None) == 1 and syncLdap:
                print "syncing ldap entry for user " + user
                hubzero.utilities.user.syncuser(user)
                changedHomeDirs = True

        if changedHomeDirs:
            print "\n\nSOME HOME DIRECTORIES MOVED!"
            print "PLEASE MOVE HOME DIRECTORIES FROM /home TO /home/" + hubname + "\n\n"

    # Fix permissions on DOCUMENT_ROOT/apps/config/*.php

    if os.path.exists(docroot + "/app"):
        print "checking CMS v2+ configuration file permissions"
    if os.path.exists(docroot + "/app/config/app.php"):
        createFile(docroot + "/app/config/app.php", "0660", webUser(), webGroup(), resetattrs=True)
    if os.path.exists(docroot + "/app/config/cache.php"):
        createFile(docroot + "/app/config/cache.php", "0660", webUser(), webGroup(), resetattrs=True)
    if os.path.exists(docroot + "/app/config/database.php"):
        createFile(docroot + "/app/config/database.php", "0660", webUser(), webGroup(), resetattrs=True)
    if os.path.exists(docroot + "/app/config/ftp.php"):
        createFile(docroot + "/app/config/ftp.php", "0660", webUser(), webGroup(), resetattrs=True)
    if os.path.exists(docroot + "/app/config/index.html"):
        createFile(docroot + "/app/config/index.html", "0660", webUser(), webGroup(), resetattrs=True)
    if os.path.exists(docroot + "/app/config/mail.php"):
        createFile(docroot + "/app/config/mail.php", "0660", webUser(), webGroup(), resetattrs=True)
    if os.path.exists(docroot + "/app/config/meta.php"):
        createFile(docroot + "/app/config/meta.php", "0660", webUser(), webGroup(), resetattrs=True)
    if os.path.exists(docroot + "/app/config/offline.php"):
        createFile(docroot + "/app/config/offline.php", "0660", webUser(), webGroup(), resetattrs=True)
    if os.path.exists(docroot + "/app/config/seo.php"):
        createFile(docroot + "/app/config/seo.php", "0660", webUser(), webGroup(), resetattrs=True)
    if os.path.exists(docroot + "/app/config/session.php"):
        createFile(docroot + "/app/config/session.php", "0660", webUser(), webGroup(), resetattrs=True)

    # Fix permissions on /apps
    if os.path.exists("/apps"):
        createDir("/apps", "2775", "apps", "apps", resetattrs=True)

    # Make sure apache config files are current with m4 template
    generateApacheM4config(hubname)
    
    # add variables and make changes to submit-server configuration file for currrent version
    fixSubmitServer()
    
    # fix /etc/resolv.conf in default OpenVZ tool templates
    fixVzTemplateResolvConf()

    # hubzero-cms-2.0.0 doesn't populate app/site the way it should
    fixSiteDirectory()

    # hubzero-cms-2.0.0 doesn't populate app/log the way it should
    fixLogDirectory()
    
    # hubzero-cms-2.0.0 doesn't populate app/tmp the way it should
    fixTmpDirectory()

    # Make sure all changes made during update are reflected in running system
    restartWebServer()

def validateArgs(args):
    """
    For system-wide argument validation, some of the sub commands will have their
    own specific checks
    """

    # hubname length check
    if len(args.hubname) > 16 :
        print "hubname too long, must be 16 characters or less"
        return 1
 
    # other hubname checks 
    p = re.compile("^[a-zA-Z][a-zA-Z0-9]+$")
    m = p.match(args.hubname)
    if not m:
        print "install hubname must be alphanumeric and start with a letter"
        return 1

    return 0

def gethostname():

    return socket.getfqdn()



def replace(dest = None, regexp = None, replace = None):

    if os.path.exists(dest):
        try:
            with open(dest, 'r+') as f:
                ftxt = f.read()
                txt = ftxt.split("\n")

                for i in range(0,len(txt)):
                    txt[i] = re.sub(regexp, replace, txt[i])

                txt = '\n'.join(txt)

                if txt != ftxt:
                    f.seek(0)
                    f.write(txt)
                    f.truncate()
                    print  dest + " patched"
                else:
                    print  dest + " unchanged"
        except Exception, ex:
            print ex
            print "replace update failed [%s]" % (dest)
            raise
    else:
        print dest + ' does not exist'

def lineinfile(dest = None, regexp = None, line = None):

    if os.path.exists(dest):
        try:
            with open(dest, 'r+') as f:
                ftxt = f.read()
                txt = ftxt.split("\n")
                last_match = -1

                for i in range(0,len(txt)):
                    if re.match(regexp, txt[i]):
                        last_match = i

                if last_match > -1:
                    txt[last_match] = line

                txt = '\n'.join(txt)

                if txt != ftxt:
                    f.seek(0)
                    f.write(txt)
                    f.truncate()
                    print  dest + " patched"
                else:
                    print  dest + " unchanged"
        except Exception, ex:
            print ex
            print "lineinfile update failed [%s]" % (dest)
            raise
    else:
        print dest + ' does not exist'

def copyfile(dest = None, content = None):

    if os.path.exists(dest):
        try:
            with open(dest,'r+') as f:
                ftxt = f.read()
                txt = content
                if txt != ftxt:
                    f.seek(0)
                    f.write(txt)
                    f.truncate()
        except Exception, ex:
            print ex
            print "copyfile update failed [%s]" % (dest)
            raise


def _changeInternalHostname(args):
    changeinternalhostname(args.hostname)

def changeinternalhostname(hostname = None):

    hubname = hubzero.config.webconfig.getDefaultSite()
    document_root = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")
    dbname = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "dbname")
    uri = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "uri")

    if hostname == None:
        hostname = gethostname()

    print "changing internal hostname to: " + hostname

    dbPW = hubzero.config.webconfig.getWebConfigDBPassword()
    dbUserName = hubzero.config.webconfig.getWebConfigDBUsername()
    dbName = hubzero.config.webconfig.getWebConfigDBName()

    replace(dest = '/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*CONDOR_HOST\s*=.*$', replace = "CONDOR_HOST = " + hostname)
    replace(dest = '/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*UID_DOMAIN\s*=.*$', replace = "UID_DOMAIN = " + hostname)
    replace(dest = '/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*FILESYSTEM_DOMAIN\s*=.*$', replace = "FILESYSTEM_DOMAIN = " + hostname)
    replace(dest = '/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*#\s*ALLOW_READ\s*=.*$', replace = "#ALLOW_READ = " + hostname)
    replace(dest = '/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*ALLOW_READ\s*=.*$', replace = "ALLOW_READ = " + hostname)
    replace(dest = '/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*#\s*ALLOW_WRITE\s*=.*$', replace = "#ALLOW_WRITE = " + hostname)
    replace(dest = '/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*ALLOW_WRITE\s*=.*$', replace = "ALLOW_WRITE = " + hostname)
    replace(dest = '/var/gridman/.ssh/authorized_keys', regexp = r'submit@[^ ]*\s*$', replace = 'submit@' + hostname)
    replace(dest = '/var/www/.ssh/authorized_keys', regexp = r'root@[^ ]*\s*$', replace = 'root@' + hostname)
    replace(dest = '/etc/mw-client/maxwell.key.pub', regexp = r'apache@[^ ]*\s*$', replace = 'apache@' + hostname)
    replace(dest = '/etc/mw-client/maxwell.key.pub', regexp = r'www-data@[^ ]*\s*$', replace = 'www-data@' + hostname)
    replace(dest = '/etc/mw-client/notify.key.pub', regexp = r'root@[^ ]*\s*$', replace = 'root@' + hostname)
    replace(dest = '/opt/submit/.ssh/submit_rsa.pub', regexp = r'submit@[^ ]*\s*$', replace = 'submit@' + hostname)
    replace(dest = '/root/.ssh/authorized_keys', regexp = r'apache@[^ ]*\s*$', replace = 'apache@' + hostname)
    replace(dest = '/root/.ssh/authorized_keys', regexp = r'www-data@[^ ]*\s*$', replace = 'www-data@' + hostname)
    replace(dest = '/etc/submit/daemons.conf', regexp = r'^\s*hostname\s*=\s*[^ ]*$', replace = 'hostname = ' + hostname)
    replace(dest = '/vz/template/debian-7.0-amd64-maxwell/etc/ssh/ssh_host_ecdsa_key.pub', regexp = r'root@[^ ]*\s*$', replace = 'root@' + hostname)
    replace(dest = '/vz/template/debian-7.0-amd64-maxwell/etc/ssh/ssh_host_dsa_key.pub', regexp = r'root@[^ ]*\s*$', replace = 'root@' + hostname)
    replace(dest = '/vz/template/debian-7.0-amd64-maxwell/etc/ssh/ssh_host_rsa_key.pub', regexp = r'root@[^ ]*\s*$', replace = 'root@' + hostname)
    replace(dest = '/vz/template/debian-7.0-amd64-maxwell/run/motd.dynamic', regexp = r'Linux [^ ]*', replace = "Linux " + hostname)

    rootpw = hubzero.config.passwords.getMySqlPW()
    rootuser = 'root'
    db =  hubzero.data.db.MySQLConnection("localhost", "mysql", rootuser, rootpw)
    sql = "UPDATE `mysql`.user SET host='" + hostname + "' WHERE user='' AND host<>'localhost' LIMIT 1;"
    db.query_rowcount(sql, None)	
    sql = "UPDATE `mysql`.user SET host='" + hostname + "' WHERE user='root' AND host<>'localhost' AND host<>'127.0.0.1' LIMIT 1;"
    db.query_rowcount(sql, None)	


def _changeHostname(args):
    changehostname(args.hostname)
               
def changehostname(hostname = None):

    hubname = hubzero.config.webconfig.getDefaultSite()
    document_root = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "DocumentRoot")
    dbname = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "dbname")
    uri = hubzero.config.hubzerositeconfig.getHubzeroConfigOption(hubname, "uri")

    if hostname == None:
        hostname = gethostname()

    print "changing public hostname to: " + hostname

    dbPW = hubzero.config.webconfig.getWebConfigDBPassword()
    dbUserName = hubzero.config.webconfig.getWebConfigDBUsername()
    dbName = hubzero.config.webconfig.getWebConfigDBName()
    db =  hubzero.data.db.MySQLConnection("localhost", dbName, dbUserName, dbPW)		

    sql = "UPDATE jos_users SET email='webmaster@" + hostname + "' WHERE username='admin' AND email LIKE 'webmaster@%'";
    db.query_rowcount(sql, None)	
    sql = "UPDATE jos_users SET email='apps@" + hostname + "' WHERE username='apps' AND email LIKE 'apps@%'";
    db.query_rowcount(sql, None)	
    sql = "UPDATE jos_users SET email='hubrepo@" + hostname + "' WHERE username='hubrepo' AND email LIKE 'hubrepo@%'";
    db.query_rowcount(sql, None)	

    sql = "UPDATE jos_xprofiles SET email='webmaster@" + hostname + "' WHERE username='admin' AND email LIKE 'webmaster@%'";
    db.query_rowcount(sql, None)	
    sql = "UPDATE jos_xprofiles SET email='apps@" + hostname + "' WHERE username='apps' AND email LIKE 'apps@%'";
    db.query_rowcount(sql, None)	
    sql = "UPDATE jos_xprofiles SET email='hubrepo@" + hostname + "' WHERE username='hubrepo' AND email LIKE 'hubrepo@%'";
    db.query_rowcount(sql, None)	

    copyfile(dest = '/etc/sysconfig/network', content = hostname)
    copyfile(dest = '/etc/hostname', content = hostname)

    try:
        proc = subprocess.Popen( ["/bin/hostname", hostname], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        procStdOut, procStdErr = proc.communicate()

        rc = proc.returncode

    except Exception, ex:
        raise

    if rc != 0:
        print procStdOut
        print procStdErr
        return None

    lineinfile(dest = '/etc/mw-service/mw-service.conf', regexp = r'^\s*submit_server\s*=.*$', line = "submit_server = \"" + hostname + "\"")
    hubzero.config.hubzerositeconfig.setHubzeroConfigOption(hubname, "uri", "https://" + hostname)
    lineinfile(dest = '/etc/mw-client/mw-client.conf', regexp = r'^\s*hub_url\s*=.*$', line = 'hub_url = "http://' + hostname + '"')
    lineinfile(dest = '/etc/submit/submit-server.conf', regexp = r'^\s*emailFrom\s*=\s*noreply@.*$', line = 'emailFrom=noreply@' + hostname)
    lineinfile(dest = '/etc/httpd/conf.d/hub.conf', regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(dest = '/etc/httpd/conf.d/hub-ssl.conf', regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(dest = '/etc/httpd/conf.d/" + hubname + ".conf', regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(dest = '/etc/httpd/conf.d/" + hubname + "-ssl.conf', regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(dest = '/etc/apache2/sites-available/hub.conf', regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(dest = '/etc/apache2/sites-available/hub.conf', regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(dest = '/etc/apache2/sites-available/" + hubname + ".conf', regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(dest = '/etc/apache2/sites-available/" + hubname + "-ssl.conf', regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(dest = document_root + "/hubconfiguration.php", regexp = r'^\s*(var|public)\s+\$forgeURL\s*=\s*.*$', line = " var $forgeURL = 'https://" + hostname + "';")
    lineinfile(dest = document_root + "/hubconfiguration.php", regexp = r'^\s*(var|public)\s+\$forgeRepoURL\s*=\s*.*$', line = " var $forgeRepoURL = 'https://" + hostname + "';")
    lineinfile(dest = document_root + "/configuration.php", regexp = r'^\s*(var|public)\s+\$mailfrom\s*=\s*\'webmaster@.*$', line = "\tvar $mailfrom = 'webmaster@" + hostname + "';")
    lineinfile(dest = document_root + "/app/config/app.php", regexp = r'^\s*\'live_site\'.*$', line = "        'live_site' => 'https://" + hostname + "',")
    lineinfile(dest = document_root + "/app/config/mail.php", regexp = r'^\s*\'mailfrom\'\s*=>\s*\'webmaster@.*$', line = "\t'mailfrom' => 'webmaster@" + hostname + "',")
    lineinfile(dest = "/etc/hubmail_gw.conf", regexp = r'^\s*(var|public)\s+\$mailfrom\s*=\s*\'webmaster@.*$', line = "	public $mailfrom = 'webmaster@" + hostname + "';")
    lineinfile(dest = "/etc/hubmail_gw.conf", regexp = r'^\s*(var|public)\s+\$hubLongURL\s*=\s*.*$', line = "	public $hubLongURL = 'https://" + hostname + "';")



def _setMySQLRootPassword(args):
    setMySQLRootPassword(args.username, args.password)

def setMySQLRootPassword(username = 'root', password = None):

    if password == None:
        password = generateAlphaNumPassword(autoGenPWLength)
        
    setMySQLPW(username, password)

    if not os.path.exists("/root/.my.cnf"):
        with open('/root/.my.cnf', 'w') as f:
            f.write("[client]\nuser=" + username + "\npassword=" + password + "\n")
    else:
        config = ConfigParser.RawConfigParser()
        config.read("/root/.my.cnf")
        config.set("client", "password", password)
        config.set("client", "user", username)
        with open('/root/.my.cnf', 'wb') as configfile:
            config.write(configfile)

# ####################################################################################
# main

hostname = gethostname()

# exit if not being run by the root user
checkforroot()

# main parser
parser = argparse.ArgumentParser(prog="hzcms")
subparsers = parser.add_subparsers()

# install subcommand
parser_install = subparsers.add_parser('install', help='install a new hub')
parser_install.add_argument('hubname', help='name of new hub')
parser_install.add_argument('--uri', help='uri of new hub')
parser_install.add_argument('--dbname', help='db name of new hub')
parser_install.add_argument('--dbprefix', help='prefix for web tables', default='jos_')
parser_install.add_argument('--docroot', help='root folder for the cms web files', default='/var/www')
parser_install.add_argument('--installkey', help='alphanumeric key used to run joomla install scripts, min length=8')
parser_install.add_argument('--mailfrom', help='email of the site admin', default="")
parser_install.add_argument('--promptsiteadminpw', help='prompt for a site admin password, if not provided, one will be created and output to screen', action="store_true", default=False)
parser_install.add_argument('--createsecretsfile', help='create the /etc/hubzero.secrets file', default=True, action="store_true")
parser_install.add_argument('--siteadminemail', help='email of the site admin', default='admin@myhub.org')
parser_install.add_argument('--siteadminfirstname', help='name of the site admin', default="CMS")
parser_install.add_argument('--siteadminlastname', help='name of the site admin', default="Manager")
parser_install.add_argument('--cmsversion', help='version of HUBzero CMS to install')
parser_install.set_defaults(func=installHub)

# delete subcommand
parser_delete = subparsers.add_parser('delete', help='delete files and database of existing hub')
parser_delete.add_argument('hubname', help='name of hub to delete')
parser_delete.set_defaults(func=deleteHub)

# uninstall subcommand
parser_uninstall = subparsers.add_parser('uninstall', help='remove existing hub')
parser_uninstall.add_argument('hubname', help='name of hub to delete')
parser_uninstall.set_defaults(func=uninstallHub)

# update subcommand
parser_update = subparsers.add_parser('update', help='update existing hub')
parser_update.set_defaults(func=updateHub)

# update-cms subcommand
parser_update = subparsers.add_parser('update-cms', help='update cms part of hub')
parser_update.set_defaults(func=updateCMS)

# reconfigure subcommand
parser_reconfigure = subparsers.add_parser('reconfigure', help='regenerate m4 configfiles for existing hub')
parser_reconfigure.add_argument('hubname', help='hubname')
parser_reconfigure.set_defaults(func=reconfigureHub)

# configure command, configure command has a slew of it's own sub commands
parser_configure = subparsers.add_parser('configure', help='various configuration commands')
parser_configure_subparsers = parser_configure.add_subparsers()

# configure/ldap subcommand
parser_configure_ldap = parser_configure_subparsers.add_parser('ldap', help='configure hub ldap')
group = parser_configure_ldap.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on ldap plugin for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off ldap plugin for hub', action="store_false", default=False)
parser_configure_ldap.set_defaults(func=_ldapConfigure)

# configure/webdav subcommand
parser_configure_webdav = parser_configure_subparsers.add_parser('webdav', help='configure hub webdav')
group = parser_configure_webdav.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on webdav functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off webdav functionality for hub', action="store_false", default=False)
parser_configure_webdav.set_defaults(func=_webdavConfigure)

# configure/subversion
parser_configure_subversion = parser_configure_subparsers.add_parser('subversion', help='configure hub ')
group = parser_configure_subversion.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on subversion functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off subversion functionality for hub', action="store_false", default=False)
parser_configure_subversion.set_defaults(func=_subversionConfigure)

# configure/filexfer
parser_configure_filexfer = parser_configure_subparsers.add_parser('filexfer', help='configure hub filexfer')
group = parser_configure_filexfer.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on filexfer functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off filexfer functionality for hub', action="store_false", default=False)
parser_configure_filexfer.set_defaults(func=_filexferConfigure)

# configure/forcecnanno
parser_configure_forcecanon = parser_configure_subparsers.add_parser('forcecanon', help='configure hub forcecanon')
group = parser_configure_forcecanon.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on forcecanon functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off forcecanon functionality for hub', action="store_false", default=False)
parser_configure_forcecanon.set_defaults(func=_forcecanonConfigure)

# configure/forge
parser_configure_forge = parser_configure_subparsers.add_parser('forge', help='configure hub forge')
group = parser_configure_forge.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on forge functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off forge functionality for hub', action="store_false", default=False)
parser_configure_forge.set_defaults(func=_forgeConfigure)

# configure/hostsupdate
parser_configure_hosts = parser_configure_subparsers.add_parser('hosts', help='installs hook to auto update /etc/hosts to include hostname for host IP obtained from DHCP (only matters in VM/DHCP installs)')
group = parser_configure_hosts.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on forge functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off forge functionality for hub', action="store_false", default=False)
parser_configure_hosts.set_defaults(func=_createDHCPExitHookFile)

# configure/mailgateway
parser_configure_mailgateway = parser_configure_subparsers.add_parser('mailgateway', help='configure hub metrics')
group = parser_configure_mailgateway.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on mailgateway functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off mailgateway functionality for hub', action="store_false", default=False)
parser_configure_mailgateway.set_defaults(func=_mailgateway)

# configure/metrics
parser_configure_metrics = parser_configure_subparsers.add_parser('metrics', help='configure hub metrics')
group = parser_configure_metrics.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on metrics functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off metrics functionality for hub', action="store_false", default=False)
parser_configure_metrics.set_defaults(func=_mwMetrics)

# configure/mw-client
parser_configure_mwclient = parser_configure_subparsers.add_parser('mw-client', help='configure hub mw-client')
group = parser_configure_mwclient.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on mw-client functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off mw-client functionality for hub', action="store_false", default=False)
parser_configure_mwclient.set_defaults(func=_mwClientConfigure)

# configure/_mw-service
parser_configure_mwservice = parser_configure_subparsers.add_parser('mw-service', help='configure hub mw-service')
group = parser_configure_mwservice.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on mw-service functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off mw-service functionality for hub', action="store_false", default=False)
parser_configure_mwservice.set_defaults(func=_mwServiceConfigure)

# configure/submit-server
parser_configure_submitserver = parser_configure_subparsers.add_parser('submit-server', help='configure hub submit server')
group = parser_configure_submitserver.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on submit server functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off submit server functionality for hub', action="store_false", default=False)
parser_configure_submitserver.set_defaults(func=_submitserverConfigure)

# configure/ssh
parser_configure_ssh = parser_configure_subparsers.add_parser('ssh', help='configure ssh settings for hub')
group = parser_configure_ssh.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on ssh functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off ssh functionality for hub', action="store_false", default=False)
parser_configure_ssh.set_defaults(func=_sshConfigure)

# configure/sftp
parser_configure_sftp = parser_configure_subparsers.add_parser('sftp', help='configure sftp setting for hub')
group = parser_configure_sftp.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on sftp server functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off sftp server functionality for hub', action="store_false", default=False)
parser_configure_sftp.set_defaults(func=_sftpConfigure)

# configure/mw-virtualssh
parser_configure_mwvirtualssh = parser_configure_subparsers.add_parser('mw-virtualssh', help='configure mw-virtualssh settings for hub')
group = parser_configure_mwvirtualssh.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on mw-virtualssh functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off mw-virtualssh functionality for hub', action="store_false", default=False)
parser_configure_mwvirtualssh.set_defaults(func=_mwVirtualsshConfigure)

# configure/telequotad
parser_configure_telequotad = parser_configure_subparsers.add_parser('telequotad', help='configure telequotad setting for hub')
group = parser_configure_telequotad.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on telequotad functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off telequotad functionality for hub', action="store_false", default=False)
parser_configure_telequotad.set_defaults(func=_telequotadConfigure)

# configure/cron
parser_configure_cron = parser_configure_subparsers.add_parser('cron', help='configure cron setting for hub')
group = parser_configure_cron.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on cron functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off cron functionality for hub', action="store_false", default=False)
parser_configure_cron.set_defaults(func=_cronConfigure)

# configure/openvz
parser_configure_openvz = parser_configure_subparsers.add_parser('openvz', help='configure openvz setting for hub')
group = parser_configure_openvz.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on openvz functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off openvz functionality for hub', action="store_false", default=False)
parser_configure_openvz.set_defaults(func=_openvzConfigure)

# configure/textifier
parser_configure_textifier = parser_configure_subparsers.add_parser('textifier', help='configure hub textifier')
group = parser_configure_textifier.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on textifier functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off textifier functionality for hub', action="store_false", default=False)
parser_configure_textifier.set_defaults(func=_textifierConfigure)

# configure/trac
parser_configure_trac = parser_configure_subparsers.add_parser('trac', help='configure hub trac')
group = parser_configure_trac.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on trac functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off trac functionality for hub', action="store_false", default=False)
parser_configure_trac.set_defaults(func=_tracConfigure)

# configure/vncproxy
parser_configure_vncproxy = parser_configure_subparsers.add_parser('vncproxy', help='configure hub vncproxy')
group = parser_configure_vncproxy.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on vncproxy functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off vncproxy functionality for hub', action="store_false", default=False)
parser_configure_vncproxy.set_defaults(func=_vncProxyConfigure)

# configure/dataviewer
parser_configure_dataviewer = parser_configure_subparsers.add_parser('dataviewer', help='configure dataviewer component')
group = parser_configure_dataviewer.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on dataviewer functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off dataviewer functionality for hub', action="store_false", default=False)
parser_configure_dataviewer.set_defaults(func=_dataviewerConfigure)

# configure/hubgraph
parser_configure_hubgraph = parser_configure_subparsers.add_parser('hubgraph', help='configure hubgraph component')
group = parser_configure_hubgraph.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on hubgraph functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off hubgraph functionality for hub', action="store_false", default=False)
parser_configure_hubgraph.set_defaults(func=_hubgraphConfigure)

# creathubdatabase subcommand
parser_installdb = subparsers.add_parser('createhubdatabase', help='create a new hub database in mysql')
parser_installdb.add_argument('--dbname', help='database name', required=True)
parser_installdb.set_defaults(func=_mySQLDatabaseSetup)

# confighubfile subcommand
parser_config = subparsers.add_parser('confighubfile', help='get and set config values for a hub')
parser_config.add_argument('hubname', help='hubname')
parser_config.add_argument('section', help='section name')
parser_config.add_argument('option', help='option name')
parser_config.set_defaults(func=configHubFile)

# reconfigure subcommand
parser_reconfigure = subparsers.add_parser('reconfigure', help='regenerate m4 configfiles for existing hub')
parser_reconfigure.add_argument('hubname', help='hubname')
parser_reconfigure.set_defaults(func=reconfigureHub)

# create snakeoil certs
parser_sslsnakeoil = subparsers.add_parser('generate-default-snakeoil-cert', help='generate self signed SSL certificates (snakeoil)')
parser_sslsnakeoil.add_argument('--force-overwrite', action="store_true",  help='overwrite existing snakeoil certificates if present')
parser_sslsnakeoil.set_defaults(func=generateDefaultSnakeoilCert)

# update timezone database
parser_tzdatabase = subparsers.add_parser('update-timezone-database', help='update mySQL timezone database from tzdata')
parser_tzdatabase.add_argument('--force', action="store_true",  help='reload tzdata even if flagged as already done')
parser_tzdatabase.set_defaults(func=_updateTimezoneDatabase)

# change hostname
parser_hostname = subparsers.add_parser('change-hostname', help='change hostname of hub')
parser_hostname.add_argument('hostname', help='hostname to change to', default = None)
parser_hostname.set_defaults(func=_changeHostname)

# change internal hostname
parser_localhostname = subparsers.add_parser('change-internal-hostname', help='change internal hostname of hub')
parser_localhostname.add_argument('hostname', help='internal hostname to change to', default = None)
parser_localhostname.set_defaults(func=_changeInternalHostname)

# resetmysqlpw subcommand
parser_resetmysqlpw = subparsers.add_parser('resetmysqlpw', help='reset mysql password')
parser_resetmysqlpw.add_argument('--username', help='username', required=True)
parser_resetmysqlpw.add_argument('--pw', help='password', required=True)
parser_resetmysqlpw.set_defaults(func=_setMySQLPW)

# uninstall subcommand
parser_uninstall = subparsers.add_parser('uninstall', help='remove existing hub')
parser_uninstall.add_argument('hubname', help='name of hub to delete')
parser_uninstall.set_defaults(func=uninstallHub)

# set-mysql-root-password subcommand
parser_setmysqlrootpassword = subparsers.add_parser('set-mysql-root-password', help='set mysql root password')
parser_setmysqlrootpassword.add_argument('--username', help='username', default="root")
parser_setmysqlrootpassword.add_argument('--password', help='password', default=None)
parser_setmysqlrootpassword.set_defaults(func=_setMySQLRootPassword)

args =  parser.parse_args()

args.func(args)
