#!/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.2/cms/index.php"):
    HUBZERO_CMS_DIR = "/usr/share/hubzero-cms-2.2"
    hubzero.utilities.misc.JOOMLA_25 = True
elif os.path.exists("/usr/share/hubzero-cms-2.2.0/cms/index.php"):
    HUBZERO_CMS_DIR = "/usr/share/hubzero-cms-2.2.0"
    hubzero.utilities.misc.JOOMLA_25 = True
elif os.path.exists("/usr/share/hubzero-cms-2.1/cms/index.php"):
    HUBZERO_CMS_DIR = "/usr/share/hubzero-cms-2.1"
    hubzero.utilities.misc.JOOMLA_25 = True
elif 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"

apache_2_2 = True
apache_bin = False

if os.path.exists('/usr/sbin/apachectl'):
    apache_bin = '/usr/sbin/apachectl'
elif os.path.exists('/opt/rh/httpd24/root/usr/sbin/apachectl'):
    apache_bin = '/opt/rh/httpd24/root/usr/sbin/apachectl'

if apache_bin:
    proc = subprocess.Popen([apache_bin, "-v"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    out, err = proc.communicate()
    needle = r'(?m)^.*Apache/(\d+)\.(\d+)\.(\d+).*$'
    m = re.match(needle, out)

    if int(m.group(1)) >= 2 and int(m.group(2)) > 2:
        apache_2_2 = False

(distname, distversion, distid) = platform.linux_distribution(full_distribution_name=False)

# dist might be used elsewhere, not sure
if distname == 'redhat' or distname == 'centos' or distname == 'CentOS':
    dist = DIST_RH
elif distname == 'debian':
    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 ""

# return the user and group for the web user
def webGroup():
    if distname == 'redhat' or distname == 'centos' or distname == 'CentOS':
        return "apache"
    elif distname == 'debian':
        return "www-data"

# return the user and group for the web user
def webUser():
    if distname == 'redhat' or distname == 'centos' or distname == 'CentOS':
        return "apache"
    elif distname == 'debian':
        return "www-data"

# return the apache config directory 
def apacheConfigDir():
    if distname == 'redhat' or distname == 'centos' or distname == 'CentOS':
        # @TODO: A smarter check here would be to determine if the httpd24 scl package is enabled
        if os.path.exists('/opt/rh/httpd24/root/usr') and os.path.exists('/opt/rh/httpd24/root/etc/httpd'):
            return "/opt/rh/httpd24/root/etc/httpd"
        else:
            return "/etc/httpd"
    elif distname == 'debian':
        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'):

    if service == 'php':
        if os.path.exists('/usr/lib64/httpd/modules/libphp5.so'):
            service = 'httpd'
        elif os.path.exists('/etc/init.d/rh-php56-php-fpm'):
            service = 'rh-php56-php-fpm'
        elif os.path.exists('/etc/init.d/php-fpm'):
            service = 'php-fpm'
        elif os.path.exists('/usr/lib/apache2/modules/libphp5.so'):
            service = 'apache2'

    if service == 'apache2':
        if (not os.path.exists('/etc/init.d/apache2') and not os.path.exists('/usr/lib/systemd/system/apache2.service')):
            if (os.path.exists('/etc/init.d/httpd24-httpd')):
                service = 'httpd24-httpd'
            elif (os.path.exists('/etc/init.d/httpd') or os.path.exists('/usr/lib/systemd/system/httpd.service')):
                service = 'httpd'

    if service == 'httpd':
        if (os.path.exists('/etc/init.d/httpd24-httpd')):
            service = 'httpd24-httpd'
        elif (not os.path.exists('/etc/init.d/httpd') and not os.path.exists('/usr/lib/systemd/system/httpd.service')) and (os.path.exists('/etc/init.d/apache2') or os.path.exists('/usr/lib/systemd/system/apache2.service')):
            service = 'apache2'

    if service == 'mysql':
        if (not os.path.exists('/etc/init.d/mysql') and not os.path.exists('/usr/lib/systemd/system/mysql.service')) and (os.path.exists('/etc/init.d/mysqld') or os.path.exists('/usr/lib/systemd/system/mysqld.service')):
            service = 'mysqld'

    if service == 'mysqld':
        if (not os.path.exists('/etc/init.d/mysqld') and not os.path.exists('/usr/lib/systemd/system/mysqld.service')) and (os.path.exists('/etc/init.d/mysql') or os.path.exists('/usr/lib/systemd/system/mysql.service')):
            service = 'mysql'

    if service == 'crond':
        if (not os.path.exists('/etc/init.d/crond') and not os.path.exists('/usr/lib/systemd/system/crond.service')) and (os.path.exists('/etc/init.d/cron') or os.path.exists('/usr/lib/systemd/system/cron.service')):
            service = 'cron'

    if service == 'cron':
        if (not os.path.exists('/etc/init.d/cron') and not os.path.exists('/usr/lib/systemd/system/cron.service')) and (os.path.exists('/etc/init.d/crond') or os.path.exists('/usr/lib/systemd/system/crond.service')):
            service = 'crond'

    if os.path.exists('/sbin/service'):
        serviceCmd = '/sbin/service'
    elif os.path.exists('/usr/sbin/service'):
        serviceCmd = '/usr/sbin/service'

    try:
        print serviceCmd + " " + service + " " + action
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand([serviceCmd, service, action])
    except:
        print serviceCmd + " " + service + " " + 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(CMSAdminPW, 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("CMS-ADMIN=" + CMSAdminPW + "\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(['chmod', hubzeroConfigFilePath, '0644'])

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 hubzeroConfigFilePath, 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('/var/run/mysqld/mysqld.pid'):
        serviceInit('mysql','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
        serviceInit('mysql','start')
        blockTillMySQLRunning()

        # wait for mysql to stop
        serviceInit('mysql','stop')
        blockTillMySQLStopped()

    print "Starting MySQL in safe mode for password change"

    # 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", "--skip-syslog"])

    # wait for mysql server to restart
    print "Waiting for mysql server to be available"
    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 + "'")

    print "Stopping MySQL (safe mode)"
    subprocess.Popen(["/usr/bin/mysqladmin", "-u", "root", "-p"+pw, "shutdown"])

    # restart normal mysql server
    serviceInit('mysql','stop')
    blockTillMySQLStopped()
    print "Starting MySQL in production mode"
    serviceInit('mysql','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):

    if isinstance(owner,float) or isinstance(owner,complex) or isinstance(owner,bool):
        raise TypeError

    if isinstance(owner,int) or isinstance(owner,long):
        owner = int(owner)

        if isinstance(owner,long):
            raise ValueError

        ownerUid = owner
        owner = str(owner)
    else:
        ownerUid = pwd.getpwnam(owner).pw_uid

    if isinstance(group,float) or isinstance(group,complex) or isinstance(group,bool):
        raise TypeError

    if isinstance(group,int) or isinstance(group,long):
        group = int(group)

        if isinstance(group,long):
            raise ValueError

        ownerGid = group
        group = str(group)
    else:
        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):

    if isinstance(owner,float) or isinstance(owner,complex) or isinstance(owner,bool):
        raise TypeError

    if isinstance(owner,int) or isinstance(owner,long):
        owner = int(owner)

        if isinstance(owner,long):
            raise ValueError

        ownerUid = owner
        owner = str(owner)
    else:
        ownerUid = pwd.getpwnam(owner).pw_uid

    if isinstance(group,float) or isinstance(group,complex) or isinstance(group,bool):
        raise TypeError

    if isinstance(group,int) or isinstance(group,long):
        group = int(group)

        if isinstance(group,long):
            raise ValueError

        ownerGid = group
        group = str(group)
    else:
        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/rh-php56/root/usr/bin/php'):
        if not os.path.exists('/usr/bin/php'):
            print "ln -s /opt/rh/rh-php56/root/usr/bin/php /usr/bin/php"
            os.symlink('/opt/rh/rh-php56/root/usr/bin/php', '/usr/bin/php')
    elif 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('/etc/opt/rh/rh-php56/php.ini'):
        filename = '/etc/opt/rh/rh-php56/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('php','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.isfile('/var/lock/apache2/RewriteLock'):
            os.remove('/var/lock/apache2/RewriteLock')

        if apache_2_2:
            createDir("/var/lock/apache2", "0755", webServerUser, "root", resetattrs=True)
            createDir("/var/lock/apache2/RewriteLock", "0750", webServerUser, webServerGroup, resetattrs=True)
        else:
            if os.path.isdir("/var/lock/apache2/RewriteLock"):
                os.rmdir("/var/lock/apache2/RewriteLock")


    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)

        if os.path.isfile('/var/lock/httpd/RewriteLock'):
            os.remove('/var/lock/httpd/RewriteLock')

        if apache_2_2:
            createDir("/var/lock/httpd", "0750", webServerUser, webServerGroup, resetattrs=True)
            createDir("/var/lock/httpd/RewriteLock", "0750", webServerUser, webServerGroup, resetattrs=True)
        else:
            if os.path.isdir("/var/lock/httpd/RewriteLock"):
                os.rmdir("/var/lock/httpd/RewriteLock")
            if os.path.isdir("/var/lock/httpd"):
                os.rmdir("/var/lock/httpd")

    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')

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

def mySQLDatabaseSetup(dbName, host, dbPW = '', dbRootPW=''):
    """
    dbName - name of new database
    host - database host
    dbRootPW - pw for the DB root user
    """
    if not dbPW:
        dbPW = generateAlphaNumPassword(14)

    print "creating mySQL databases"

    if distname == 'debian':

        # 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 db user
        # Note: user name matches database name
        print "creating database user: " + dbName
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand([
            "/usr/bin/mysql",
            "--defaults-file=/etc/mysql/debian.cnf",
            "-e", "CREATE USER " + dbName + "@localhost"])

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

        # Give db user full permissions over the new database
        print "grant database access to 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 distname == 'redhat' or distname == 'centos' or distname == 'CentOS':

        # 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"
        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 
        # 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", "CREATE USER " + dbName + "@localhost"])

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

        # Give db user full permissions over the new database
        print "grant database access to 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 distribution: " + distname)

    return dbPW

def generateLogrotateFiles(hubname):

    if os.path.exists(HUBZERO_CMS_DIR + "/conf"):
        HUBZERO_LOGROTATE_CONF_DATADIR = HUBZERO_CMS_DIR + "/conf"
        HUBZERO_LOGROTATE_PHP_CONF_DATADIR = HUBZERO_CMS_DIR + "/conf"
    else:
        HUBZERO_LOGROTATE_CONF_DATADIR = "/usr/share/hubzero-apache2/conf"
        HUBZERO_LOGROTATE_PHP_CONF_DATADIR = "/usr/share/hubzero-apache2/conf"

    if os.path.exists('/usr/share/hubzero-php/conf'):
        HUBZERO_LOGROTATE_PHP_CONF_DATADIR = "/usr/share/hubzero-php/conf"

    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_LOGROTATE_PHP_CONF_DATADIR + "/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_LOGROTATE_PHP_CONF_DATADIR + "/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_LOGROTATE_PHP_CONF_DATADIR + "/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_LOGROTATE_CONF_DATADIR + "/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_LOGROTATE_CONF_DATADIR + "/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):

    if os.path.exists(HUBZERO_CMS_DIR + "/conf"):
        HUBZERO_APACHE2_CONF_DATADIR = HUBZERO_CMS_DIR + "/conf"
    else:
        HUBZERO_APACHE2_CONF_DATADIR = "/usr/share/hubzero-apache2/conf"

    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/apache2/conf/hub.m4 " + m4dir + hubname + ".m4"
    hubzero.utilities.misc.exShellCommand(["cp", HUBZERO_APACHE2_CONF_DATADIR + "/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/apache2/conf/hub-ssl.m4 " + m4dir + hubname + "-ssl.m4"
    hubzero.utilities.misc.exShellCommand(["cp", HUBZERO_APACHE2_CONF_DATADIR + "/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 (distname == 'redhat' or distname == 'centos' or distname == 'CentOS') and os.path.exists(apacheConfigDir() + "/conf.d/ssl.conf"):
        os.remove(apacheConfigDir() + "/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 distname == 'debian':

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

        if os.path.exists(apacheConfigDir() + "/ssl.crt/" + hubname + "-cert.pem"):
            if os.path.exists(apacheConfigDir() + "/ssl.key/" + hubname + "-privkey.pem"):
                m4ApacheConfigOptions.append("-DSSLCERTFILE=" + apacheConfigDir() + "/ssl.crt/" + hubname + "-cert.pem")
                m4ApacheConfigOptions.append("-DSSLCERTKEYFILE=" + apacheConfigDir() + "/ssl.key/" + hubname + "-privkey.pem")

        if os.path.exists(apacheConfigDir() + "/ssl.crt/" + hubname + "-chain.pem"):
            m4ApacheConfigOptions.append("-DSSLCERTIFICATECHAINFILE=" + apacheConfigDir() + "/ssl.crt/" + hubname + "-chain.pem")

        m4ApacheConfigOptions.append("-DTRACROOT=/usr/share/pyshared/")
        m4ApacheConfigOptions.append("-DAPACHE_HOME=apache2")
        m4ApacheConfigOptions.append("-DAPACHE_SERVER=apache2")
        m4ApacheConfigOptions.append("-DDISTDEB=1")

        if apache_2_2:
            m4ApacheConfigOptions.append("-DAPACHE_22=1")
            suffix = ''
        else:
            suffix = '.conf'

        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 + suffix
            m4Processing(apacheConfigDir() + "/sites-m4/" + hubname + ".m4",
                         apacheConfigDir() + "/sites-available/" + hubname + suffix,
                         m4ApacheConfigOptions,
                         0644, "root", "root")

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

            generatedM4File = True

    elif distname == 'redhat' or distname == 'centos' or distname == 'CentOS':

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

        if os.path.exists(apacheConfigDir() + "/ssl.crt/" + hubname + "-cert.pem"):
            if os.path.exists(apacheConfigDir() + "/ssl.key/" + hubname + "-privkey.pem"):
                m4ApacheConfigOptions.append("-DSSLCERTFILE=" + apacheConfigDir() + "/ssl.crt/" + hubname + "-cert.pem")
                m4ApacheConfigOptions.append("-DSSLCERTKEYFILE=" + apacheConfigDir() + "/ssl.key/" + hubname + "-privkey.pem")

        if os.path.exists(apacheConfigDir() + "/ssl.crt/" + hubname + "-chain.pem"):
            m4ApacheConfigOptions.append("-DSSLCERTIFICATECHAINFILE=" + apacheConfigDir() + "/ssl.crt/" + hubname + "-chain.pem")

        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("-DAPACHE_SERVER=httpd")
        m4ApacheConfigOptions.append("-DDISTRH=1")

        if apache_2_2:
            m4ApacheConfigOptions.append("-DAPACHE_22=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() + "/conf.d/" + hubname + ".conf"
            m4Processing(apacheConfigDir() + "/sites-m4/" + hubname + ".m4",
                         apacheConfigDir() + "/conf.d/" + hubname + ".conf",
                         m4ApacheConfigOptions,
                         0644, "root", "root")

            #print "processing " + apacheConfigDir() + "/sites-m4/" + hubname + "-ssl.m4 to " + apacheConfigDir() + "/conf.d/" + hubname + "-ssl.conf"
            m4Processing(apacheConfigDir() + "/sites-m4/" + hubname + "-ssl.m4",
                         apacheConfigDir() + "/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" in HUBZERO_CMS_DIR:
            dbsqlfile = open(HUBZERO_CMS_DIR + "/cms/core/bootstrap/install/sql/mysql/joomla.sql", "r")
        elif "hubzero-cms-2.2" 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" in HUBZERO_CMS_DIR:
        dbsqlfile = open(HUBZERO_CMS_DIR + "/cms/core/bootstrap/install/sql/mysql/hubzero.sql", "r")
    elif "hubzero-cms-2.2" 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" in HUBZERO_CMS_DIR:
        dbsqlfile = open(HUBZERO_CMS_DIR + "/cms/core/bootstrap/install/sql/mysql/hz_sample_data.sql", "r")
    elif "hubzero-cms-2.2" 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" in HUBZERO_CMS_DIR:
        configfilepath = HUBZERO_CMS_DIR + "/cms/core/bootstrap/tmpl/configuration.html"
    elif "hubzero-cms-2.2" 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)

    if os.path.exists("/etc/cron.d/" + args.hubname + "-cmscron"):
        cronConfigure(True)

def generateDefaultSnakeoilCert(args):

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


def fixApacheCerts():

    hubname = hubzero.config.webconfig.getDefaultSite() 

    createSSLCerts()

    sys_certpath = "/etc/ssl/certs"

    if os.path.exists("/etc/ssl/private"):
        sys_keypath = "/etc/ssl/private"
    else:
        sys_keypath = "/etc/ssl/certs/private"

    createDir(apacheConfigDir() + "/ssl.crt", "0750", "root", "root", resetattrs=True)

    createDir(apacheConfigDir() + "/ssl.key", "0750", "root", "root", resetattrs=True)

    if not os.path.exists(apacheConfigDir() + "/ssl.crt/" + hubname + "-cert.pem") or not os.path.exists(apacheConfigDir() + "/ssl.key/" + hubname + "-privkey.pem"):
        if os.path.exists(sys_certpath + "/ssl-cert-snakeoil.pem") and os.path.exists(sys_keypath + "/ssl-cert-snakeoil.key"):
            shutil.copyfile(sys_certpath + "/ssl-cert-snakeoil.pem", apacheConfigDir() + "/ssl.crt/" + hubname + "-cert.pem")
            shutil.copyfile(sys_keypath + "/ssl-cert-snakeoil.key", apacheConfigDir() + "/ssl.key/" + hubname + "-privkey.pem")
            if os.path.exists(apacheConfigDir() + "/ssl.crt/" + hubname + "-chain.pem"):
                os.remove(apacheConfigDir() + "/ssl.crt/" + hubname + "-chain.pem")

    if os.path.exists(apacheConfigDir() + "/ssl.crt/" + hubname + "-cert.pem"):
        createFile(apacheConfigDir() + "/ssl.crt/" + hubname + "-cert.pem", "0640", resetattrs=True)

    if os.path.exists(apacheConfigDir() + "/ssl.crt/" + hubname + "-chain.pem"):
        createFile(apacheConfigDir() + "/ssl.crt/" + hubname + "-chain.pem", "0640", resetattrs=True)

    if os.path.exists(apacheConfigDir() + "/ssl.key/" + hubname + "-privkey.pem"):
        createFile(apacheConfigDir() + "/ssl.key/" + hubname + "-privkey.pem", "0640", resetattrs=True)


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 " + hubzeroConfigFilePath + " " + 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 distname == 'debian':
        print "Debian install"
        return installHubDebian(args)
    elif distname == 'redhat' or distname == 'centos' or distname == 'CentOS':
        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 " + hubzeroConfigFilePath + " 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", 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")
   
    fixApacheCerts()

    # generate the apache web config files
    if not apacheOgreManaged():
        generateApacheConfFiles(hubname)

    # add 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
    createDir("/home/" + hubname, "0755", "root", "root", resetattrs=True)

    # 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"

    # skipCreateLDAPUser is True because LDAP is not require to run just the CMS so we can't
    # guarantee it is availale

    hubzero.utilities.user.addhubuser(args.hubname,
                                      username = 'admin', 
                                      email = 'webmaster@' + hostname,
                                      pw = adminpw,
                                      gecos = "CMS Manager",
                                      joomlagidNumber = 25,
                                      uidNumber = 1000,
                                      loginShell = '/bin/bash',
                                      homeDir='/home/'+hubname+'/admin',
                                      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)
    cronConfigure(True)

    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(apacheConfigDir() + "/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 " + hubzeroConfigFilePath + " 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  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", 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

    fixApacheCerts()

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

    # 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(apacheConfigDir() + "/conf/httpd.conf"):
        confDir = apacheConfigDir() + "/" + 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"

    # skipCreateLDAPUser is True because LDAP is not require to run just the CMS so we can't
    # guarantee it is availale

    hubzero.utilities.user.addhubuser(args.hubname,
                                      username = 'admin', 
                                      email = 'webmaster@' + hostname,
                                      pw = adminpw,
                                      gecos = "CMS Manager",
                                      joomlagidNumber = 25,
                                      uidNumber = 1000,
                                      loginShell = '/bin/bash',
                                      homeDir='/home/'+hubname+'/admin',
                                      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)

    print "restarting web server"
    serviceInit('apache2','restart')

    # 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)
    cronConfigure(True)

    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 hubzeroConfigFilePath (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-available/" + hubname + ".conf"): os.remove(apacheConfigDir()+ "/sites-available/" + hubname + ".conf") 
    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-available/" + hubname + "-ssl.conf"): os.remove(apacheConfigDir() + "/sites-available/" + hubname + "-ssl.conf")
    if os.path.exists(apacheConfigDir() + "/sites-enabled/" + hubname + "-ssl"): os.remove(apacheConfigDir() + "/sites-enabled/" + hubname + "-ssl")
    if os.path.exists(apacheConfigDir() + "/sites-enabled/" + hubname + "-ssl.conf"): os.remove(apacheConfigDir() + "/sites-enabled/" + hubname + "-ssl.conf")
    if os.path.exists(apacheConfigDir() + "/sites-enabled/" + hubname): os.remove(apacheConfigDir() + "/sites-enabled/" + hubname)
    if os.path.exists(apacheConfigDir() + "/sites-enabled/" + hubname + ".conf"): os.remove(apacheConfigDir() + "/sites-enabled/" + hubname + ".conf")

    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 invalidateUserGroupCache():

    if os.path.exists('/var/lib/sss'):
        print "clearing sssd cache"
        fix_sssd_conf()
        serviceInit('sssd','stop')
        subprocess.call('/bin/rm /var/lib/sss/db/* -Rf', shell=True)
        serviceInit('sssd','start')
    else:
        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:
            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
            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)

        invalidateUserGroupCache()

        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"

        invalidateUserGroupCache()

        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"

        # Ensure proper permissions on home directory root
        createDir("/home/" + hubname, "0755", "root", "root", resetattrs=True)

        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 distname == 'debian':
            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):
        serviceInit('apache2','restart')

    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):
        serviceInit('apache2','restart')

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

def filexferConfigure(enable):
    hubname = hubzero.config.webconfig.getDefaultSite() 
    webServerUser = webUser()
    webServerGroup = webGroup()

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

    if os.path.exists('/usr/sbin/apache2'):
        createDir("/var/lock/apache2", "0750", webServerUser, webServerGroup, resetattrs=True)
        if os.path.isfile('/var/lock/apache2/RewriteLock'):
            os.remove('/var/lock/apache2/RewriteLock')
        createDir("/var/lock/apache2/RewriteLock", "0750", webServerUser, webServerGroup, resetattrs=True)

    if os.path.exists('/usr/sbin/httpd'):
        createDir("/var/lock/httpd", "0750", webServerUser, webServerGroup, resetattrs=True)
        if os.path.isfile('/var/lock/httpd/RewriteLock'):
            os.remove('/var/lock/httpd/RewriteLock')
        createDir("/var/lock/httpd/RewriteLock", "0750", webServerUser, webServerGroup, resetattrs=True)

    # regenerate the apache config files to use the new option setting
    if generateApacheM4config(hubname):
        serviceInit('apache2','restart')

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):
        serviceInit('apache2','restart')

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

def forgeConfigure(enable):

    hubname = hubzero.config.webconfig.getDefaultSite() 

    # 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) 

    if hubzero.config.webconfig.getPluginEnabled('user','ldap'):
        syncLdap = True
    else:
        syncLdap = False
        
    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',
                                      homeDir='/home/'+hubname+'/apps',
                                      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 'mw-login'
        print "checking group 'mw-login'"
        if not hubzero.utilities.group.groupExists("mw-login"):
            print "adding group 'mw-login'"
            hubzero.utilities.group.addhubgroup("mw-login", "mw-login")

        db.query_rowcount(
            "UPDATE jos_xgroups SET type='0', published='0' WHERE cn='mw-login'", None)
        if syncLdap:
            hubzero.utilities.group.syncgroup('mw-login', verbose=True)

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

        # 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")

        invalidateUserGroupCache()

        # 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):
        serviceInit('apache2','restart')

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):
        serviceInit('apache2','restart')
    
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 distname=='redhat' or distname == 'centos' or distname == 'CentOS' 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 apachaConfigDir() + /conf/httpd.conf
        if distname == 'redhat' or distname == 'centos' or distname == 'CentOS':
            filename = apacheConfigDir() + "/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 apacheConfigDir() + /conf/httpd.conf
        if distname == 'redhat' or distname == 'centos' or distname == 'CentOS':
            filename = apacheConfigDir() + "/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):
        serviceInit('apache2','restart')

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 installPubAuthorizedKeys(sources, authkeysfile, options):
    """
    Check the list of sources for a public key.  If found install it in the
    authorized_keys file, with the options provided.
    """
    keypath = None
    for p in sources:
        if os.path.exists(p):
            keypath = p
    if keypath is None:
        errmsg = "No public key to install in %s, looked in (" + ', '.join(sources) + ").  Transfer the key from the web server or if this is the web server, there may be more packages you need to install."
        raise Exception (errmsg % authkeysfile)
        
    f1 = open(keypath, '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 "appending %s to %s" % (keypath, authkeysfile)
            keyfile = open(authkeysfile, "a")
            keyfile.write(options)
            keyfile.write(' ')
            keyfile.write(key)
            keyfile.close()
        else:
            # if the key is present, is it prefaced with the right options?
            # if not, insert or remove and readd
            print "key already in %s" % authkeysfile
            with open(authkeysfile, "r") as keyfile:
                lines = keyfile.readlines()
            with open(authkeysfile, "w") as keyfile:
                for line in lines:
                    if line.find(key) != -1:
                        # already there!  Does it start with the right options? (additional options are OK, like a "from")
                        if line.find(options) != 0:
                            print "rewriting %s with new SSH key options" % authkeysfile
                            keyfile.write(options)
                            keyfile.write(' ')
                            keyfile.write(key)
                        else:
                            keyfile.write(line)
                    else:
                        keyfile.write(line)

    else: # create file
        print "Created %s using %s" % (authkeysfile, keypath)
        # create .ssh directory if it doesn't exist
        try:
            os.makedirs(os.path.dirname(authkeysfile))
        except OSError:
            pass
        keyfile = open(authkeysfile, "w")
        keyfile.write(options)
        keyfile.write(' ')
        keyfile.write(key)
        keyfile.close()         
    os.chmod(authkeysfile, 0600)

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

def mwServiceConfigure_v1(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='0' 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 _mwServiceConfigure_v2(args):
    mw2erviceConfigure_v2(args.enable)

def mwServiceConfigure_v2(enable):
    """Middleware setup on execution hosts.  
    MySQL may not be available, if this is a separate execution host.
    Do NOT assume that this is being installed on a web server.
    Check for the presence of /etc/mw-client -- if it's there, try MySQL.  If not, skip MySQL ops  
    There's no MySQL server on a separate execution host.  
    Tasks:
    -Add maxwell public key to /root/.ssh, using forced command to filter and validate input
    -Setup /etc/vz/vz.conf
    -Configure /etc/mw-service/exec.conf
    """
    import glob
    if glob.glob("/usr/lib/python*/*-packages/hubzero/mw/container.py") == []:
        mwServiceConfigure_v1(enable)
        return
    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"
            
        if not os.path.exists('/etc/mw-service/exec.conf'):
            raise Exception("/etc/mw-service/exec.conf must exist.  Install the hubzero-mw2-exec-service package first.")

        if not os.path.exists('/etc/mw-service/notify.key'):
            # mw-service seems installed, copy the notify key
            if os.path.exists('/etc/mw-client/notify.key'):
                shutil.copyfile('/etc/mw-client/notify.key', '/etc/mw-service/notify.key')
            else:
                raise Exception("/etc/mw-service/notify.key must exist.  Transfer it from the web server, or if this is the web server, install the hubzero-mw2-client package first.")
                
        os.chown('/etc/mw-service/notify.key', 0, 0)
        os.chmod('/etc/mw-service/notify.key', 0400)

        """
        Add public key used by www-data or apache on the web server, to /root/.ssh/authorized_keys on execution host.  
        Rely on package hubzero-mw2-client for SSH key pair creation.
        If the execution host and web server are separate, the public key must have been exchanged
        by some other means prior to running this.
        1. Find suitable public key
        1b if no key found, abort.
        
        2. Add the key with forced command and from option.
        """
        # from="127.0.0.1"?  What's the web server's IP address?
        # no-pty option breaks Virtual SSH
        installPubAuthorizedKeys(('/etc/mw-client/maxwell.key.pub', '/etc/mw-service/maxwell.key.pub'), '/root/.ssh/authorized_keys', 'no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-user-rc,command="/usr/bin/dispatch"')
        
        # Setup vz.conf
        # VE_STOP_MODE=stop
        # VE_LAYOUT=simfs
        # IPV6="no"
        # VZFASTBOOT=no
        # DISK_QUOTA=yes in production
        # DISK_QUOTA=no to support a single filesytem deployment
        confFileName = "/etc/vz/vz.conf"

        with open(confFileName, "r") as clientConf:
            lines = clientConf.readlines()
        with open(confFileName, "w") as clientConf:
            found_stopmode = False
            found_layout = False
            found_IPV6 = False
            found_fastboot = False
            found_quota = False
            for line in lines:
                if line.find('VE_STOP_MODE') != -1:
                    clientConf.write("VE_STOP_MODE=stop\n")
                    found_stopmode = True
                    continue
                if line.find('VE_LAYOUT') != -1:
                    clientConf.write("VE_LAYOUT=simfs\n")
                    found_layout = True
                    continue
                if line.find('IPV6') != -1:
                    clientConf.write('IPV6=no\n')
                    found_IPV6 = True
                    continue
                if line.find('VZFASTBOOT') != -1:
                    clientConf.write("VZFASTBOOT=no\n")
                    found_fastboot = True
                    continue
                if line.find('DISK_QUOTA') != -1:
                    clientConf.write("DISK_QUOTA=no\n")
                    found_quota = True
                    continue
                else:
                    clientConf.write(line)
            if not found_stopmode:
                clientConf.write("VE_STOP_MODE=stop\n")
            if not found_layout:
                clientConf.write("VE_LAYOUT=simfs\n")
            if not found_IPV6:
                clientConf.write('IPV6=no\n')
            if not found_fastboot:
                clientConf.write("VZFASTBOOT=no\n")
            if not found_quota:
                clientConf.write("DISK_QUOTA=no\n")
        if False:
            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"

        # Setup /etc/mw-service/exec.conf
        # set these:
        # notify_hosts = 'localhost' # your hub's DNS name goes here
        # CONTAINER_CONF = {
        # "HOME_DIR": '/home/@{HUB_NAME}',
        # "PRIVATE_NET": '192.168.%d.%d',  -> choose one that this host doesn't live on already?
        #   "INPUT_CHAIN": "",
        #   "MW_PROTECTED_NETWORK": "128.46.16.0/20",
        #   "FW_GROUP_MAP": [

        confFileName = "/etc/mw-service/exec.conf"

        print "checking " + confFileName
        
        # try to find which network has been setup by the firewall package, and match that
        cmd = "/sbin/iptables-save | egrep '^-A FORWARD -s [0-9\.\/]* \-i venet0 -j ACCEPT' | awk '{print $4}'"
        ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        private_net = ps.communicate()[0]
        s = private_net.rfind('.0.0')
        if s == -1:
            net_format = '192.168.%d.%d'
        else:
            net_format = private_net[:s] + '.%d.%d'
        
        with open(confFileName, "r") as clientConf:
            lines = clientConf.readlines()
        with open(confFileName, "w") as clientConf:
            for line in lines:
                if line.find('HOME_DIR') != -1:
                    clientConf.write("  \"HOME_DIR\": \"/home/" + hubname + "\",\n")
                elif line.find('INPUT_CHAIN') != -1:
                    clientConf.write("  \"INPUT_CHAIN\": \"AUTO_INPUT\",\n")
                # hub_homedir is for "set_quota"'s benefit only, perhaps should go in a file-service.conf file?
                elif line.find('hub_homedir') != -1:
                    clientConf.write("hub_homedir = \"/home/" + hubname + "\"\n")
                elif line.find('PRIVATE_NET') != -1:
                    if private_net == '':
                        clientConf.write(line)
                    else:
                        clientConf.write("  \"PRIVATE_NET\": \"" + net_format + "\",\n")
                else:
                    clientConf.write(line)
        os.chown(confFileName, 0, 0)
        os.chmod(confFileName, 0660)

        if os.path.exists('/etc/mw-client/maxwell.key'):
            # this host is a web server and also an execution host
            # add localhost to database of execution hosts
            # do some db work
            # @TODO Should probably use proper fqdn rather than localhost
            print "configuring host table"
            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',provisions='14' WHERE hostname='localhost';"
            db.query_rowcount(sql, None)    

            if hubzero.config.webconfig.getPluginEnabled('user','ldap'):
                syncLdap = True
            else:
                syncLdap = False
                
        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')        

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

def mwServiceConfigure(enable):
    """Middleware setup on execution hosts.  
    """
    import glob
    if glob.glob("/usr/lib/python*/*-packages/hubzero/mw/container.py") == []:
        mwServiceConfigure_v1(enable)
        return
    else:
        mwServiceConfigure_v2(enable)
        return

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

def mwClientConfigure_v1(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 _mwClientConfigure_v2(args):
    mwClientConfigure(args.enable)

def mwClientConfigure_v2(enable):
    """ Run on the web server.  
    Tasks:
    -Add public key from mw-service (on execution host) to /var/www/.ssh/authorized_keys, 
        using forced command to call maxwell.  Rely on package hubzero-mw2-service for SSH key pair creation.
    -Edit /etc/mw-client/mw2-client.conf to add database information (do not replace)
    """
    hubname = hubzero.config.webconfig.getDefaultSite() 

    if enable:
        print "enabling mw2-client"
        
        if not os.path.exists('/etc/mw-client/maxwell.key'):
            raise Exception("/etc/mw-client/maxwell.key must exist.  Install the hubzero-mw2-client package first.")
                
        """Run on the web server.
        Add public key used by root on execution hosts to notify the web server when a session ended.
        Rely on package hubzero-mw2-service for SSH key pair creation.
        If the execution host and web server are separate, the public key must have been exchanged
        by some other means prior to running this.
        1. Find suitable public key
        1b if no key found, abort.
        
        2. Add the key with forced command and from option."""
        # ,from="127.0.0.1" :  what could be the IP address of the execution host?
        installPubAuthorizedKeys(('/etc/mw-client/notify.key.pub', '/etc/mw-service/notify.key.pub'), '/var/www/.ssh/authorized_keys', 'no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,command="/usr/bin/maxwell notify"')
        if webUser() is not None:
            hubzero.utilities.misc.exShellCommand(['chown', webUser() + ":" + webGroup(), '/var/www/.ssh/authorized_keys'])
            # allow the webuser to have a shell so notifications work
            hubzero.utilities.misc.exShellCommand(['usermod', '-s', '/bin/sh', webUser()])
        
        
        # generate /etc/mw-client/mw2-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)

        confFileName = '/etc/mw-client/mw2-client.conf'
        if os.path.exists(confFileName):
            with open(confFileName, "r") as clientConf:
                lines = clientConf.readlines()
            found_ws_proxy = False
            found_vnc_proxy = False
            found_filexfer_decoration = False
            with open(confFileName, "w") as clientConf:
                for line in lines:
                    if line.find('#mysql_host') == 0:
                        clientConf.write("mysql_host = \"localhost\"\n")
                    elif line.find('#mysql_user') == 0:
                        clientConf.write("mysql_user=\"" + dbUserName + "\"\n")
                    elif line.find('#mysql_password') == 0:
                        clientConf.write("mysql_password=\"" + dbPW + "\"\n")
                    elif line.find('#mysql_db') == 0:
                        clientConf.write("mysql_db=\"" + dbName + "\"\n")
                    elif line.find('#hub_name') == 0:
                        clientConf.write("hub_name=\"" + hubname + "\"\n")
                    elif line.find('#hub_url') == 0:
                        clientConf.write("hub_url=\"" + uri + "\"\n")
                    elif line.find('#hub_homedir') == 0:
                        clientConf.write("hub_homedir=\"/home/" + hubname + "\"\n")
                    elif line.find('#hub_template') == 0:
                        clientConf.write("hub_template=\"" + template + "\"\n")
                    elif line.find('WS_PROXY_SERVER') != -1:
                        found_ws_proxy = True
                        clientConf.write('  "WS_PROXY_SERVER": "",\n')
                        continue
                    elif line.find('VNC_PROXY_SERVER') != -1:
                        found_vnc_proxy = True
                        clientConf.write('  "VNC_PROXY_SERVER": "",\n')
                        continue
                    elif line.find('filexfer_decoration =') == 0:
                        found_filexfer_decoration = True
                        clientConf.write('filexfer_decoration = \'filexfer_sitelogo { <h1><a href="%s" title="%s home page"><span>%s: online simulations and more</span></a></h1> }\\nfilexfer_stylesheet %s/templates/filexfer/upload.css"\\n\'' % (uri, hubname, hubname, uri) )
                        continue
                    else:
                        clientConf.write(line)
                if not found_ws_proxy:
                    print "ERROR: missing configuration line for WS_PROXY_SERVER in SESSION_CONF section, will add a commented out version.  Manual repair to %s needed" % confFileName
                    clientConf.write('#  "WS_PROXY_SERVER": "",\n')
                if not found_vnc_proxy:
                    print "ERROR: missing configuration line for VNC_PROXY_SERVER in SESSION_CONF section, will add a commented out version.  Manual repair to %s needed" % confFileName
                    clientConf.write('#  "VNC_PROXY_SERVER": "",\n')
                if not found_filexfer_decoration:
                    print "ERROR: missing configuration line for filexfer_decoration, adding default"
                    clientConf.write('filexfer_decoration = \'filexfer_sitelogo { <h1><a href="%s" title="%s home page"><span>%s: online simulations and more</span></a></h1> }\\nfilexfer_stylesheet %s/templates/filexfer/upload.css"\\n\'' % (uri, hubname, hubname, uri) )
        else:

            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"
                "mysql_prefix = 'jos'\n" )


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

    SESSION_CONF = {
    # the hostname and port for the VNC proxy serving HTML5
    # if this is the web server then you must use a different port than 443
    # use a different IP address and hostname to be able to use port 443
    # port 443 is standard and is let through firewalls more easily than others
    "WS_PROXY_SERVER": "",
    "WS_PROXY_PORT": 8443,
    # Java VNC proxy
    # paths to .jar files.  Leave empty to let web code decide, putting anything here overrides
    "JAVA_APPLET_PATH": "",
    "JAVA_SIGNED_APPLET_PATH": "",
    "JAVA_SIGNED_APPLET_WINPATH": "",
    # VNC format string
    "CONNECT_FORMAT": "vncsession:%s",
    # the hostname and port for the VNC proxy serving Java
    # Port to use for VNC proxy using Java, uses Apache so port 443 is OK
    "VNC_PROXY_SERVER": "",
    "VNC_PROXY_PORT":443
    }

    # for automatic session creation by virtual SSH when a user doesn't have any tool session running
    # -- this configuration file is also read by mw2-front-virtualssh
    DEFAULT_APP = 'workspace' 

    # Default for when a tool doesn't specify host requirements.
    # can be useful when migrating to a different container template
    APP_CONF = {
    "HOST_REQ_DEFAULTS": ['sessions']
    }

    # Default tool timeout
    default_vnc_timeout = 86400
    """)

            f3.close()
            
        if webGroup() is not None:
            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

        # in case database migration didn't happen
        try:
            sql = 'alter table host add column first_display int Default 0'
            db.query_rowcount(sql, None)
        except (_mysql_exceptions.ProgrammingError,_mysql_exceptions.OperationalError):
            pass
        try:
            sql = 'alter table host add column max_uses int Default 0'
            db.query_rowcount(sql, None)
        except (_mysql_exceptions.ProgrammingError,_mysql_exceptions.OperationalError):
            pass


            
        serviceInit('expire-sessions','restart')
        modifyHubConfigFile("package-config", 'mw-client', 'true')      

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

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

def mwClientConfigure(enable):
    """ Run on the web server.  
    """
    import glob
    if glob.glob("/usr/lib/python*/*-packages/hubzero/mw/container.py") == []:
        mwClientConfigure_v1(enable)
        return
    else:
        mwClientConfigure_v2(enable)
        return


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"
        if distname == 'debian':
            confFileGroup = "Debian-exim"
        else:
            confFileGroup = "postfix"
        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()+":"+confFileGroup, confFileName])   
        if rc: 
            print procStdErr

        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["chmod", "0640", confFileName]) 
        if rc: 
            print procStdErr
    
        if os.path.exists('/etc/default/spamassassin'):
            filename = '/etc/default/spamassassin'
        else:
            filename = '/etc/sysconfig/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 filename + " not found, unable to patch"

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

        if distname == 'redhat' or distname == 'centos' or distname == 'CentOS':
            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 distname == 'redhat' or distname == 'centos' or distname == 'CentOS':
            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='0' 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 "reconfigureSshdConfig deprecated"
    return
    
    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):
    print "This command is deprecated, use configure mwFrontvirtualsshConfigure and mwExecvirtualsshConfigure"

def mwVirtualsshConfigureOld(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 ssh_config_string(webuser, privileged_groups):
   return """
# X forwarding support
# xauth-incoming needs SSH_ORIGINAL_COMMAND to detect the "session" command
# and this is set only when a ForceCommand is executed
XAuthLocation /usr/bin/xauth-incoming

# Set X11_VSSH to enable X11 forwarding through tool container
# Privileged users may need to set "SendEnv X11_VSSH" in their .ssh/config file (on their workstation/laptop)
AcceptEnv LANG LC_* X11_VSSH SESSION SESSIONDIR RESULTSDIR

# limit exposure of Apache user if the SSH key isn't setup with a forced command and "from" options
Match User %s
        X11Forwarding no
        ForceCommand /usr/bin/maxwell notify
        Banner /etc/ssh/nobanner

# Force everyone but members of privileged groups to use SFTP.
# exclude www-data user so ChrootDirectory isn't set.
Match Group *,!mw-login,!%s User *,!%s
        ChrootDirectory /sftp
        X11Forwarding no
        ForceCommand internal-sftp

# Force mw-login group members to access only tool session containers (and SFTP)
# unless they are also members of privileged groups
# X11 forwarding is to tool session containers (see "virtualssh/webserver/xauth-incoming" script)
Match Group mw-login,!%s
        X11DisplayOffset 10
        ForceCommand /usr/bin/session
        Banner /etc/ssh/virtualssh_banner
        
# Users that didn't match the above fall through
    \n""" % (webuser, 
    ",!".join(privileged_groups), webuser,
    ",!".join(privileged_groups))
 
def _mwFileserviceConfigure(args):
    mwFileserviceConfigure(args.enable)

def mwFileserviceConfigure(enable):

    if enable:
        # installation on file server service hosts
        installPubAuthorizedKeys(('/etc/mw-client/maxwell.key.pub', '/etc/mw-service/maxwell.key.pub'), '/root/.ssh/authorized_keys', 'no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-user-rc,command="/usr/bin/dispatch"')
    else:
        print "Remove /usr/bin/dispatch line from /root/.ssh/authorized_keys"


def _mwExecvirtualsshConfigure(args):
    mwExecvirtualsshConfigure(args.enable)
    
def mwExecvirtualsshConfigure(enable):
    # installation on execution hosts
    # SSH key pair for VSSH communication with execution hosts
    # this should be a separate key from maxwell.key used for mw-service control,
    # in case the VSSH private key gets leaked
    # this is a possibility because the VSSH private key is copied with user read permissions
    if os.path.exists('/etc/mw-virtualssh/vssh.key.pub'):
        installPubAuthorizedKeys(('/etc/mw-virtualssh/vssh.key.pub'), '/root/.ssh/authorized_keys', 'no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-user-rc,command="/usr/bin/vssh_exec_proxy"')
    else:
        print "No dedicated, separate SSH key pair found for Virtual SSH.  The key pair for all service operations (maxwell.key) will be used."

def _mwFrontvirtualsshConfigure(args):
    mwFrontvirtualsshConfigure(args.enable)

def mwFrontvirtualsshConfigure(enable):
    """We need to modify /etc/ssh/sshd_config, but first testing the new copy with sshd -t
    /etc/sudoers.d/virtualssh is  installed by the package to allow calling ssh_session.
    autofs files for SFTP
    Create these groups:
    - access-sshfwd for people to do SSH forwarding
    - mw-login
    - access-host
    
    Parts in /etc/ssh/sshd_config:
    - on webservers, for notifications to www-data or the notification user
    - on execution hosts, for service commands
    - for SFTP, forcing everyone to use internal-sftp, except privileged users identified by membership in group wheel, admin, access-host and the like
    - for VirtualSSH, for people allowed to use it but not allowed to login (e.g., mw-login), except privileged users
    - privileged users fall through to the end and can login as normal
    
    
    Assume that everything below a specific header is ours and delete/rewrite it.
    """
    hubname = hubzero.config.webconfig.getDefaultSite()
    confFileName = '/etc/ssh/sshd_config'
    test_confFileName = '/etc/ssh/sshd_config_hztest'
    start_pattern = '# hubzero-mw2-front-virtualssh -- DO NOT REMOVE THIS LINE\n'
    end_pattern = '# hubzero-mw2-front-virtualssh -- DO NOT REMOVE THIS LINE\n'
    if enable:
        print "enabling VirtualSSH"
        
        # find if wheel or similar group exists, if not create access-host
        # this list should match what's in xauth-incoming
        privileged_groups = []
        for group in ('root', 'wheel', 'staff', 'sudo', 'access-host'):
            if groupExists(group):
                privileged_groups.append(group)
        print "members of the following groups will be able to login directly on the server:"
        print ", ".join(privileged_groups)
        
        # mw-login to run the workspace tool and access VSSH
        if not groupExists("mw-login"):
            print "adding 'mw-login' group"
            rc, stdOut, stdErr = hubzero.utilities.misc.exShellCommand(["groupadd", "mw-login"])
            
        # rewrite SSHD configuration
        if os.path.exists(confFileName):
            with open(confFileName, "r") as clientConf:
                lines = clientConf.readlines()
            found_vssh_section_start = False
            found_vssh_section_end = False
            with open(test_confFileName, "w") as clientConf:
                for line in lines:
                    if found_vssh_section_start:
                        if found_vssh_section_end: 
                            # pass through what's written after our section
                            clientConf.write(line)
                        else:
                            if line.find(end_pattern) == 0:
                                found_vssh_section_end = True
                                clientConf.write(line)
                            else:
                                # we effectively delete these lines
                                pass
                    else:
                        if line.find(start_pattern) == 0:
                            found_vssh_section_start = True
                            clientConf.write(line)
                            # write our new configuration
                            clientConf.write(ssh_config_string(webUser(), privileged_groups))
                        else:
                            clientConf.write(line)

                if not found_vssh_section_start:
                    clientConf.write(start_pattern)
                    clientConf.write(ssh_config_string(webUser(), privileged_groups))
                if not found_vssh_section_end:
                    clientConf.write(end_pattern)
        

        modifyHubConfigFile("package-config", 'mw-virtualssh', 'true')     
    else:
        print "disabling VirtualSSH"
        if os.path.exists(confFileName):
            with open(confFileName, "r") as clientConf:
                lines = clientConf.readlines()
            found_vssh_section_start = False
            found_vssh_section_end = False
            with open(test_confFileName, "w") as clientConf:
                for line in lines:
                    if found_vssh_section_start:
                        if found_vssh_section_end: 
                            # pass through what's written after our section
                            clientConf.write(line)
                        else:
                            if line.find(end_pattern) == 0:
                                found_vssh_section_end = True
                                clientConf.write(line)
                            else:
                                # we effectively delete these lines
                                pass
                    else:
                        if line.find(start_pattern) == 0:
                            found_vssh_section_start = True
                            clientConf.write(line)
                        else:
                            clientConf.write(line)
        modifyHubConfigFile("package-config", 'mw-virtualssh', 'false')    
         
    # test new configuration
    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(['sshd', '-t', '-f', test_confFileName])
    if rc:
        print "The new SSHD configuration at %s is invalid" % test_confFileName
        print "It has not been made active.  Try to fix it or report a bug:"
        print "output: %s" % procStdOut
        print "errors: %s" % procStdErr
        return
    # make it active
    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(['/bin/mv', test_confFileName, confFileName])
    if rc:
        print "Moving the new SSHD configuration in place failed" 
        print "It has not been made active.  Try to fix it or report a bug:"
        print "output: %s" % procStdOut
        print "errors: %s" % procStdErr
        return
    
    
    serviceInit('sshd','restart')


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"

    if distname == 'redhat' or distname == 'centos' or distname == 'CentOS':
        print "hzcms doesn't know how to configure openvz on RedHat"
        return

    if distname != 'debian':
        print "hzcms doesn't know how to configure openvz on this unknown Linux distribution"
        return

    if distversion.startswith('5.') or distversion.startswith('6.'):
        kernelstring = 'openvz'
        init = ''
    elif distversion.startswith('7.'):
        kernelstring = 'stab'
        init = ''
    elif distversion.startswith('8.') or distversion.startswith('9.'):
        kernelstring = 'stab'
        init = '/lib/sysvinit/init'
    else:
        print "hzcms doesn't know to configure openvz on this version of Debian GNU/Linux: " + distversion
        return

    # Regenerate /boot/grub/grub.cfg
    # e.g., package sysvinit added since this was last run

    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/update-grub"]) 
    if rc: print procStdErr

    with open('/boot/grub/grub.cfg','r') as grubfh:
        grubtxt = grubfh.read()

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

    for menuentry in menuentries:
        if menuentry.find(kernelstring) != -1 and menuentry.find(' single') == -1 and menuentry.find(init) != -1:
            break
        entry = entry + 1
    
    if entry >= len(menuentries):
        print "hzcms didn't find an appropriate openvz kernel in the grub menu list."
        return

    print "checking /etc/default/grub"

    if (entry > 1) and distversion.startswith('8.') or distversion.startswith('9.'):
        entry = '"1>' + str(entry-1) + '"'
    else:
        entry = '"' + str(entry) + '"'

    if lineinfile(path = "/etc/default/grub", regexp="^\s*GRUB_DEFAULT\s*=\s*.*$", line="GRUB_DEFAULT=" + entry):
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/update-grub"]) 
        if rc: print procStdErr

    if os.path.exists('/etc/modules'):
        print "checking /etc/modules"
        lineinfile(path = '/etc/modules', regexp = '^\s*#?loop($|\s+.*$)', line = '#loop')

    print "checking /etc/sysctl.conf"
    lineinfile(path = '/etc/sysctl.conf', regexp = "^\s*#?net.ipv4.ip_forward\s*=\s*.*$", line = 'net.ipv4.ip_forward = 1')

    print "setting net.ipv4.ip_forward=1"
    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand( ["/sbin/sysctl", "-w", "net.ipv4.ip_forward=1" ] )
    if rc: print procStdErr

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

    if os.path.exists(hubzeroConfigFilePath):
        modifyHubConfigFile("package-config", 'openvz', 'true')

def openvzDisable():

    print "disabling openvz"

    if distname == 'redhat' or distname == 'centos' or distname == 'CentOS':
        print "hzcms doesn't know how to unconfigure openvz on RedHat"
        return

    if distname != 'debian':
        print "hzcms doesn't know how to unconfigure openvz on this unknown Linux distribution"
        return

    if distversion.startswith('5.') or distversion.startswith('6.'):
        kernelstring = 'openvz'
        init = ''
    elif distversion.startswith('7.'):
        kernelstring = 'stab'
        init = ''
    elif distversion.startswith('8.') or distversion.startswith('9.'):
        kernelstring = 'stab'
        init = '/lib/sysvinit/init'
    else:
        print "hzcms doesn't know to unconfigure openvz on this version of Debian GNU/Linux: " + distversion
        return

    # Regenerate /boot/grub/grub.cfg
    # e.g., package sysvinit added since this was last run

    rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/update-grub"]) 
    if rc: print procStdErr

    with open('/boot/grub/grub.cfg','r') as grubfh:
        grubtxt = grubfh.read()

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

    for menuentry in menuentries:
        if menuentry.find(kernelstring) == -1 and menuentry.find(' single') == -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"

    if (entry > 1) and distversion.startswith('8.') or distversion.startswith('9.'):
        entry = '"1>' + str(entry-1) + '"'
    else:
        entry = '"' + str(entry) + '"'

    if lineinfile(path = "/etc/default/grub", regexp="^\s*GRUB_DEFAULT\s*=\s*.*$", line="GRUB_DEFAULT=" + entry):
        rc, procStdOut, procStdErr = hubzero.utilities.misc.exShellCommand(["/usr/sbin/update-grub"]) 
        if rc: print procStdErr

    if distname == 'debian' 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"

    (sysname, nodename, release, osversion, machine) = os.uname()

    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."

    if os.path.exists(hubzeroConfigFilePath):
        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):
    cronConfigure(args.enable)

def cronConfigure(enable):
    if (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)

    m4ConfigOptions = []
    m4ConfigOptions.append("-DAPACHE_USER=" + webUser())
    m4ConfigOptions.append("-DHUBNAME=" + hubname)

    m4Processing(etcfilename, cronfilename, m4ConfigOptions, 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)


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

        if rc : print procStdErr
    except:
        raise 

    m4ConfigOptions = []

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

    m4ConfigOptions.append("-DHUBNAME=" + hubname)
    m4ConfigOptions.append("-DHUBZERO_CMS_LOG_USER=" + webUser())
    m4ConfigOptions.append("-DHUBZERO_CMS_LOG_GROUP=" + webGroup())

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

    serviceInit('cron','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" in HUBZERO_CMS_DIR:
        schemaUpdateFilename = HUBZERO_CMS_DIR + "/cms/core/bootstrap/install/sql/mysql/updates.sql"
    elif "hubzero-cms-2.2" 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

    # Through 2.1.7 the CMS template copy routine did not rename the
    # template language file. Detect and fix the common case of
    # tpl_kimera.ini not being renamed.

    file_list = os.listdir( document_root + "/app/templates" )

    for template_dir in file_list:

        language_file_from = document_root + "/app/templates/" + template_dir + "/language/en-GB/en-GB.tpl_kimera.ini"
        language_file_to   = document_root + "/app/templates/" + template_dir + "/language/en-GB/en-GB.tpl_" + template_dir + ".ini"

        if os.path.exists(language_file_from) and not os.path.exists(language_file_to):
            os.rename(language_file_from, language_file_to)
            print "rename " + language_file_from + " to " + language_file_to

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

        if "leap-seconds.list" 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:
        serviceInit('mysqld','restart')
        blockTillMySQLRunning()

    return True

def _fixcron(args):
    fixCron()

def fixCron():

    # /etc/hubzero-cms/HUBNAME/cron-cmscron.m4 needs to be made distribution
    # independent. It used to hardcode the www-data user as the user to run
    # hzcms-tick. We need to modify the m4 file to make this user customizable
    # (eg, www-data for Debian, apache for RedHat)
    #
    # To fix this we:
    #   1) Add an APACHE_USER m4 variable default
    #   2) Use APACHE_USER m4 variable when specifying user to run hzcms-tick
    #   3) Regenerate /etc/cron.d/HUBNAME-cmscron if it exists

    hubname = hubzero.config.webconfig.getDefaultSite()

    cronfile = "/etc/hubzero-cms/" + hubname + "/cron-cmscron.m4"

    print "checking " + cronfile

    result = lineinfile(cronfile,
        "ifdef(`APACHE_USER',`',`define(`APACHE_USER',`www-data')')dnl", 
        insertafter=r'^\s*ifdef\(`HUBZERO_CMS_LOG_DIR\'.*$',
        regexp=r'^ifdef\(`APACHE_USER\',`\',`define\(`APACHE_USER\',`www-data\'\)\'\)dnl.*$')
    
    if result:
        print "patched " + cronfile

    result = replace(cronfile, r'www-data umask', replace = 'APACHE_USER umask')

    if result:
        print "patched " + cronfile

    if os.path.exists("/etc/cron.d/" + hubname + "-cmscron"):
        cronConfigure(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)

#
# Early versions of hubzero-vncproxyd-ws used /etc/default/hzvncproxyd-ws
# for storing init.d configuration even when running on RHEL type 
# systems. While this worked, the expected location on these systems
# would be /etc/sysconfig/hzvncproxyd-ws. This function fixes this.
# 

def fix_hubzero_vncproxyd_ws_sysconfig():
    print "checking for init.d configuration in /etc/sysconfig (hzvncproxyd-ws)"

    if os.path.exists('/etc/sysconfig'):
        if os.path.exists('/etc/default/hzvncproxyd-ws'):
            if os.path.exists('/etc/sysconfig/hzvncproxyd-ws'):
                print "mv /etc/default/hzvncproxyd-ws /etc/sysconfig/hzvncproxyd-ws.old"
                shutil.move('/etc/default/hzvncproxyd-ws','/etc/sysconfig/hzvncproxyd-ws.old')
            else:
                print "mv /etc/default/hzvncproxyd-ws /etc/sysconfig/hzvncproxyd-ws"
                shutil.move('/etc/default/hzvncproxyd-ws','/etc/sysconfig/hzvncproxyd-ws')

# Early versions of hubzero-vncproxyd-ws did not use chkconfig
# on RHEL type systems to configure what runlevels the
# hzvncproxyd-ws service would run in. This function fixes this.

def fix_hubzero_vncproxyd_ws_runlevels():
    print "configuring init.d service levels (hzvncproxyd-ws)"

    if os.path.exists('/etc/init.d/hzvncproxyd-ws'):
        if os.path.exists('/sbin/chkconfig'):
            try:
                rc = subprocess.call(["/sbin/chkconfig", "hzvncproxyd-ws"])

                if rc == 1:
                    rc = subprocess.call(["/sbin/chkconfig", "--add", "hzvncproxyd-ws"])

            except Exception as e:
                print "unable to initialize hzvncproxyd-ws init.d service levels"
                print e
                if debug:
                    raise
                return 2

# hzldap 2.1.4 didn't explicitly set file mode for /etc/sssd/sssd.conf
# so it could have incorrect permissions depending on system configuration
# (default umask). This function fixes this.

def fix_sssd_conf():
    if os.path.exists('/etc/sssd/sssd.conf'):
        createFile('/etc/sssd/sssd.conf', mode=0600, resetattrs=True)

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()

    # Ensure proper permissions on home directory root
    createDir("/home/" + hubname, "0755", "root", "root", resetattrs=True)

    # 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 permissions on hubzeroConfigFilePath
    createFile(hubzeroConfigFilePath, "0644", 0, 0, resetattrs=True)

    # Apache 2.4 expects site files to end in .conf
    if not apache_2_2:
        if os.path.lexists(apacheConfigDir() + '/sites-available/' + hubname):
            if not os.path.lexists(apacheConfigDir() + '/sites-available/' + hubname + ".conf"):
                os.rename(apacheConfigDir() + '/sites-available/' + hubname, apacheConfigDir() + '/sites-available/' + hubname + ".conf")
            else:
                os.remove(apacheConfigDir() + '/sites-available/' + hubname)

        if os.path.lexists(apacheConfigDir() + '/sites-available/' + hubname + '-ssl'):
            if not os.path.lexists(apacheConfigDir() + '/sites-available/' + hubname + "-ssl.conf"):
                os.rename(apacheConfigDir() + '/sites-available/' + hubname + '-ssl', apacheConfigDir() + '/sites-available/' + hubname + "-ssl.conf")
            else:
                os.remove(apacheConfigDir() + '/sites-available/' + hubname + '-ssl')

        if os.path.lexists(apacheConfigDir() + '/sites-enabled/' + hubname):
            if not os.path.lexists(apacheConfigDir() + '/sites-enabled/' + hubname + ".conf"):
                os.rename(apacheConfigDir() + '/sites-enabled/' + hubname, apacheConfigDir() + '/sites-enabled/' + hubname + ".conf")
            else:
                os.remove(apacheConfigDir() + '/sites-enabled/' + hubname)

        if os.path.lexists(apacheConfigDir() + '/sites-enabled/' + hubname + '-ssl'):
            if not os.path.lexists(apacheConfigDir() + '/sites-enabled/' + hubname + "-ssl.conf"):
                os.rename(apacheConfigDir() + '/sites-enabled/' + hubname + '-ssl', apacheConfigDir() + '/sites-enabled/' + hubname + "-ssl.conf")
            else:
                os.remove(apacheConfigDir() + '/sites-enabled/' + hubname + '-ssl')

        # Recreate bad links
        if os.path.islink(apacheConfigDir() + '/sites-enabled/' + hubname + ".conf") and not os.path.isfile(apacheConfigDir() + '/sites-enabled/' + hubname + ".conf"):
            os.remove(apacheConfigDir() + '/sites-enabled/' + hubname + ".conf")
            os.symlink("../sites-available/" + hubname + ".conf", apacheConfigDir() + '/sites-enabled/' + hubname + ".conf")

        if os.path.islink(apacheConfigDir() + '/sites-enabled/' + hubname + "-ssl.conf") and not os.path.isfile(apacheConfigDir() + '/sites-enabled/' + hubname + "-ssl.conf"):
            os.remove(apacheConfigDir() + '/sites-enabled/' + hubname + "-ssl.conf")
            os.symlink("../sites-available/" + hubname + "-ssl.conf", apacheConfigDir() + '/sites-enabled/' + hubname + "-ssl.conf")

    # 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\1'
        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'

        # Remove nokeepalive limit as not compatible as implemented with Apache 2.4 and 
        # its unclear if it is needed for anything beyond IE7
        pattern8 = r'(?im)^\s*<Limit\s+POST>\s*SetEnv\s+nokeepalive\s*<\/Limit>\s*$'
        repl8 = ''

        # Remove comment related to above (seperated as it may not exist in all cases)
        pattern9 = r'(?im)^\s*#\s*http:\/\/qfox.nl\/notes\/1\s*$'
        repl9 = ''

        # Apache 2.4 does away with AuthzLDAPAuthoritative
        pattern10 = False

        if not apache_2_2:
            pattern10 = r'(?im)^\s*AuthzLDAPAuthoritative\s+Off\s*$'
            repl10 = '		#AuthzLDAPAuthoritative Off'
       
        # Apache 2.4 uses IncludeOptional instead of Include for including wildcard matches
        pattern11 = False
        if not apache_2_2:
            pattern11 = r'(?im)^\s*Include\s+'
            repl11 = 'IncludeOptional '

        # Apache 2.4 uses Mutex instead of RewriteLock and isn't needed for default usage
        pattern12 = False
        pattern13 = False
        pattern14 = False
        pattern15 = False

        # Default Mutex configuration can be used by rewrite-map in Apache 2.4
        # Should it ever come up note that /var/lock might map to /run
        # and be deleted on reboot and lose the RewriteLock directory we
        # used to create for this (eg, Debian 8+)

        if not apache_2_2:
            pattern12 = r'(?im)^\s*RewriteLock /var/lock/apache2/RewriteLock'
            repl12 = ''
            pattern13 = r'(?im)^\s*RewriteLock /var/lock/httpd/RewriteLock'
            repl13 = ''
            pattern14 = r'(?im)^\s*RewriteLock /var/lock/APACHE_SERVER/RewriteLock'
            repl14 = ''
            pattern15 = r'(?im)^\s*Mutex\s+file:/var/lock/[^/]+/RewriteLock\s+rewrite-map'
            repl15 = ''

        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)
            txt = re.sub(pattern8, repl8, txt)
            txt = re.sub(pattern9, repl9, txt)
            if pattern10:
            	txt = re.sub(pattern10, repl10, txt)
            if pattern11:
            	txt = re.sub(pattern11, repl11, txt)
            if pattern12:
            	txt = re.sub(pattern12, repl12, txt)
            if pattern13:
            	txt = re.sub(pattern13, repl13, txt)
            if pattern14:
            	txt = re.sub(pattern14, repl14, txt)
            if pattern15:
            	txt = re.sub(pattern14, repl15, 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")
            txt = re.sub(pattern7, repl7, txt)
            txt = re.sub(pattern8, repl8, txt)
            txt = re.sub(pattern9, repl9, txt)
            if pattern10:
            	txt = re.sub(pattern10, repl10, txt)
            if pattern11:
            	txt = re.sub(pattern11, repl11, txt)
            if pattern12:
            	txt = re.sub(pattern12, repl12, txt)
            if pattern13:
            	txt = re.sub(pattern13, repl13, txt)
            if pattern14:
            	txt = re.sub(pattern14, repl14, txt)
            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'
        pattern3 = r'(?im)^(\s*su\s+)(apache\s+apache)(\s*.*$)'
        repl3 = 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)
            txt = re.sub(pattern3, repl3, 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'
        pattern2 = r'(?im)^(\s*su\s+)(apache\s+apache)(\s*.*$)'
        repl2 = r'\1root adm\3'

        try:
            tfilename = "/etc/logrotate.d/" + hubname + "-error"
            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:
            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[2]-client.conf"
    if os.path.exists("/etc/mw-client/mw-client.conf") or os.path.exists("/etc/mw-client/mw2-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)

        if os.path.exists("/etc/mw-client/mw-client.conf"):
            mwfilename = "/etc/mw-client/mw-client.conf"
        else:
            mwfilename = "/etc/mw-client/mw2-client.conf"

        try:
            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

        try:
            # ignore error if mwfh is not defined because the open failed
            mwfh.close()
        except NameError:
            pass

    # 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"):
        if hubzero.config.webconfig.getHubSiteConfig(hubname, "apache-config", "enable_forge").lower() == 'true':
            createDir("/apps", "2775", "apps", "apps", resetattrs=True)
        else:
            createDir("/apps", "2775", -1, -1, resetattrs=True)


    # Make sure some kind of certs for Apache are installed
    fixApacheCerts()

    # Make sure apache config files are current with m4 template
    generateApacheM4config(hubname)

    # Make sure hzcms-tick cron job is properly configured
    fixCron()
    
    # 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()

    # hubzero-vncproxyd-ws fixes
    fix_hubzero_vncproxyd_ws_sysconfig()
    fix_hubzero_vncproxyd_ws_runlevels()

    # hubzero-openldap fixes
    fix_sssd_conf()

    # Make sure all changes made during update are reflected in running system
    serviceInit('apache2','restart')
    serviceInit('php','restart')

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(args):

    replace(args.path, args.regexp, args.replace)

def replace(path, regexp, replace = None):

    if replace == None or replace == False:
        replace = ''

    if os.path.exists(path):
        with open(path, '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()
                return 1

            return 0

def _lineinfile(args):

    lineinfile(args.path, args.line, insertbefore=args.insertbefore, insertafter=args.insertafter, create=args.create, state=args.state)

def lineinfile(path, line, regexp = None, insertbefore = None, insertafter = None, create = False, ifexists = False, state = True):
    """search a file for a line, and ensure that it is present or absent.

    Keyword arguments:
    path            -- the file to modify
    line            -- the line to insert/replace into the file
    regexp          -- the regular expression to look for in the file
    insertbefore    -- the line will be inserted before the last match of specified regular expression
    insertafter     -- the line will be inserted after the last match of specified regular expression
    create          -- if true the file will be created if it does not already exist
    state           -- whether the line should be there (true) or not (false)
    ifexists        -- whether to run only if file exists

    Returns:
    0 - No change required
    1 - Changes made    
    """

    if insertbefore != None and insertafter != None:
        raise ValueError('invalid argument combination: insertbefore and insertafter')

    if (insertbefore != None or insertafter != None) and not state:
        raise ValueError('invalid argument combination: insertbefore or insertafter with state == false')

    if (not os.path.exists(path)) and create:
        with open(path, 'w+') as f:
            if line != None and state:
                f.write(line)
        return 1

    if (not os.path.exists(path)) and ifexists:
        return 0

    with open(path, 'r+') as f:
        ftxt = f.read()
        txt = ftxt.split("\n")
        regexp_match = -1
        insertafter_match = -1
        insertbefore_match = -1
        line_match = -1

        for i in range(0,len(txt)):
            if regexp == None and txt[i] == line and state:
                return 0

            if txt[i] == line:
                line_match = i
            if (regexp != None and re.match(regexp, txt[i])):
                regexp_match = i
            if (insertafter != None and insertafter  != 'EOF' and re.match(insertafter,  txt[i])):
                insertafter_match = i
            if (insertbefore != None and insertbefore != 'BOF' and re.match(insertbefore, txt[i])):
                insertbefore_match= i

        if state:
            if (regexp_match != -1 and insertafter == None and insertbefore == None):
                txt[regexp_match] = line
            elif (regexp_match != -1):
                return 0
            elif (insertbefore == 'BOF'):
                txt.insert(0, line)
            elif (insertafter == 'EOF'):
                txt.append(line)
            elif (insertafter_match != -1):
                txt.insert(insertafter_match + 1, line) 
            elif (insertbefore_match != -1):
                txt.insert(insertbefore_match + 1, line) 
            elif (insertafter != None):
                txt.append(line)
            elif (insertbefore != None):
                txt.append(line)
            else:
                txt.append(line)        
        else:
            if regexp_match != -1:
                txt.pop(regexp_match)
            elif line_match != -1:
                txt.pop(line_match)

        txt = '\n'.join(txt)

        if txt != ftxt:
            f.seek(0)
            f.write(txt)
            f.truncate()
            return 1

        return 0

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('/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*CONDOR_HOST\s*=.*$', replace = "CONDOR_HOST = " + hostname)
    replace('/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*UID_DOMAIN\s*=.*$', replace = "UID_DOMAIN = " + hostname)
    replace('/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*FILESYSTEM_DOMAIN\s*=.*$', replace = "FILESYSTEM_DOMAIN = " + hostname)
    replace('/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*#\s*ALLOW_READ\s*=.*$', replace = "#ALLOW_READ = " + hostname)
    replace('/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*ALLOW_READ\s*=.*$', replace = "ALLOW_READ = " + hostname)
    replace('/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*#\s*ALLOW_WRITE\s*=.*$', replace = "#ALLOW_WRITE = " + hostname)
    replace('/var/condor/Grid/etc/condor_config.local', regexp = r'^\s*ALLOW_WRITE\s*=.*$', replace = "ALLOW_WRITE = " + hostname)
    replace('/var/gridman/.ssh/authorized_keys', regexp = r'submit@[^ ]*\s*$', replace = 'submit@' + hostname)
    replace('/var/www/.ssh/authorized_keys', regexp = r'root@[^ ]*\s*$', replace = 'root@' + hostname)
    replace('/etc/mw-client/maxwell.key.pub', regexp = r'apache@[^ ]*\s*$', replace = 'apache@' + hostname)
    replace('/etc/mw-client/maxwell.key.pub', regexp = r'www-data@[^ ]*\s*$', replace = 'www-data@' + hostname)
    replace('/etc/mw-client/notify.key.pub', regexp = r'root@[^ ]*\s*$', replace = 'root@' + hostname)
    replace('/opt/submit/.ssh/submit_rsa.pub', regexp = r'submit@[^ ]*\s*$', replace = 'submit@' + hostname)
    replace('/root/.ssh/authorized_keys', regexp = r'apache@[^ ]*\s*$', replace = 'apache@' + hostname)
    replace('/root/.ssh/authorized_keys', regexp = r'www-data@[^ ]*\s*$', replace = 'www-data@' + hostname)
    replace('/etc/submit/daemons.conf', regexp = r'^\s*hostname\s*=\s*[^ ]*$', replace = 'hostname = ' + hostname)
    replace('/vz/template/debian-7.0-amd64-maxwell/etc/ssh/ssh_host_ecdsa_key.pub', regexp = r'root@[^ ]*\s*$', replace = 'root@' + hostname)
    replace('vz/template/debian-7.0-amd64-maxwell/etc/ssh/ssh_host_dsa_key.pub', regexp = r'root@[^ ]*\s*$', replace = 'root@' + hostname)
    replace('/vz/template/debian-7.0-amd64-maxwell/etc/ssh/ssh_host_rsa_key.pub', regexp = r'root@[^ ]*\s*$', replace = 'root@' + hostname)
    replace('/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

    hubzero.config.hubzerositeconfig.setHubzeroConfigOption(hubname, "uri", "https://" + hostname)

    lineinfile(path = '/etc/mw-service/mw-service.conf', ifexists = True, regexp = r'^\s*submit_server\s*=.*$', line = "submit_server = \"" + hostname + "\"")
    lineinfile(path = '/etc/mw-client/mw-client.conf', ifexists = True, regexp = r'^\s*hub_url\s*=.*$', line = 'hub_url = "http://' + hostname + '"')
    lineinfile(path = '/etc/mw-client/mw2-client.conf', ifexists = True, regexp = r'^\s*hub_url\s*=.*$', line = 'hub_url = "http://' + hostname + '"')
    lineinfile(path = '/etc/submit/submit-server.conf', ifexists = True, regexp = r'^\s*emailFrom\s*=\s*noreply@.*$', line = 'emailFrom=noreply@' + hostname)
    lineinfile(path = apacheConfigDir() + '/conf.d/hub.conf', ifexists = True, regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(path = apacheConfigDir() + '/conf.d/hub-ssl.conf', ifexists = True, regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(path = apacheConfigDir() + '/conf.d/" + hubname + ".conf', ifexists = True, regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(path = apacheConfigDir() + '/conf.d/" + hubname + "-ssl.conf', ifexists = True, regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(path = apacheConfigDir() + '/sites-available/hub.conf', ifexists = True, regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(path = apacheConfigDir() + '/sites-available/hub.conf', ifexists = True, regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(path = apacheConfigDir() + '/sites-available/" + hubname + ".conf', ifexists = True, regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(path = apacheConfigDir() + '/sites-available/" + hubname + "-ssl.conf', ifexists = True, regexp = r'^\s*ServerName\s+.*$', line = "ServerName " + hostname)
    lineinfile(path = document_root + "/hubconfiguration.php", ifexists = True, regexp = r'^\s*(var|public)\s+\$forgeURL\s*=\s*.*$', line = " var $forgeURL = 'https://" + hostname + "';")
    lineinfile(path = document_root + "/hubconfiguration.php", ifexists = True, regexp = r'^\s*(var|public)\s+\$forgeRepoURL\s*=\s*.*$', line = " var $forgeRepoURL = 'https://" + hostname + "';")
    lineinfile(path = document_root + "/configuration.php", ifexists = True, regexp = r'^\s*(var|public)\s+\$mailfrom\s*=\s*\'webmaster@.*$', line = "\tvar $mailfrom = 'webmaster@" + hostname + "';")
    lineinfile(path = document_root + "/app/config/app.php", ifexists = True, regexp = r'^\s*\'live_site\'.*$', line = "        'live_site' => 'https://" + hostname + "',")
    lineinfile(path = document_root + "/app/config/mail.php", ifexists = True, regexp = r'^\s*\'mailfrom\'\s*=>\s*\'webmaster@.*$', line = "\t'mailfrom' => 'webmaster@" + hostname + "',")
    lineinfile(path = "/etc/hubmail_gw.conf", ifexists = True, regexp = r'^\s*(var|public)\s+\$mailfrom\s*=\s*\'webmaster@.*$', line = " public $mailfrom = 'webmaster@" + hostname + "';")
    lineinfile(path = "/etc/hubmail_gw.conf", ifexists = True, 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)

def _hosttype(args):

    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 args.action == 'delete':

        if args.name == None:
            print "Invalid hosttype name [] passwed with delete action"
            return 1

        if args.description <> None:
            print "Invalid parameter [%s] passed with delete action" % args.description
            return 2

        if args.value <> None:
            print "Invalid parameter [%s] passed with delete action" % args.value
            return 3

        sql = "DELETE FROM  `hosttype` WHERE name='" + args.name + "'"

        count = db.query_rowcount(sql, None)

        print "[%s] rows changed" % count

    elif args.action == 'add':

        if args.name == None:
            print "Invalid hosttype name [] passwed with add action"
            return 4

        if args.description == None:
            args.description = ''
        
        if args.value == None:
            print "Invalid value parameter [] passed with add action" 
            return 5

        sql = "SELECT * FROM  `hosttype` WHERE name='" + args.name + "'"

        count = db.query_rowcount(sql, None)    

        if count > 0:
            print "A hosttype with name [%s] already exists" % args.name
            return 6

        print "[%s] rows exist" % count

        sql = "INSERT IGNORE INTO `hosttype` (`name`,`value`,`description`) VALUE ('" + args.name + "','" + args.value + "','" + args.description + "')"
        
        count = db.query_rowcount(sql, None)    

        print "[%s] rows changed" % count


    return 0

#
# host delete name
# host add name up workspace fileserver pubnet
# 

def _host(args):

    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 args.action == 'delete':

        if args.hostname == None:
            print "Invalid hostname name [] passed with delete action"
            return 1

        if args.provisions <> None and len(args.provisions) > 0:
            print "Invalid provisions parameter [%s] passed with delete action" % args.provisions
            return 2

        if args.status <> None:
            print "Invalid parameter [%s] passed with delete action" % args.status
            return 3

        sql = "DELETE FROM  `host` WHERE hostname='" + args.hostname + "'"

        count = db.query_rowcount(sql, None)

        print "[%s] rows changed" % count

        return 0

    elif args.action == 'add':

        if args.hostname == None:
            print "No hostname passed with add action"
            return 4

        if args.status == None:
            print "No status passed with add action"
            return 5

        if args.provisions == None:
            print "No provisions passed with add action"
            return 6

        if len(args.provisions) == 0:
            print "Invalid provisions [] passed with add action"
            return 7

        sql = "SELECT name,value FROM `hosttype`;"

        hosttypes = db.query(sql, [])

        provisions = 0

        for myprovision in args.provisions:
            for hosttype in hosttypes:
                if hosttype.name == myprovision:
                    provisions = provisions | hosttype.value


        sql = "SELECT hostname,provisions,status FROM `host` where `hostname` = '" + args.hostname + "' AND provisions = '" + str(provisions) + "' AND status = '" + args.status + "'"
       
        count = db.query_rowcount(sql, None)

        if count == 1:
            print "%s already configured as requested" % args.hostname
            return 0

        sql = "INSERT IGNORE INTO `host` (`hostname`,`provisions`,`status`,`max_uses`) VALUE ('" + args.hostname + "','" + str(provisions) + "','" + args.status + "','100')"

        try:
            count = db.query_rowcount(sql, None)    
        except:
            count = 0
            pass

        print "[%s] rows changed" % count

        if count <> 1:
            print "Unable to add [%s] to host table (perhaps already exists in different configuration)" % hostname
            return 8

        return 0



# ####################################################################################
# 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/mw2-client
parser_configure_mw2client = parser_configure_subparsers.add_parser('mw2-client', help='configure hub mw2-client')
group = parser_configure_mw2client.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on mw2-client functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off mw2-client functionality for hub', action="store_false", default=False)
parser_configure_mw2client.set_defaults(func=_mwClientConfigure_v2)

# configure/mw2-service
parser_configure_mw2service = parser_configure_subparsers.add_parser('mw2-service', help='configure hub mw2-service')
group = parser_configure_mw2service.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on mw2-service functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off mw2-service functionality for hub', action="store_false", default=False)
parser_configure_mw2service.set_defaults(func=_mwServiceConfigure_v2)

# configure/mw1-client
parser_configure_mw1client = parser_configure_subparsers.add_parser('mw1-client', help='configure hub mw1-client')
group = parser_configure_mw1client.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on mw1-client functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off mw1-client functionality for hub', action="store_false", default=False)
parser_configure_mw1client.set_defaults(func=_mwClientConfigure_v1)

# configure/mw1-service
parser_configure_mw1service = parser_configure_subparsers.add_parser('mw1-service', help='configure hub mw1-service')
group = parser_configure_mw1service.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on mw1-service functionality for hub', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off mw1-service functionality for hub', action="store_false", default=False)
parser_configure_mw2service.set_defaults(func=_mwServiceConfigure_v1)

# 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/mw2-front-virtualssh
parser_configure_mw2frontvirtualssh = parser_configure_subparsers.add_parser('mw2-front-virtualssh', help='configure virtualssh settings on the web server')
group = parser_configure_mw2frontvirtualssh.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on virtualssh functionality on the web server', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off virtualssh functionality on the web server', action="store_false", default=False)
parser_configure_mw2frontvirtualssh.set_defaults(func=_mwFrontvirtualsshConfigure)

# configure/mw2-exec-virtualssh
parser_configure_mw2execvirtualssh = parser_configure_subparsers.add_parser('mw2-exec-virtualssh', help='configure virtualssh settings on execution hosts')
group = parser_configure_mw2execvirtualssh.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on virtualssh functionality on execution hosts', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off virtualssh functionality on execution hosts', action="store_false", default=False)
parser_configure_mw2execvirtualssh.set_defaults(func=_mwExecvirtualsshConfigure)

# configure/mw2-file-service
parser_configure_mw2fileservice = parser_configure_subparsers.add_parser('mw2-file-service', help='configure middleware file server services')
group = parser_configure_mw2fileservice.add_mutually_exclusive_group()
group.add_argument('--enable', dest='enable', help='turn on mw2 file server services', action="store_true", default=True)
group.add_argument('--disable', dest='enable', help='turn off mw2 file server services', action="store_false", default=False)
parser_configure_mw2fileservice.set_defaults(func=_mwFileserviceConfigure)

# 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)

# lineinfile path line --regexp --insertbefore --insertafter --create --state
parser_lineinfile = subparsers.add_parser('lineinfile', help='Ensure a particular line is in a file')
parser_lineinfile.add_argument('path', help='the file to modify')
parser_lineinfile.add_argument('line', help='the line to insert/replace into the file')
parser_lineinfile.add_argument('--regexp', help='the regular expression to look for in the file')
parser_lineinfile.add_argument('--insertbefore', help='the line will be inserted before the last match of specified regular expression')
parser_lineinfile.add_argument('--insertafter', help='the line will be inserted after the last match of specified regular expression')
parser_lineinfile.add_argument('--create', help='the file will be created if it does not already exist', action="store_true", default=False)
parser_lineinfile.add_argument('--absent', dest='state', help='remove line', action="store_false", default=True)
parser_lineinfile.add_argument('--present', dest='state', help='add line', action="store_true", default=True)
parser_lineinfile.set_defaults(func=_lineinfile)

# fixcron
parser_fixcron = subparsers.add_parser('fixcron', help='fix hubzero cron configuration')
parser_fixcron.set_defaults(func=_fixcron)

# mw-hosttype add workspace 1 "Workspace sessions"
# mw-hosttype delete workspace
parser_hosttype = subparsers.add_parser('mw-hosttype', help='manage hosttype middleware table')
parser_hosttype.add_argument('action', choices=['add','delete'], help='action to perform (add or delete)')
parser_hosttype.add_argument('name', help='the hosttype to add')
parser_hosttype.add_argument('value', nargs='?', help='the value to assign to it')
parser_hosttype.add_argument('description', nargs='?', help='description of hosttype')
parser_hosttype.set_defaults(func=_hosttype)

# mw-host add localhost up fileserver
# mw-host add exec1 up sessions pubnet openvz
# mw-host delete exec2
parser_host = subparsers.add_parser('mw-host', help='manage hosttype middleware table')
parser_host.add_argument('action', choices=['add','delete'], help='action to perform (add or delete)')
parser_host.add_argument('hostname', help='the hostname to add')
parser_host.add_argument('status', nargs='?', choices=['up','down'], help='status of host')
parser_host.add_argument('provisions', nargs='*', help='the value to assign to it')
parser_host.set_defaults(func=_host)

args =  parser.parse_args()

args.func(args)
