Handling Procfile

pull/1/head
Rui Carmo 2016-03-29 20:24:17 +01:00
rodzic 5057111f83
commit 97402ba148
1 zmienionych plików z 51 dodań i 24 usunięć

75
piku.py
Wyświetl plik

@ -44,32 +44,54 @@ def setup_authorized_keys(ssh_fingerprint, script_path, pubkey):
# Restrict features and force all SSH commands to go through our script # Restrict features and force all SSH commands to go through our script
with open(authorized_keys, 'a') as h: with open(authorized_keys, 'a') as h:
h.write("""command="FINGERPRINT=%(ssh_fingerprint)s NAME=default %(script_path)s $SSH_ORIGINAL_COMMAND",no-agent-forwarding,no-user-rc,no-X11-forwarding,no-port-forwarding %(pubkey)s\n""" % locals()) h.write("""command="FINGERPRINT=%(ssh_fingerprint)s NAME=default %(script_path)s $SSH_ORIGINAL_COMMAND",no-agent-forwarding,no-user-rc,no-X11-forwarding,no-port-forwarding %(pubkey)s\n""" % locals())
def parse_procfile(filename):
"""Parses a Procfile and returns the worker types. Only one worker of each type is allowed."""
workers = {}
if not exists(filename):
return None
with open(filename, 'r') as procfile:
for line in procfile:
kind, command = map(lambda x: x.strip(), line.split(":", 1))
if kind in ['web', 'worker', 'wsgi']:
workers[kind] = command
# WSGI trumps regular web workers
if 'wsgi' in workers:
if 'web' in workers:
del(workers['web'])
return workers
def do_deploy(app): def do_deploy(app):
"""Deploy an app by resetting the work directory""" """Deploy an app by resetting the work directory"""
app_path = join(APP_ROOT, app) app_path = join(APP_ROOT, app)
procfile = join(app_path, 'Procfile')
env = {'GIT_WORK_DIR': app_path} env = {'GIT_WORK_DIR': app_path}
if exists(app_path): if exists(app_path):
echo("-----> Deploying app '%s'" % app, fg='green') echo("-----> Deploying app '%s'" % app, fg='green')
call('git pull --quiet', cwd=app_path, env=env, shell=True) call('git pull --quiet', cwd=app_path, env=env, shell=True)
call('git checkout -f', cwd=app_path, env=env, shell=True) call('git checkout -f', cwd=app_path, env=env, shell=True)
if exists(join(app_path, 'requirements.txt')): workers = parse_procfile(procfile)
echo("-----> Python app detected.", fg='green') if workers:
deploy_python(app) if exists(join(app_path, 'requirements.txt')):
echo("-----> Python app detected.", fg='green')
deploy_python(app, workers)
else:
echo("-----> Could not detect runtime!", fg='red')
# TODO: detect other runtimes
else: else:
echo("-----> Could not detect runtime!", fg='red') echo("Error: Procfile not found for app '%s'." % app, fg='red')
# TODO: detect other runtimes
else: else:
echo("Error: app '%s' not found." % app, fg='red') echo("Error: app '%s' not found." % app, fg='red')
def deploy_python(app): def deploy_python(app, workers):
"""Deploy a Python application""" """Deploy a Python application"""
env_path = join(ENV_ROOT, app) env_path = join(ENV_ROOT, app)
available = join(UWSGI_AVAILABLE, '%s.ini' % app) available = join(UWSGI_AVAILABLE, '%s.ini' % app)
enabled = join(UWSGI_ENABLED, '%s.ini' % app) enabled = join(UWSGI_ENABLED, '%s.ini' % app)
if not exists(env_path): if not exists(env_path):
echo("-----> Creating virtualenv for '%s'" % app, fg='green') echo("-----> Creating virtualenv for '%s'" % app, fg='green')
os.makedirs(env_path) os.makedirs(env_path)
@ -83,26 +105,31 @@ def deploy_python(app):
# Generate a uWSGI vassal config # Generate a uWSGI vassal config
# TODO: check for worker processes and scaling # TODO: check for worker processes and scaling
config = ConfigParser()
# TODO: allow user to define the port # TODO: allow user to define the port
port = get_free_port() port = get_free_port()
settings = { settings = [
'http': ':%d' % port, ('http', ':%d' % port),
'virtualenv': join(ENV_ROOT, app), ('virtualenv', join(ENV_ROOT, app)),
'chdir': join(APP_ROOT, app), ('chdir', join(APP_ROOT, app)),
'master': 'false', ('master', 'false'),
'project': app, ('project', app),
'max-requests': '1000', ('max-requests', '1000'),
'module': '%%(project).app:app', # TODO: override this via Procfile ('processes', '2'),
'processes': '2', ('logto', "%s.log" % join(LOG_ROOT, app)),
'env': 'WSGI_PORT=http', # TODO: multiple environment settings ('env', 'WSGI_PORT=http'),
'logto': "%s.web.1.log" % join(LOG_ROOT, app) ('env', 'PORT=%d' % port)
} ]
config.add_section('uwsgi') for v in ['PATH', 'VIRTUAL_ENV']:
for k, v in settings.iteritems(): settings.append(('env', '%s=%s' % (v, os.environ[v])))
config.set('uwsgi', k, v)
if 'wsgi' in workers:
settings.append(('module', workers['wsgi']))
else:
settings.append(('attach-daemon', workers['web']))
with open(available, 'w') as h: with open(available, 'w') as h:
config.write(h) h.write('[uwsgi]\n')
for k, v in settings:
h.write("%s = %s\n" % (k, v))
echo("-----> Enabling '%s' at port %d" % (app, port), fg='green') echo("-----> Enabling '%s' at port %d" % (app, port), fg='green')
# Copying the file across makes uWSGI (re)start the vassal # Copying the file across makes uWSGI (re)start the vassal
shutil.copyfile(available, enabled) shutil.copyfile(available, enabled)