Check the compose templates at startup

Depsolve the packages included in the templates and report any errors
using the /api/status 'msgs' field. This should help narrow down
problems with package sources not being setup correctly.
This commit is contained in:
Brian C. Lane 2018-07-12 09:25:22 -07:00
parent f1814ce35f
commit d692a7dddd
4 changed files with 50 additions and 5 deletions

View File

@ -46,13 +46,41 @@ from pyanaconda.simpleconfig import SimpleConfigFile
from pykickstart.parser import KickstartParser
from pykickstart.version import makeVersion, RHEL7
from pylorax.api.projects import projects_depsolve_with_size, dep_nevra
from pylorax.api.projects import projects_depsolve, projects_depsolve_with_size, dep_nevra
from pylorax.api.projects import ProjectsError
from pylorax.api.recipes import read_recipe_and_id
from pylorax.imgutils import default_image_name
from pylorax.sysutils import joinpaths
def test_templates(yb, share_dir):
""" Try depsolving each of the the templates and report any errors
:param yb: yum base object
:type yb: YumBase
:returns: List of template types and errors
:rtype: List of errors
Return a list of templates and errors encountered or an empty list
"""
template_errors = []
for compose_type in compose_types(share_dir):
# Read the kickstart template for this type
ks_template_path = joinpaths(share_dir, "composer", compose_type) + ".ks"
ks_template = open(ks_template_path, "r").read()
# How much space will the packages in the default template take?
ks_version = makeVersion(RHEL7)
ks = KickstartParser(ks_version, errorsAreFatal=False, missingIncludeIsFatal=False)
ks.readKickstartFromString(ks_template+"\n%end\n")
pkgs = [(name, "*") for name in ks.handler.packages.packageList]
try:
_ = projects_depsolve(yb, pkgs)
except ProjectsError as e:
template_errors.append("Error depsolving %s: %s" % (compose_type, str(e)))
return template_errors
def repo_to_ks(r, url="url"):
""" Return a kickstart line with the correct args.

View File

@ -65,13 +65,19 @@ def v0_status():
"db_supported": true,
"db_version": "0",
"schema_version": "0",
"backend": "lorax-composer"}
"backend": "lorax-composer",
"msgs": []}
The 'msgs' field can be a list of strings describing startup problems or status that
should be displayed to the user. eg. if the compose templates are not depsolving properly
the errors will be in 'msgs'.
"""
return jsonify(backend="lorax-composer",
build=vernum,
api="0",
db_version="0",
schema_version="0",
db_supported=True)
db_supported=True,
msgs=server.config["TEMPLATE_ERRORS"])
v0_api(server)

View File

@ -37,6 +37,7 @@ from gevent.pywsgi import WSGIServer
from pylorax import vernum
from pylorax.api.config import configure, make_yum_dirs, make_queue_dirs
from pylorax.api.compose import test_templates
from pylorax.api.queue import start_queue_monitor
from pylorax.api.recipes import open_or_create_repo, commit_recipe_directory
from pylorax.api.server import server, GitLock, YumLock
@ -280,6 +281,9 @@ if __name__ == '__main__':
yb = get_base_object(server.config["COMPOSER_CFG"])
server.config["YUMLOCK"] = YumLock(yb=yb, lock=Lock())
# Depsolve the templates and make a note of the failures for /api/status to report
server.config["TEMPLATE_ERRORS"] = test_templates(yb, server.config["COMPOSER_CFG"].get("composer", "share_dir"))
# Setup access to the git repo
server.config["REPO_DIR"] = opts.BLUEPRINTS
repo = open_or_create_repo(server.config["REPO_DIR"])

View File

@ -61,6 +61,9 @@ class ServerTestCase(unittest.TestCase):
yb = get_base_object(server.config["COMPOSER_CFG"])
server.config["YUMLOCK"] = YumLock(yb=yb, lock=Lock())
# Include a message in /api/status output
server.config["TEMPLATE_ERRORS"] = ["Test message"]
server.config['TESTING'] = True
self.server = server.test_client()
self.repo_dir = repo_dir
@ -84,12 +87,16 @@ class ServerTestCase(unittest.TestCase):
def test_01_status(self):
"""Test the /api/status route"""
status_fields = ["build", "api", "db_version", "schema_version", "db_supported", "backend"]
status_fields = ["build", "api", "db_version", "schema_version", "db_supported", "backend", "msgs"]
resp = self.server.get("/api/status")
data = json.loads(resp.data)
# Just make sure the fields are present
# Make sure the fields are present
self.assertEqual(sorted(data.keys()), sorted(status_fields))
# Check for test message
self.assertEqual(data["msgs"], ["Test message"])
def test_02_blueprints_list(self):
"""Test the /api/v0/blueprints/list route"""
list_dict = {"blueprints":["atlas", "custom-base", "development", "glusterfs", "http-server",