seafile-containerized/scripts/bootstrap.py

185 lines
5.7 KiB
Python
Executable file

#!/usr/bin/env python
#coding: UTF-8
"""
This script calls the appropriate seafile init scripts (e.g.
setup-seafile.sh or setup-seafile-mysql.sh. It's supposed to run inside the
container.
"""
import argparse
import os
from os.path import abspath, basename, exists, dirname, join, isdir
import shutil
import sys
import uuid
import time
from utils import (
call, get_conf, get_install_dir, show_progress,
get_script, render_template, get_seafile_version, eprint,
cert_has_valid_days, get_version_stamp_file, update_version_stamp
)
seafile_version = get_seafile_version()
installdir = get_install_dir()
topdir = dirname(installdir)
shared_seafiledir = '/shared/seafile'
ssl_dir = '/shared/ssl'
generated_dir = '/bootstrap/generated'
def init_letsencrypt():
show_progress('Preparing for letsencrypt ...')
if not exists(ssl_dir):
os.mkdir(ssl_dir)
domain = get_conf('server.hostname')
context = {
'ssl_dir': ssl_dir,
'domain': domain,
}
render_template(
'/templates/letsencrypt.cron.template',
join(generated_dir, 'letsencrypt.cron'),
context
)
ssl_crt = '/shared/ssl/{}.crt'.format(domain)
if exists(ssl_crt):
show_progress('Found existing cert file {}'.format(ssl_crt))
if cert_has_valid_days(ssl_crt, 30):
show_progress('Skip letsencrypt verification since we have a valid certificate')
return
show_progress('Starting letsencrypt verification')
# Create a temporary nginx conf to start a server, which would accessed by letsencrypt
context = {
'https': False,
'domain': domain,
}
render_template('/templates/seafile.nginx.conf.template',
'/etc/nginx/sites-enabled/seafile.nginx.conf', context)
# TODO: The 5 seconds heuristic is not good, how can we know for sure nginx is ready?
print 'waiting for nginx server to be ready'
time.sleep(5)
call('nginx -s reload')
call('/scripts/ssl.sh {0} {1}'.format(ssl_dir, domain))
# if call('/scripts/ssl.sh {0} {1}'.format(ssl_dir, domain), check_call=False) != 0:
# eprint('Now waiting 1000s for postmortem')
# time.sleep(1000)
# sys.exit(1)
def generate_local_nginx_conf():
# Now create the final nginx configuratin
domain = get_conf('server.hostname')
context = {
'https': is_https(),
'domain': domain,
}
render_template(
'/templates/seafile.nginx.conf.template',
join(generated_dir, 'seafile.nginx.conf'),
context
)
def is_https():
return get_conf('server.letsencrypt', '').lower() == 'true'
def generate_local_dockerfile():
show_progress('Generating local Dockerfile ...')
context = {
'seafile_version': seafile_version,
'https': is_https(),
'domain': get_conf('server.domain'),
}
render_template('/templates/Dockerfile.template', join(generated_dir, 'Dockerfile'), context)
def parse_args():
ap = argparse.ArgumentParser()
ap.add_argument('--parse-ports', action='store_true')
return ap.parse_args()
def do_parse_ports():
"""
Parse the server.port_mappings option and print docker command line port
mapping flags like "-p 80:80 -p 443:443"
"""
# conf is like '80:80,443:443'
conf = get_conf('server.port_mappings', '').strip()
if conf:
sys.stdout.write(' '.join(['-p {}'.format(part.strip()) for part in conf.split(',')]))
sys.stdout.flush()
def init_seafile_server():
version_stamp_file = get_version_stamp_file()
if exists(join(shared_seafiledir, 'seafile-data')):
if not exists(version_stamp_file):
update_version_stamp(version_stamp_file, os.environ['SEAFILE_VERSION'])
show_progress('Skip running setup-seafile-mysql.py because there is existing seafile-data folder.')
return
show_progress('Now running setup-seafile-mysql.py in auto mode.')
env = {
'SERVER_NAME': 'seafile',
'SERVER_IP': get_conf('server.hostname'),
'MYSQL_USER': 'seafile',
'MYSQL_USER_PASSWD': str(uuid.uuid4()),
'MYSQL_USER_HOST': '127.0.0.1',
# Default MariaDB root user has empty password and can only connect from localhost.
'MYSQL_ROOT_PASSWD': '',
}
# Change the script to allow mysql root password to be empty
call('''sed -i -e 's/if not mysql_root_passwd/if not mysql_root_passwd and "MYSQL_ROOT_PASSWD" not in os.environ/g' {}'''
.format(get_script('setup-seafile-mysql.py')))
setup_script = get_script('setup-seafile-mysql.sh')
call('{} auto -n seafile'.format(setup_script), env=env)
domain = get_conf('server.hostname')
proto = 'https' if is_https() else 'http'
with open(join(topdir, 'conf', 'seahub_settings.py'), 'a+') as fp:
fp.write('\n')
fp.write('FILE_SERVER_ROOT = "{proto}://{domain}/seafhttp"'.format(proto=proto, domain=domain))
fp.write('\n')
files_to_copy = ['conf', 'ccnet', 'seafile-data', 'seahub-data',]
for fn in files_to_copy:
src = join(topdir, fn)
dst = join(shared_seafiledir, fn)
if not exists(dst) and exists(src):
shutil.move(src, shared_seafiledir)
update_version_stamp(version_stamp_file, os.environ['SEAFILE_VERSION'])
def main():
args = parse_args()
if args.parse_ports:
do_parse_ports()
return
if not exists(shared_seafiledir):
os.mkdir(shared_seafiledir)
if not exists(generated_dir):
os.mkdir(generated_dir)
generate_local_dockerfile()
if is_https():
init_letsencrypt()
generate_local_nginx_conf()
init_seafile_server()
show_progress('Generated local config.')
if __name__ == '__main__':
# TODO: validate the content of bootstrap.conf is valid
main()