mirror of
https://github.com/haiwen/seafile-server.git
synced 2025-04-27 11:10:49 +00:00
929 lines
26 KiB
Python
Executable File
929 lines
26 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# coding: UTF-8
|
|
'''This is the helper script to setup/manage your seafile server
|
|
'''
|
|
|
|
import sys
|
|
|
|
####################
|
|
### Requires Python 2.6+
|
|
####################
|
|
if sys.version_info.major == 3:
|
|
print 'Python 3 not supported yet. Quit now'
|
|
sys.exit(1)
|
|
if sys.version_info.minor < 6:
|
|
print 'Python 2.6 or above is required. Quit now'
|
|
sys.exit(1)
|
|
|
|
import os
|
|
import time
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import argparse
|
|
import uuid
|
|
|
|
try:
|
|
import readline
|
|
# Avoid pylint 'unused import' warning
|
|
dummy = readline
|
|
except ImportError:
|
|
pass
|
|
|
|
####################
|
|
### Cosntants
|
|
####################
|
|
SERVER_MANUAL_HTTP = 'https://github.com/haiwen/seafile/wiki'
|
|
SEAFILE_GOOGLE_GROUP = 'https://groups.google.com/forum/?fromgroups#!forum/seafile'
|
|
SEAFILE_WEBSITE = 'http://www.seafile.com'
|
|
SEAHUB_DOWNLOAD_URL = 'https://seafile.com.cn/downloads/seahub-latest.tar.gz'
|
|
|
|
####################
|
|
### Global variables
|
|
####################
|
|
cwd = os.getcwd()
|
|
SCRIPT_NAME = os.path.basename(sys.argv[0])
|
|
|
|
PYTHON = sys.executable
|
|
|
|
conf = {}
|
|
CONF_CCNET_DIR = 'ccnet_dir'
|
|
CONF_SEAFILE_DIR = 'seafile_dir'
|
|
CONF_SEAHUB_DIR = 'seafile_dir'
|
|
CONF_SEAFILE_PORT = 'seafile_port'
|
|
CONF_FILESERVER_PORT = 'fileserver_port'
|
|
CONF_IP_OR_DOMAIN = 'ip_or_domain'
|
|
|
|
CONF_SEAHUB_CONF = 'seahub_conf'
|
|
CONF_SEAHUB_DIR = 'seahub_dir'
|
|
CONF_SEAHUB_PORT = 'seahub_port'
|
|
|
|
CONF_SEAHUB_PIDFILE = 'seahub_pidfile'
|
|
CONF_SEAHUB_OUTLOG = 'seahub_outlog'
|
|
CONF_SEAHUB_ERRLOG = 'seahub_errlog'
|
|
|
|
CONF_CCNET_CONF_EXISTS = 'ccnet_conf_exists'
|
|
CONF_SEAFILE_CONF_EXISTS = 'seafile_conf_exists'
|
|
|
|
CONF_ADMIN_EMAIL = 'admin_email'
|
|
CONF_ADMIN_PASSWORD = 'admin_password'
|
|
CONF_SEAFILE_CENTRAL_CONF_DIR = 'central_config_dir'
|
|
|
|
####################
|
|
### Common helper functions
|
|
|
|
|
|
def highlight(content):
|
|
'''Add ANSI color to content to get it highlighted on terminal'''
|
|
return '\x1b[33m%s\x1b[m' % content
|
|
|
|
|
|
def info(msg):
|
|
print msg
|
|
|
|
|
|
def error(msg):
|
|
print 'Error: ' + msg
|
|
sys.exit(1)
|
|
|
|
|
|
def ask_question(desc,
|
|
key=None,
|
|
note=None,
|
|
default=None,
|
|
validate=None,
|
|
yes_or_no=False,
|
|
invalidate_msg=None):
|
|
'''Ask a question, return the answer. The optional validate param is a
|
|
function used to validate the answer. If yes_or_no is True, then a boolean
|
|
value would be returned.
|
|
|
|
'''
|
|
assert key or yes_or_no
|
|
desc = highlight(desc)
|
|
if note:
|
|
desc += ' (%s)' % note
|
|
if default:
|
|
desc += '\n' + ('[default %s ]' % default)
|
|
else:
|
|
if yes_or_no:
|
|
desc += '\n[yes or no]'
|
|
else:
|
|
desc += '\n' + ('[%s ]' % key)
|
|
|
|
desc += ' '
|
|
while True:
|
|
answer = raw_input(desc)
|
|
if not answer:
|
|
if default:
|
|
print ''
|
|
return default
|
|
else:
|
|
continue
|
|
|
|
answer = answer.strip()
|
|
|
|
if yes_or_no:
|
|
if answer != 'yes' and answer != 'no':
|
|
print '\nPlease answer yes or no\n'
|
|
continue
|
|
else:
|
|
return answer == 'yes'
|
|
else:
|
|
if validate and not validate(answer):
|
|
if invalidate_msg:
|
|
print '\n%s\n' % invalidate_msg
|
|
else:
|
|
print '\n"%s" is not a valid %s\n' % (answer, key)
|
|
continue
|
|
|
|
print ''
|
|
return answer
|
|
|
|
|
|
def run_argv(argv,
|
|
cwd=None,
|
|
env=None,
|
|
suppress_stdout=False,
|
|
suppress_stderr=False):
|
|
'''Run a program and wait it to finish, and return its exit code. The
|
|
standard output of this program is supressed.
|
|
|
|
'''
|
|
with open(os.devnull, 'w') as devnull:
|
|
if suppress_stdout:
|
|
stdout = devnull
|
|
else:
|
|
stdout = sys.stdout
|
|
|
|
if suppress_stderr:
|
|
stderr = devnull
|
|
else:
|
|
stderr = sys.stderr
|
|
|
|
proc = subprocess.Popen(argv,
|
|
cwd=cwd,
|
|
stdout=stdout,
|
|
stderr=stderr,
|
|
env=env)
|
|
return proc.wait()
|
|
|
|
|
|
def run(cmdline,
|
|
cwd=None,
|
|
env=None,
|
|
suppress_stdout=False,
|
|
suppress_stderr=False):
|
|
'''Like run_argv but specify a command line string instead of argv'''
|
|
with open(os.devnull, 'w') as devnull:
|
|
if suppress_stdout:
|
|
stdout = devnull
|
|
else:
|
|
stdout = sys.stdout
|
|
|
|
if suppress_stderr:
|
|
stderr = devnull
|
|
else:
|
|
stderr = sys.stderr
|
|
|
|
proc = subprocess.Popen(cmdline,
|
|
cwd=cwd,
|
|
stdout=stdout,
|
|
stderr=stderr,
|
|
env=env,
|
|
shell=True)
|
|
return proc.wait()
|
|
|
|
|
|
def is_running(process):
|
|
'''Detect if there is a process with the given name running'''
|
|
argv = ['pgrep', '-f', process]
|
|
|
|
return run_argv(argv, suppress_stdout=True) == 0
|
|
|
|
|
|
def pkill(process):
|
|
'''Kill the program with the given name'''
|
|
argv = ['pkill', '-f', process]
|
|
|
|
run_argv(argv)
|
|
|
|
|
|
def kill(pid):
|
|
'''Kill the program with the given pid'''
|
|
argv = ['kill', pid]
|
|
|
|
run_argv(argv)
|
|
|
|
|
|
def must_mkdir(path):
|
|
'''Create a directory, exit on failure'''
|
|
try:
|
|
os.mkdir(path)
|
|
except OSError, e:
|
|
error('failed to create directory %s:%s' % (path, e))
|
|
|
|
### END of Common helper functions
|
|
####################
|
|
|
|
|
|
def check_seafile_install():
|
|
'''Check if seafile has been correctly built and installed in this
|
|
system
|
|
|
|
'''
|
|
dirs = os.environ['PATH'].split(':')
|
|
|
|
def exist_in_path(prog):
|
|
'''Test whether prog exists in system path'''
|
|
for d in dirs:
|
|
if d == '':
|
|
continue
|
|
path = os.path.join(d, prog)
|
|
if os.path.exists(path):
|
|
return True
|
|
|
|
return False
|
|
|
|
def check_prog(name):
|
|
if not exist_in_path(name):
|
|
error(
|
|
'%s not found in PATH. Have you built and installed seafile server?'
|
|
% name)
|
|
|
|
progs = [
|
|
'ccnet-init',
|
|
'seaf-server-init',
|
|
'seaf-server',
|
|
'ccnet-server',
|
|
'seafile-controller',
|
|
]
|
|
|
|
for prog in progs:
|
|
check_prog(prog)
|
|
|
|
|
|
def get_seahub_env():
|
|
'''And PYTHONPATH and CCNET_CONF_DIR/SEAFILE_CONF_DIR to env, which is
|
|
needed by seahub
|
|
|
|
'''
|
|
seahub_dir = conf[CONF_SEAHUB_DIR]
|
|
seahub_thirdpart_dir = os.path.join(seahub_dir, 'thirdpart')
|
|
|
|
env = dict(os.environ)
|
|
pypath = env.get('PYTHONPATH', '')
|
|
|
|
pathlist = [p for p in pypath.split(':') if p != '']
|
|
pathlist.append(seahub_thirdpart_dir)
|
|
newpypath = ':'.join(pathlist)
|
|
env['PYTHONPATH'] = newpypath
|
|
env['CCNET_CONF_DIR'] = conf[CONF_CCNET_DIR]
|
|
env['SEAFILE_CONF_DIR'] = conf[CONF_SEAFILE_DIR]
|
|
env['SEAFILE_CENTRAL_CONF_DIR'] = conf[CONF_SEAFILE_CENTRAL_CONF_DIR]
|
|
return env
|
|
|
|
|
|
####################
|
|
### <setup> command
|
|
####################
|
|
def welcome():
|
|
'''Show welcome message when running the <setup> command'''
|
|
welcome_msg = '''\
|
|
-----------------------------------------------------------------
|
|
This script will guide you to config and setup your seafile server.
|
|
Make sure you have read seafile server manual at
|
|
|
|
%s
|
|
|
|
Press [ENTER] to continue
|
|
-----------------------------------------------------------------
|
|
''' % SERVER_MANUAL_HTTP
|
|
print welcome_msg
|
|
raw_input()
|
|
|
|
def get_server_ip_or_domain():
|
|
def validate(s):
|
|
r = r'^[^.].+\..+[^.]$'
|
|
return bool(re.match(r, s))
|
|
|
|
question = 'What is the ip of the server?'
|
|
key = 'ip or domain'
|
|
note = 'For example: www.mycompany.com, 192.168.1.101'
|
|
conf[CONF_IP_OR_DOMAIN] = ask_question(question,
|
|
key=key,
|
|
note=note,
|
|
validate=validate)
|
|
|
|
|
|
def get_ccnet_conf_dir():
|
|
ccnet_conf_dir = os.path.join(cwd, 'ccnet')
|
|
|
|
if os.path.exists(ccnet_conf_dir):
|
|
question = 'It seems there already exists ccnet config files in %s, Do you want to use them?' % ccnet_conf_dir
|
|
yesno = ask_question(question, yes_or_no=True)
|
|
if not yesno:
|
|
print highlight(
|
|
'\nRemove the directory %s first, and run the script again.\n'
|
|
% ccnet_conf_dir)
|
|
sys.exit(1)
|
|
else:
|
|
conf[CONF_CCNET_CONF_EXISTS] = True
|
|
else:
|
|
conf[CONF_CCNET_CONF_EXISTS] = False
|
|
|
|
conf[CONF_CCNET_DIR] = ccnet_conf_dir
|
|
|
|
|
|
def get_seafile_port():
|
|
def validate(s):
|
|
try:
|
|
port = int(s)
|
|
except ValueError:
|
|
return False
|
|
|
|
return port > 0 and port < 65536
|
|
|
|
question = 'Which port do you want to use for the seafile server?'
|
|
key = 'seafile server port'
|
|
default = '12001'
|
|
conf[CONF_SEAFILE_PORT] = ask_question(question,
|
|
key=key,
|
|
default=default,
|
|
validate=validate)
|
|
|
|
|
|
def get_fileserver_port():
|
|
def validate(s):
|
|
try:
|
|
port = int(s)
|
|
except ValueError:
|
|
return False
|
|
|
|
return port > 0 and port < 65536
|
|
|
|
question = 'Which port do you want to use for the seafile fileserver?'
|
|
key = 'seafile fileserver port'
|
|
default = '8082'
|
|
conf[CONF_FILESERVER_PORT] = ask_question(question,
|
|
key=key,
|
|
default=default,
|
|
validate=validate)
|
|
|
|
|
|
def get_seafile_data_dir():
|
|
question = 'Where do you want to put your seafile data?'
|
|
key = 'seafile-data'
|
|
note = 'Please use a volume with enough free space'
|
|
default = os.path.join(cwd, 'seafile-data')
|
|
seafile_data_dir = ask_question(question,
|
|
key=key,
|
|
note=note,
|
|
default=default)
|
|
|
|
if os.path.exists(seafile_data_dir):
|
|
question = 'It seems there already exists seafile data in %s, Do you want to use them?' % seafile_data_dir
|
|
yesno = ask_question(question, yes_or_no=True)
|
|
if not yesno:
|
|
print highlight(
|
|
'\nRemove the directory %s first, and run the script again.\n'
|
|
% seafile_data_dir)
|
|
sys.exit(1)
|
|
else:
|
|
conf[CONF_SEAFILE_CONF_EXISTS] = True
|
|
else:
|
|
conf[CONF_SEAFILE_CONF_EXISTS] = False
|
|
|
|
conf[CONF_SEAFILE_DIR] = seafile_data_dir
|
|
|
|
|
|
def create_gunicorn_conf():
|
|
runtime_dir = os.path.join(cwd, 'seafile-server', 'runtime')
|
|
confpath = os.path.join(runtime_dir, 'seahub.conf')
|
|
|
|
if os.path.exists(confpath):
|
|
return
|
|
|
|
if not os.path.exists(runtime_dir):
|
|
must_mkdir(runtime_dir)
|
|
|
|
content = '''\
|
|
import os
|
|
daemon = True
|
|
workers = 3
|
|
|
|
# Logging
|
|
runtime_dir = os.path.dirname(__file__)
|
|
pidfile = os.path.join(runtime_dir, 'seahub.pid')
|
|
errorlog = os.path.join(runtime_dir, 'error.log')
|
|
accesslog = os.path.join(runtime_dir, 'access.log')
|
|
'''
|
|
|
|
try:
|
|
with open(confpath, 'w') as fp:
|
|
fp.write(content)
|
|
except:
|
|
error('Failed to write seahub config')
|
|
|
|
|
|
def gen_seahub_secret_key():
|
|
data = str(uuid.uuid4()) + str(uuid.uuid4())
|
|
return data[:40]
|
|
|
|
|
|
def create_seahub_settings_py():
|
|
seahub_settings_py = os.path.join(cwd, 'conf', 'seahub_settings.py')
|
|
try:
|
|
with open(seahub_settings_py, 'w') as fp:
|
|
line = "SECRET_KEY = '%s'" % gen_seahub_secret_key()
|
|
fp.write(line)
|
|
except Exception, e:
|
|
error('failed to create %s: %s' % (seahub_settings_py, e))
|
|
|
|
|
|
def move_avatar():
|
|
seahub_data_dir = os.path.join(cwd, 'seahub-data')
|
|
outside_avatar_dir = os.path.join(seahub_data_dir, 'avatars')
|
|
seahub_avatar_dir = os.path.join(conf[CONF_SEAHUB_DIR], 'media', 'avatars')
|
|
|
|
if os.path.exists(outside_avatar_dir):
|
|
return
|
|
|
|
if not os.path.exists(seahub_data_dir):
|
|
must_mkdir(seahub_data_dir)
|
|
|
|
# move the avatars dir outside
|
|
shutil.move(seahub_avatar_dir, outside_avatar_dir)
|
|
# make the the original avatars dir a symlink pointing to the outside dir
|
|
os.symlink(outside_avatar_dir, seahub_avatar_dir)
|
|
|
|
|
|
def init_seahub():
|
|
seahub_dir = conf[CONF_SEAHUB_DIR]
|
|
|
|
# create seahub_settings.py
|
|
create_seahub_settings_py()
|
|
|
|
argv = [PYTHON, 'manage.py', 'syncdb']
|
|
# Set proper PYTHONPATH before run django syncdb command
|
|
env = get_seahub_env()
|
|
|
|
print
|
|
print
|
|
info('Now initializing seahub database, please wait...')
|
|
print
|
|
|
|
if run_argv(argv, cwd=seahub_dir, env=env) != 0:
|
|
error('Seahub syncdb failed')
|
|
|
|
info('done')
|
|
|
|
move_avatar()
|
|
create_gunicorn_conf()
|
|
|
|
|
|
def check_django_version():
|
|
'''Requires django 1.8'''
|
|
import django
|
|
if django.VERSION[0] != 1 or django.VERSION[1] != 8:
|
|
error('Django 1.8 is required')
|
|
del django
|
|
|
|
|
|
def check_python_module(import_name, package_name=None, silent=False):
|
|
package_name = package_name or import_name
|
|
if not silent:
|
|
info('checking %s' % package_name)
|
|
try:
|
|
__import__(import_name)
|
|
except ImportError:
|
|
error('Python module "%s" not found. Please install it first' %
|
|
package_name)
|
|
|
|
|
|
def check_python_dependencies(silent=False):
|
|
'''Ensure all python libraries we need are installed'''
|
|
|
|
if not silent:
|
|
info('check python modules ...')
|
|
check_django_version()
|
|
def check(*a, **kw):
|
|
kw.setdefault('silent', silent)
|
|
check_python_module(*a, **kw)
|
|
pkgs = [
|
|
'sqlite3',
|
|
'chardet',
|
|
'six',
|
|
'pytz',
|
|
'rest_framework',
|
|
'compressor',
|
|
'statici18n',
|
|
'jsonfield',
|
|
'dateutil',
|
|
'constance',
|
|
'openpyxl',
|
|
] # yapf: disable
|
|
for pkg in pkgs:
|
|
check(pkg)
|
|
check('PIL', 'python imaging library(PIL)')
|
|
|
|
print
|
|
|
|
|
|
def config_ccnet_seafile():
|
|
get_ccnet_conf_dir()
|
|
if not conf[CONF_CCNET_CONF_EXISTS]:
|
|
get_server_ip_or_domain()
|
|
|
|
get_seafile_data_dir()
|
|
if not conf[CONF_SEAFILE_CONF_EXISTS]:
|
|
get_seafile_port()
|
|
get_fileserver_port()
|
|
|
|
info('This is your configuration')
|
|
info('------------------------------------------')
|
|
if conf[CONF_CCNET_CONF_EXISTS]:
|
|
info('ccnet config: use existing config in %s' %
|
|
highlight(conf[CONF_CCNET_DIR]))
|
|
else:
|
|
info('ccnet conf dir: %s' % highlight(conf[CONF_CCNET_DIR]))
|
|
info('server host: %s' %
|
|
highlight(conf[CONF_IP_OR_DOMAIN]))
|
|
|
|
if conf[CONF_SEAFILE_CONF_EXISTS]:
|
|
info('seafile: use existing config in %s' %
|
|
highlight(conf[CONF_SEAFILE_DIR]))
|
|
else:
|
|
info('seafile data dir: %s' %
|
|
highlight(conf[CONF_SEAFILE_DIR]))
|
|
info('seafile port: %s' %
|
|
highlight(conf[CONF_SEAFILE_PORT]))
|
|
info('seafile fileserver port: %s' %
|
|
highlight(conf[CONF_FILESERVER_PORT]))
|
|
|
|
info('------------------------------------------')
|
|
info('Press ENTER if the config is right, or anything else to re-config ')
|
|
|
|
if raw_input() != '':
|
|
config_ccnet_seafile()
|
|
else:
|
|
return
|
|
|
|
|
|
def init_ccnet_seafile():
|
|
if not conf[CONF_CCNET_CONF_EXISTS]:
|
|
info('Generating ccnet configuration...')
|
|
argv = [
|
|
'ccnet-init',
|
|
'-F',
|
|
conf[CONF_SEAFILE_CENTRAL_CONF_DIR],
|
|
'-c',
|
|
conf[CONF_CCNET_DIR],
|
|
'--host',
|
|
conf[CONF_IP_OR_DOMAIN],
|
|
]
|
|
|
|
if run_argv(argv) != 0:
|
|
error('failed to init ccnet configuration')
|
|
|
|
info('done')
|
|
|
|
if not conf[CONF_SEAFILE_CONF_EXISTS]:
|
|
info('Generating seafile configuration...')
|
|
argv = [
|
|
'seaf-server-init',
|
|
'-F',
|
|
conf[CONF_SEAFILE_CENTRAL_CONF_DIR],
|
|
'--seafile-dir',
|
|
conf[CONF_SEAFILE_DIR],
|
|
'--port',
|
|
conf[CONF_SEAFILE_PORT],
|
|
'--fileserver-port',
|
|
conf[CONF_FILESERVER_PORT],
|
|
]
|
|
|
|
if run_argv(argv) != 0:
|
|
error('failed to init seafile configuration')
|
|
|
|
info('done')
|
|
|
|
seafile_ini = os.path.join(conf[CONF_CCNET_DIR], 'seafile.ini')
|
|
with open(seafile_ini, 'w') as fp:
|
|
fp.write(conf[CONF_SEAFILE_DIR])
|
|
|
|
|
|
####################
|
|
### <start> command
|
|
####################
|
|
def start_controller():
|
|
argv = [
|
|
'seafile-controller',
|
|
'-c',
|
|
conf[CONF_CCNET_DIR],
|
|
'-d',
|
|
conf[CONF_SEAFILE_DIR],
|
|
'-F',
|
|
conf[CONF_SEAFILE_CENTRAL_CONF_DIR],
|
|
]
|
|
|
|
info('Starting seafile-server...')
|
|
if run_argv(argv) != 0:
|
|
error('Failed to start seafile')
|
|
|
|
# check again after several seconds
|
|
time.sleep(10)
|
|
|
|
if not is_running('seafile-controller'):
|
|
error('Failed to start seafile')
|
|
|
|
|
|
def start_seahub_gunicorn():
|
|
argv = [
|
|
'gunicorn',
|
|
'seahub.wsgi:application',
|
|
'-c',
|
|
conf[CONF_SEAHUB_CONF],
|
|
'-b',
|
|
'0.0.0.0:%s' % conf[CONF_SEAHUB_PORT],
|
|
]
|
|
|
|
info('Starting seahub...')
|
|
env = get_seahub_env()
|
|
if run_argv(argv, cwd=conf[CONF_SEAHUB_DIR], env=env) != 0:
|
|
error('Failed to start seahub')
|
|
|
|
info('Seahub running on port %s' % conf[CONF_SEAHUB_PORT])
|
|
|
|
|
|
def start_seahub_fastcgi():
|
|
info('Starting seahub in fastcgi mode...')
|
|
argv = [
|
|
PYTHON,
|
|
'manage.py',
|
|
'runfcgi',
|
|
'host=%(host)s',
|
|
'port=%(port)s',
|
|
'pidfile=%(pidfile)s',
|
|
'outlog=%(outlog)s',
|
|
'errlog=%(errlog)s',
|
|
]
|
|
|
|
host = os.environ.get('SEAFILE_FASTCGI_HOST', '127.0.0.1')
|
|
cmdline = ' '.join(argv) % \
|
|
dict(host=host,
|
|
port=conf[CONF_SEAHUB_PORT],
|
|
pidfile=conf[CONF_SEAHUB_PIDFILE],
|
|
outlog=conf[CONF_SEAHUB_OUTLOG],
|
|
errlog=conf[CONF_SEAHUB_ERRLOG])
|
|
|
|
env = get_seahub_env()
|
|
|
|
if run(cmdline, cwd=conf[CONF_SEAHUB_DIR], env=env) != 0:
|
|
error('Failed to start seahub in fastcgi mode')
|
|
|
|
info('Seahub running on port %s (fastcgi)' % conf[CONF_SEAHUB_PORT])
|
|
|
|
|
|
def read_seafile_data_dir(ccnet_conf_dir):
|
|
'''Read the location of seafile-data from seafile.ini, also consider the
|
|
upgrade from older version which do not has the seafile.ini feature
|
|
|
|
'''
|
|
seafile_ini = os.path.join(ccnet_conf_dir, 'seafile.ini')
|
|
if os.path.exists(seafile_ini):
|
|
with open(seafile_ini, 'r') as fp:
|
|
seafile_data_dir = fp.read().strip()
|
|
else:
|
|
# In previous seafile-admin, seafiled-data folder must be under
|
|
# the top level directory, so we do not store the location of
|
|
# seafile-data folder in seafile.ini
|
|
seafile_data_dir = os.path.join(cwd, 'seafile-data')
|
|
if os.path.exists(seafile_data_dir):
|
|
with open(seafile_ini, 'w') as fp:
|
|
fp.write(seafile_data_dir)
|
|
|
|
return seafile_data_dir
|
|
|
|
|
|
def check_layout(args):
|
|
def error_not_found(path):
|
|
error('%s not found' % path)
|
|
|
|
ccnet_conf_dir = os.path.join(cwd, 'ccnet')
|
|
if not os.path.exists(ccnet_conf_dir):
|
|
error_not_found(ccnet_conf_dir)
|
|
|
|
central_config_dir = os.path.join(cwd, 'conf')
|
|
|
|
ccnet_conf = os.path.join(central_config_dir, 'ccnet.conf')
|
|
if not os.path.exists(ccnet_conf):
|
|
error_not_found(ccnet_conf)
|
|
|
|
seafile_data_dir = read_seafile_data_dir(ccnet_conf_dir)
|
|
if not os.path.exists(seafile_data_dir):
|
|
error_not_found(seafile_data_dir)
|
|
|
|
seafile_conf = os.path.join(central_config_dir, 'seafile.conf')
|
|
if not os.path.exists(seafile_conf):
|
|
error_not_found(seafile_conf)
|
|
|
|
runtime_dir = os.path.join(cwd, 'seafile-server', 'runtime')
|
|
seahub_conf = os.path.join(runtime_dir, 'seahub.conf')
|
|
if not os.path.exists(seahub_conf):
|
|
error_not_found(seahub_conf)
|
|
|
|
seahub_dir = os.path.join(cwd, 'seafile-server', 'seahub')
|
|
if not os.path.exists(seahub_conf):
|
|
error_not_found(seahub_dir)
|
|
|
|
conf[CONF_SEAFILE_CENTRAL_CONF_DIR] = central_config_dir
|
|
conf[CONF_CCNET_DIR] = ccnet_conf_dir
|
|
conf[CONF_SEAFILE_DIR] = seafile_data_dir
|
|
conf[CONF_SEAHUB_DIR] = seahub_dir
|
|
conf[CONF_SEAHUB_CONF] = seahub_conf
|
|
conf[CONF_SEAHUB_PIDFILE] = os.path.join(runtime_dir, 'seahub.pid')
|
|
conf[CONF_SEAHUB_OUTLOG] = os.path.join(runtime_dir, 'access.log')
|
|
conf[CONF_SEAHUB_ERRLOG] = os.path.join(runtime_dir, 'error.log')
|
|
|
|
|
|
def check_config(args):
|
|
check_layout(args)
|
|
|
|
try:
|
|
port = int(args.port)
|
|
except ValueError:
|
|
error('invalid port: %s' % args.port)
|
|
else:
|
|
if port <= 0 or port > 65535:
|
|
error('invalid port: %s' % args.port)
|
|
|
|
conf[CONF_SEAHUB_PORT] = port
|
|
|
|
|
|
def check_directory_layout():
|
|
seaf_server_dir = os.path.join(cwd, 'seafile-server')
|
|
if not os.path.exists(seaf_server_dir):
|
|
error(
|
|
'"seafile-server/" not found in current directory. \nPlease run seafile-admin in the correct directory.')
|
|
|
|
seahub_dir = os.path.join(seaf_server_dir, 'seahub')
|
|
if not os.path.exists(seahub_dir):
|
|
error(
|
|
'"seafile-server/seahub/" not found. \nPlease download seahub first.')
|
|
|
|
conf[CONF_SEAHUB_DIR] = seahub_dir
|
|
|
|
|
|
def setup_seafile(args):
|
|
# avoid pylint "unused variable" warning
|
|
dummy = args
|
|
|
|
welcome()
|
|
check_python_dependencies()
|
|
conf[CONF_SEAFILE_CENTRAL_CONF_DIR] = os.path.join(cwd, 'conf')
|
|
config_ccnet_seafile()
|
|
init_ccnet_seafile()
|
|
init_seahub()
|
|
|
|
print
|
|
print '-----------------------------------------------------------------'
|
|
print '-----------------------------------------------------------------'
|
|
print 'Your seafile server configuration has been finished successfully.'
|
|
print '-----------------------------------------------------------------'
|
|
print '-----------------------------------------------------------------'
|
|
print
|
|
print 'To start/stop seafile server:'
|
|
print
|
|
print highlight(' $ cd %s' % cwd)
|
|
print highlight(' $ %s { start | stop }' % SCRIPT_NAME)
|
|
print
|
|
print 'If you have any problem, refer to\n'
|
|
print
|
|
print ' Seafile server manual: %s' % SERVER_MANUAL_HTTP
|
|
print
|
|
print ' Seafile discussion group: %s' % SEAFILE_GOOGLE_GROUP
|
|
print
|
|
print ' Seafile website: %s' % SEAFILE_WEBSITE
|
|
print
|
|
print 'for more information.'
|
|
print
|
|
|
|
|
|
def check_necessary_files():
|
|
files = [
|
|
os.path.join(cwd, 'conf', 'ccnet.conf'),
|
|
os.path.join(cwd, 'seafile-server', 'runtime', 'seahub.conf'),
|
|
os.path.join(cwd, 'seahub.db'),
|
|
os.path.join(cwd, 'conf', 'seahub_settings.py'),
|
|
]
|
|
|
|
for fpath in files:
|
|
if not os.path.exists(fpath):
|
|
error('%s not found' % fpath)
|
|
|
|
|
|
def start_seafile(args):
|
|
'''start ccnet/seafile/seahub/fileserver'''
|
|
if is_running('seafile-controller'):
|
|
error(highlight('NOTE: Seafile is already running'))
|
|
|
|
check_python_dependencies(silent=True)
|
|
if args.fastcgi:
|
|
check_python_module('flup', 'flup', silent=True)
|
|
else:
|
|
check_python_module('gunicorn', 'gunicorn', silent=True)
|
|
|
|
check_necessary_files()
|
|
|
|
check_config(args)
|
|
|
|
start_controller()
|
|
|
|
if args.port:
|
|
try:
|
|
port = int(args.port)
|
|
except ValueError:
|
|
error('invalid port: %s' % args.port)
|
|
else:
|
|
if port <= 0 or port > 65535:
|
|
error('invalid port: %s' % args.port)
|
|
|
|
if args.fastcgi:
|
|
start_seahub_fastcgi()
|
|
else:
|
|
start_seahub_gunicorn()
|
|
|
|
info('Done')
|
|
|
|
|
|
def stop_seafile(dummy):
|
|
info('Stopping seafile server')
|
|
pkill('seafile-controller')
|
|
runtime_dir = os.path.join(cwd, 'seafile-server', 'runtime')
|
|
pidfile = os.path.join(runtime_dir, 'seahub.pid')
|
|
try:
|
|
with open(pidfile, 'r') as fp:
|
|
pid = fp.read().strip('\n ')
|
|
if pid:
|
|
kill(pid)
|
|
except:
|
|
pass
|
|
|
|
info('done')
|
|
|
|
|
|
def reset_admin(args):
|
|
'''reset seafile admin account'''
|
|
check_layout(args)
|
|
env = get_seahub_env()
|
|
|
|
argv = [PYTHON, 'manage.py', 'createsuperuser']
|
|
|
|
env = get_seahub_env()
|
|
seahub_dir = conf[CONF_SEAHUB_DIR]
|
|
run_argv(argv, cwd=seahub_dir, env=env)
|
|
|
|
|
|
def main():
|
|
check_seafile_install()
|
|
check_directory_layout()
|
|
|
|
parser = argparse.ArgumentParser()
|
|
subparsers = parser.add_subparsers(title='subcommands', description='')
|
|
|
|
parser_setup = subparsers.add_parser('setup',
|
|
help='setup the seafile server')
|
|
parser_setup.set_defaults(func=setup_seafile)
|
|
|
|
parser_start = subparsers.add_parser('start',
|
|
help='start the seafile server')
|
|
parser_start.set_defaults(func=start_seafile)
|
|
|
|
parser_start.add_argument('--fastcgi',
|
|
help='start seahub in fastcgi mode',
|
|
action='store_true')
|
|
|
|
parser_start.add_argument('--port',
|
|
help='start seahub in fastcgi mode',
|
|
default='8000')
|
|
|
|
parser_stop = subparsers.add_parser('stop', help='stop the seafile server')
|
|
parser_stop.set_defaults(func=stop_seafile)
|
|
|
|
parser_reset_admin = subparsers.add_parser(
|
|
'reset-admin',
|
|
help='reset seafile admin account')
|
|
parser_reset_admin.set_defaults(func=reset_admin)
|
|
|
|
parser_create_admin = subparsers.add_parser(
|
|
'create-admin',
|
|
help='create seafile admin account')
|
|
parser_create_admin.set_defaults(func=reset_admin)
|
|
|
|
args = parser.parse_args()
|
|
args.func(args)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|