#!/usr/bin/env python # $Id$ # Creates a new BOINC project. # TODO: use database.py (mainly for setup_project.py) # TODO: don't add app / app version here. # TODO: create 'apps' subdirectory and set it in config.xml # TODO: use configxml module import boinc_path_config from Boinc.setup_project import * from Boinc import database, db_mid, configxml, tools import sys, os, getopt, re, socket def gethostname(): try: return socket.gethostbyaddr(socket.gethostname())[0] 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 = gethostname() 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].capitalize() 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/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 ) 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') 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 None Order allow,deny Allow from all Options FollowSymLinks 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 Tasks to do: 1. Add platform(s) %(proot)s/bin/add platform --name=c64 --user_f="Commodore 64" %(proot)s/bin/add platform --name=i686-pc-linux-gnu --user_f="Linux x86" 2. Add application(s) %(proot)s/bin/add app --name=SpaghettiAtHome 3. Add core client and application binaries 3a. Place compiled clients in %(proot)s/apps/boinc/ and %(proot)s/apps/APP/ 3b. Run %(proot)s/bin/update_versions 4. Generate work : read documentation at http://boinc.berkeley.edu/ '''%locals()