#! /usr/bin/env python

import os, commands, pwd
from optparse import OptionParser
from Boinc.Debian import *

# Popen preexec hook for running the command as a different user
def do_setuid():
    global uid, gid

    os.setgid(gid)
    os.setuid(uid)

parser = OptionParser(usage="usage: %prog [options]")

parser.add_option("-n", "--name", dest="name", action="store", \
                  default=None, help="Short name of the project (used in URLs)")
parser.add_option("-l", "--long-name", dest="long_name", action="store", \
                  default=None, help="Long name of the project (displayed to users)")
parser.add_option("--db-password", dest="dbpass", action="store",
                  default=None, help="Use the specified database password (default: generate random password)")
parser.add_option("--db-host", dest="dbhost", action="store",
                  default=None, help="Database host name (default: localhost)")
parser.add_option("--db-user", dest="dbuser", action="store",
                  default=None, help="Database user name")
parser.add_option("--db-name", dest="dbname", action="store",
                  default=None, help="Database name")

options,args = parser.parse_args()

if not options.name or not options.long_name:
    raise SystemExit("You must specify the short and long name")

open_logfile()

# XXX Implement this in Python, and drop dependency on pwgen
if not options.dbpass:
    options.dbpass = Popen(["pwgen", "-s", "10", "1"], stdout=PIPE).communicate()[0]
    options.dbpass = options.dbpass.rstrip()
if not options.dbuser:
    options.dbuser = "boinc_" + options.name
if not options.dbname:
    options.dbname = "boinc_" + options.name
if not options.dbhost:
    options.dbhost = 'localhost'

username = "boinc-" + options.name
homedir = os.path.join("/var/lib/boinc", options.name)
crontab = os.path.join(homedir, "project", options.name + ".crontab")
projectroot = os.path.join(homedir, "project")

# Check if the user already exists
try:
    pwd.getpwnam(username)
    raise SystemExit("The user " + username + " already exists")
except KeyError:
    pass

notice("Creating new project: " + options.name + " (" + options.long_name + ")")

#######################################################################
# Create the user account

run_command("/usr/sbin/adduser",
            "--system",
            "--quiet",
            "--home", homedir,
            "--gecos", options.long_name,
            "--shell", "/bin/bash",
            "--group",
            username)
run_command("/usr/sbin/adduser", "--quiet", "www-data", username)

# Retrieve the uid/gid we got
pw = pwd.getpwnam(username)
uid = pw[2]
gid = pw[3]

# Set up the login environment
print >> open(os.path.join(homedir, ".profile"), "w"), \
'''# Generated by boinc_create_project
BOINC_PROJECT_DIR="%s"
export BOINC_PROJECT_DIR
TMPDIR="$HOME/tmp"
export TMPDIR
umask 022
''' % projectroot
print >> open(os.path.join(homedir, ".bashrc"), "w"), \
'''# Generated by boinc_create_project
[ -f ~/.profile ] && . ~/.profile
. /etc/bash.bashrc
'''
print >> open(os.path.join(homedir, ".bash_profile"), "w"), \
'''# Generated by boinc_create_project
[ -f ~/.bashrc ] && . ~/.bashrc
'''
print >> open(os.path.join(homedir, ".my.cnf"), "w"), \
'''[mysql]
user     = %(dbuser)s
password = %(dbpass)s
host     = %(dbhost)s
''' % options.__dict__
os.chmod(os.path.join(homedir, ".my.cnf"), 0600)

os.mkdir(homedir + "/tmp", 0770)

map(lambda f: os.chown(os.path.join(homedir, f), uid, gid),
    [".profile", ".bashrc", ".bash_profile", ".my.cnf", "tmp"])

#######################################################################
# Set up the database

# Do the database setup only if the DB server is local
if not options.dbhost or options.dbhost == "localhost":
    options.dbhost = "localhost"
    notice("Setting up database permissions")
    run_command("mysql", "-e",
                "GRANT ALL ON %(dbname)s.* TO '%(dbuser)s' IDENTIFIED BY '%(dbpass)s'" % options.__dict__)
    run_command("mysql", "-e",
                "GRANT ALL ON %(dbname)s.* TO '%(dbuser)s'@'localhost' IDENTIFIED BY '%(dbpass)s'" % options.__dict__)

#######################################################################
# Run make_project

notice("Setting up the project directory")
run_command("make_project", "-v", "--no_query",
            "--user_name", username,
            "--project_root", projectroot,
            "--db_name", options.dbname,
            "--db_user", options.dbuser,
            "--db_passwd", options.dbpass,
            "--db_host", options.dbhost,
            options.name,
            options.long_name,
            preexec_fn = do_setuid)


# Activate the crontab
notice("Activating the crontab")
run_command("crontab", "-u", username, crontab)

# Activate the Apache configuration
notice("Activating the Apache configuration")
os.symlink(os.path.join(homedir, "project", options.name + ".httpd.conf"),
           os.path.join("/etc/apache2/conf.d", "boinc-" + options.name + ".conf"))
# Use "restart" so the new group membership becomes effective
run_command("invoke-rc.d", "--quiet", "apache2", "restart")
