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 33*f1835fddSVladimir Kotalfrom flask import Flask 34*f1835fddSVladimir Kotalfrom flask_httpauth import HTTPTokenAuth 35*f1835fddSVladimir Kotalfrom waitress import serve 36b2d29daeSVladimir Kotal 37b2d29daeSVladimir Kotalfrom opengrok_tools.utils.log import get_console_logger, \ 38b2d29daeSVladimir Kotal get_log_level, get_class_basename 39b2d29daeSVladimir Kotalfrom opengrok_tools.deploy import deploy_war 40b2d29daeSVladimir Kotalfrom opengrok_tools.utils.indexer import Indexer 41b2d29daeSVladimir Kotalfrom opengrok_tools.sync import do_sync 42b2d29daeSVladimir Kotalfrom opengrok_tools.utils.opengrok import list_projects, \ 431822b591SVladimir Kotal add_project, delete_project, get_configuration, set_config_value 44b2d29daeSVladimir Kotalfrom opengrok_tools.utils.readconfig import read_config 45b2d29daeSVladimir Kotalfrom opengrok_tools.utils.exitvals import SUCCESS_EXITVAL 46b2d29daeSVladimir Kotal 47b2d29daeSVladimir Kotal 48b2d29daeSVladimir Kotalfs_root = os.path.abspath('.').split(os.path.sep)[0] + os.path.sep 49b2d29daeSVladimir Kotalif os.environ.get('OPENGROK_TOMCAT_ROOT'): # debug only 50b2d29daeSVladimir Kotal tomcat_root = os.environ.get('OPENGROK_TOMCAT_ROOT') 51b2d29daeSVladimir Kotalelse: 52b2d29daeSVladimir Kotal tomcat_root = os.path.join(fs_root, "usr", "local", "tomcat") 53b2d29daeSVladimir Kotal 54b2d29daeSVladimir Kotalif os.environ.get('OPENGROK_ROOT'): # debug only 55b2d29daeSVladimir Kotal OPENGROK_BASE_DIR = os.environ.get('OPENGROK_ROOT') 56b2d29daeSVladimir Kotalelse: 57b2d29daeSVladimir Kotal OPENGROK_BASE_DIR = os.path.join(fs_root, "opengrok") 58b2d29daeSVladimir Kotal 59b2d29daeSVladimir KotalOPENGROK_LIB_DIR = os.path.join(OPENGROK_BASE_DIR, "lib") 60b2d29daeSVladimir KotalOPENGROK_DATA_ROOT = os.path.join(OPENGROK_BASE_DIR, "data") 61b2d29daeSVladimir KotalOPENGROK_SRC_ROOT = os.path.join(OPENGROK_BASE_DIR, "src") 62b2d29daeSVladimir KotalBODY_INCLUDE_FILE = os.path.join(OPENGROK_DATA_ROOT, "body_include") 63b2d29daeSVladimir KotalOPENGROK_CONFIG_FILE = os.path.join(OPENGROK_BASE_DIR, "etc", 64b2d29daeSVladimir Kotal "configuration.xml") 65b2d29daeSVladimir KotalOPENGROK_WEBAPPS_DIR = os.path.join(tomcat_root, "webapps") 664810eb96SVladimir KotalOPENGROK_JAR = os.path.join(OPENGROK_LIB_DIR, 'opengrok.jar') 67b2d29daeSVladimir Kotal 68*f1835fddSVladimir Kotalexpected_token = None 69*f1835fddSVladimir Kotal 70*f1835fddSVladimir Kotalsleep_event = threading.Event() 71*f1835fddSVladimir Kotalapp = Flask(__name__) 72*f1835fddSVladimir Kotalauth = HTTPTokenAuth(scheme='Bearer') 73*f1835fddSVladimir Kotal 74*f1835fddSVladimir Kotal 75*f1835fddSVladimir Kotal@auth.verify_token 76*f1835fddSVladimir Kotaldef verify_token(token): 77*f1835fddSVladimir Kotal if expected_token is None: 78*f1835fddSVladimir Kotal return "yes" 79*f1835fddSVladimir Kotal 80*f1835fddSVladimir Kotal if token is not None and token == expected_token: 81*f1835fddSVladimir Kotal return "yes" 82*f1835fddSVladimir Kotal 83*f1835fddSVladimir Kotal 84*f1835fddSVladimir Kotal@app.route('/reindex') 85*f1835fddSVladimir Kotal@auth.login_required 86*f1835fddSVladimir Kotaldef index(): 87*f1835fddSVladimir Kotal # Signal the sync/indexer thread. 88*f1835fddSVladimir Kotal sleep_event.set() 89*f1835fddSVladimir Kotal sleep_event.clear() 90*f1835fddSVladimir Kotal 91*f1835fddSVladimir Kotal return "Reindex triggered" 92*f1835fddSVladimir Kotal 93*f1835fddSVladimir Kotal 94*f1835fddSVladimir Kotaldef rest_function(logger, rest_port): 95*f1835fddSVladimir Kotal logger.info("Starting REST app on port {}".format(rest_port)) 96*f1835fddSVladimir Kotal serve(app, host="0.0.0.0", port=rest_port) 97*f1835fddSVladimir Kotal 98b2d29daeSVladimir Kotal 99f7d6d77cSVladimir Kotaldef set_url_root(logger, url_root): 100b2d29daeSVladimir Kotal """ 101b2d29daeSVladimir Kotal Set URL root and URI based on input 102788f14d3SVladimir Kotal :param logger: logger instance 103b2d29daeSVladimir Kotal :param url_root: input 104b2d29daeSVladimir Kotal :return: URI and URL root 105b2d29daeSVladimir Kotal """ 106b2d29daeSVladimir Kotal if not url_root: 107b2d29daeSVladimir Kotal url_root = '/' 108b2d29daeSVladimir Kotal 109b2d29daeSVladimir Kotal if ' ' in url_root: 110b2d29daeSVladimir Kotal logger.warn('Deployment path contains spaces. Deploying to root') 111b2d29daeSVladimir Kotal url_root = '/' 112b2d29daeSVladimir Kotal 113b2d29daeSVladimir Kotal # Remove leading and trailing slashes 114b2d29daeSVladimir Kotal if url_root.startswith('/'): 115b2d29daeSVladimir Kotal url_root = url_root[1:] 116b2d29daeSVladimir Kotal if url_root.endswith('/'): 117b2d29daeSVladimir Kotal url_root = url_root[:-1] 118b2d29daeSVladimir Kotal 119b2d29daeSVladimir Kotal uri = "http://localhost:8080/" + url_root 120b2d29daeSVladimir Kotal # 121b2d29daeSVladimir Kotal # Make sure URI ends with slash. This is important for the various API 122b2d29daeSVladimir Kotal # calls, notably for those that check the HTTP error code. 123b2d29daeSVladimir Kotal # Normally accessing the URI without the terminating slash results in 124b2d29daeSVladimir Kotal # HTTP redirect (code 302) instead of success (200). 125b2d29daeSVladimir Kotal # 126b2d29daeSVladimir Kotal if not uri.endswith('/'): 127b2d29daeSVladimir Kotal uri = uri + '/' 128b2d29daeSVladimir Kotal 129b2d29daeSVladimir Kotal return uri, url_root 130b2d29daeSVladimir Kotal 131b2d29daeSVladimir Kotal 132b2d29daeSVladimir Kotaldef get_war_name(url_root): 133d44cbea0SVladimir Kotal """ 134d44cbea0SVladimir Kotal :param url_root: web app URL root 135d44cbea0SVladimir Kotal :return: filename of the WAR file 136d44cbea0SVladimir Kotal """ 137b2d29daeSVladimir Kotal if len(url_root) == 0: 138b2d29daeSVladimir Kotal return "ROOT.war" 139f7d6d77cSVladimir Kotal 140b2d29daeSVladimir Kotal return url_root + ".war" 141b2d29daeSVladimir Kotal 142b2d29daeSVladimir Kotal 143f7d6d77cSVladimir Kotaldef deploy(logger, url_root): 144b2d29daeSVladimir Kotal """ 145b2d29daeSVladimir Kotal Deploy the web application 146788f14d3SVladimir Kotal :param logger: logger instance 147b2d29daeSVladimir Kotal :param url_root: web app URL root 148b2d29daeSVladimir Kotal """ 149b2d29daeSVladimir Kotal 150b2d29daeSVladimir Kotal logger.info('Deploying web application') 151b2d29daeSVladimir Kotal webapps_dir = os.path.join(tomcat_root, 'webapps') 152b2d29daeSVladimir Kotal if not os.path.isdir(webapps_dir): 153b2d29daeSVladimir Kotal raise Exception("{} is not a directory".format(webapps_dir)) 154b2d29daeSVladimir Kotal 155b2d29daeSVladimir Kotal for item in os.listdir(webapps_dir): 156b2d29daeSVladimir Kotal subdir = os.path.join(webapps_dir, item) 157b2d29daeSVladimir Kotal if os.path.isdir(subdir): 158b2d29daeSVladimir Kotal logger.debug("Removing '{}' directory recursively".format(subdir)) 159b2d29daeSVladimir Kotal shutil.rmtree(subdir) 160b2d29daeSVladimir Kotal 161b2d29daeSVladimir Kotal deploy_war(logger, os.path.join(OPENGROK_LIB_DIR, "source.war"), 162b2d29daeSVladimir Kotal os.path.join(OPENGROK_WEBAPPS_DIR, get_war_name(url_root)), 163b2d29daeSVladimir Kotal OPENGROK_CONFIG_FILE, None) 164b2d29daeSVladimir Kotal 165b2d29daeSVladimir Kotal 166f7d6d77cSVladimir Kotaldef setup_redirect_source(logger, url_root): 167b2d29daeSVladimir Kotal """ 168b2d29daeSVladimir Kotal Set up redirect from /source 169b2d29daeSVladimir Kotal """ 170b2d29daeSVladimir Kotal logger.debug("Setting up redirect from /source to '{}'".format(url_root)) 171b2d29daeSVladimir Kotal source_dir = os.path.join(OPENGROK_WEBAPPS_DIR, "source") 172b2d29daeSVladimir Kotal if not os.path.isdir(source_dir): 173b2d29daeSVladimir Kotal os.makedirs(source_dir) 174b2d29daeSVladimir Kotal 175b2d29daeSVladimir Kotal with open(os.path.join(source_dir, "index.jsp"), "w+") as index: 176b2d29daeSVladimir Kotal index.write("<% response.sendRedirect(\"/{}\"); %>".format(url_root)) 177b2d29daeSVladimir Kotal 178b2d29daeSVladimir Kotal 179f7d6d77cSVladimir Kotaldef wait_for_tomcat(logger, uri): 180b2d29daeSVladimir Kotal """ 181b2d29daeSVladimir Kotal Active/busy waiting for Tomcat to come up. 182b2d29daeSVladimir Kotal Currently there is no upper time bound. 183b2d29daeSVladimir Kotal """ 184b2d29daeSVladimir Kotal logger.info("Waiting for Tomcat to start") 185b2d29daeSVladimir Kotal 186b2d29daeSVladimir Kotal while True: 187b2d29daeSVladimir Kotal try: 188d44cbea0SVladimir Kotal ret = get(uri) 189d44cbea0SVladimir Kotal status = ret.status_code 190b2d29daeSVladimir Kotal except ConnectionError: 191b2d29daeSVladimir Kotal status = 0 192b2d29daeSVladimir Kotal 193b2d29daeSVladimir Kotal if status != 200: 194b2d29daeSVladimir Kotal logger.debug("Got status {} for {}, sleeping for 1 second". 195b2d29daeSVladimir Kotal format(status, uri)) 196b2d29daeSVladimir Kotal time.sleep(1) 197b2d29daeSVladimir Kotal else: 198b2d29daeSVladimir Kotal break 199b2d29daeSVladimir Kotal 200b2d29daeSVladimir Kotal logger.info("Tomcat is ready") 201b2d29daeSVladimir Kotal 202b2d29daeSVladimir Kotal 203f7d6d77cSVladimir Kotaldef refresh_projects(logger, uri): 204b2d29daeSVladimir Kotal """ 205b2d29daeSVladimir Kotal Ensure each immediate source root subdirectory is a project. 206b2d29daeSVladimir Kotal """ 207b2d29daeSVladimir Kotal webapp_projects = list_projects(logger, uri) 208b2d29daeSVladimir Kotal logger.debug('Projects from the web app: {}'.format(webapp_projects)) 209b2d29daeSVladimir Kotal src_root = OPENGROK_SRC_ROOT 210b2d29daeSVladimir Kotal 211b2d29daeSVladimir Kotal # Add projects. 212b2d29daeSVladimir Kotal for item in os.listdir(src_root): 213b2d29daeSVladimir Kotal logger.debug('Got item {}'.format(item)) 214b2d29daeSVladimir Kotal if os.path.isdir(os.path.join(src_root, item)): 215b2d29daeSVladimir Kotal if item not in webapp_projects: 216b2d29daeSVladimir Kotal logger.info("Adding project {}".format(item)) 217b2d29daeSVladimir Kotal add_project(logger, item, uri) 218b2d29daeSVladimir Kotal 219b2d29daeSVladimir Kotal # Remove projects 220b2d29daeSVladimir Kotal for item in webapp_projects: 221b2d29daeSVladimir Kotal if not os.path.isdir(os.path.join(src_root, item)): 222b2d29daeSVladimir Kotal logger.info("Deleting project {}".format(item)) 223b2d29daeSVladimir Kotal delete_project(logger, item, uri) 224b2d29daeSVladimir Kotal 225b2d29daeSVladimir Kotal 226f7d6d77cSVladimir Kotaldef save_config(logger, uri, config_path): 227b2d29daeSVladimir Kotal """ 228b2d29daeSVladimir Kotal Retrieve configuration from the web app and write it to file. 229788f14d3SVladimir Kotal :param logger: logger instance 230b2d29daeSVladimir Kotal :param uri: web app URI 231b2d29daeSVladimir Kotal :param config_path: file path 232b2d29daeSVladimir Kotal """ 233b2d29daeSVladimir Kotal 234b2d29daeSVladimir Kotal logger.info('Saving configuration to {}'.format(config_path)) 235b2d29daeSVladimir Kotal config = get_configuration(logger, uri) 236b2d29daeSVladimir Kotal with open(config_path, "w+") as config_file: 237b2d29daeSVladimir Kotal config_file.write(config) 238b2d29daeSVladimir Kotal 239b2d29daeSVladimir Kotal 240b2d29daeSVladimir Kotaldef merge_commands_env(commands, env): 241b2d29daeSVladimir Kotal """ 242b2d29daeSVladimir Kotal Merge environment into command structure. If any of the commands has 243b2d29daeSVladimir Kotal an environment already set, the env is merged in. 244b2d29daeSVladimir Kotal :param commands: commands structure 245b2d29daeSVladimir Kotal :param env: environment dictionary 246b2d29daeSVladimir Kotal :return: updated commands structure 247b2d29daeSVladimir Kotal """ 248b2d29daeSVladimir Kotal for cmd in commands: 249b2d29daeSVladimir Kotal cmd_env = cmd.get('env') 250b2d29daeSVladimir Kotal if cmd_env: 251b2d29daeSVladimir Kotal cmd.env.update(env) 252b2d29daeSVladimir Kotal else: 253b2d29daeSVladimir Kotal cmd['env'] = env 254b2d29daeSVladimir Kotal 255b2d29daeSVladimir Kotal return commands 256b2d29daeSVladimir Kotal 257b2d29daeSVladimir Kotal 2584810eb96SVladimir Kotaldef indexer_no_projects(logger, uri, config_path, sync_period, 2594810eb96SVladimir Kotal extra_indexer_options): 2604810eb96SVladimir Kotal """ 2614810eb96SVladimir Kotal Project less indexer 2624810eb96SVladimir Kotal """ 2634810eb96SVladimir Kotal 2644810eb96SVladimir Kotal wait_for_tomcat(logger, uri) 2654810eb96SVladimir Kotal 266*f1835fddSVladimir Kotal periodic_sync = True 267*f1835fddSVladimir Kotal if sync_period is None or sync_period == 0: 268*f1835fddSVladimir Kotal periodic_sync = False 269*f1835fddSVladimir Kotal 2704810eb96SVladimir Kotal while True: 271*f1835fddSVladimir Kotal if not periodic_sync: 272*f1835fddSVladimir Kotal sleep_event.wait() 273*f1835fddSVladimir Kotal 2744810eb96SVladimir Kotal indexer_options = ['-s', OPENGROK_SRC_ROOT, 2754810eb96SVladimir Kotal '-d', OPENGROK_DATA_ROOT, 2764810eb96SVladimir Kotal '-c', '/usr/local/bin/ctags', 2774810eb96SVladimir Kotal '--remote', 'on', 2784810eb96SVladimir Kotal '-H', 2794810eb96SVladimir Kotal '-W', config_path, 2804810eb96SVladimir Kotal '-U', uri] 2814810eb96SVladimir Kotal if extra_indexer_options: 2824810eb96SVladimir Kotal logger.debug("Adding extra indexer options: {}". 2834810eb96SVladimir Kotal format(extra_indexer_options)) 2844810eb96SVladimir Kotal indexer_options.extend(extra_indexer_options.split()) 2854810eb96SVladimir Kotal indexer = Indexer(indexer_options, logger=logger, 286d2f093daSVladimir Kotal jar=OPENGROK_JAR, doprint=True) 2874810eb96SVladimir Kotal indexer.execute() 2884810eb96SVladimir Kotal 289*f1835fddSVladimir Kotal if periodic_sync: 2904810eb96SVladimir Kotal sleep_seconds = sync_period * 60 2914810eb96SVladimir Kotal logger.info("Sleeping for {} seconds".format(sleep_seconds)) 2924810eb96SVladimir Kotal time.sleep(sleep_seconds) 2934810eb96SVladimir Kotal 2944810eb96SVladimir Kotal 2954810eb96SVladimir Kotaldef project_syncer(logger, loglevel, uri, config_path, sync_period, 2964810eb96SVladimir Kotal numworkers, env): 297b2d29daeSVladimir Kotal """ 298b2d29daeSVladimir Kotal Wrapper for running opengrok-sync. 299b2d29daeSVladimir Kotal To be run in a thread/process in the background. 300b2d29daeSVladimir Kotal """ 301b2d29daeSVladimir Kotal 302f7d6d77cSVladimir Kotal wait_for_tomcat(logger, uri) 303b2d29daeSVladimir Kotal 3041822b591SVladimir Kotal set_config_value(logger, 'projectsEnabled', 'true', uri) 3051822b591SVladimir Kotal 306*f1835fddSVladimir Kotal periodic_sync = True 307*f1835fddSVladimir Kotal if sync_period is None or sync_period == 0: 308*f1835fddSVladimir Kotal periodic_sync = False 309*f1835fddSVladimir Kotal 310b2d29daeSVladimir Kotal while True: 311*f1835fddSVladimir Kotal if not periodic_sync: 312*f1835fddSVladimir Kotal sleep_event.wait() 313*f1835fddSVladimir Kotal 314f7d6d77cSVladimir Kotal refresh_projects(logger, uri) 315b2d29daeSVladimir Kotal 316b2d29daeSVladimir Kotal if os.environ.get('OPENGROK_SYNC_YML'): # debug only 317b2d29daeSVladimir Kotal config_file = os.environ.get('OPENGROK_SYNC_YML') 318b2d29daeSVladimir Kotal else: 319b2d29daeSVladimir Kotal config_file = os.path.join(fs_root, 'scripts', 'sync.yml') 320b2d29daeSVladimir Kotal config = read_config(logger, config_file) 321b2d29daeSVladimir Kotal if config is None: 322b2d29daeSVladimir Kotal logger.error("Cannot read config file from {}".format(config_file)) 323b2d29daeSVladimir Kotal raise Exception("no sync config") 324b2d29daeSVladimir Kotal 325b2d29daeSVladimir Kotal projects = list_projects(logger, uri) 326b2d29daeSVladimir Kotal # 327b2d29daeSVladimir Kotal # The driveon=True is needed for the initial indexing of newly 328b2d29daeSVladimir Kotal # added project, otherwise the incoming check in the opengrok-mirror 3293d5852a4SVladimir Kotal # program would short circuit it. 330b2d29daeSVladimir Kotal # 331b2d29daeSVladimir Kotal if env: 332b2d29daeSVladimir Kotal logger.info('Merging commands with environment') 333b2d29daeSVladimir Kotal commands = merge_commands_env(config["commands"], env) 334b2d29daeSVladimir Kotal logger.debug(config['commands']) 335b2d29daeSVladimir Kotal else: 336b2d29daeSVladimir Kotal commands = config["commands"] 337b2d29daeSVladimir Kotal 338b2d29daeSVladimir Kotal logger.info("Sync starting") 339b2d29daeSVladimir Kotal do_sync(loglevel, commands, config.get('cleanup'), 340b2d29daeSVladimir Kotal projects, config.get("ignore_errors"), uri, 341b2d29daeSVladimir Kotal numworkers, driveon=True, logger=logger, print_output=True) 342b2d29daeSVladimir Kotal logger.info("Sync done") 343b2d29daeSVladimir Kotal 344b2d29daeSVladimir Kotal # Workaround for https://github.com/oracle/opengrok/issues/1670 345b2d29daeSVladimir Kotal Path(os.path.join(OPENGROK_DATA_ROOT, 'timestamp')).touch() 346b2d29daeSVladimir Kotal 347f7d6d77cSVladimir Kotal save_config(logger, uri, config_path) 348b2d29daeSVladimir Kotal 349*f1835fddSVladimir Kotal if periodic_sync: 3503d5852a4SVladimir Kotal sleep_seconds = sync_period * 60 351b2d29daeSVladimir Kotal logger.info("Sleeping for {} seconds".format(sleep_seconds)) 352b2d29daeSVladimir Kotal time.sleep(sleep_seconds) 353b2d29daeSVladimir Kotal 354b2d29daeSVladimir Kotal 3559d6d7c28SVladimir Kotaldef create_bare_config(logger, extra_indexer_options=None): 356b2d29daeSVladimir Kotal """ 357b2d29daeSVladimir Kotal Create bare configuration file with a few basic settings. 358b2d29daeSVladimir Kotal """ 359b2d29daeSVladimir Kotal 360b2d29daeSVladimir Kotal logger.info('Creating bare configuration in {}'. 361b2d29daeSVladimir Kotal format(OPENGROK_CONFIG_FILE)) 3624810eb96SVladimir Kotal indexer_options = ['-s', OPENGROK_SRC_ROOT, 363b2d29daeSVladimir Kotal '-d', OPENGROK_DATA_ROOT, 364b2d29daeSVladimir Kotal '-c', '/usr/local/bin/ctags', 365b2d29daeSVladimir Kotal '--remote', 'on', 3664810eb96SVladimir Kotal '-H', 367b2d29daeSVladimir Kotal '-W', OPENGROK_CONFIG_FILE, 3684810eb96SVladimir Kotal '--noIndex'] 3694810eb96SVladimir Kotal 3709d6d7c28SVladimir Kotal if extra_indexer_options: 3715b279385SVladimir Kotal if type(extra_indexer_options) is not list: 3725b279385SVladimir Kotal raise Exception("extra_indexer_options has to be a list") 3739d6d7c28SVladimir Kotal indexer_options.extend(extra_indexer_options) 3744810eb96SVladimir Kotal indexer = Indexer(indexer_options, 3754810eb96SVladimir Kotal jar=OPENGROK_JAR, 376b2d29daeSVladimir Kotal logger=logger, doprint=True) 377b2d29daeSVladimir Kotal indexer.execute() 378b2d29daeSVladimir Kotal ret = indexer.getretcode() 379b2d29daeSVladimir Kotal if ret != SUCCESS_EXITVAL: 380b2d29daeSVladimir Kotal logger.error('Command returned {}'.format(ret)) 381b2d29daeSVladimir Kotal logger.error(indexer.geterroutput()) 382b2d29daeSVladimir Kotal raise Exception("Failed to create bare configuration") 383b2d29daeSVladimir Kotal 384b2d29daeSVladimir Kotal 385*f1835fddSVladimir Kotaldef get_num_from_env(logger, env_name, default_value): 386*f1835fddSVladimir Kotal value = default_value 387*f1835fddSVladimir Kotal env_str = os.environ.get(env_name) 388*f1835fddSVladimir Kotal if env_str: 389*f1835fddSVladimir Kotal try: 390*f1835fddSVladimir Kotal n = int(env_str) 391*f1835fddSVladimir Kotal if n >= 0: 392*f1835fddSVladimir Kotal value = n 393*f1835fddSVladimir Kotal except ValueError: 394*f1835fddSVladimir Kotal logger.error("{} is not a number: {}". 395*f1835fddSVladimir Kotal format(env_name, env_str)) 396*f1835fddSVladimir Kotal 397*f1835fddSVladimir Kotal return value 398*f1835fddSVladimir Kotal 399*f1835fddSVladimir Kotal 400f7d6d77cSVladimir Kotaldef main(): 401b2d29daeSVladimir Kotal log_level = os.environ.get('OPENGROK_LOG_LEVEL') 402b2d29daeSVladimir Kotal if log_level: 403b2d29daeSVladimir Kotal log_level = get_log_level(log_level) 404b2d29daeSVladimir Kotal else: 405b2d29daeSVladimir Kotal log_level = logging.INFO 406b2d29daeSVladimir Kotal 407b2d29daeSVladimir Kotal logger = get_console_logger(get_class_basename(), log_level) 408b2d29daeSVladimir Kotal 409f7d6d77cSVladimir Kotal uri, url_root = set_url_root(logger, os.environ.get('URL_ROOT')) 410f7d6d77cSVladimir Kotal logger.debug("URL_ROOT = {}".format(url_root)) 411f7d6d77cSVladimir Kotal logger.debug("URI = {}".format(uri)) 412b2d29daeSVladimir Kotal 4133d5852a4SVladimir Kotal # default period for syncing (in minutes) 414*f1835fddSVladimir Kotal sync_period = get_num_from_env(logger, 'SYNC_TIME_MINUTES', 10) 4153d5852a4SVladimir Kotal if sync_period == 0: 4163d5852a4SVladimir Kotal logger.info("synchronization disabled") 417b2d29daeSVladimir Kotal else: 4183d5852a4SVladimir Kotal logger.info("synchronization period = {} minutes".format(sync_period)) 419b2d29daeSVladimir Kotal 420b2d29daeSVladimir Kotal # Note that deploy is done before Tomcat is started. 421f7d6d77cSVladimir Kotal deploy(logger, url_root) 422b2d29daeSVladimir Kotal 423f7d6d77cSVladimir Kotal if url_root != '/source': 424f7d6d77cSVladimir Kotal setup_redirect_source(logger, url_root) 425b2d29daeSVladimir Kotal 426b2d29daeSVladimir Kotal env = {} 427dadacd3dSAdam Hornacek extra_indexer_options = os.environ.get('INDEXER_OPT', '') 4284810eb96SVladimir Kotal if extra_indexer_options: 4294810eb96SVladimir Kotal logger.info("extra indexer options: {}".format(extra_indexer_options)) 4304810eb96SVladimir Kotal env['OPENGROK_INDEXER_OPTIONAL_ARGS'] = extra_indexer_options 431b2d29daeSVladimir Kotal if os.environ.get('NOMIRROR'): 432b2d29daeSVladimir Kotal env['OPENGROK_NO_MIRROR'] = os.environ.get('NOMIRROR') 433b2d29daeSVladimir Kotal logger.debug('Extra environment: {}'.format(env)) 434b2d29daeSVladimir Kotal 4354810eb96SVladimir Kotal use_projects = True 4364810eb96SVladimir Kotal if os.environ.get('AVOID_PROJECTS'): 4374810eb96SVladimir Kotal use_projects = False 4384810eb96SVladimir Kotal 439b2d29daeSVladimir Kotal # 440b2d29daeSVladimir Kotal # Create empty configuration to avoid the non existent file exception 441b2d29daeSVladimir Kotal # in the web app during the first web app startup. 442b2d29daeSVladimir Kotal # 443b2d29daeSVladimir Kotal if not os.path.exists(OPENGROK_CONFIG_FILE) or \ 444b2d29daeSVladimir Kotal os.path.getsize(OPENGROK_CONFIG_FILE) == 0: 445c6f6c3d1SVladimir Kotal create_bare_config(logger, extra_indexer_options.split()) 446b2d29daeSVladimir Kotal 4474810eb96SVladimir Kotal if use_projects: 448*f1835fddSVladimir Kotal num_workers = get_num_from_env(logger, 'WORKERS', 449*f1835fddSVladimir Kotal multiprocessing.cpu_count()) 450b2d29daeSVladimir Kotal logger.info('Number of sync workers: {}'.format(num_workers)) 451b2d29daeSVladimir Kotal 4524810eb96SVladimir Kotal worker_function = project_syncer 4534810eb96SVladimir Kotal syncer_args = (logger, log_level, uri, 454f7d6d77cSVladimir Kotal OPENGROK_CONFIG_FILE, 4554810eb96SVladimir Kotal sync_period, num_workers, env) 4564810eb96SVladimir Kotal else: 4574810eb96SVladimir Kotal worker_function = indexer_no_projects 4584810eb96SVladimir Kotal syncer_args = (logger, uri, OPENGROK_CONFIG_FILE, sync_period, 4594810eb96SVladimir Kotal extra_indexer_options) 4604810eb96SVladimir Kotal 4614810eb96SVladimir Kotal logger.debug("Starting sync thread") 4624810eb96SVladimir Kotal thread = threading.Thread(target=worker_function, name="Sync thread", 4634810eb96SVladimir Kotal args=syncer_args) 464f7d6d77cSVladimir Kotal thread.start() 465b2d29daeSVladimir Kotal 466*f1835fddSVladimir Kotal rest_port = get_num_from_env(logger, 'REST_PORT', 5000) 467*f1835fddSVladimir Kotal token = os.environ.get('REST_TOKEN') 468*f1835fddSVladimir Kotal global expected_token 469*f1835fddSVladimir Kotal if token: 470*f1835fddSVladimir Kotal logger.debug("Setting expected token for REST endpoint" 471*f1835fddSVladimir Kotal "on port {} to '{}'".format(rest_port, token)) 472*f1835fddSVladimir Kotal expected_token = token 473*f1835fddSVladimir Kotal logger.debug("Starting REST thread") 474*f1835fddSVladimir Kotal thread = threading.Thread(target=rest_function, name="REST thread", 475*f1835fddSVladimir Kotal args=(logger, rest_port)) 476*f1835fddSVladimir Kotal thread.start() 477*f1835fddSVladimir Kotal 478b2d29daeSVladimir Kotal # Start Tomcat last. It will be the foreground process. 479b2d29daeSVladimir Kotal logger.info("Starting Tomcat") 480b2d29daeSVladimir Kotal subprocess.run([os.path.join(tomcat_root, 'bin', 'catalina.sh'), 'run']) 481f7d6d77cSVladimir Kotal 482f7d6d77cSVladimir Kotal 483f7d6d77cSVladimir Kotalif __name__ == "__main__": 484f7d6d77cSVladimir Kotal main() 485