lorax/src/sbin/lorax-composer

182 lines
6.3 KiB
Plaintext
Raw Normal View History

#!/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 <http://www.gnu.org/licenses/>.
#
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 ConfigParser
import os
import sys
from threading import Lock
from gevent.wsgi import WSGIServer
from pylorax import vernum
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 ComposerConfig(ConfigParser.SafeConfigParser):
def get_default(self, section, option, default):
try:
return self.get(section, option)
except ConfigParser.Error:
return default
def configure(conf_file="/etc/lorax/composer.conf"):
"""lorax-composer configuration"""
conf = ComposerConfig()
# set defaults
conf.add_section("composer")
conf.set("composer", "yum_conf", "/var/lib/lorax/composer/yum.conf")
conf.set("composer", "repo_dir", "/var/lib/lorax/composer/repos.d/")
conf.set("composer", "cache_dir", "/var/cache/lorax/composer/yum/")
conf.add_section("users")
conf.set("users", "root", "1")
# Enable all available repo files by default
conf.add_section("repos")
conf.set("repos", "use_system_repos", "1")
conf.set("repos", "enabled", "*")
# read the config file
if os.path.isfile(conf_file):
conf.read(conf_file)
# Create any missing directories
for section, key in [("composer", "yum_conf"), ("composer", "repo_dir"), ("composer", "cache_dir")]:
path = conf.get(section, key)
if not os.path.isdir(os.path.dirname(path)):
os.makedirs(os.path.dirname(path))
return conf
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(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()