#!/usr/bin/env python # $Id$ # Creates a new BOINC project. import boinc_path_config from Boinc.setup_project import * from Boinc import database, db_mid, configxml, tools import sys, os, getopt, re, socket def getfqdn(): try: return socket.getfqdn() except: return 'localhost' def isurl(s): return s.startswith('http://') or s.startswith('https://') argv0 = sys.argv[0] HOME = os.path.expanduser('~') USER = os.environ['USER'] NODENAME = getfqdn() HELP = """ syntax: %(argv0)s [options] project ['Project Long Name'] Creates a new project with given name with everything running on a single server. Misc options: --verbose={0,1,2} default: 1 -v alias for --verbose=2 --no_query accept all directories without querying --user_name default: $USER (%(USER)s) --delete_prev_inst delete project-root first (from prev installation) --drop_db_first drop database first (from prev installation) Dir-options: --base default: $HOME (%(HOME)s) --key_dir default: BASE/keys --project_root default: BASE/projects/PROJECT --url_base default: http://$NODENAME/ (http://%(NODENAME)s/) --html_user_url default: URL_BASE/PROJECT/ --html_ops_url default: URL_BASE/PROJECT_ops/ --cgi_url default: URL_BASE/PROJECT_cgi/ Other: --db_name default: PROJECT Example command line: ./make_project --base $HOME/boinc --url_base http://boink/ yah 'YETI @ Home' Then upload_dir = $HOME/boinc/projects/yah/upload and cgi_url = http://boink/yah_cgi/ By default, directory options will be queried if they do not exist yet. """ %locals() # Project-specific directory structure that you probably don't need to change: # --bin_dir default: PROJECT_ROOT/bin # --cgi_bin_dir default: PROJECT_ROOT/cgi-bin # --html_user_dir default: PROJECT_ROOT/html_user # --html_ops_dir default: PROJECT_ROOT/html_ops # --download_dir default: PROJECT_ROOT/download # --upload_dir default: PROJECT_ROOT/upload # --log_dir default: PROJECT_ROOT/log # --pid_dir default: PROJECT_ROOT/pid def syntax_error(str): raise SystemExit('%s; See "%s --help" for help\n' % (str,sys.argv[0])) def usage(): print HELP raise SystemExit try: opts, args = getopt.getopt(sys.argv[1:], 'hv', [ 'help', 'verbose=', 'no_query', 'user_name=', 'drop_db_first', 'delete_prev_inst', 'base=', 'key_dir=', 'project_root=', 'url_base=', 'html_user_url=', 'html_ops_url=', 'cgi_url=', # 'bin_dir=', # 'cgi_bin_dir=', # 'html_user_dir=', # 'html_ops_dir=', # 'download_dir=', # 'upload_dir=', # 'log_dir=', # 'pid_dir=' ]) except getopt.GetoptError, e: syntax_error(e) options.url_base = None options.no_query = False options.delete_prev_inst = False for o,a in opts: if o == '-h' or o == '--help': usage() elif o == '-v': options.echo_verbose = 2 elif o == '--verbose': options.echo_verbose = int(a) elif o == '--no_query': options.no_query = True elif o == '--user_name': options.user_name = a elif o == '--drop_db_first': options.drop_db_first = True elif o == '--delete_prev_inst': options.delete_prev_inst = True elif o == '--base': options.base = a elif o == '--key_dir': options.key_dir = a elif o == '--project_root': options.project_root = a elif o == '--url_base': options.url_base = a elif o == '--html_user_url': options.html_user_url = a elif o == '--html_ops_url': options.html_ops_url = a elif o == '--cgi_url': options.cgi_url = a elif o == '--db_name': options.db_name = a # elif o == '--bin_dir': options.bin_dir = a # elif o == '--cgi_bin_dir': options.cgi_bin_dir = a # elif o == '--html_user_dir': options.html_user_dir = a # elif o == '--html_ops_dir': options.html_ops_dir = a # elif o == '--download_dir': options.download_dir = a # elif o == '--upload_dir': options.upload_dir = a # elif o == '--log_dir': options.log_dir = a # elif o == '--pid_dir': options.pid_dir = a else: raise SystemExit('internal error o=%s'%o) if len(args) == 2: (project_shortname, project_longname) = args elif len(args) == 1: (project_shortname, project_longname) = args[0], args[0] else: syntax_error('Need one or two arguments') opt_repls = {'PROJECT':project_shortname, 'PROJECT_ops':project_shortname+'_ops', 'PROJECT_cgi':project_shortname+'_cgi'} def delete_slash(str): return os.path.join(str,'')[:-1] def add_slash(str, action=True): if action: return os.path.join(str,'') else: return str def replopt(str): for key in opt_repls: str = str.replace(key, delete_slash(opt_repls[key])) return str def defopt(name, v, isdir=True): options.__dict__[name] = opt_repls[name.upper()] = add_slash(replopt(options.__dict__.get(name) or v), isdir) defopt('url_base' , 'http://%s/'%NODENAME) if not isurl(options.url_base): syntax_error('url_base needs to be an URL') defopt('html_user_url' , 'URL_BASE/PROJECT') defopt('html_ops_url' , 'URL_BASE/PROJECT_ops') defopt('cgi_url' , 'URL_BASE/PROJECT_cgi') defopt('user_name' , USER, isdir=False) defopt('base' , HOME) defopt('key_dir' , 'BASE/projects/PROJECT/keys') defopt('project_root' , 'BASE/projects/PROJECT') defopt('db_name' , 'PROJECT', isdir=False) print "Creating project '%s' (short name '%s'):" %(project_longname, project_shortname) for k in ['base', 'key_dir', 'project_root', 'url_base', 'html_user_url', 'html_ops_url', 'cgi_url' ]: print k.upper().rjust(15), "=", options.__dict__[k] project_root_parent = os.path.realpath(os.path.join(options.project_root,'..')) if not os.path.exists(project_root_parent): os.makedirs(project_root_parent) if os.path.exists(options.project_root): if options.delete_prev_inst: if not options.no_query: if not query_noyes('Delete %s?'%options.project_root): raise SystemExit('Aborted') print "Deleting", options.project_root rmtree(options.project_root) else: raise SystemExit('Project root already exists! Specify --delete_prev_inst --drop_db_first to clobber') if not options.no_query: if not query_yesno("Continue?"): raise SystemExit('Aborted') options.install_method = 'copy' init() project = Project(project_shortname, project_longname, project_dir = options.project_root, master_url = options.html_user_url, cgi_url = options.cgi_url, key_dir = options.key_dir, db_name = options.db_name, production = 1 ) project.install_project() project.sched_install('feeder') project.sched_install('transitioner') # project.sched_install('validate_test') # project.sched_install('assimilator') project.sched_install('file_deleter') print '''Done installing default daemons.''' httpd_conf_template_filename = os.path.join(options.project_root, project_shortname+'.httpd.conf') proot = delete_slash(options.project_root) html_user_url = options.html_user_url html_ops_url = options.html_ops_url print >>open(httpd_conf_template_filename,'w'), ''' ## Settings for BOINC project %(project_longname)s Alias /%(project_shortname)s %(proot)s/html/user Alias /%(project_shortname)s_ops %(proot)s/html/ops ScriptAlias /%(project_shortname)s_cgi %(proot)s/cgi-bin # Note: projects/*/keys/ should NOT be readable! Options Indexes FollowSymlinks MultiViews AllowOverride AuthConfig Order allow,deny Allow from all Options ExecCGI Order allow,deny Allow from all ''' %locals() print '''Done installing files. Steps to complete installation: 1. Set permissions for Apache: cat %(httpd_conf_template_filename)s >> /etc/apache/httpd.conf && apachectl restart (path to httpd.conf varies) 2. Add to crontab (as %(USER)s) (If cron cannot run "start", try using a helper script to set PATH and PYTHONPATH) 0,5,10,15,20,25,30,35,40,45,50,55 * * * * %(proot)s/bin/start --cron To start, show status, stop BOINC daemons run: %(proot)s/bin/start %(proot)s/bin/status %(proot)s/bin/stop Master URL: %(html_user_url)s Administration URL: %(html_ops_url)s 3. Add Work Generator, Validator and Assimilator daemons for your applications Further steps are necessary to add applications and work. See the online documentation at http://boinc.berkeley.edu/ '''%locals()