xref: /OpenGrok/docker/start.py (revision d2f093daaa520c55b671bc8f1b75d7cec4716bba)
1b2d29daeSVladimir Kotal#!/usr/bin/env python3
2b2d29daeSVladimir Kotal
3b2d29daeSVladimir Kotal# CDDL HEADER START
4b2d29daeSVladimir Kotal#
5b2d29daeSVladimir Kotal# The contents of this file are subject to the terms of the
6b2d29daeSVladimir Kotal# Common Development and Distribution License (the "License").
7b2d29daeSVladimir Kotal# You may not use this file except in compliance with the License.
8b2d29daeSVladimir Kotal#
9b2d29daeSVladimir Kotal# See LICENSE.txt included in this distribution for the specific
10b2d29daeSVladimir Kotal# language governing permissions and limitations under the License.
11b2d29daeSVladimir Kotal#
12b2d29daeSVladimir Kotal# When distributing Covered Code, include this CDDL HEADER in each
13b2d29daeSVladimir Kotal# file and include the License file at LICENSE.txt.
14b2d29daeSVladimir Kotal# If applicable, add the following below this CDDL HEADER, with the
15b2d29daeSVladimir Kotal# fields enclosed by brackets "[]" replaced with your own identifying
16b2d29daeSVladimir Kotal# information: Portions Copyright [yyyy] [name of copyright owner]
17b2d29daeSVladimir Kotal#
18b2d29daeSVladimir Kotal# CDDL HEADER END
19b2d29daeSVladimir Kotal
20b2d29daeSVladimir Kotal#
21b2d29daeSVladimir Kotal# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
22b2d29daeSVladimir Kotal#
23b2d29daeSVladimir Kotal
24b2d29daeSVladimir Kotalimport os
25b2d29daeSVladimir Kotalimport logging
26b2d29daeSVladimir Kotalimport multiprocessing
27b2d29daeSVladimir Kotalimport shutil
28b2d29daeSVladimir Kotalimport subprocess
29b2d29daeSVladimir Kotalimport threading
30b2d29daeSVladimir Kotalimport time
31d44cbea0SVladimir Kotalfrom pathlib import Path
32d44cbea0SVladimir Kotalfrom requests import get, ConnectionError
33b2d29daeSVladimir Kotal
34b2d29daeSVladimir Kotalfrom opengrok_tools.utils.log import get_console_logger, \
35b2d29daeSVladimir Kotal    get_log_level, get_class_basename
36b2d29daeSVladimir Kotalfrom opengrok_tools.deploy import deploy_war
37b2d29daeSVladimir Kotalfrom opengrok_tools.utils.indexer import Indexer
38b2d29daeSVladimir Kotalfrom opengrok_tools.sync import do_sync
39b2d29daeSVladimir Kotalfrom opengrok_tools.utils.opengrok import list_projects, \
40b2d29daeSVladimir Kotal    add_project, delete_project, get_configuration
41b2d29daeSVladimir Kotalfrom opengrok_tools.utils.readconfig import read_config
42b2d29daeSVladimir Kotalfrom opengrok_tools.utils.exitvals import SUCCESS_EXITVAL
43b2d29daeSVladimir Kotal
44b2d29daeSVladimir Kotal
45b2d29daeSVladimir Kotalfs_root = os.path.abspath('.').split(os.path.sep)[0] + os.path.sep
46b2d29daeSVladimir Kotalif os.environ.get('OPENGROK_TOMCAT_ROOT'):  # debug only
47b2d29daeSVladimir Kotal    tomcat_root = os.environ.get('OPENGROK_TOMCAT_ROOT')
48b2d29daeSVladimir Kotalelse:
49b2d29daeSVladimir Kotal    tomcat_root = os.path.join(fs_root, "usr", "local", "tomcat")
50b2d29daeSVladimir Kotal
51b2d29daeSVladimir Kotalif os.environ.get('OPENGROK_ROOT'):  # debug only
52b2d29daeSVladimir Kotal    OPENGROK_BASE_DIR = os.environ.get('OPENGROK_ROOT')
53b2d29daeSVladimir Kotalelse:
54b2d29daeSVladimir Kotal    OPENGROK_BASE_DIR = os.path.join(fs_root, "opengrok")
55b2d29daeSVladimir Kotal
56b2d29daeSVladimir KotalOPENGROK_LIB_DIR = os.path.join(OPENGROK_BASE_DIR, "lib")
57b2d29daeSVladimir KotalOPENGROK_DATA_ROOT = os.path.join(OPENGROK_BASE_DIR, "data")
58b2d29daeSVladimir KotalOPENGROK_SRC_ROOT = os.path.join(OPENGROK_BASE_DIR, "src")
59b2d29daeSVladimir KotalBODY_INCLUDE_FILE = os.path.join(OPENGROK_DATA_ROOT, "body_include")
60b2d29daeSVladimir KotalOPENGROK_CONFIG_FILE = os.path.join(OPENGROK_BASE_DIR, "etc",
61b2d29daeSVladimir Kotal                                    "configuration.xml")
62b2d29daeSVladimir KotalOPENGROK_WEBAPPS_DIR = os.path.join(tomcat_root, "webapps")
634810eb96SVladimir KotalOPENGROK_JAR = os.path.join(OPENGROK_LIB_DIR, 'opengrok.jar')
64b2d29daeSVladimir Kotal
65b2d29daeSVladimir Kotal
66f7d6d77cSVladimir Kotaldef set_url_root(logger, url_root):
67b2d29daeSVladimir Kotal    """
68b2d29daeSVladimir Kotal    Set URL root and URI based on input
69788f14d3SVladimir Kotal    :param logger: logger instance
70b2d29daeSVladimir Kotal    :param url_root: input
71b2d29daeSVladimir Kotal    :return: URI and URL root
72b2d29daeSVladimir Kotal    """
73b2d29daeSVladimir Kotal    if not url_root:
74b2d29daeSVladimir Kotal        url_root = '/'
75b2d29daeSVladimir Kotal
76b2d29daeSVladimir Kotal    if ' ' in url_root:
77b2d29daeSVladimir Kotal        logger.warn('Deployment path contains spaces. Deploying to root')
78b2d29daeSVladimir Kotal        url_root = '/'
79b2d29daeSVladimir Kotal
80b2d29daeSVladimir Kotal    # Remove leading and trailing slashes
81b2d29daeSVladimir Kotal    if url_root.startswith('/'):
82b2d29daeSVladimir Kotal        url_root = url_root[1:]
83b2d29daeSVladimir Kotal    if url_root.endswith('/'):
84b2d29daeSVladimir Kotal        url_root = url_root[:-1]
85b2d29daeSVladimir Kotal
86b2d29daeSVladimir Kotal    uri = "http://localhost:8080/" + url_root
87b2d29daeSVladimir Kotal    #
88b2d29daeSVladimir Kotal    # Make sure URI ends with slash. This is important for the various API
89b2d29daeSVladimir Kotal    # calls, notably for those that check the HTTP error code.
90b2d29daeSVladimir Kotal    # Normally accessing the URI without the terminating slash results in
91b2d29daeSVladimir Kotal    # HTTP redirect (code 302) instead of success (200).
92b2d29daeSVladimir Kotal    #
93b2d29daeSVladimir Kotal    if not uri.endswith('/'):
94b2d29daeSVladimir Kotal        uri = uri + '/'
95b2d29daeSVladimir Kotal
96b2d29daeSVladimir Kotal    return uri, url_root
97b2d29daeSVladimir Kotal
98b2d29daeSVladimir Kotal
99b2d29daeSVladimir Kotaldef get_war_name(url_root):
100d44cbea0SVladimir Kotal    """
101d44cbea0SVladimir Kotal    :param url_root: web app URL root
102d44cbea0SVladimir Kotal    :return: filename of the WAR file
103d44cbea0SVladimir Kotal    """
104b2d29daeSVladimir Kotal    if len(url_root) == 0:
105b2d29daeSVladimir Kotal        return "ROOT.war"
106f7d6d77cSVladimir Kotal
107b2d29daeSVladimir Kotal    return url_root + ".war"
108b2d29daeSVladimir Kotal
109b2d29daeSVladimir Kotal
110f7d6d77cSVladimir Kotaldef deploy(logger, url_root):
111b2d29daeSVladimir Kotal    """
112b2d29daeSVladimir Kotal    Deploy the web application
113788f14d3SVladimir Kotal    :param logger: logger instance
114b2d29daeSVladimir Kotal    :param url_root: web app URL root
115b2d29daeSVladimir Kotal    """
116b2d29daeSVladimir Kotal
117b2d29daeSVladimir Kotal    logger.info('Deploying web application')
118b2d29daeSVladimir Kotal    webapps_dir = os.path.join(tomcat_root, 'webapps')
119b2d29daeSVladimir Kotal    if not os.path.isdir(webapps_dir):
120b2d29daeSVladimir Kotal        raise Exception("{} is not a directory".format(webapps_dir))
121b2d29daeSVladimir Kotal
122b2d29daeSVladimir Kotal    for item in os.listdir(webapps_dir):
123b2d29daeSVladimir Kotal        subdir = os.path.join(webapps_dir, item)
124b2d29daeSVladimir Kotal        if os.path.isdir(subdir):
125b2d29daeSVladimir Kotal            logger.debug("Removing '{}' directory recursively".format(subdir))
126b2d29daeSVladimir Kotal            shutil.rmtree(subdir)
127b2d29daeSVladimir Kotal
128b2d29daeSVladimir Kotal    deploy_war(logger, os.path.join(OPENGROK_LIB_DIR, "source.war"),
129b2d29daeSVladimir Kotal               os.path.join(OPENGROK_WEBAPPS_DIR, get_war_name(url_root)),
130b2d29daeSVladimir Kotal               OPENGROK_CONFIG_FILE, None)
131b2d29daeSVladimir Kotal
132b2d29daeSVladimir Kotal
133f7d6d77cSVladimir Kotaldef setup_redirect_source(logger, url_root):
134b2d29daeSVladimir Kotal    """
135b2d29daeSVladimir Kotal    Set up redirect from /source
136b2d29daeSVladimir Kotal    """
137b2d29daeSVladimir Kotal    logger.debug("Setting up redirect from /source to '{}'".format(url_root))
138b2d29daeSVladimir Kotal    source_dir = os.path.join(OPENGROK_WEBAPPS_DIR, "source")
139b2d29daeSVladimir Kotal    if not os.path.isdir(source_dir):
140b2d29daeSVladimir Kotal        os.makedirs(source_dir)
141b2d29daeSVladimir Kotal
142b2d29daeSVladimir Kotal    with open(os.path.join(source_dir, "index.jsp"), "w+") as index:
143b2d29daeSVladimir Kotal        index.write("<% response.sendRedirect(\"/{}\"); %>".format(url_root))
144b2d29daeSVladimir Kotal
145b2d29daeSVladimir Kotal
146f7d6d77cSVladimir Kotaldef wait_for_tomcat(logger, uri):
147b2d29daeSVladimir Kotal    """
148b2d29daeSVladimir Kotal    Active/busy waiting for Tomcat to come up.
149b2d29daeSVladimir Kotal    Currently there is no upper time bound.
150b2d29daeSVladimir Kotal    """
151b2d29daeSVladimir Kotal    logger.info("Waiting for Tomcat to start")
152b2d29daeSVladimir Kotal
153b2d29daeSVladimir Kotal    while True:
154b2d29daeSVladimir Kotal        try:
155d44cbea0SVladimir Kotal            ret = get(uri)
156d44cbea0SVladimir Kotal            status = ret.status_code
157b2d29daeSVladimir Kotal        except ConnectionError:
158b2d29daeSVladimir Kotal            status = 0
159b2d29daeSVladimir Kotal
160b2d29daeSVladimir Kotal        if status != 200:
161b2d29daeSVladimir Kotal            logger.debug("Got status {} for {}, sleeping for 1 second".
162b2d29daeSVladimir Kotal                         format(status, uri))
163b2d29daeSVladimir Kotal            time.sleep(1)
164b2d29daeSVladimir Kotal        else:
165b2d29daeSVladimir Kotal            break
166b2d29daeSVladimir Kotal
167b2d29daeSVladimir Kotal    logger.info("Tomcat is ready")
168b2d29daeSVladimir Kotal
169b2d29daeSVladimir Kotal
170f7d6d77cSVladimir Kotaldef refresh_projects(logger, uri):
171b2d29daeSVladimir Kotal    """
172b2d29daeSVladimir Kotal    Ensure each immediate source root subdirectory is a project.
173b2d29daeSVladimir Kotal    """
174b2d29daeSVladimir Kotal    webapp_projects = list_projects(logger, uri)
175b2d29daeSVladimir Kotal    logger.debug('Projects from the web app: {}'.format(webapp_projects))
176b2d29daeSVladimir Kotal    src_root = OPENGROK_SRC_ROOT
177b2d29daeSVladimir Kotal
178b2d29daeSVladimir Kotal    # Add projects.
179b2d29daeSVladimir Kotal    for item in os.listdir(src_root):
180b2d29daeSVladimir Kotal        logger.debug('Got item {}'.format(item))
181b2d29daeSVladimir Kotal        if os.path.isdir(os.path.join(src_root, item)):
182b2d29daeSVladimir Kotal            if item not in webapp_projects:
183b2d29daeSVladimir Kotal                logger.info("Adding project {}".format(item))
184b2d29daeSVladimir Kotal                add_project(logger, item, uri)
185b2d29daeSVladimir Kotal
186b2d29daeSVladimir Kotal    # Remove projects
187b2d29daeSVladimir Kotal    for item in webapp_projects:
188b2d29daeSVladimir Kotal        if not os.path.isdir(os.path.join(src_root, item)):
189b2d29daeSVladimir Kotal            logger.info("Deleting project {}".format(item))
190b2d29daeSVladimir Kotal            delete_project(logger, item, uri)
191b2d29daeSVladimir Kotal
192b2d29daeSVladimir Kotal
193f7d6d77cSVladimir Kotaldef save_config(logger, uri, config_path):
194b2d29daeSVladimir Kotal    """
195b2d29daeSVladimir Kotal    Retrieve configuration from the web app and write it to file.
196788f14d3SVladimir Kotal    :param logger: logger instance
197b2d29daeSVladimir Kotal    :param uri: web app URI
198b2d29daeSVladimir Kotal    :param config_path: file path
199b2d29daeSVladimir Kotal    """
200b2d29daeSVladimir Kotal
201b2d29daeSVladimir Kotal    logger.info('Saving configuration to {}'.format(config_path))
202b2d29daeSVladimir Kotal    config = get_configuration(logger, uri)
203b2d29daeSVladimir Kotal    with open(config_path, "w+") as config_file:
204b2d29daeSVladimir Kotal        config_file.write(config)
205b2d29daeSVladimir Kotal
206b2d29daeSVladimir Kotal
207b2d29daeSVladimir Kotaldef merge_commands_env(commands, env):
208b2d29daeSVladimir Kotal    """
209b2d29daeSVladimir Kotal    Merge environment into command structure. If any of the commands has
210b2d29daeSVladimir Kotal    an environment already set, the env is merged in.
211b2d29daeSVladimir Kotal    :param commands: commands structure
212b2d29daeSVladimir Kotal    :param env: environment dictionary
213b2d29daeSVladimir Kotal    :return: updated commands structure
214b2d29daeSVladimir Kotal    """
215b2d29daeSVladimir Kotal    for cmd in commands:
216b2d29daeSVladimir Kotal        cmd_env = cmd.get('env')
217b2d29daeSVladimir Kotal        if cmd_env:
218b2d29daeSVladimir Kotal            cmd.env.update(env)
219b2d29daeSVladimir Kotal        else:
220b2d29daeSVladimir Kotal            cmd['env'] = env
221b2d29daeSVladimir Kotal
222b2d29daeSVladimir Kotal    return commands
223b2d29daeSVladimir Kotal
224b2d29daeSVladimir Kotal
2254810eb96SVladimir Kotaldef indexer_no_projects(logger, uri, config_path, sync_period,
2264810eb96SVladimir Kotal                        extra_indexer_options):
2274810eb96SVladimir Kotal    """
2284810eb96SVladimir Kotal    Project less indexer
2294810eb96SVladimir Kotal    """
2304810eb96SVladimir Kotal
2314810eb96SVladimir Kotal    wait_for_tomcat(logger, uri)
2324810eb96SVladimir Kotal
2334810eb96SVladimir Kotal    while True:
2344810eb96SVladimir Kotal        indexer_options = ['-s', OPENGROK_SRC_ROOT,
2354810eb96SVladimir Kotal                           '-d', OPENGROK_DATA_ROOT,
2364810eb96SVladimir Kotal                           '-c', '/usr/local/bin/ctags',
2374810eb96SVladimir Kotal                           '--remote', 'on',
2384810eb96SVladimir Kotal                           '-H',
2394810eb96SVladimir Kotal                           '-W', config_path,
2404810eb96SVladimir Kotal                           '-U', uri]
2414810eb96SVladimir Kotal        if extra_indexer_options:
2424810eb96SVladimir Kotal            logger.debug("Adding extra indexer options: {}".
2434810eb96SVladimir Kotal                         format(extra_indexer_options))
2444810eb96SVladimir Kotal            indexer_options.extend(extra_indexer_options.split())
2454810eb96SVladimir Kotal        indexer = Indexer(indexer_options, logger=logger,
246*d2f093daSVladimir Kotal                          jar=OPENGROK_JAR, doprint=True)
2474810eb96SVladimir Kotal        indexer.execute()
2484810eb96SVladimir Kotal
2494810eb96SVladimir Kotal        sleep_seconds = sync_period * 60
2504810eb96SVladimir Kotal        logger.info("Sleeping for {} seconds".format(sleep_seconds))
2514810eb96SVladimir Kotal        time.sleep(sleep_seconds)
2524810eb96SVladimir Kotal
2534810eb96SVladimir Kotal
2544810eb96SVladimir Kotaldef project_syncer(logger, loglevel, uri, config_path, sync_period,
2554810eb96SVladimir Kotal                   numworkers, env):
256b2d29daeSVladimir Kotal    """
257b2d29daeSVladimir Kotal    Wrapper for running opengrok-sync.
258b2d29daeSVladimir Kotal    To be run in a thread/process in the background.
259b2d29daeSVladimir Kotal    """
260b2d29daeSVladimir Kotal
261f7d6d77cSVladimir Kotal    wait_for_tomcat(logger, uri)
262b2d29daeSVladimir Kotal
263b2d29daeSVladimir Kotal    while True:
264f7d6d77cSVladimir Kotal        refresh_projects(logger, uri)
265b2d29daeSVladimir Kotal
266b2d29daeSVladimir Kotal        if os.environ.get('OPENGROK_SYNC_YML'):  # debug only
267b2d29daeSVladimir Kotal            config_file = os.environ.get('OPENGROK_SYNC_YML')
268b2d29daeSVladimir Kotal        else:
269b2d29daeSVladimir Kotal            config_file = os.path.join(fs_root, 'scripts', 'sync.yml')
270b2d29daeSVladimir Kotal        config = read_config(logger, config_file)
271b2d29daeSVladimir Kotal        if config is None:
272b2d29daeSVladimir Kotal            logger.error("Cannot read config file from {}".format(config_file))
273b2d29daeSVladimir Kotal            raise Exception("no sync config")
274b2d29daeSVladimir Kotal
275b2d29daeSVladimir Kotal        projects = list_projects(logger, uri)
276b2d29daeSVladimir Kotal        #
277b2d29daeSVladimir Kotal        # The driveon=True is needed for the initial indexing of newly
278b2d29daeSVladimir Kotal        # added project, otherwise the incoming check in the opengrok-mirror
2793d5852a4SVladimir Kotal        # program would short circuit it.
280b2d29daeSVladimir Kotal        #
281b2d29daeSVladimir Kotal        if env:
282b2d29daeSVladimir Kotal            logger.info('Merging commands with environment')
283b2d29daeSVladimir Kotal            commands = merge_commands_env(config["commands"], env)
284b2d29daeSVladimir Kotal            logger.debug(config['commands'])
285b2d29daeSVladimir Kotal        else:
286b2d29daeSVladimir Kotal            commands = config["commands"]
287b2d29daeSVladimir Kotal
288b2d29daeSVladimir Kotal        logger.info("Sync starting")
289b2d29daeSVladimir Kotal        do_sync(loglevel, commands, config.get('cleanup'),
290b2d29daeSVladimir Kotal                projects, config.get("ignore_errors"), uri,
291b2d29daeSVladimir Kotal                numworkers, driveon=True, logger=logger, print_output=True)
292b2d29daeSVladimir Kotal        logger.info("Sync done")
293b2d29daeSVladimir Kotal
294b2d29daeSVladimir Kotal        # Workaround for https://github.com/oracle/opengrok/issues/1670
295b2d29daeSVladimir Kotal        Path(os.path.join(OPENGROK_DATA_ROOT, 'timestamp')).touch()
296b2d29daeSVladimir Kotal
297f7d6d77cSVladimir Kotal        save_config(logger, uri, config_path)
298b2d29daeSVladimir Kotal
2993d5852a4SVladimir Kotal        sleep_seconds = sync_period * 60
300b2d29daeSVladimir Kotal        logger.info("Sleeping for {} seconds".format(sleep_seconds))
301b2d29daeSVladimir Kotal        time.sleep(sleep_seconds)
302b2d29daeSVladimir Kotal
303b2d29daeSVladimir Kotal
3044810eb96SVladimir Kotaldef create_bare_config(logger, use_projects=True):
305b2d29daeSVladimir Kotal    """
306b2d29daeSVladimir Kotal    Create bare configuration file with a few basic settings.
307b2d29daeSVladimir Kotal    """
308b2d29daeSVladimir Kotal
309b2d29daeSVladimir Kotal    logger.info('Creating bare configuration in {}'.
310b2d29daeSVladimir Kotal                format(OPENGROK_CONFIG_FILE))
3114810eb96SVladimir Kotal    indexer_options = ['-s', OPENGROK_SRC_ROOT,
312b2d29daeSVladimir Kotal                       '-d', OPENGROK_DATA_ROOT,
313b2d29daeSVladimir Kotal                       '-c', '/usr/local/bin/ctags',
314b2d29daeSVladimir Kotal                       '--remote', 'on',
3154810eb96SVladimir Kotal                       '-H',
316b2d29daeSVladimir Kotal                       '-W', OPENGROK_CONFIG_FILE,
3174810eb96SVladimir Kotal                       '--noIndex']
3184810eb96SVladimir Kotal    if use_projects:
3194810eb96SVladimir Kotal        indexer_options.append('-P')
3204810eb96SVladimir Kotal
3214810eb96SVladimir Kotal    indexer = Indexer(indexer_options,
3224810eb96SVladimir Kotal                      jar=OPENGROK_JAR,
323b2d29daeSVladimir Kotal                      logger=logger, doprint=True)
324b2d29daeSVladimir Kotal    indexer.execute()
325b2d29daeSVladimir Kotal    ret = indexer.getretcode()
326b2d29daeSVladimir Kotal    if ret != SUCCESS_EXITVAL:
327b2d29daeSVladimir Kotal        logger.error('Command returned {}'.format(ret))
328b2d29daeSVladimir Kotal        logger.error(indexer.geterroutput())
329b2d29daeSVladimir Kotal        raise Exception("Failed to create bare configuration")
330b2d29daeSVladimir Kotal
331b2d29daeSVladimir Kotal
332f7d6d77cSVladimir Kotaldef main():
333b2d29daeSVladimir Kotal    log_level = os.environ.get('OPENGROK_LOG_LEVEL')
334b2d29daeSVladimir Kotal    if log_level:
335b2d29daeSVladimir Kotal        log_level = get_log_level(log_level)
336b2d29daeSVladimir Kotal    else:
337b2d29daeSVladimir Kotal        log_level = logging.INFO
338b2d29daeSVladimir Kotal
339b2d29daeSVladimir Kotal    logger = get_console_logger(get_class_basename(), log_level)
340b2d29daeSVladimir Kotal
341f7d6d77cSVladimir Kotal    uri, url_root = set_url_root(logger, os.environ.get('URL_ROOT'))
342f7d6d77cSVladimir Kotal    logger.debug("URL_ROOT = {}".format(url_root))
343f7d6d77cSVladimir Kotal    logger.debug("URI = {}".format(uri))
344b2d29daeSVladimir Kotal
3453d5852a4SVladimir Kotal    # default period for syncing (in minutes)
3463d5852a4SVladimir Kotal    sync_period = 10
3473d5852a4SVladimir Kotal    sync_env = os.environ.get('SYNC_TIME_MINUTES')
3483d5852a4SVladimir Kotal    if sync_env:
3493d5852a4SVladimir Kotal        try:
3503d5852a4SVladimir Kotal            n = int(sync_env)
3513d5852a4SVladimir Kotal            if n >= 0:
3523d5852a4SVladimir Kotal                sync_period = n
3533d5852a4SVladimir Kotal        except ValueError:
3543d5852a4SVladimir Kotal            logger.error("SYNC_TIME_MINUTES is not a number: {}".
3553d5852a4SVladimir Kotal                         format(sync_env))
3563d5852a4SVladimir Kotal
3573d5852a4SVladimir Kotal    if sync_period == 0:
3583d5852a4SVladimir Kotal        logger.info("synchronization disabled")
359b2d29daeSVladimir Kotal    else:
3603d5852a4SVladimir Kotal        logger.info("synchronization period = {} minutes".format(sync_period))
361b2d29daeSVladimir Kotal
362b2d29daeSVladimir Kotal    # Note that deploy is done before Tomcat is started.
363f7d6d77cSVladimir Kotal    deploy(logger, url_root)
364b2d29daeSVladimir Kotal
365f7d6d77cSVladimir Kotal    if url_root != '/source':
366f7d6d77cSVladimir Kotal        setup_redirect_source(logger, url_root)
367b2d29daeSVladimir Kotal
368b2d29daeSVladimir Kotal    env = {}
3694810eb96SVladimir Kotal    extra_indexer_options = os.environ.get('INDEXER_OPT')
3704810eb96SVladimir Kotal    if extra_indexer_options:
3714810eb96SVladimir Kotal        logger.info("extra indexer options: {}".format(extra_indexer_options))
3724810eb96SVladimir Kotal        env['OPENGROK_INDEXER_OPTIONAL_ARGS'] = extra_indexer_options
373b2d29daeSVladimir Kotal    if os.environ.get('NOMIRROR'):
374b2d29daeSVladimir Kotal        env['OPENGROK_NO_MIRROR'] = os.environ.get('NOMIRROR')
375b2d29daeSVladimir Kotal    logger.debug('Extra environment: {}'.format(env))
376b2d29daeSVladimir Kotal
3774810eb96SVladimir Kotal    use_projects = True
3784810eb96SVladimir Kotal    if os.environ.get('AVOID_PROJECTS'):
3794810eb96SVladimir Kotal        use_projects = False
3804810eb96SVladimir Kotal
381b2d29daeSVladimir Kotal    #
382b2d29daeSVladimir Kotal    # Create empty configuration to avoid the non existent file exception
383b2d29daeSVladimir Kotal    # in the web app during the first web app startup.
384b2d29daeSVladimir Kotal    #
385b2d29daeSVladimir Kotal    if not os.path.exists(OPENGROK_CONFIG_FILE) or \
386b2d29daeSVladimir Kotal            os.path.getsize(OPENGROK_CONFIG_FILE) == 0:
3874810eb96SVladimir Kotal        create_bare_config(logger, use_projects=use_projects)
388b2d29daeSVladimir Kotal
3893d5852a4SVladimir Kotal    if sync_period > 0:
3904810eb96SVladimir Kotal        if use_projects:
391b2d29daeSVladimir Kotal            num_workers = multiprocessing.cpu_count()
3923d5852a4SVladimir Kotal            workers_env = os.environ.get('WORKERS')
3933d5852a4SVladimir Kotal            if workers_env:
3943d5852a4SVladimir Kotal                try:
3953d5852a4SVladimir Kotal                    n = int(workers_env)
3963d5852a4SVladimir Kotal                    if n > 0:
3973d5852a4SVladimir Kotal                        num_workers = n
3983d5852a4SVladimir Kotal                except ValueError:
3994810eb96SVladimir Kotal                    logger.error("WORKERS is not a number: {}".
4004810eb96SVladimir Kotal                                 format(workers_env))
4013d5852a4SVladimir Kotal
402b2d29daeSVladimir Kotal            logger.info('Number of sync workers: {}'.format(num_workers))
403b2d29daeSVladimir Kotal
4044810eb96SVladimir Kotal            worker_function = project_syncer
4054810eb96SVladimir Kotal            syncer_args = (logger, log_level, uri,
406f7d6d77cSVladimir Kotal                           OPENGROK_CONFIG_FILE,
4074810eb96SVladimir Kotal                           sync_period, num_workers, env)
4084810eb96SVladimir Kotal        else:
4094810eb96SVladimir Kotal            worker_function = indexer_no_projects
4104810eb96SVladimir Kotal            syncer_args = (logger, uri, OPENGROK_CONFIG_FILE, sync_period,
4114810eb96SVladimir Kotal                           extra_indexer_options)
4124810eb96SVladimir Kotal
4134810eb96SVladimir Kotal        logger.debug("Starting sync thread")
4144810eb96SVladimir Kotal        thread = threading.Thread(target=worker_function, name="Sync thread",
4154810eb96SVladimir Kotal                                  args=syncer_args)
416f7d6d77cSVladimir Kotal        thread.start()
417b2d29daeSVladimir Kotal
418b2d29daeSVladimir Kotal    # Start Tomcat last. It will be the foreground process.
419b2d29daeSVladimir Kotal    logger.info("Starting Tomcat")
420b2d29daeSVladimir Kotal    subprocess.run([os.path.join(tomcat_root, 'bin', 'catalina.sh'), 'run'])
421f7d6d77cSVladimir Kotal
422f7d6d77cSVladimir Kotal
423f7d6d77cSVladimir Kotalif __name__ == "__main__":
424f7d6d77cSVladimir Kotal    main()
425