2020-07-15 07:46:11 +00:00
|
|
|
#!/usr/bin/env python3
|
2020-07-13 10:14:54 +00:00
|
|
|
#coding: UTF-8
|
|
|
|
|
|
|
|
'''This script would guide the seafile admin to setup seafile with MySQL'''
|
|
|
|
import argparse
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import time
|
|
|
|
import re
|
|
|
|
import shutil
|
|
|
|
import glob
|
|
|
|
import subprocess
|
|
|
|
import hashlib
|
|
|
|
import getpass
|
|
|
|
import uuid
|
|
|
|
import warnings
|
|
|
|
import socket
|
|
|
|
from configparser import ConfigParser
|
|
|
|
|
|
|
|
import pymysql
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
import readline # pylint: disable=W0611
|
|
|
|
except ImportError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2020-07-14 08:46:48 +00:00
|
|
|
SERVER_MANUAL_HTTP = 'https://download.seafile.com/published/seafile-manual/home.md'
|
2020-07-13 10:14:54 +00:00
|
|
|
|
|
|
|
class Utils(object):
|
|
|
|
'''Groups all helper functions here'''
|
|
|
|
@staticmethod
|
|
|
|
def welcome():
|
|
|
|
'''Show welcome message'''
|
|
|
|
welcome_msg = '''\
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
This script will guide you to setup your seafile server using MySQL.
|
|
|
|
Make sure you have read seafile server manual at
|
|
|
|
|
|
|
|
%s
|
|
|
|
|
|
|
|
Press ENTER to continue
|
|
|
|
-----------------------------------------------------------------''' % SERVER_MANUAL_HTTP
|
|
|
|
print(welcome_msg)
|
|
|
|
input()
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def highlight(content):
|
|
|
|
'''Add ANSI color to content to get it highlighted on terminal'''
|
|
|
|
return '\x1b[33m%s\x1b[m' % content
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def info(msg):
|
|
|
|
print(msg)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def error(msg):
|
|
|
|
'''Print error and exit'''
|
|
|
|
print()
|
|
|
|
print('Error: ' + msg)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
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()
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
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()
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def get_command_output(args, *a, **kw):
|
|
|
|
return subprocess.check_output(args, *a, **kw)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def prepend_env_value(name, value, env=None, seperator=':'):
|
|
|
|
'''prepend a new value to a list'''
|
|
|
|
if env is None:
|
|
|
|
env = os.environ
|
|
|
|
|
|
|
|
try:
|
|
|
|
current_value = env[name]
|
|
|
|
except KeyError:
|
|
|
|
current_value = ''
|
|
|
|
|
|
|
|
new_value = value
|
|
|
|
if current_value:
|
|
|
|
new_value += seperator + current_value
|
|
|
|
|
|
|
|
env[name] = new_value
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def must_mkdir(path):
|
|
|
|
'''Create a directory, exit on failure'''
|
|
|
|
if os.path.exists(path):
|
|
|
|
return
|
|
|
|
try:
|
|
|
|
os.mkdir(path)
|
|
|
|
except OSError as e:
|
|
|
|
Utils.error('failed to create directory %s:%s' % (path, e))
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def must_copy(src, dst):
|
|
|
|
'''Copy src to dst, exit on failure'''
|
|
|
|
try:
|
|
|
|
shutil.copy(src, dst)
|
|
|
|
except Exception as e:
|
|
|
|
Utils.error('failed to copy %s to %s: %s' % (src, dst, e))
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def find_in_path(prog):
|
|
|
|
if 'win32' in sys.platform:
|
|
|
|
sep = ';'
|
|
|
|
else:
|
|
|
|
sep = ':'
|
|
|
|
|
|
|
|
dirs = os.environ['PATH'].split(sep)
|
|
|
|
for d in dirs:
|
|
|
|
d = d.strip()
|
|
|
|
if d == '':
|
|
|
|
continue
|
|
|
|
path = os.path.join(d, prog)
|
|
|
|
if os.path.exists(path):
|
|
|
|
return path
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def get_python_executable():
|
|
|
|
'''Return the python executable. This should be the PYTHON environment
|
|
|
|
variable which is set in setup-seafile-mysql.sh
|
|
|
|
|
|
|
|
'''
|
|
|
|
return os.environ['PYTHON']
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def read_config(fn):
|
|
|
|
'''Return a case sensitive ConfigParser by reading the file "fn"'''
|
|
|
|
cp = ConfigParser()
|
|
|
|
cp.optionxform = str
|
|
|
|
cp.read(fn)
|
|
|
|
|
|
|
|
return cp
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def write_config(cp, fn):
|
|
|
|
'''Return a case sensitive ConfigParser by reading the file "fn"'''
|
|
|
|
with open(fn, 'w') as fp:
|
|
|
|
cp.write(fp)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def ask_question(desc,
|
|
|
|
key=None,
|
|
|
|
note=None,
|
|
|
|
default=None,
|
|
|
|
validate=None,
|
|
|
|
yes_or_no=False,
|
|
|
|
password=False):
|
|
|
|
'''Ask a question, return the answer.
|
|
|
|
@desc description, e.g. "What is the port of ccnet?"
|
|
|
|
|
|
|
|
@key a name to represent the target of the question, e.g. "port for
|
|
|
|
ccnet server"
|
|
|
|
|
|
|
|
@note additional information for the question, e.g. "Must be a valid
|
|
|
|
port number"
|
|
|
|
|
|
|
|
@default the default value of the question. If the default value is
|
|
|
|
not None, when the user enter nothing and press [ENTER], the default
|
|
|
|
value would be returned
|
|
|
|
|
|
|
|
@validate a function that takes the user input as the only parameter
|
|
|
|
and validate it. It should return a validated value, or throws an
|
|
|
|
"InvalidAnswer" exception if the input is not valid.
|
|
|
|
|
|
|
|
@yes_or_no If true, the user must answer "yes" or "no", and a boolean
|
|
|
|
value would be returned
|
|
|
|
|
|
|
|
@password If true, the user input would not be echoed to the
|
|
|
|
console
|
|
|
|
|
|
|
|
'''
|
|
|
|
assert key or yes_or_no
|
|
|
|
# Format description
|
|
|
|
print()
|
|
|
|
if note:
|
|
|
|
desc += '\n' + note
|
|
|
|
|
|
|
|
desc += '\n'
|
|
|
|
if yes_or_no:
|
|
|
|
desc += '[ yes or no ]'
|
|
|
|
else:
|
|
|
|
if default:
|
|
|
|
desc += '[ default "%s" ]' % default
|
|
|
|
else:
|
|
|
|
desc += '[ %s ]' % key
|
|
|
|
|
|
|
|
desc += ' '
|
|
|
|
while True:
|
|
|
|
# prompt for user input
|
|
|
|
if password:
|
|
|
|
answer = getpass.getpass(desc).strip()
|
|
|
|
else:
|
|
|
|
answer = input(desc).strip()
|
|
|
|
|
|
|
|
# No user input: use default
|
|
|
|
if not answer:
|
|
|
|
if default:
|
|
|
|
answer = default
|
|
|
|
else:
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Have user input: validate answer
|
|
|
|
if yes_or_no:
|
|
|
|
if answer not in ['yes', 'no']:
|
|
|
|
print(Utils.highlight('\nPlease answer yes or no\n'))
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
return answer == 'yes'
|
|
|
|
else:
|
|
|
|
if validate:
|
|
|
|
try:
|
|
|
|
return validate(answer)
|
|
|
|
except InvalidAnswer as e:
|
|
|
|
print(Utils.highlight('\n%s\n' % e))
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
return answer
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def validate_port(port):
|
|
|
|
try:
|
|
|
|
port = int(port)
|
|
|
|
except ValueError:
|
|
|
|
raise InvalidAnswer('%s is not a valid port' % Utils.highlight(port))
|
|
|
|
|
|
|
|
if port <= 0 or port > 65535:
|
|
|
|
raise InvalidAnswer('%s is not a valid port' % Utils.highlight(port))
|
|
|
|
|
|
|
|
return port
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidAnswer(Exception):
|
|
|
|
def __init__(self, msg):
|
|
|
|
Exception.__init__(self)
|
|
|
|
self.msg = msg
|
|
|
|
def __str__(self):
|
|
|
|
return self.msg
|
|
|
|
|
|
|
|
class InvalidParams(Exception):
|
|
|
|
def __init__(self, msg):
|
|
|
|
Exception.__init__(self)
|
|
|
|
self.msg = msg
|
|
|
|
def __str__(self):
|
|
|
|
return self.msg
|
|
|
|
|
|
|
|
### END of Utils
|
|
|
|
####################
|
|
|
|
|
|
|
|
class EnvManager(object):
|
|
|
|
'''System environment and directory layout'''
|
|
|
|
def __init__(self):
|
|
|
|
self.install_path = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
self.top_dir = os.path.dirname(self.install_path)
|
|
|
|
self.bin_dir = os.path.join(self.install_path, 'seafile', 'bin')
|
|
|
|
self.central_config_dir = os.path.join(self.top_dir, 'conf')
|
2020-07-14 08:46:48 +00:00
|
|
|
self.central_pids_dir = os.path.join(self.top_dir, 'pids')
|
|
|
|
self.central_logs_dir = os.path.join(self.top_dir, 'logs')
|
2020-07-13 10:14:54 +00:00
|
|
|
Utils.must_mkdir(self.central_config_dir)
|
|
|
|
|
|
|
|
def check_pre_condiction(self):
|
|
|
|
def error_if_not_exists(path):
|
|
|
|
if not os.path.exists(path):
|
|
|
|
Utils.error('"%s" not found' % path)
|
|
|
|
|
|
|
|
paths = [
|
|
|
|
os.path.join(self.install_path, 'seafile'),
|
|
|
|
os.path.join(self.install_path, 'seahub'),
|
|
|
|
os.path.join(self.install_path, 'runtime'),
|
|
|
|
]
|
|
|
|
|
|
|
|
for path in paths:
|
|
|
|
error_if_not_exists(path)
|
|
|
|
|
|
|
|
if os.path.exists(ccnet_config.ccnet_dir):
|
|
|
|
Utils.error('Ccnet config dir \"%s\" already exists.' % ccnet_config.ccnet_dir)
|
|
|
|
|
|
|
|
def get_seahub_env(self):
|
|
|
|
'''Prepare for seahub syncdb'''
|
|
|
|
env = dict(os.environ)
|
|
|
|
env['CCNET_CONF_DIR'] = ccnet_config.ccnet_dir
|
|
|
|
env['SEAFILE_CONF_DIR'] = seafile_config.seafile_dir
|
|
|
|
env['SEAFES_DIR'] = os.path.join(self.install_path, 'pro', 'python', 'seafes')
|
|
|
|
self.setup_python_path(env)
|
|
|
|
return env
|
|
|
|
|
|
|
|
def setup_python_path(self, env):
|
|
|
|
'''And PYTHONPATH and CCNET_CONF_DIR/SEAFILE_CONF_DIR to env, which is
|
|
|
|
needed by seahub
|
|
|
|
|
|
|
|
'''
|
|
|
|
install_path = self.install_path
|
|
|
|
pro_pylibs_dir = os.path.join(install_path, 'pro', 'python')
|
|
|
|
extra_python_path = [
|
|
|
|
pro_pylibs_dir,
|
|
|
|
|
|
|
|
os.path.join(install_path, 'seahub', 'thirdpart'),
|
|
|
|
os.path.join(install_path, 'seahub-extra'),
|
|
|
|
os.path.join(install_path, 'seahub-extra', 'thirdparts'),
|
|
|
|
|
2020-07-14 08:46:48 +00:00
|
|
|
os.path.join(install_path, 'seafile/lib/python3.6/site-packages'),
|
|
|
|
os.path.join(install_path, 'seafile/lib64/python3.6/site-packages'),
|
2020-07-13 10:14:54 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
for path in extra_python_path:
|
|
|
|
Utils.prepend_env_value('PYTHONPATH', path, env=env)
|
|
|
|
|
|
|
|
def get_binary_env(self):
|
|
|
|
'''Set LD_LIBRARY_PATH for seafile server executables'''
|
|
|
|
env = dict(os.environ)
|
|
|
|
lib_dir = os.path.join(self.install_path, 'seafile', 'lib')
|
|
|
|
lib64_dir = os.path.join(self.install_path, 'seafile', 'lib64')
|
|
|
|
Utils.prepend_env_value('LD_LIBRARY_PATH', lib_dir, env=env)
|
|
|
|
Utils.prepend_env_value('LD_LIBRARY_PATH', lib64_dir, env=env)
|
|
|
|
return env
|
|
|
|
|
|
|
|
class AbstractConfigurator(object):
|
|
|
|
'''Abstract Base class for ccnet/seafile/seahub/db configurator'''
|
|
|
|
def __init__(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def ask_questions(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def generate(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
|
|
|
class AbstractDBConfigurator(AbstractConfigurator):
|
|
|
|
'''Abstract class for database related configuration'''
|
|
|
|
def __init__(self):
|
|
|
|
AbstractConfigurator.__init__(self)
|
|
|
|
self.mysql_host = 'localhost'
|
|
|
|
self.mysql_port = 3306
|
2020-07-14 08:46:48 +00:00
|
|
|
self.unix_socket = None
|
2020-07-13 10:14:54 +00:00
|
|
|
|
|
|
|
self.use_existing_db = False
|
|
|
|
|
|
|
|
self.seafile_mysql_user = ''
|
|
|
|
self.seafile_mysql_password = ''
|
2020-07-14 08:46:48 +00:00
|
|
|
self.seafile_mysql_userhost = '127.0.0.1'
|
2020-07-13 10:14:54 +00:00
|
|
|
|
|
|
|
self.root_password = ''
|
|
|
|
self.root_conn = ''
|
|
|
|
|
|
|
|
self.ccnet_db_name = ''
|
|
|
|
self.seafile_db_name = ''
|
|
|
|
self.seahub_db_name = ''
|
|
|
|
|
|
|
|
self.seahub_admin_email = ''
|
|
|
|
self.seahub_admin_password = ''
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def ask_use_existing_db():
|
|
|
|
def validate(choice):
|
|
|
|
if choice not in ['1', '2']:
|
|
|
|
raise InvalidAnswer('Please choose 1 or 2')
|
|
|
|
|
|
|
|
return choice == '2'
|
|
|
|
|
|
|
|
question = '''\
|
|
|
|
-------------------------------------------------------
|
|
|
|
Please choose a way to initialize seafile databases:
|
|
|
|
-------------------------------------------------------
|
|
|
|
'''
|
|
|
|
|
|
|
|
note = '''\
|
|
|
|
[1] Create new ccnet/seafile/seahub databases
|
|
|
|
[2] Use existing ccnet/seafile/seahub databases
|
|
|
|
'''
|
|
|
|
return Utils.ask_question(question,
|
|
|
|
key='1 or 2',
|
|
|
|
note=note,
|
|
|
|
validate=validate)
|
|
|
|
|
|
|
|
def validate_mysql_host(self, host):
|
|
|
|
if not re.match(r'^[a-zA-Z0-9_\-\.]+$', host):
|
|
|
|
raise InvalidAnswer('%s is not a valid host' % Utils.highlight(host))
|
|
|
|
|
|
|
|
if host == 'localhost':
|
|
|
|
host = '127.0.0.1'
|
|
|
|
return host
|
|
|
|
|
|
|
|
def ask_mysql_host(self):
|
|
|
|
question = 'What is the host of mysql server?'
|
|
|
|
key = 'mysql server host'
|
|
|
|
default = 'localhost'
|
|
|
|
self.mysql_host = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
default=default,
|
|
|
|
validate=self.validate_mysql_host)
|
|
|
|
|
|
|
|
def validate_mysql_user_host(self, host):
|
|
|
|
MYSQL_HOST_RE = re.compile(r'^(%|[^.].+\..+[^.])$')
|
|
|
|
if not MYSQL_HOST_RE.match(host):
|
|
|
|
raise InvalidAnswer('invalid mysql user host: {}'.format(host))
|
|
|
|
return host
|
|
|
|
|
|
|
|
def ask_mysql_user_host(self):
|
|
|
|
self.seafile_mysql_userhost = Utils.ask_question(
|
|
|
|
'From which hosts could the mysql account be used?',
|
|
|
|
key='mysql user host',
|
|
|
|
default='%',
|
|
|
|
validate=self.validate_mysql_user_host
|
|
|
|
)
|
|
|
|
|
|
|
|
def ask_mysql_port(self):
|
|
|
|
question = 'What is the port of mysql server?'
|
|
|
|
key = 'mysql server port'
|
|
|
|
default = '3306'
|
|
|
|
port = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
default=default,
|
|
|
|
validate=Utils.validate_port)
|
|
|
|
|
|
|
|
# self.check_mysql_server(host, port)
|
|
|
|
self.mysql_port = port
|
|
|
|
|
|
|
|
def ask_mysql_host_port(self):
|
|
|
|
self.ask_mysql_host()
|
|
|
|
if self.mysql_host != '127.0.0.1':
|
|
|
|
self.ask_mysql_user_host()
|
|
|
|
self.ask_mysql_port()
|
|
|
|
|
|
|
|
def check_mysql_server(self, host, port):
|
|
|
|
print('\nverifying mysql server running ... ', end=' ')
|
|
|
|
try:
|
|
|
|
dummy = pymysql.connect(host=host, port=port)
|
|
|
|
except Exception:
|
|
|
|
print()
|
|
|
|
raise InvalidAnswer('Failed to connect to mysql server at "%s:%s"' \
|
|
|
|
% (host, port))
|
|
|
|
|
|
|
|
print('done')
|
|
|
|
|
2020-07-14 08:46:48 +00:00
|
|
|
def check_mysql_user(self, user, password, host=None, unix_socket=None):
|
2020-07-13 10:14:54 +00:00
|
|
|
print('\nverifying password of user %s ... ' % user, end=' ')
|
2020-07-14 08:46:48 +00:00
|
|
|
kwargs = dict(port=self.mysql_port,
|
2020-07-13 10:14:54 +00:00
|
|
|
user=user,
|
|
|
|
passwd=password)
|
2020-07-14 08:46:48 +00:00
|
|
|
if unix_socket:
|
|
|
|
kwargs['unix_socket'] = unix_socket
|
|
|
|
else:
|
|
|
|
kwargs['host'] = host or self.mysql_host
|
2020-07-13 10:14:54 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
conn = pymysql.connect(**kwargs)
|
|
|
|
except Exception as e:
|
2020-07-14 08:46:48 +00:00
|
|
|
if isinstance(e, pymysql.err.OperationalError):
|
2020-07-13 10:14:54 +00:00
|
|
|
raise InvalidAnswer('Failed to connect to mysql server using user "%s" and password "***": %s' \
|
|
|
|
% (user, e.args[1]))
|
|
|
|
else:
|
|
|
|
raise InvalidAnswer('Failed to connect to mysql server using user "%s" and password "***": %s' \
|
|
|
|
% (user, e))
|
|
|
|
|
|
|
|
print('done')
|
|
|
|
return conn
|
|
|
|
|
|
|
|
def create_seahub_admin(self):
|
|
|
|
try:
|
|
|
|
conn = pymysql.connect(host=self.mysql_host,
|
|
|
|
port=self.mysql_port,
|
|
|
|
user=self.seafile_mysql_user,
|
|
|
|
passwd=self.seafile_mysql_password,
|
|
|
|
db=self.ccnet_db_name)
|
|
|
|
except Exception as e:
|
2020-07-14 08:46:48 +00:00
|
|
|
if isinstance(e, pymysql.err.OperationalError):
|
2020-07-13 10:14:54 +00:00
|
|
|
Utils.error('Failed to connect to mysql database %s: %s' % (self.ccnet_db_name, e.args[1]))
|
|
|
|
else:
|
|
|
|
Utils.error('Failed to connect to mysql database %s: %s' % (self.ccnet_db_name, e))
|
|
|
|
|
|
|
|
cursor = conn.cursor()
|
|
|
|
sql = '''\
|
|
|
|
CREATE TABLE IF NOT EXISTS EmailUser (id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, email VARCHAR(255), passwd CHAR(64), is_staff BOOL NOT NULL, is_active BOOL NOT NULL, ctime BIGINT, UNIQUE INDEX (email)) ENGINE=INNODB'''
|
|
|
|
|
|
|
|
try:
|
|
|
|
cursor.execute(sql)
|
|
|
|
except Exception as e:
|
2020-07-14 08:46:48 +00:00
|
|
|
if isinstance(e, pymysql.err.OperationalError):
|
2020-07-13 10:14:54 +00:00
|
|
|
Utils.error('Failed to create ccnet user table: %s' % e.args[1])
|
|
|
|
else:
|
|
|
|
Utils.error('Failed to create ccnet user table: %s' % e)
|
|
|
|
|
|
|
|
sql = '''REPLACE INTO EmailUser(email, passwd, is_staff, is_active, ctime) VALUES ('%s', '%s', 1, 1, 0)''' \
|
|
|
|
% (seahub_config.admin_email, seahub_config.hashed_admin_password())
|
|
|
|
|
|
|
|
try:
|
|
|
|
cursor.execute(sql)
|
|
|
|
except Exception as e:
|
2020-07-14 08:46:48 +00:00
|
|
|
if isinstance(e, pymysql.err.OperationalError):
|
2020-07-13 10:14:54 +00:00
|
|
|
Utils.error('Failed to create admin user: %s' % e.args[1])
|
|
|
|
else:
|
|
|
|
Utils.error('Failed to create admin user: %s' % e)
|
|
|
|
|
|
|
|
conn.commit()
|
|
|
|
|
|
|
|
def ask_questions(self):
|
|
|
|
'''Ask questions and do database operations'''
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
|
|
|
class NewDBConfigurator(AbstractDBConfigurator):
|
|
|
|
'''Handles the case of creating new mysql databases for ccnet/seafile/seahub'''
|
|
|
|
def __init__(self):
|
|
|
|
AbstractDBConfigurator.__init__(self)
|
|
|
|
|
|
|
|
def ask_questions(self):
|
|
|
|
self.ask_mysql_host_port()
|
|
|
|
|
|
|
|
self.ask_root_password()
|
|
|
|
self.ask_seafile_mysql_user_password()
|
|
|
|
|
|
|
|
self.ask_db_names()
|
|
|
|
|
|
|
|
def generate(self):
|
|
|
|
#if not self.mysql_user_exists(self.seafile_mysql_user):
|
|
|
|
# self.create_user()
|
|
|
|
#self.create_databases()
|
|
|
|
pass
|
|
|
|
|
|
|
|
def validate_root_passwd(self, password):
|
|
|
|
try:
|
|
|
|
self.root_conn = self.check_mysql_user('root', password)
|
|
|
|
except InvalidAnswer:
|
|
|
|
# For MariaDB on Ubuntu 16.04, the msyql root user can only be
|
|
|
|
# accessed from localhost with unix socket. So we retry with
|
|
|
|
# localhost when failing with 127.0.0.1.
|
|
|
|
if self.mysql_host == '127.0.0.1':
|
2020-07-14 08:46:48 +00:00
|
|
|
self.root_conn = self.check_mysql_user('root', password, unix_socket=self.unix_socket)
|
2020-07-13 10:14:54 +00:00
|
|
|
else:
|
|
|
|
raise
|
|
|
|
return password
|
|
|
|
|
|
|
|
def ask_root_password(self):
|
|
|
|
question = 'What is the password of the mysql root user?'
|
|
|
|
key = 'root password'
|
|
|
|
self.root_password = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
validate=self.validate_root_passwd,
|
|
|
|
password=True)
|
|
|
|
|
|
|
|
def mysql_user_exists(self, user):
|
|
|
|
cursor = self.root_conn.cursor()
|
|
|
|
|
|
|
|
sql = '''SELECT EXISTS(SELECT 1 FROM mysql.user WHERE user = '%s' and host = '%s')''' % \
|
|
|
|
(user, self.seafile_mysql_userhost)
|
|
|
|
|
|
|
|
try:
|
|
|
|
cursor.execute(sql)
|
|
|
|
return cursor.fetchall()[0][0]
|
|
|
|
except Exception as e:
|
2020-07-14 08:46:48 +00:00
|
|
|
if isinstance(e, pymysql.err.OperationalError):
|
2020-07-13 10:14:54 +00:00
|
|
|
Utils.error('Failed to check mysql user %s@%s: %s' % \
|
|
|
|
(user, self.seafile_mysql_userhost, e.args[1]))
|
|
|
|
else:
|
|
|
|
Utils.error('Failed to check mysql user %s@%s: %s' % \
|
|
|
|
(user, self.seafile_mysql_userhost, e))
|
|
|
|
finally:
|
|
|
|
cursor.close()
|
|
|
|
|
|
|
|
|
|
|
|
def ask_seafile_mysql_user_password(self):
|
|
|
|
def validate(user):
|
|
|
|
if user == 'root':
|
|
|
|
raise InvalidAnswer(
|
|
|
|
'Using mysql "root" user is not allowed for security reasons. Please specify a different database user.'
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
question = 'Enter the password for mysql user "%s":' % Utils.highlight(user)
|
|
|
|
key = 'password for %s' % user
|
|
|
|
password = Utils.ask_question(question, key=key, password=True)
|
|
|
|
# If the user already exists, check the password here
|
|
|
|
#if self.mysql_user_exists(user):
|
|
|
|
# self.check_mysql_user(user, password)
|
|
|
|
self.seafile_mysql_password = password
|
|
|
|
|
|
|
|
return user
|
|
|
|
|
|
|
|
|
|
|
|
question = 'Enter the name for mysql user of seafile. It would be created if not exists.'
|
|
|
|
key = 'mysql user for seafile'
|
|
|
|
default = 'seafile'
|
|
|
|
self.seafile_mysql_user = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
default=default,
|
|
|
|
validate=validate)
|
|
|
|
|
|
|
|
def ask_db_name(self, program, default):
|
|
|
|
question = 'Enter the database name for %s:' % program
|
|
|
|
key = '%s database' % program
|
|
|
|
return Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
default=default,
|
|
|
|
validate=self.validate_db_name)
|
|
|
|
|
|
|
|
def ask_db_names(self):
|
|
|
|
self.ccnet_db_name = self.ask_db_name('ccnet-server', 'ccnet-db')
|
|
|
|
self.seafile_db_name = self.ask_db_name('seafile-server', 'seafile-db')
|
|
|
|
self.seahub_db_name = self.ask_db_name('seahub', 'seahub-db')
|
|
|
|
|
|
|
|
def validate_db_name(self, db_name):
|
|
|
|
return db_name
|
|
|
|
|
|
|
|
def create_user(self):
|
|
|
|
cursor = self.root_conn.cursor()
|
|
|
|
sql = '''CREATE USER '{}'@'{}' IDENTIFIED BY '{}' '''.format(
|
|
|
|
self.seafile_mysql_user,
|
|
|
|
self.seafile_mysql_userhost,
|
|
|
|
self.seafile_mysql_password
|
|
|
|
)
|
|
|
|
|
|
|
|
try:
|
|
|
|
cursor.execute(sql)
|
|
|
|
except Exception as e:
|
2020-07-14 08:46:48 +00:00
|
|
|
if isinstance(e, pymysql.err.OperationalError):
|
2020-07-13 10:14:54 +00:00
|
|
|
Utils.error('Failed to create mysql user {}@{}: {}'.format(self.seafile_mysql_user, self.seafile_mysql_userhost, e.args[1]))
|
|
|
|
else:
|
|
|
|
Utils.error('Failed to create mysql user {}@{}: {}'.format(self.seafile_mysql_user, self.seafile_mysql_userhost, e))
|
|
|
|
finally:
|
|
|
|
cursor.close()
|
|
|
|
|
|
|
|
|
|
|
|
def create_db(self, db_name):
|
|
|
|
cursor = self.root_conn.cursor()
|
|
|
|
sql = '''CREATE DATABASE IF NOT EXISTS `%s` CHARACTER SET UTF8''' \
|
|
|
|
% db_name
|
|
|
|
|
|
|
|
try:
|
|
|
|
cursor.execute(sql)
|
|
|
|
except Exception as e:
|
2020-07-14 08:46:48 +00:00
|
|
|
if isinstance(e, pymysql.err.OperationalError):
|
2020-07-13 10:14:54 +00:00
|
|
|
Utils.error('Failed to create database %s: %s' % (db_name, e.args[1]))
|
|
|
|
else:
|
|
|
|
Utils.error('Failed to create database %s: %s' % (db_name, e))
|
|
|
|
finally:
|
|
|
|
cursor.close()
|
|
|
|
|
|
|
|
def grant_db_permission(self, db_name):
|
|
|
|
cursor = self.root_conn.cursor()
|
|
|
|
sql = '''GRANT ALL PRIVILEGES ON `{}`.* to `{}`@`{}` '''.format(
|
|
|
|
db_name,
|
|
|
|
self.seafile_mysql_user,
|
|
|
|
self.seafile_mysql_userhost
|
|
|
|
)
|
|
|
|
|
|
|
|
try:
|
|
|
|
cursor.execute(sql)
|
|
|
|
except Exception as e:
|
2020-07-14 08:46:48 +00:00
|
|
|
if isinstance(e, pymysql.err.OperationalError):
|
2020-07-13 10:14:54 +00:00
|
|
|
Utils.error('Failed to grant permission of database %s: %s' % (db_name, e.args[1]))
|
|
|
|
else:
|
|
|
|
Utils.error('Failed to grant permission of database %s: %s' % (db_name, e))
|
|
|
|
finally:
|
|
|
|
cursor.close()
|
|
|
|
|
|
|
|
def create_databases(self):
|
|
|
|
self.create_db(self.ccnet_db_name)
|
|
|
|
self.create_db(self.seafile_db_name)
|
|
|
|
self.create_db(self.seahub_db_name)
|
|
|
|
|
|
|
|
if self.seafile_mysql_user != 'root':
|
|
|
|
self.grant_db_permission(self.ccnet_db_name)
|
|
|
|
self.grant_db_permission(self.seafile_db_name)
|
|
|
|
self.grant_db_permission(self.seahub_db_name)
|
|
|
|
|
|
|
|
|
|
|
|
class ExistingDBConfigurator(AbstractDBConfigurator):
|
|
|
|
'''Handles the case of use existing mysql databases for ccnet/seafile/seahub'''
|
|
|
|
def __init__(self):
|
|
|
|
AbstractDBConfigurator.__init__(self)
|
|
|
|
self.use_existing_db = True
|
|
|
|
|
|
|
|
def ask_questions(self):
|
|
|
|
self.ask_mysql_host_port()
|
|
|
|
|
|
|
|
self.ask_existing_mysql_user_password()
|
|
|
|
|
|
|
|
self.ccnet_db_name = self.ask_db_name('ccnet')
|
|
|
|
self.seafile_db_name = self.ask_db_name('seafile')
|
|
|
|
self.seahub_db_name = self.ask_db_name('seahub')
|
|
|
|
|
|
|
|
def generate(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def ask_existing_mysql_user_password(self):
|
|
|
|
def validate(user):
|
|
|
|
if user == 'root':
|
|
|
|
raise InvalidAnswer(
|
|
|
|
'Using root is not allowed for security reasons. Please specify a different database user.'
|
|
|
|
)
|
|
|
|
question = 'What is the password for mysql user "%s"?' % Utils.highlight(user)
|
|
|
|
key = 'password for %s' % user
|
|
|
|
password = Utils.ask_question(question, key=key, password=True)
|
|
|
|
#self.check_mysql_user(user, password)
|
|
|
|
self.seafile_mysql_password = password
|
|
|
|
return user
|
|
|
|
|
|
|
|
question = 'Which mysql user to use for seafile?'
|
|
|
|
key = 'mysql user for seafile'
|
|
|
|
self.seafile_mysql_user = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
validate=validate)
|
|
|
|
|
|
|
|
def validate_db_name(self, db_name):
|
|
|
|
self.check_user_db_access(db_name)
|
|
|
|
return db_name
|
|
|
|
|
|
|
|
def ask_db_name(self, program):
|
|
|
|
question = 'Enter the existing database name for %s:' % program
|
|
|
|
key = '%s database' % program
|
|
|
|
return Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
validate=self.validate_db_name)
|
|
|
|
|
|
|
|
def check_user_db_access(self, db_name):
|
|
|
|
user = self.seafile_mysql_user
|
|
|
|
password = self.seafile_mysql_password
|
|
|
|
|
|
|
|
print('\nverifying user "%s" access to database %s ... ' % (user, db_name), end=' ')
|
|
|
|
try:
|
|
|
|
conn = pymysql.connect(host=self.mysql_host,
|
|
|
|
port=self.mysql_port,
|
|
|
|
user=user,
|
|
|
|
passwd=password,
|
|
|
|
db=db_name)
|
|
|
|
|
|
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute('show tables')
|
|
|
|
cursor.close()
|
|
|
|
except Exception as e:
|
2020-07-14 08:46:48 +00:00
|
|
|
if isinstance(e, pymysql.err.OperationalError):
|
2020-07-13 10:14:54 +00:00
|
|
|
raise InvalidAnswer('Failed to access database %s using user "%s" and password "***": %s' \
|
|
|
|
% (db_name, user, e.args[1]))
|
|
|
|
else:
|
|
|
|
raise InvalidAnswer('Failed to access database %s using user "%s" and password "***": %s' \
|
|
|
|
% (db_name, user, e))
|
|
|
|
|
|
|
|
print('done')
|
|
|
|
|
|
|
|
return conn
|
|
|
|
|
|
|
|
|
|
|
|
class CcnetConfigurator(AbstractConfigurator):
|
|
|
|
SERVER_NAME_REGEX = r'^[a-zA-Z0-9_\-]{3,15}$'
|
|
|
|
SERVER_IP_OR_DOMAIN_REGEX = r'^[^.].+\..+[^.]$'
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
'''Initialize default values of ccnet configuration'''
|
|
|
|
AbstractConfigurator.__init__(self)
|
|
|
|
self.ccnet_dir = os.path.join(env_mgr.top_dir, 'ccnet')
|
|
|
|
self.port = 10001
|
|
|
|
self.server_name = None
|
|
|
|
self.ip_or_domain = None
|
|
|
|
self.ccnet_conf = os.path.join(env_mgr.central_config_dir, 'ccnet.conf')
|
|
|
|
|
|
|
|
def ask_questions(self):
|
|
|
|
if not self.server_name:
|
|
|
|
self.ask_server_name()
|
|
|
|
if not self.ip_or_domain:
|
|
|
|
self.ask_server_ip_or_domain()
|
|
|
|
# self.ask_port()
|
|
|
|
|
|
|
|
def generate(self):
|
|
|
|
print('Generating ccnet configuration ...\n')
|
|
|
|
ccnet_init = os.path.join(env_mgr.bin_dir, 'ccnet-init')
|
|
|
|
argv = [
|
|
|
|
ccnet_init,
|
|
|
|
'-F', env_mgr.central_config_dir,
|
|
|
|
'--config-dir', self.ccnet_dir,
|
|
|
|
'--host', self.ip_or_domain,
|
|
|
|
]
|
|
|
|
|
|
|
|
if Utils.run_argv(argv, env=env_mgr.get_binary_env()) != 0:
|
|
|
|
Utils.error('Failed to generate ccnet configuration')
|
|
|
|
|
|
|
|
time.sleep(1)
|
|
|
|
self.generate_db_conf()
|
|
|
|
|
|
|
|
def generate_db_conf(self):
|
|
|
|
config = Utils.read_config(self.ccnet_conf)
|
|
|
|
# [Database]
|
|
|
|
# ENGINE=
|
|
|
|
# HOST=
|
|
|
|
# USER=
|
|
|
|
# PASSWD=
|
|
|
|
# DB=
|
|
|
|
db_section = 'Database'
|
|
|
|
if not config.has_section(db_section):
|
|
|
|
config.add_section(db_section)
|
|
|
|
config.set(db_section, 'ENGINE', 'mysql')
|
|
|
|
config.set(db_section, 'HOST', db_config.mysql_host)
|
2020-07-14 08:46:48 +00:00
|
|
|
config.set(db_section, 'PORT', str(db_config.mysql_port))
|
2020-07-13 10:14:54 +00:00
|
|
|
config.set(db_section, 'USER', db_config.seafile_mysql_user)
|
|
|
|
config.set(db_section, 'PASSWD', db_config.seafile_mysql_password)
|
|
|
|
config.set(db_section, 'DB', db_config.ccnet_db_name)
|
|
|
|
config.set(db_section, 'CONNECTION_CHARSET', 'utf8')
|
|
|
|
|
|
|
|
Utils.write_config(config, self.ccnet_conf)
|
|
|
|
|
|
|
|
def validate_server_name(self, name):
|
|
|
|
if not re.match(self.SERVER_NAME_REGEX, name):
|
|
|
|
raise InvalidAnswer('%s is not a valid name' % Utils.highlight(name))
|
|
|
|
return name
|
|
|
|
|
|
|
|
def ask_server_name(self):
|
|
|
|
question = 'What is the name of the server? It will be displayed on the client.'
|
|
|
|
key = 'server name'
|
|
|
|
note = '3 - 15 letters or digits'
|
|
|
|
self.server_name = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
note=note,
|
|
|
|
validate=self.validate_server_name)
|
|
|
|
|
|
|
|
def validate_server_ip(self, ip_or_domain):
|
|
|
|
if not re.match(self.SERVER_IP_OR_DOMAIN_REGEX, ip_or_domain):
|
|
|
|
raise InvalidAnswer('%s is not a valid ip or domain' % ip_or_domain)
|
|
|
|
return ip_or_domain
|
|
|
|
|
|
|
|
def ask_server_ip_or_domain(self):
|
|
|
|
question = 'What is the ip or domain of the server?'
|
|
|
|
key = 'This server\'s ip or domain'
|
|
|
|
note = 'For example: www.mycompany.com, 192.168.1.101'
|
|
|
|
self.ip_or_domain = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
note=note,
|
|
|
|
validate=self.validate_server_ip)
|
|
|
|
|
|
|
|
def ask_port(self):
|
|
|
|
def validate(port):
|
|
|
|
return Utils.validate_port(port)
|
|
|
|
|
|
|
|
question = 'Which port do you want to use for the ccnet server?'
|
|
|
|
key = 'ccnet server port'
|
|
|
|
default = 10001
|
|
|
|
self.port = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
default=default,
|
|
|
|
validate=validate)
|
|
|
|
|
|
|
|
|
|
|
|
class SeafileConfigurator(AbstractConfigurator):
|
|
|
|
def __init__(self):
|
|
|
|
AbstractConfigurator.__init__(self)
|
2020-07-14 08:46:48 +00:00
|
|
|
self.seafile_dir = os.path.join(env_mgr.top_dir, 'seafile-data')
|
2020-07-13 10:14:54 +00:00
|
|
|
self.port = 12001
|
|
|
|
self.fileserver_port = None
|
|
|
|
self.seafile_conf = os.path.join(env_mgr.central_config_dir, 'seafile.conf')
|
|
|
|
|
|
|
|
def ask_questions(self):
|
2020-07-14 08:46:48 +00:00
|
|
|
# if not self.seafile_dir:
|
|
|
|
# self.ask_seafile_dir()
|
2020-07-13 10:14:54 +00:00
|
|
|
# self.ask_port()
|
|
|
|
if not self.fileserver_port:
|
|
|
|
self.ask_fileserver_port()
|
|
|
|
|
|
|
|
def generate(self):
|
|
|
|
print('Generating seafile configuration ...\n')
|
|
|
|
seafserv_init = os.path.join(env_mgr.bin_dir, 'seaf-server-init')
|
|
|
|
argv = [
|
|
|
|
seafserv_init,
|
|
|
|
'-F', env_mgr.central_config_dir,
|
|
|
|
'--seafile-dir', self.seafile_dir,
|
|
|
|
'--fileserver-port', str(self.fileserver_port),
|
|
|
|
]
|
|
|
|
|
|
|
|
if Utils.run_argv(argv, env=env_mgr.get_binary_env()) != 0:
|
|
|
|
Utils.error('Failed to generate ccnet configuration')
|
|
|
|
|
|
|
|
time.sleep(1)
|
|
|
|
self.generate_db_conf()
|
2020-07-14 08:46:48 +00:00
|
|
|
|
|
|
|
## use default seafile-data path: seafile_data_dir=${TOPDIR}/seafile-data
|
|
|
|
# self.write_seafile_ini()
|
|
|
|
|
2020-07-13 10:14:54 +00:00
|
|
|
print('done')
|
|
|
|
|
|
|
|
def generate_db_conf(self):
|
|
|
|
config = Utils.read_config(self.seafile_conf)
|
|
|
|
# [database]
|
|
|
|
# type=
|
|
|
|
# host=
|
|
|
|
# user=
|
|
|
|
# password=
|
|
|
|
# db_name=
|
|
|
|
# unix_socket=
|
|
|
|
db_section = 'database'
|
|
|
|
if not config.has_section(db_section):
|
|
|
|
config.add_section(db_section)
|
|
|
|
config.set(db_section, 'type', 'mysql')
|
|
|
|
config.set(db_section, 'host', db_config.mysql_host)
|
2020-07-14 08:46:48 +00:00
|
|
|
config.set(db_section, 'port', str(db_config.mysql_port))
|
2020-07-13 10:14:54 +00:00
|
|
|
config.set(db_section, 'user', db_config.seafile_mysql_user)
|
|
|
|
config.set(db_section, 'password', db_config.seafile_mysql_password)
|
|
|
|
config.set(db_section, 'db_name', db_config.seafile_db_name)
|
|
|
|
config.set(db_section, 'connection_charset', 'utf8')
|
|
|
|
|
|
|
|
Utils.write_config(config, self.seafile_conf)
|
|
|
|
|
|
|
|
def validate_seafile_dir(self, path):
|
|
|
|
if os.path.exists(path):
|
|
|
|
raise InvalidAnswer('%s already exists' % Utils.highlight(path))
|
|
|
|
return path
|
|
|
|
|
|
|
|
def ask_seafile_dir(self):
|
|
|
|
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(env_mgr.top_dir, 'seafile-data')
|
|
|
|
self.seafile_dir = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
note=note,
|
|
|
|
default=default,
|
|
|
|
validate=self.validate_seafile_dir)
|
|
|
|
|
|
|
|
def ask_port(self):
|
|
|
|
def validate(port):
|
|
|
|
port = Utils.validate_port(port)
|
|
|
|
if port == ccnet_config.port:
|
|
|
|
raise InvalidAnswer('%s is used by ccnet server, choose another one' \
|
|
|
|
% Utils.highlight(port))
|
|
|
|
return port
|
|
|
|
|
|
|
|
question = 'Which port do you want to use for the seafile server?'
|
|
|
|
key = 'seafile server port'
|
|
|
|
default = 12001
|
|
|
|
self.port = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
default=default,
|
|
|
|
validate=validate)
|
|
|
|
|
|
|
|
def ask_fileserver_port(self):
|
|
|
|
question = 'Which port do you want to use for the seafile fileserver?'
|
|
|
|
key = 'seafile fileserver port'
|
|
|
|
default = 8082
|
|
|
|
self.fileserver_port = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
default=default,
|
|
|
|
validate=Utils.validate_port)
|
|
|
|
|
|
|
|
def write_seafile_ini(self):
|
|
|
|
seafile_ini = os.path.join(ccnet_config.ccnet_dir, 'seafile.ini')
|
|
|
|
with open(seafile_ini, 'w') as fp:
|
|
|
|
fp.write(self.seafile_dir)
|
|
|
|
|
|
|
|
class SeahubConfigurator(AbstractConfigurator):
|
|
|
|
def __init__(self):
|
|
|
|
AbstractConfigurator.__init__(self)
|
|
|
|
self.admin_email = ''
|
|
|
|
self.admin_password = ''
|
|
|
|
self.seahub_settings_py = os.path.join(env_mgr.central_config_dir, 'seahub_settings.py')
|
|
|
|
|
|
|
|
def hashed_admin_password(self):
|
|
|
|
return hashlib.sha1(self.admin_password).hexdigest() # pylint: disable=E1101
|
|
|
|
|
|
|
|
def ask_questions(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def generate(self):
|
|
|
|
'''Generating seahub_settings.py'''
|
|
|
|
print('Generating seahub configuration ...\n')
|
|
|
|
time.sleep(1)
|
|
|
|
with open(self.seahub_settings_py, 'w') as fp:
|
|
|
|
self.write_utf8_comment(fp)
|
|
|
|
fp.write('\n')
|
|
|
|
self.write_secret_key(fp)
|
|
|
|
fp.write('\n')
|
|
|
|
self.write_database_config(fp)
|
|
|
|
|
|
|
|
def write_utf8_comment(self, fp):
|
|
|
|
fp.write('# -*- coding: utf-8 -*-')
|
|
|
|
|
|
|
|
def write_secret_key(self, fp):
|
|
|
|
script = os.path.join(env_mgr.install_path, 'seahub/tools/secret_key_generator.py')
|
|
|
|
cmd = [
|
|
|
|
Utils.get_python_executable(),
|
|
|
|
script,
|
|
|
|
]
|
|
|
|
key = Utils.get_command_output(cmd).strip()
|
|
|
|
fp.write('SECRET_KEY = "%s"' % key)
|
|
|
|
|
|
|
|
def write_database_config(self, fp):
|
|
|
|
template = '''\
|
|
|
|
\nDATABASES = {
|
|
|
|
'default': {
|
|
|
|
'ENGINE': 'django.db.backends.mysql',
|
|
|
|
'NAME': '%(name)s',
|
|
|
|
'USER': '%(username)s',
|
|
|
|
'PASSWORD': '%(password)s',
|
|
|
|
'HOST': '%(host)s',
|
|
|
|
'PORT': '%(port)s'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
'''
|
|
|
|
text = template % dict(name=db_config.seahub_db_name,
|
|
|
|
username=db_config.seafile_mysql_user,
|
|
|
|
password=db_config.seafile_mysql_password,
|
|
|
|
host=db_config.mysql_host,
|
|
|
|
port=db_config.mysql_port)
|
|
|
|
|
|
|
|
fp.write(text)
|
|
|
|
|
|
|
|
def ask_admin_email(self):
|
|
|
|
print()
|
|
|
|
print('----------------------------------------')
|
|
|
|
print('Now let\'s create the admin account')
|
|
|
|
print('----------------------------------------')
|
|
|
|
def validate(email):
|
|
|
|
# whitespace is not allowed
|
|
|
|
if re.match(r'[\s]', email):
|
|
|
|
raise InvalidAnswer('%s is not a valid email address' % Utils.highlight(email))
|
|
|
|
# must be a valid email address
|
|
|
|
if not re.match(r'^.+@.*\..+$', email):
|
|
|
|
raise InvalidAnswer('%s is not a valid email address' % Utils.highlight(email))
|
|
|
|
|
|
|
|
return email
|
|
|
|
|
|
|
|
key = 'admin email'
|
|
|
|
question = 'What is the ' + Utils.highlight('email') + ' for the admin account?'
|
|
|
|
self.admin_email = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
validate=validate)
|
|
|
|
|
|
|
|
def ask_admin_password(self):
|
|
|
|
def validate(password):
|
|
|
|
key = 'admin password again'
|
|
|
|
question = 'Enter the ' + Utils.highlight('password again:')
|
|
|
|
password_again = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
password=True)
|
|
|
|
|
|
|
|
if password_again != password:
|
|
|
|
raise InvalidAnswer('password mismatch')
|
|
|
|
|
|
|
|
return password
|
|
|
|
|
|
|
|
key = 'admin password'
|
|
|
|
question = 'What is the ' + Utils.highlight('password') + ' for the admin account?'
|
|
|
|
self.admin_password = Utils.ask_question(question,
|
|
|
|
key=key,
|
|
|
|
password=True,
|
|
|
|
validate=validate)
|
|
|
|
|
|
|
|
def prepare_avatar_dir(self):
|
|
|
|
# media_dir=${INSTALLPATH}/seahub/media
|
|
|
|
# orig_avatar_dir=${INSTALLPATH}/seahub/media/avatars
|
|
|
|
# dest_avatar_dir=${TOPDIR}/seahub-data/avatars
|
|
|
|
|
|
|
|
# if [[ ! -d ${dest_avatar_dir} ]]; then
|
|
|
|
# mkdir -p "${TOPDIR}/seahub-data"
|
|
|
|
# mv "${orig_avatar_dir}" "${dest_avatar_dir}"
|
|
|
|
# ln -s ../../../seahub-data/avatars ${media_dir}
|
|
|
|
# fi
|
|
|
|
|
|
|
|
try:
|
|
|
|
media_dir = os.path.join(env_mgr.install_path, 'seahub', 'media')
|
|
|
|
orig_avatar_dir = os.path.join(media_dir, 'avatars')
|
|
|
|
|
|
|
|
seahub_data_dir = os.path.join(env_mgr.top_dir, 'seahub-data')
|
|
|
|
dest_avatar_dir = os.path.join(seahub_data_dir, 'avatars')
|
|
|
|
|
|
|
|
if os.path.exists(dest_avatar_dir):
|
|
|
|
return
|
|
|
|
|
|
|
|
if not os.path.exists(seahub_data_dir):
|
|
|
|
os.mkdir(seahub_data_dir)
|
|
|
|
|
|
|
|
shutil.move(orig_avatar_dir, dest_avatar_dir)
|
|
|
|
os.symlink('../../../seahub-data/avatars', orig_avatar_dir)
|
|
|
|
except Exception as e:
|
|
|
|
Utils.error('Failed to prepare seahub avatars dir: %s' % e)
|
|
|
|
|
|
|
|
class SeafDavConfigurator(AbstractConfigurator):
|
|
|
|
def __init__(self):
|
|
|
|
AbstractConfigurator.__init__(self)
|
|
|
|
self.seafdav_conf = None
|
|
|
|
|
|
|
|
def ask_questions(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def generate(self):
|
|
|
|
self.seafdav_conf = os.path.join(env_mgr.central_config_dir, 'seafdav.conf')
|
|
|
|
text = '''
|
|
|
|
[WEBDAV]
|
|
|
|
enabled = false
|
|
|
|
port = 8080
|
|
|
|
fastcgi = false
|
|
|
|
share_name = /
|
|
|
|
'''
|
|
|
|
|
|
|
|
with open(self.seafdav_conf, 'w') as fp:
|
|
|
|
fp.write(text)
|
|
|
|
|
|
|
|
class ProfessionalConfigurator(AbstractConfigurator):
|
|
|
|
'''Seafile Pro related configuration'''
|
|
|
|
def __init__(self):
|
|
|
|
AbstractConfigurator.__init__(self)
|
|
|
|
self.pro_py = os.path.join(env_mgr.install_path, 'pro', 'pro.py')
|
|
|
|
self.pro_data_dir = os.path.join(env_mgr.top_dir, 'pro-data')
|
|
|
|
|
|
|
|
def ask_questions(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def generate(self):
|
|
|
|
argv = [
|
|
|
|
Utils.get_python_executable(),
|
|
|
|
self.pro_py,
|
|
|
|
'setup',
|
|
|
|
'--mysql',
|
|
|
|
'--mysql_host=%s' % db_config.mysql_host,
|
|
|
|
'--mysql_port=%s' % db_config.mysql_port,
|
|
|
|
'--mysql_user=%s' % db_config.seafile_mysql_user,
|
|
|
|
'--mysql_password=%s' % db_config.seafile_mysql_password,
|
|
|
|
'--mysql_db=%s' % db_config.seahub_db_name,
|
|
|
|
]
|
|
|
|
if Utils.run_argv(argv, env=env_mgr.get_seahub_env()) != 0:
|
|
|
|
Utils.error('Failed to generate seafile pro configuration')
|
|
|
|
|
2020-07-14 08:46:48 +00:00
|
|
|
class GunicornConfigurator(AbstractConfigurator):
|
|
|
|
def __init__(self):
|
|
|
|
AbstractConfigurator.__init__(self)
|
|
|
|
self.gunicorn_conf = None
|
|
|
|
|
|
|
|
def ask_questions(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def generate(self):
|
|
|
|
self.gunicorn_conf = os.path.join(env_mgr.central_config_dir, 'gunicorn.conf.py')
|
|
|
|
template = '''
|
|
|
|
import os
|
|
|
|
|
|
|
|
daemon = True
|
|
|
|
workers = 5
|
|
|
|
|
|
|
|
# default localhost:8000
|
|
|
|
bind = "127.0.0.1:8000"
|
|
|
|
|
|
|
|
# Pid
|
|
|
|
pids_dir = '%(pids_dir)s'
|
|
|
|
pidfile = os.path.join(pids_dir, 'seahub.pid')
|
|
|
|
|
|
|
|
# for file upload, we need a longer timeout value (default is only 30s, too short)
|
|
|
|
timeout = 1200
|
|
|
|
|
|
|
|
limit_request_line = 8190
|
|
|
|
'''
|
|
|
|
|
|
|
|
text = template % dict(pids_dir=env_mgr.central_pids_dir,
|
|
|
|
logs_dir=env_mgr.central_logs_dir)
|
|
|
|
|
|
|
|
with open(self.gunicorn_conf, 'w') as fp:
|
|
|
|
fp.write(text)
|
|
|
|
|
|
|
|
|
2020-07-13 10:14:54 +00:00
|
|
|
class UserManualHandler(object):
|
|
|
|
def __init__(self):
|
|
|
|
self.src_docs_dir = os.path.join(env_mgr.install_path, 'seafile', 'docs')
|
|
|
|
self.library_template_dir = None
|
|
|
|
|
|
|
|
def copy_user_manuals(self):
|
|
|
|
self.library_template_dir = os.path.join(seafile_config.seafile_dir, 'library-template')
|
|
|
|
Utils.must_mkdir(self.library_template_dir)
|
|
|
|
|
|
|
|
pattern = os.path.join(self.src_docs_dir, '*.doc')
|
|
|
|
|
|
|
|
for doc in glob.glob(pattern):
|
|
|
|
Utils.must_copy(doc, self.library_template_dir)
|
|
|
|
|
|
|
|
def report_config():
|
|
|
|
print()
|
|
|
|
print('---------------------------------')
|
|
|
|
print('This is your configuration')
|
|
|
|
print('---------------------------------')
|
|
|
|
print()
|
|
|
|
|
|
|
|
template = '''\
|
|
|
|
server name: %(server_name)s
|
|
|
|
server ip/domain: %(ip_or_domain)s
|
|
|
|
|
|
|
|
seafile data dir: %(seafile_dir)s
|
|
|
|
fileserver port: %(fileserver_port)s
|
|
|
|
|
|
|
|
database: %(use_existing_db)s
|
|
|
|
ccnet database: %(ccnet_db_name)s
|
|
|
|
seafile database: %(seafile_db_name)s
|
|
|
|
seahub database: %(seahub_db_name)s
|
|
|
|
database user: %(db_user)s
|
|
|
|
|
|
|
|
'''
|
|
|
|
config = {
|
|
|
|
'server_name' : ccnet_config.server_name,
|
|
|
|
'ip_or_domain' : ccnet_config.ip_or_domain,
|
|
|
|
|
|
|
|
'seafile_dir' : seafile_config.seafile_dir,
|
|
|
|
'fileserver_port' : seafile_config.fileserver_port,
|
|
|
|
|
|
|
|
'admin_email' : seahub_config.admin_email,
|
|
|
|
|
|
|
|
|
|
|
|
'use_existing_db': 'use existing' if db_config.use_existing_db else 'create new',
|
|
|
|
'ccnet_db_name': db_config.ccnet_db_name,
|
|
|
|
'seafile_db_name': db_config.seafile_db_name,
|
|
|
|
'seahub_db_name': db_config.seahub_db_name,
|
|
|
|
'db_user': db_config.seafile_mysql_user
|
|
|
|
}
|
|
|
|
|
|
|
|
print(template % config)
|
|
|
|
|
|
|
|
if need_pause:
|
|
|
|
print()
|
|
|
|
print('---------------------------------')
|
|
|
|
print('Press ENTER to continue, or Ctrl-C to abort')
|
|
|
|
print('---------------------------------')
|
|
|
|
|
|
|
|
input()
|
|
|
|
|
|
|
|
|
2020-07-14 08:46:48 +00:00
|
|
|
def create_seafile_server_symlink():
|
|
|
|
print('\ncreating seafile-server-latest symbolic link ... ', end=' ')
|
|
|
|
seafile_server_symlink = os.path.join(env_mgr.top_dir, 'seafile-server-latest')
|
|
|
|
try:
|
|
|
|
os.symlink(os.path.basename(env_mgr.install_path), seafile_server_symlink)
|
|
|
|
except Exception as e:
|
|
|
|
print('\n')
|
|
|
|
Utils.error('Failed to create symbolic link %s: %s' % (seafile_server_symlink, e))
|
|
|
|
else:
|
|
|
|
print('done\n\n')
|
|
|
|
|
2020-07-13 10:14:54 +00:00
|
|
|
def set_file_perm():
|
|
|
|
filemode = 0o600
|
|
|
|
dirmode = 0o700
|
|
|
|
files = [
|
|
|
|
seahub_config.seahub_settings_py,
|
|
|
|
]
|
|
|
|
dirs = [
|
|
|
|
env_mgr.central_config_dir,
|
|
|
|
ccnet_config.ccnet_dir,
|
|
|
|
seafile_config.seafile_dir,
|
|
|
|
seahub_config.seahub_settings_py,
|
|
|
|
]
|
|
|
|
for fpath in files:
|
|
|
|
os.chmod(fpath, filemode)
|
|
|
|
for dpath in dirs:
|
|
|
|
os.chmod(dpath, dirmode)
|
|
|
|
|
|
|
|
env_mgr = EnvManager()
|
|
|
|
ccnet_config = CcnetConfigurator()
|
|
|
|
seafile_config = SeafileConfigurator()
|
|
|
|
seafdav_config = SeafDavConfigurator()
|
2020-07-14 08:46:48 +00:00
|
|
|
gunicorn_config = GunicornConfigurator()
|
2020-07-13 10:14:54 +00:00
|
|
|
seahub_config = SeahubConfigurator()
|
|
|
|
user_manuals_handler = UserManualHandler()
|
|
|
|
pro_config = ProfessionalConfigurator()
|
|
|
|
# Would be created after AbstractDBConfigurator.ask_use_existing_db()
|
|
|
|
db_config = None
|
|
|
|
need_pause = True
|
|
|
|
|
|
|
|
def get_param_val(arg, env, default=None):
|
|
|
|
return arg or os.environ.get(env, default)
|
|
|
|
|
|
|
|
def check_params(args):
|
|
|
|
server_name = 'seafile'
|
|
|
|
ccnet_config.server_name = ccnet_config.validate_server_name(server_name)
|
|
|
|
|
|
|
|
server_ip = get_param_val(args.server_ip, 'SERVER_IP', '127.0.0.1')
|
|
|
|
ccnet_config.ip_or_domain = ccnet_config.validate_server_ip(server_ip)
|
|
|
|
|
|
|
|
fileserver_port = get_param_val(args.fileserver_port, 'FILESERVER_PORT', '8082')
|
|
|
|
seafile_config.fileserver_port = Utils.validate_port(fileserver_port)
|
|
|
|
|
|
|
|
seafile_dir = get_param_val(args.seafile_dir, 'SEAFILE_DIR',
|
|
|
|
os.path.join(env_mgr.top_dir, 'seafile-data'))
|
|
|
|
seafile_config.seafile_dir = seafile_config.validate_seafile_dir(seafile_dir)
|
|
|
|
|
|
|
|
global db_config
|
|
|
|
|
|
|
|
use_existing_db = get_param_val(args.use_existing_db, 'USE_EXISTING_DB', '0')
|
|
|
|
# pylint: disable=redefined-variable-type
|
|
|
|
if use_existing_db == '0':
|
|
|
|
db_config = NewDBConfigurator()
|
|
|
|
elif use_existing_db == '1':
|
|
|
|
db_config = ExistingDBConfigurator()
|
|
|
|
else:
|
|
|
|
raise InvalidParams('Invalid use existing db parameter, the value can only be 0 or 1')
|
|
|
|
|
|
|
|
mysql_host = get_param_val(args.mysql_host, 'MYSQL_HOST', '127.0.0.1')
|
|
|
|
if not mysql_host:
|
|
|
|
raise InvalidParams('Incomplete mysql configuration parameters, ' \
|
|
|
|
'missing mysql host parameter')
|
|
|
|
db_config.mysql_host = db_config.validate_mysql_host(mysql_host)
|
|
|
|
|
|
|
|
mysql_port = get_param_val(args.mysql_port, 'MYSQL_PORT', '3306')
|
|
|
|
db_config.mysql_port = Utils.validate_port(mysql_port)
|
|
|
|
|
|
|
|
mysql_user = get_param_val(args.mysql_user, 'MYSQL_USER')
|
|
|
|
if not mysql_user:
|
|
|
|
raise InvalidParams('Incomplete mysql configuration parameters, ' \
|
|
|
|
'missing mysql user name parameter')
|
|
|
|
|
|
|
|
mysql_user_passwd = get_param_val(args.mysql_user_passwd, 'MYSQL_USER_PASSWD')
|
|
|
|
if not mysql_user_passwd:
|
|
|
|
raise InvalidParams('Incomplete mysql configuration parameters, ' \
|
|
|
|
'missing mysql user password parameter')
|
|
|
|
|
|
|
|
ccnet_db = get_param_val(args.ccnet_db, 'CCNET_DB', 'ccnet_db')
|
|
|
|
if not ccnet_db:
|
|
|
|
raise InvalidParams('Incomplete mysql configuration parameters, ' \
|
|
|
|
'missing ccnet db name parameter')
|
|
|
|
|
|
|
|
seafile_db = get_param_val(args.seafile_db, 'SEAFILE_DB', 'seafile_db')
|
|
|
|
if not seafile_db:
|
|
|
|
raise InvalidParams('Incomplete mysql configuration parameters, ' \
|
|
|
|
'missing seafile db name parameter')
|
|
|
|
|
|
|
|
seahub_db = get_param_val(args.seahub_db, 'SEAHUB_DB', 'seahub_db')
|
|
|
|
if not seahub_db:
|
|
|
|
raise InvalidParams('Incomplete mysql configuration parameters, ' \
|
|
|
|
'missing seahub db name parameter')
|
|
|
|
|
|
|
|
mysql_user_host = get_param_val(args.mysql_user_host, 'MYSQL_USER_HOST')
|
|
|
|
mysql_root_passwd = get_param_val(args.mysql_root_passwd, 'MYSQL_ROOT_PASSWD')
|
|
|
|
|
|
|
|
if db_config.use_existing_db:
|
|
|
|
db_config.check_mysql_user(mysql_user, mysql_user_passwd)
|
|
|
|
db_config.seafile_mysql_user = mysql_user
|
|
|
|
db_config.seafile_mysql_password = mysql_user_passwd
|
|
|
|
db_config.ccnet_db_name = db_config.validate_db_name(ccnet_db)
|
|
|
|
db_config.seafile_db_name = db_config.validate_db_name(seafile_db)
|
|
|
|
db_config.seahub_db_name = db_config.validate_db_name(seahub_db)
|
|
|
|
else:
|
|
|
|
if db_config.mysql_host != '127.0.0.1' and not mysql_user_host:
|
|
|
|
raise InvalidParams('mysql user host parameter is missing in creating new db mode')
|
|
|
|
if not mysql_user_host:
|
2020-07-14 08:46:48 +00:00
|
|
|
db_config.seafile_mysql_userhost = '127.0.0.1'
|
2020-07-13 10:14:54 +00:00
|
|
|
else:
|
|
|
|
db_config.seafile_mysql_userhost = db_config.validate_mysql_user_host(mysql_user_host)
|
|
|
|
|
|
|
|
if not mysql_root_passwd and "MYSQL_ROOT_PASSWD" not in os.environ:
|
|
|
|
raise InvalidParams('mysql root password parameter is missing in creating new db mode')
|
|
|
|
db_config.root_password = mysql_root_passwd
|
|
|
|
|
|
|
|
if mysql_user == 'root':
|
|
|
|
db_config.seafile_mysql_user = 'root'
|
|
|
|
db_config.seafile_mysql_password = db_config.root_password
|
|
|
|
else:
|
|
|
|
#if db_config.mysql_user_exists(mysql_user):
|
|
|
|
# db_config.check_mysql_user(mysql_user, mysql_user_passwd)
|
|
|
|
db_config.seafile_mysql_user = mysql_user
|
|
|
|
db_config.seafile_mysql_password = mysql_user_passwd
|
|
|
|
db_config.ccnet_db_name = ccnet_db
|
|
|
|
db_config.seafile_db_name = seafile_db
|
|
|
|
db_config.seahub_db_name = seahub_db
|
|
|
|
|
|
|
|
global need_pause
|
|
|
|
need_pause = False
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
if len(sys.argv) > 2 and sys.argv[1] == 'auto':
|
|
|
|
sys.argv.remove('auto')
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument('-n', '--server-name', help='server name')
|
|
|
|
parser.add_argument('-i', '--server-ip', help='server ip or domain')
|
|
|
|
parser.add_argument('-p', '--fileserver-port', help='fileserver port')
|
|
|
|
parser.add_argument('-d', '--seafile-dir', help='seafile dir to store seafile data')
|
|
|
|
parser.add_argument('-e', '--use-existing-db',
|
|
|
|
help='use mysql existing dbs or create new dbs, '
|
|
|
|
'0: create new dbs 1: use existing dbs')
|
|
|
|
parser.add_argument('-o', '--mysql-host', help='mysql host')
|
|
|
|
parser.add_argument('-t', '--mysql-port', help='mysql port')
|
|
|
|
parser.add_argument('-u', '--mysql-user', help='mysql user name')
|
|
|
|
parser.add_argument('-w', '--mysql-user-passwd', help='mysql user password')
|
|
|
|
parser.add_argument('-q', '--mysql-user-host', help='mysql user host')
|
|
|
|
parser.add_argument('-r', '--mysql-root-passwd', help='mysql root password')
|
|
|
|
parser.add_argument('-c', '--ccnet-db', help='ccnet db name')
|
|
|
|
parser.add_argument('-s', '--seafile-db', help='seafile db name')
|
|
|
|
parser.add_argument('-b', '--seahub-db', help='seahub db name')
|
|
|
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
try:
|
|
|
|
check_params(args)
|
|
|
|
except (InvalidAnswer, InvalidParams) as e:
|
|
|
|
print(Utils.highlight('\n%s\n' % e))
|
|
|
|
sys.exit(-1)
|
|
|
|
|
|
|
|
global db_config
|
|
|
|
|
|
|
|
if need_pause:
|
|
|
|
Utils.welcome()
|
|
|
|
warnings.filterwarnings('ignore', category=pymysql.Warning)
|
|
|
|
|
|
|
|
env_mgr.check_pre_condiction()
|
|
|
|
|
|
|
|
# Part 1: collect configuration
|
|
|
|
ccnet_config.ask_questions()
|
|
|
|
seafile_config.ask_questions()
|
|
|
|
seahub_config.ask_questions()
|
|
|
|
pro_config.ask_questions()
|
|
|
|
|
|
|
|
# pylint: disable=redefined-variable-type
|
|
|
|
if not db_config:
|
|
|
|
if AbstractDBConfigurator.ask_use_existing_db():
|
|
|
|
db_config = ExistingDBConfigurator()
|
|
|
|
else:
|
|
|
|
db_config = NewDBConfigurator()
|
|
|
|
|
|
|
|
db_config.ask_questions()
|
|
|
|
|
|
|
|
report_config()
|
|
|
|
|
|
|
|
# Part 2: generate configuration
|
|
|
|
db_config.generate()
|
|
|
|
ccnet_config.generate()
|
|
|
|
seafile_config.generate()
|
|
|
|
seafdav_config.generate()
|
2020-07-14 08:46:48 +00:00
|
|
|
gunicorn_config.generate()
|
2020-07-13 10:14:54 +00:00
|
|
|
seahub_config.generate()
|
|
|
|
pro_config.generate()
|
|
|
|
|
|
|
|
seahub_config.prepare_avatar_dir()
|
|
|
|
# db_config.create_seahub_admin()
|
|
|
|
user_manuals_handler.copy_user_manuals()
|
|
|
|
#create_seafile_server_symlink()
|
|
|
|
|
|
|
|
set_file_perm()
|
|
|
|
|
|
|
|
report_success()
|
|
|
|
|
|
|
|
def report_success():
|
|
|
|
message = '''\
|
|
|
|
|
|
|
|
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
Your seafile server configuration has been finished successfully.
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
|
|
|
run seafile server: ./seafile.sh { start | stop | restart }
|
|
|
|
run seahub server: ./seahub.sh { start <port> | stop | restart <port> }
|
|
|
|
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
If you are behind a firewall, remember to allow input/output of these tcp ports:
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
|
|
|
port of seafile fileserver: %(fileserver_port)s
|
|
|
|
port of seahub: 8000
|
|
|
|
|
|
|
|
When problems occur, Refer to
|
|
|
|
|
|
|
|
%(server_manual_http)s
|
|
|
|
|
|
|
|
for information.
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
print(message % dict(fileserver_port=seafile_config.fileserver_port,
|
|
|
|
server_manual_http=SERVER_MANUAL_HTTP))
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
try:
|
|
|
|
main()
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
print()
|
|
|
|
print(Utils.highlight('The setup process is aborted'))
|
|
|
|
print()
|