diff --git a/nimsapi.wsgi b/nimsapi.wsgi index 6d4106524a43aee42895514c5925964278273600..ba24f7f644b53718581bdaeb7dcc129250ad6b33 100644 --- a/nimsapi.wsgi +++ b/nimsapi.wsgi @@ -6,45 +6,172 @@ import os import sys import site import ConfigParser +import logging +import logging.config -configfile = '../production.ini' -config = ConfigParser.ConfigParser() -config.read(configfile) +def apply_config(configfile): + """Return a ConfigParser object""" + config = ConfigParser.ConfigParser() + config.read(configfile) + site.addsitedir(os.path.join(config.get('nims', 'virtualenv'), 'lib', 'python2.7', 'site-packages')) + sys.path.append(config.get('nims', 'here')) + os.environ['PYTHON_EGG_CACHE'] = config.get('nims', 'python_egg_cache') + return config -site.addsitedir(os.path.join(config.get('nims', 'virtualenv'), 'lib', 'python2.7', 'site-packages')) -sys.path.append(config.get('nims', 'here')) -os.environ['PYTHON_EGG_CACHE'] = config.get('nims', 'python_egg_cache') -import pymongo -import webapp2 -import nimsapi -import nimsutil -import ConfigParser -import Crypto.PublicKey.RSA +def configure_logger(configfile): + """return a nimsapi configured logger""" + logging.config.fileConfig(configfile, disable_existing_loggers=False) + return logging.getLogger('nimsapi') -import logging -import logging.config -logging.config.fileConfig(configfile) -log = logging.getLogger('nimsapi') +def read_privkey(privkey_file): + """reads SSL private key. returns key content as RSA.key object""" + try: + privkey = Crypto.PublicKey.RSA.importKey(open(privkey_file).read()) + except: + log.warn(privkey_file + ' is not a valid private SSL key file') + privkey = None + else: + log.info('successfully loaded private SSL key from ' + privkey_file) + return privkey + + +def connect_db(db_uri): + """return mongodb default database""" + kwargs = dict(tz_aware=True) + db_client = pymongo.MongoReplicaSetClient(db_uri, **kwargs) if 'replicaSet' in db_uri else pymongo.MongoClient(db_uri, **kwargs) + db = db_client.get_default_database() + db.remotes.ensure_index('UTC', expireAfterSeconds=120) + return db + + +def internimsclient(db, hostname, site_id, privkey, internims_url): + """sends is alive to internims central. no return""" + # TODO: create a list of non-local users, who have permissions on experiments + users = [users['_id'] for users in list(db.users.find({}, {'_id': True}))] + + payload = json.dumps({'iid': site_id, 'hostname': hostname, 'users': users}) + h = Crypto.Hash.SHA.new(payload) + signature = Crypto.Signature.PKCS1_v1_5.new(privkey).sign(h) + headers = {'Authorization': base64.b64encode(signature)} + + r = requests.post(url=internims_url, data=payload, headers=headers, verify=True) + if r.status_code == 200: + sites = json.loads(r.content) + for site in sites: + site['UTC'] = datetime.datetime.strptime(site['timestamp'], '%Y-%m-%dT%H:%M:%S.%f') + db.remotes.find_and_modify(query={'_id': site['_id']}, update=site, upsert=True) + log.debug('upserting remote site ' + site['_id']) + else: + log.info((r.status_code, r.reason)) + + +if __name__ == '__main__': + import argparse + + arg_parser = argparse.ArgumentParser() + arg_parser.add_argument('-c', '--configfile', help='path to configuration file') + arg_parser.add_argument('--internims_url', help='https://internims.appspot.com') + arg_parser.add_argument('--db_uri', help='DB URI') + arg_parser.add_argument('--hostname', help='fqdn, without protocol') + arg_parser.add_argument('--site_id', help='instance ID') + arg_parser.add_argument('--sleeptime', default=60, type=int, help='time to sleep between is alive signals') + arg_parser.add_argument('-k', '--privkey', help='path to privkey file') + args = arg_parser.parse_args() -privkey_file = config.get('nims', 'privkey_file') -db_uri = config.get('nims', 'db_uri') -stage_path = config.get('nims', 'stage_path') + # read config + config = apply_config(args.configfile) -db_client = pymongo.MongoReplicaSetClient(db_uri) if 'replicaSet' in db_uri else pymongo.MongoClient(db_uri) + # import everything else + import json + import time + import base64 + import pymongo + import webapp2 + import nimsapi + import nimsutil + import requests + import datetime + import Crypto.Random + import Crypto.Hash.SHA + import Crypto.PublicKey.RSA + import Crypto.Signature.PKCS1_v1_5 + import signal # not in uwsgi execution + + # configure logger + log = configure_logger(args.configfile) + + # args override configfile + db_uri = args.db_uri or config.get('nims', 'db_uri') + hostname = args.hostname or config.get('nims', 'hostname') + site_id = args.site_id or config.get('nims', 'site_id') + internims_url = args.internims_url or config.get('nims', 'internims_url') + privkey_file = args.privkey or config.get('nims', 'privkey_file') + + # load in the privkey + privkey = read_privkey(privkey_file) + + # connect to db + db = connect_db(db_uri) + + def term_handler(signum, stack): + alive = False + log.debug('Recieved SIGTERM - shuttin down') + + signal.signal(signal.SIGTERM, term_handler) + + alive = True + while alive: + internimsclient(db, hostname, site_id, privkey, internims_url) + time.sleep(args.sleeptime) -try: - privkey = Crypto.PublicKey.RSA.importKey(open(privkey_file).read()) -except: - log.warn(privkey_file + ' is not a valid private SSL key file') # FIXME use logging - privkey = None else: - log.info('successfully loaded private SSL key from ' + privkey_file) # FIXME use logging + # read config + configfile = '../production.ini' + config = apply_config(configfile) + + # import everything else + import json + import time + import base64 + import pymongo + import webapp2 + import nimsapi + import argparse + import datetime + import nimsutil + import requests + import Crypto.Random + import Crypto.Hash.SHA + import Crypto.PublicKey.RSA + import Crypto.Signature.PKCS1_v1_5 + import uwsgidecorators # only in uwsgi execution + + # configure logger + log = configure_logger(configfile) + + db_uri = config.get('nims', 'db_uri') + stage_path = config.get('nims', 'stage_path') + site_id = config.get('nims', 'site_id') + + # load in privkey + privkey = read_privkey(config.get('nims', 'privkey_file')) + + # config uwsgi application + application = nimsapi.app + application.config['stage_path'] = stage_path + application.config['site_id'] = site_id + application.config['privkey'] = privkey + + # connect db + application.db = connect_db(db_uri) + + @uwsgidecorators.postfork + def random_atfork(): + Crypto.Random.atfork() -application = nimsapi.app -application.config['stage_path'] = config.get('nims', 'stage_path') -application.config['site_id'] = config.get('nims', 'site_id') -application.config['privkey'] = privkey -application.db = db_client.get_default_database() + @uwsgidecorators.timer(60) + def internimsclient_timer(signum): + internimsclient(application.db, config.get('nims', 'hostname'), config.get('nims', 'site_id'), privkey, config.get('nims', 'internims_url'))