fine tune socket handling

pull/7/head
Rui Carmo 2016-04-25 13:23:00 +01:00
rodzic 5785e431a8
commit 42b519628b
2 zmienionych plików z 55 dodań i 59 usunięć

Wyświetl plik

@ -18,9 +18,8 @@ From the bottom up:
- [ ] Sample Go app
- [ ] Support Go deployments (in progress)
- [ ] CLI command documentation
- [ ] nginx SSL optimization/cypher suites, HTTPv2
- [ ] nginx log rotation docs
- [x] Basic nginx SSL config
- [ ] nginx SSL optimization/cypher suites, HTTPv2, own certificates
- [x] Basic nginx SSL config with self-signed certificates
- [x] nginx support - creates an nginx config file if `SERVER_NAME` is defined
- [x] Testing with pre-packaged [uWSGI][uwsgi] versions on Debian Jessie (yes, it was painful)
- [x] Support barebones binary deployments

109
piku.py
Wyświetl plik

@ -17,7 +17,6 @@ from time import sleep
PIKU_ROOT = os.environ.get('PIKU_ROOT', join(os.environ['HOME'],'.piku'))
APP_ROOT = abspath(join(PIKU_ROOT, "apps"))
CA_ROOT = abspath(join(PIKU_ROOT, "certs"))
ENV_ROOT = abspath(join(PIKU_ROOT, "envs"))
GIT_ROOT = abspath(join(PIKU_ROOT, "repos"))
LOG_ROOT = abspath(join(PIKU_ROOT, "logs"))
@ -29,19 +28,23 @@ UWSGI_LOG_MAXSIZE = '1048576'
NGINX_TEMPLATE = """
upstream $APP {
server $BIND_ADDRESS:$PORT;
server $NGINX_ROOT/$APP.sock;
# server $BIND_ADDRESS:$PORT;
}
server {
listen [::]:80;
listen 80;
listen [::]:443 ssl;
listen 443 ssl;
listen [::]:$NGINX_SSL;
listen $NGINX_SSL;
ssl on;
ssl_certificate $CA_ROOT/$APP.crt;
ssl_certificate_key $CA_ROOT/$APP.key;
ssl_certificate $NGINX_ROOT/$APP.crt;
ssl_certificate_key $NGINX_ROOT/$APP.key;
server_name $SERVER_NAME;
access_log $LOG_ROOT/$APP/access.log;
error_log $LOG_ROOT/$APP/error.log;
# These are not required under systemd - enable for debugging only
# access_log $LOG_ROOT/$APP/access.log;
# error_log $LOG_ROOT/$APP/error.log;
# set a custom header for requests
add_header X-Deployed-By Piku;
@ -60,27 +63,6 @@ server {
}
"""
SSL_TEMPLATE = """
prompt = no
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
C = US
ST = NY
L = New York
O = Piku
OU = Private Certificate Authority
CN = %(domain)s
emailAddress = piku@%(domain)s
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = %(domain)s
DNS.2 = *.%(domain)s
"""
# === Utility functions ===
def sanitize_app_name(app):
@ -163,6 +145,14 @@ def expandvars(buffer, env, default=None, skip_escaped=False):
return re.sub(pattern, replace_var, buffer)
def command_output(cmd):
"""executes a command and grabs its output, if any"""
try:
return check_output(cmd, shell=True)
except:
return ""
def parse_settings(filename, env={}):
"""Parses a settings file and returns a dict with environment variables"""
@ -281,16 +271,14 @@ def spawn_app(app, deltas={}):
live = join(ENV_ROOT, app, 'LIVE_ENV')
# Scaling
scaling = join(ENV_ROOT, app, 'SCALING')
# Bootstrap environment
env = {
'APP': app,
'CA_ROOT': CA_ROOT,
'LOG_ROOT': LOG_ROOT,
'HOME': os.environ['HOME'],
'USER': os.environ['USER'],
'PATH': os.environ['PATH'],
'PORT': str(get_free_port()),
'PWD': dirname(env_file),
'VIRTUAL_ENV': virtualenv_path,
}
@ -302,7 +290,25 @@ def spawn_app(app, deltas={}):
# Override with custom settings (if any)
if exists(settings):
env.update(parse_settings(settings, env))
# Pick a port if none defined and we're not running under nginx
if 'PORT' not in env and 'SERVER_NAME' not in env:
env['PORT'] = str(get_free_port())
# Set up nginx if needed
if 'SERVER_NAME' in env:
nginx = command_output("nginx -V")
nginx_ssl = "443 ssl"
if "--with-http_v2_module" in nginx:
nginx_ssl += " http2"
elif "--with-http_spdy_module" in nginx:
nginx_ssl += " spdy"
env.update({
'NGINX_SSL': nginx_ssl,
'NGINX_ROOT': NGINX_ROOT,
})
# Configured worker count
if exists(scaling):
worker_count.update({k: int(v) for k,v in parse_procfile(scaling).iteritems()})
@ -340,19 +346,12 @@ def spawn_app(app, deltas={}):
# Set up nginx if $SERVER_NAME is present
if 'SERVER_NAME' in env:
domain = env['SERVER_NAME'].split()[0]
key, req, crt, conf = [join(CA_ROOT,'%s.%s' % (app,x)) for x in ['key','req','crt','conf']]
cakey, cacrt = [join(CA_ROOT, 'ca.%s' % x) for x in ['key','crt']]
serial = md5(domain + str(datetime.now())).hexdigest()
key, crt = [join(NGINX_ROOT,'%s.%s' % (app,x)) for x in ['key','crt']]
if not exists(key):
call('openssl genrsa -out %(key)s 1024' % locals(), shell=True)
with open(conf,'w') as h:
h.write(SSL_TEMPLATE % locals())
call('openssl req -new -key %(key)s -out %(req)s -config %(conf)s' % locals(), shell=True)
call('openssl x509 -req -days 3650 -in %(req)s -CA %(cacrt)s -CAkey %(cakey)s -passin pass:piku -set_serial 0x%(serial)s -out %(crt)s -extensions v3_req -extfile %(conf)s' % locals(), shell=True)
call('openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj "/C=US/ST=NY/L=New York/O=Piku/OU=Self-Signed/CN=%(domain)s" -keyout %(key)s -out %(crt)s' % locals(), shell=True)
buffer = expandvars(NGINX_TEMPLATE, env)
echo("-----> Setting up nginx for '%s:%s'" % (app, env['SERVER_NAME']))
echo(buffer)
with open(join(NGINX_ROOT,"%s.conf" % app), "w") as h:
h.write(buffer)
@ -386,9 +385,18 @@ def spawn_worker(app, kind, command, env, ordinal=1):
('module', command),
('threads', '4'),
('plugin', 'python'),
('http', ':%s' % env['PORT']),
('http-socket', ':%s' % env['PORT']),
])
# If running under nginx, don't expose a port at all
if 'SERVER_NAME' in env:
settings.extend([
('socket', join(NGINX_ROOT, app, "%s.sock" % app)),
])
else:
settings.extend([
('http', ':%s' % env['PORT']),
('http-socket', ':%s' % env['PORT']),
])
else:
settings.append(('attach-daemon', command))
@ -573,8 +581,7 @@ def destroy_app(app):
echo("Removing file '%s'" % f, fg='yellow')
os.remove(f)
nginx_files = [join(CA_ROOT, "%s.%s" % (app,x)) for x in ['conf','key','crt']]
nginx_files.append(join(NGINX_ROOT,"%s.conf" % app))
nginx_files = [join(NGINX_ROOT, "%s.%s" % (app,x)) for x in ['sock','key','crt']]
for f in nginx_files:
if exists(f):
echo("Removing file '%s'" % f, fg='yellow')
@ -662,7 +669,7 @@ def init_paths():
"""Initialize environment"""
# Create required paths
for p in [APP_ROOT, CA_ROOT, GIT_ROOT, ENV_ROOT, UWSGI_ROOT, UWSGI_AVAILABLE, UWSGI_ENABLED, LOG_ROOT, NGINX_ROOT]:
for p in [APP_ROOT, GIT_ROOT, ENV_ROOT, UWSGI_ROOT, UWSGI_AVAILABLE, UWSGI_ENABLED, LOG_ROOT, NGINX_ROOT]:
if not exists(p):
echo("Creating '%s'." % p, fg='green')
os.makedirs(p)
@ -682,16 +689,6 @@ def init_paths():
h.write('[uwsgi]\n')
for k, v in settings:
h.write("%s = %s\n" % (k, v))
# Create a local certificate authority
key, crt, conf = [join(CA_ROOT, 'ca.%s' % x) for x in ['key','crt','conf']]
domain = 'piku.local'
if not exists(key):
echo("Creating local certificate authority...", fg='yellow')
call('openssl genrsa -des3 -out %(key)s 4096' % locals(), shell=True)
with open(conf,'w') as h:
h.write(SSL_TEMPLATE % locals())
call('openssl req -new -x509 -days 3650 -key %(key)s -passout pass:piku -out %(crt)s -config %(conf)s' % locals(), shell=True)
# mark this script as executable (in case we were invoked via interpreter)
this_script = realpath(__file__)