diff --git a/lib/galaxy/main.py b/lib/galaxy/main.py deleted file mode 100644 index 87ecd3f3b66..00000000000 --- a/lib/galaxy/main.py +++ /dev/null @@ -1,246 +0,0 @@ -""" Entry point for starting Galaxy without starting as part of a web server. - -Example Usage: Start a job/workflow handler without a web server and with -a given name using. - -python lib/galaxy/main.py --server-name handler0 - -Start as a daemon with (requires daemonized - install with 'pip install daemonize'): - -python lib/galaxy/main.py -d --daemon-log-file=handler0-daemon.log --pid-file handler0.pid --server-name handler0 - -In daemon mode logging of Galaxy (as opposed to this script) is configured via -a loggers section in Galaxy's ini file - this can be overridden with sensible -defaults logging to a single file with the following: - -python lib/galaxy/main.py -d --server-name handler0 --daemon-log-file=handler0-daemon.log --pid-file handler0.pid --log-file handler0.log - -""" -import logging -from logging.config import fileConfig - -import functools -import os -import time -import sys - -try: - import ConfigParser as configparser -except ImportError: - import configparser - -try: - from daemonize import Daemonize -except ImportError: - Daemonize = None - -# Vaguely Python 2.6 compatibile ArgumentParser import -try: - from argparse import ArgumentParser -except ImportError: - from optparse import OptionParser - - class ArgumentParser(OptionParser): - - def __init__(self, **kwargs): - self.delegate = OptionParser(**kwargs) - - def add_argument(self, *args, **kwargs): - if "required" in kwargs: - del kwargs["required"] - return self.delegate.add_option(*args, **kwargs) - - def parse_args(self, args=None): - (options, args) = self.delegate.parse_args(args) - return options - -REQUIRES_DAEMONIZE_MESSAGE = "Attempted to use Galaxy in daemon mode, but daemonize is unavailable." - -log = logging.getLogger(__name__) - -GALAXY_ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) -GALAXY_LIB_DIR = os.path.join(GALAXY_ROOT_DIR, "lib") -DEFAULT_INI_APP = "main" -DEFAULT_INIS = ["config/galaxy.ini", "universe_wsgi.ini", "config/galaxy.ini.sample"] - -DEFAULT_PID = "galaxy.pid" -DEFAULT_VERBOSE = True -DESCRIPTION = "Daemonized entry point for Galaxy." - - -def load_galaxy_app( - config_builder, - config_env=False, - log=None, - **kwds -): - # Allow specification of log so daemon can reuse properly configured one. - if log is None: - log = logging.getLogger(__name__) - - # If called in daemon mode, set the ROOT directory and ensure Galaxy is on - # sys.path. - if config_env: - try: - os.chdir(GALAXY_ROOT_DIR) - except Exception: - log.exception("Failed to chdir") - raise - try: - sys.path.insert(1, GALAXY_LIB_DIR) - except Exception: - log.exception("Failed to add Galaxy to sys.path") - raise - - config_builder.setup_logging() - from galaxy.util.properties import load_app_properties - kwds = config_builder.app_kwds() - kwds = load_app_properties(**kwds) - from galaxy.app import UniverseApplication - app = UniverseApplication( - global_conf={"__file__": config_builder.ini_path}, - **kwds - ) - app.control_worker.bind_and_start() - return app - - -def app_loop(args, log): - try: - config_builder = GalaxyConfigBuilder(args) - galaxy_app = load_galaxy_app( - config_builder, - config_env=True, - log=log, - ) - except BaseException: - log.exception("Failed to initialize Galaxy application") - raise - sleep = True - while sleep: - try: - time.sleep(5) - except KeyboardInterrupt: - sleep = False - except SystemExit: - sleep = False - except Exception: - pass - try: - galaxy_app.shutdown() - except Exception: - log.exception("Failed to shutdown Galaxy application") - raise - - -def absolute_config_path(path, galaxy_root): - if path and not os.path.isabs(path): - path = os.path.join(galaxy_root, path) - return path - - -def find_ini(supplied_ini, galaxy_root): - if supplied_ini: - return supplied_ini - - # If not explicitly supplied an ini, check server.ini and then - # just restort to sample if that has not been configured. - for guess in DEFAULT_INIS: - ini_path = os.path.join(galaxy_root, guess) - if os.path.exists(ini_path): - return ini_path - - return guess - - -class GalaxyConfigBuilder(object): - """ Generate paste-like configuration from supplied command-line arguments. - """ - - def __init__(self, args=None, **kwds): - ini_path = kwds.get("ini_path", None) or (args and args.ini_path) - # If given app_conf_path - use that - else we need to ensure we have an - # ini path. - if not ini_path: - galaxy_root = kwds.get("galaxy_root", GALAXY_ROOT_DIR) - ini_path = find_ini(ini_path, galaxy_root) - ini_path = absolute_config_path(ini_path, galaxy_root=galaxy_root) - self.ini_path = ini_path - self.app_name = kwds.get("app") or (args and args.app) or DEFAULT_INI_APP - self.log_file = (args and args.log_file) - - @classmethod - def populate_options(cls, arg_parser): - arg_parser.add_argument("-c", "--ini-path", default=None, help="Galaxy ini config file (defaults to config/galaxy.ini)") - arg_parser.add_argument("--app", default=DEFAULT_INI_APP, help="app section in ini file (defaults to main)") - arg_parser.add_argument("-d", "--daemonize", default=False, help="Daemonzie process", action="store_true") - arg_parser.add_argument("--daemon-log-file", default=None, help="log file for daemon script ") - arg_parser.add_argument("--log-file", default=None, help="Galaxy log file (overrides log configuration in ini_path if set)") - arg_parser.add_argument("--pid-file", default=DEFAULT_PID, help="pid file (default is %s)" % DEFAULT_PID) - arg_parser.add_argument("--server-name", default=None, help="set a galaxy server name") - - def app_kwds(self): - config = dict( - ini_file=self.ini_path, - ini_section="app:%s" % self.app_name, - ) - return config - - def setup_logging(self): - # Galaxy will attempt to setup logging if loggers is not present in - # ini config file - this handles that loggers block however if present - # (the way paste normally would) - if not self.ini_path: - return - raw_config = configparser.ConfigParser() - raw_config.read([self.ini_path]) - if raw_config.has_section('loggers'): - config_file = os.path.abspath(self.ini_path) - fileConfig( - config_file, - dict(__file__=config_file, here=os.path.dirname(config_file)) - ) - - -def main(): - arg_parser = ArgumentParser(description=DESCRIPTION) - GalaxyConfigBuilder.populate_options(arg_parser) - args = arg_parser.parse_args() - if args.log_file: - os.environ["GALAXY_CONFIG_LOG_DESTINATION"] = os.path.abspath(args.log_file) - if args.server_name: - os.environ["GALAXY_CONFIG_SERVER_NAME"] = args.server_name - pid_file = args.pid_file - - log.setLevel(logging.DEBUG) - log.propagate = False - if args.daemonize: - if Daemonize is None: - raise ImportError(REQUIRES_DAEMONIZE_MESSAGE) - - keep_fds = [] - if args.daemon_log_file: - fh = logging.FileHandler(args.daemon_log_file, "w") - fh.setLevel(logging.DEBUG) - log.addHandler(fh) - keep_fds.append(fh.stream.fileno()) - else: - fh = logging.StreamHandler(sys.stderr) - fh.setLevel(logging.DEBUG) - log.addHandler(fh) - - daemon = Daemonize( - app="galaxy", - pid=pid_file, - action=functools.partial(app_loop, args, log), - verbose=DEFAULT_VERBOSE, - logger=log, - keep_fds=keep_fds, - ) - daemon.start() - else: - app_loop(args, log) - - -if __name__ == "__main__": - main() diff --git a/lib/galaxy/main.py b/lib/galaxy/main.py new file mode 120000 index 00000000000..e9cd3b70f01 --- /dev/null +++ b/lib/galaxy/main.py @@ -0,0 +1 @@ +../../scripts/galaxy-main \ No newline at end of file diff --git a/scripts/galaxy-main b/scripts/galaxy-main new file mode 100755 index 00000000000..f01b23c20cc --- /dev/null +++ b/scripts/galaxy-main @@ -0,0 +1,251 @@ +#!/usr/bin/env python +""" Entry point for starting Galaxy without starting as part of a web server. + +Example Usage: Start a job/workflow handler without a web server and with +a given name using. + +galaxy-main --server-name handler0 + +Start as a daemon with (requires daemonized - install with 'pip install daemonize'): + +galaxy-main -d --daemon-log-file=handler0-daemon.log --pid-file handler0.pid --server-name handler0 + +In daemon mode logging of Galaxy (as opposed to this script) is configured via +a loggers section in Galaxy's ini file - this can be overridden with sensible +defaults logging to a single file with the following: + +galaxy-main -d --server-name handler0 --daemon-log-file=handler0-daemon.log --pid-file handler0.pid --log-file handler0.log + +""" +import logging +from logging.config import fileConfig + +import functools +import os +import time +import sys + +try: + import ConfigParser as configparser +except ImportError: + import configparser + +try: + from daemonize import Daemonize +except ImportError: + Daemonize = None + +# Vaguely Python 2.6 compatibile ArgumentParser import +try: + from argparse import ArgumentParser +except ImportError: + from optparse import OptionParser + + class ArgumentParser(OptionParser): + + def __init__(self, **kwargs): + self.delegate = OptionParser(**kwargs) + + def add_argument(self, *args, **kwargs): + if "required" in kwargs: + del kwargs["required"] + return self.delegate.add_option(*args, **kwargs) + + def parse_args(self, args=None): + (options, args) = self.delegate.parse_args(args) + return options + +REQUIRES_DAEMONIZE_MESSAGE = "Attempted to use Galaxy in daemon mode, but daemonize is unavailable." + +log = logging.getLogger(__name__) + +base_file = os.path.basename(__file__) +if base_file == 'main.py': + GALAXY_ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) +elif base_file == 'galaxy-main': + GALAXY_ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) +GALAXY_LIB_DIR = os.path.join(GALAXY_ROOT_DIR, "lib") +DEFAULT_INI_APP = "main" +DEFAULT_INIS = ["config/galaxy.ini", "universe_wsgi.ini", "config/galaxy.ini.sample"] + +DEFAULT_PID = "galaxy.pid" +DEFAULT_VERBOSE = True +DESCRIPTION = "Daemonized entry point for Galaxy." + + +def load_galaxy_app( + config_builder, + config_env=False, + log=None, + **kwds +): + # Allow specification of log so daemon can reuse properly configured one. + if log is None: + log = logging.getLogger(__name__) + + # If called in daemon mode, set the ROOT directory and ensure Galaxy is on + # sys.path. + if config_env: + try: + os.chdir(GALAXY_ROOT_DIR) + except Exception: + log.exception("Failed to chdir") + raise + try: + sys.path.insert(1, GALAXY_LIB_DIR) + except Exception: + log.exception("Failed to add Galaxy to sys.path") + raise + + config_builder.setup_logging() + from galaxy.util.properties import load_app_properties + kwds = config_builder.app_kwds() + kwds = load_app_properties(**kwds) + from galaxy.app import UniverseApplication + app = UniverseApplication( + global_conf={"__file__": config_builder.ini_path}, + **kwds + ) + app.control_worker.bind_and_start() + return app + + +def app_loop(args, log): + try: + config_builder = GalaxyConfigBuilder(args) + galaxy_app = load_galaxy_app( + config_builder, + config_env=True, + log=log, + ) + except BaseException: + log.exception("Failed to initialize Galaxy application") + raise + sleep = True + while sleep: + try: + time.sleep(5) + except KeyboardInterrupt: + sleep = False + except SystemExit: + sleep = False + except Exception: + pass + try: + galaxy_app.shutdown() + except Exception: + log.exception("Failed to shutdown Galaxy application") + raise + + +def absolute_config_path(path, galaxy_root): + if path and not os.path.isabs(path): + path = os.path.join(galaxy_root, path) + return path + + +def find_ini(supplied_ini, galaxy_root): + if supplied_ini: + return supplied_ini + + # If not explicitly supplied an ini, check server.ini and then + # just restort to sample if that has not been configured. + for guess in DEFAULT_INIS: + ini_path = os.path.join(galaxy_root, guess) + if os.path.exists(ini_path): + return ini_path + + return guess + + +class GalaxyConfigBuilder(object): + """ Generate paste-like configuration from supplied command-line arguments. + """ + + def __init__(self, args=None, **kwds): + ini_path = kwds.get("ini_path", None) or (args and args.ini_path) + # If given app_conf_path - use that - else we need to ensure we have an + # ini path. + if not ini_path: + galaxy_root = kwds.get("galaxy_root", GALAXY_ROOT_DIR) + ini_path = find_ini(ini_path, galaxy_root) + ini_path = absolute_config_path(ini_path, galaxy_root=galaxy_root) + self.ini_path = ini_path + self.app_name = kwds.get("app") or (args and args.app) or DEFAULT_INI_APP + self.log_file = (args and args.log_file) + + @classmethod + def populate_options(cls, arg_parser): + arg_parser.add_argument("-c", "--ini-path", default=None, help="Galaxy ini config file (defaults to config/galaxy.ini)") + arg_parser.add_argument("--app", default=DEFAULT_INI_APP, help="app section in ini file (defaults to main)") + arg_parser.add_argument("-d", "--daemonize", default=False, help="Daemonzie process", action="store_true") + arg_parser.add_argument("--daemon-log-file", default=None, help="log file for daemon script ") + arg_parser.add_argument("--log-file", default=None, help="Galaxy log file (overrides log configuration in ini_path if set)") + arg_parser.add_argument("--pid-file", default=DEFAULT_PID, help="pid file (default is %s)" % DEFAULT_PID) + arg_parser.add_argument("--server-name", default=None, help="set a galaxy server name") + + def app_kwds(self): + config = dict( + ini_file=self.ini_path, + ini_section="app:%s" % self.app_name, + ) + return config + + def setup_logging(self): + # Galaxy will attempt to setup logging if loggers is not present in + # ini config file - this handles that loggers block however if present + # (the way paste normally would) + if not self.ini_path: + return + raw_config = configparser.ConfigParser() + raw_config.read([self.ini_path]) + if raw_config.has_section('loggers'): + config_file = os.path.abspath(self.ini_path) + fileConfig( + config_file, + dict(__file__=config_file, here=os.path.dirname(config_file)) + ) + + +def main(): + arg_parser = ArgumentParser(description=DESCRIPTION) + GalaxyConfigBuilder.populate_options(arg_parser) + args = arg_parser.parse_args() + if args.log_file: + os.environ["GALAXY_CONFIG_LOG_DESTINATION"] = os.path.abspath(args.log_file) + if args.server_name: + os.environ["GALAXY_CONFIG_SERVER_NAME"] = args.server_name + pid_file = args.pid_file + + log.setLevel(logging.DEBUG) + log.propagate = False + if args.daemonize: + if Daemonize is None: + raise ImportError(REQUIRES_DAEMONIZE_MESSAGE) + + keep_fds = [] + if args.daemon_log_file: + fh = logging.FileHandler(args.daemon_log_file, "w") + fh.setLevel(logging.DEBUG) + log.addHandler(fh) + keep_fds.append(fh.stream.fileno()) + else: + fh = logging.StreamHandler(sys.stderr) + fh.setLevel(logging.DEBUG) + log.addHandler(fh) + + daemon = Daemonize( + app="galaxy", + pid=pid_file, + action=functools.partial(app_loop, args, log), + verbose=DEFAULT_VERBOSE, + logger=log, + keep_fds=keep_fds, + ) + daemon.start() + else: + app_loop(args, log) + + +if __name__ == "__main__": + main()