#!/usr/bin/python # # lorax-composer # # Copyright (C) 2017 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import logging log = logging.getLogger("lorax-composer") program_log = logging.getLogger("program") pylorax_log = logging.getLogger("pylorax") server_log = logging.getLogger("server") import argparse import os import sys from threading import Lock from gevent.wsgi import WSGIServer from pylorax import vernum from pylorax.api.config import configure from pylorax.api.recipes import open_or_create_repo, commit_recipe_directory from pylorax.api.server import server, GitLock, YumLock from pylorax.api.yumbase import get_base_object VERSION = "{0}-{1}".format(os.path.basename(sys.argv[0]), vernum) def get_parser(): """ Return the ArgumentParser for lorax-composer""" parser = argparse.ArgumentParser(description="Lorax Composer API Server", fromfile_prefix_chars="@") parser.add_argument("--host", default="127.0.0.1", metavar="HOST", help="Host or IP to bind to (127.0.0.1)") parser.add_argument("--port", default=4000, metavar="PORT", help="Port to bind to (4000)") parser.add_argument("--log", dest="logfile", default="/var/log/lorax-composer/composer.log", metavar="LOG", help="Path to logfile (/var/log/lorax-composer/composer.log)") parser.add_argument("--mockfiles", default="/var/tmp/bdcs-mockfiles/", metavar="MOCKFILES", help="Path to JSON files used for /api/mock/ paths (/var/tmp/bdcs-mockfiles/)") parser.add_argument("-V", action="store_true", dest="showver", help="show program's version number and exit") parser.add_argument("-c", "--config", default="/etc/lorax/composer.conf", metavar="CONFIG", help="Path to lorax-composer configuration file.") parser.add_argument("RECIPES", metavar="RECIPES", help="Path to the recipes") return parser def setup_logging(logfile): # Setup logging to console and to logfile log.setLevel(logging.DEBUG) pylorax_log.setLevel(logging.DEBUG) sh = logging.StreamHandler() sh.setLevel(logging.INFO) fmt = logging.Formatter("%(asctime)s: %(message)s") sh.setFormatter(fmt) log.addHandler(sh) pylorax_log.addHandler(sh) fh = logging.FileHandler(filename=logfile) fh.setLevel(logging.DEBUG) fmt = logging.Formatter("%(asctime)s %(levelname)s %(name)s: %(message)s") fh.setFormatter(fmt) log.addHandler(fh) pylorax_log.addHandler(fh) # External program output log program_log.setLevel(logging.DEBUG) logfile = os.path.abspath(os.path.dirname(logfile))+"/program.log" fh = logging.FileHandler(filename=logfile) fh.setLevel(logging.DEBUG) program_log.addHandler(fh) # Server request logging server_log.setLevel(logging.DEBUG) logfile = os.path.abspath(os.path.dirname(logfile))+"/server.log" fh = logging.FileHandler(filename=logfile) fh.setLevel(logging.DEBUG) server_log.addHandler(fh) class LogWrapper(object): """Wrapper for the WSGIServer which only calls write()""" def __init__(self, log_obj): self.log = log_obj def write(self, msg): """Log everything as INFO""" self.log.info(msg.strip()) if __name__ == '__main__': # parse the arguments opts = get_parser().parse_args() if opts.showver: print(VERSION) sys.exit(0) logpath = os.path.abspath(os.path.dirname(opts.logfile)) if not os.path.isdir(logpath): os.makedirs(logpath) setup_logging(opts.logfile) log.debug("opts=%s", opts) if not os.path.isdir(opts.RECIPES): log.warn("Creating empty recipe directory at %s", opts.RECIPES) os.makedirs(opts.RECIPES) server.config["REPO_DIR"] = opts.RECIPES repo = open_or_create_repo(server.config["REPO_DIR"]) server.config["GITLOCK"] = GitLock(repo=repo, lock=Lock(), dir=opts.RECIPES) server.config["COMPOSER_CFG"] = configure(conf_file=opts.config) # Get a YumBase to share with the requests yb = get_base_object(server.config["COMPOSER_CFG"]) server.config["YUMLOCK"] = YumLock(yb=yb, lock=Lock()) # Import example recipes commit_recipe_directory(server.config["GITLOCK"].repo, "master", opts.RECIPES) log.info("Starting %s on %s:%d with recipes from %s", VERSION, opts.host, opts.port, opts.RECIPES) http_server = WSGIServer((opts.host, opts.port), server, log=LogWrapper(server_log)) # The server writes directly to a file object, so point to our log directory http_server.serve_forever()