From a2ce0686ca598de002dad173544ae427be20b23c Mon Sep 17 00:00:00 2001 From: Chris Lumens Date: Wed, 8 Aug 2018 10:57:46 -0400 Subject: [PATCH] Add error IDs for when an unknown build UUID is requested. Note that this also changes the return type of uuid_info to return None when an unknown ID is given. The other uuid_* functions are fine because they are checked ahead of time. (cherry picked from commit 6497b4fb65dcdf4ff61e795ce252728278398e7f) --- src/pylorax/api/errors.py | 3 +++ src/pylorax/api/queue.py | 4 ++-- src/pylorax/api/v0.py | 24 +++++++++++++++--------- tests/pylorax/test_server.py | 17 ++++++++++------- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/pylorax/api/errors.py b/src/pylorax/api/errors.py index b46d3cfb..823d8532 100644 --- a/src/pylorax/api/errors.py +++ b/src/pylorax/api/errors.py @@ -24,3 +24,6 @@ BAD_LIMIT_OR_OFFSET = "BadLimitOrOffset" # what it currently is. This most often happens when asking for results from # a build that is not yet done. BUILD_IN_WRONG_STATE = "BuildInWrongState" + +# Returned from the API when a UUID that was requested does not exist. +UNKNOWN_UUID = "UnknownUUID" diff --git a/src/pylorax/api/queue.py b/src/pylorax/api/queue.py index dc2d419d..b6344e26 100644 --- a/src/pylorax/api/queue.py +++ b/src/pylorax/api/queue.py @@ -456,7 +456,7 @@ def uuid_info(cfg, uuid): :type cfg: ComposerConfig :param uuid: The UUID of the build :type uuid: str - :returns: dictionary of information about the composition + :returns: dictionary of information about the composition or None :rtype: dict :raises: RuntimeError if there was a problem @@ -472,7 +472,7 @@ def uuid_info(cfg, uuid): """ uuid_dir = joinpaths(cfg.get("composer", "lib_dir"), "results", uuid) if not os.path.exists(uuid_dir): - raise RuntimeError("%s is not a valid build_id" % uuid) + return None # Load the compose configuration cfg_path = joinpaths(uuid_dir, "config.toml") diff --git a/src/pylorax/api/v0.py b/src/pylorax/api/v0.py index d0cab2fa..53166a8d 100644 --- a/src/pylorax/api/v0.py +++ b/src/pylorax/api/v0.py @@ -1791,12 +1791,15 @@ def v0_api(api): return jsonify(status=False, errors=["Invalid characters in API path"]), 400 results = [] + errors = [] for uuid in [n.strip().lower() for n in uuids.split(",")]: details = uuid_status(api.config["COMPOSER_CFG"], uuid) if details is not None: results.append(details) + else: + errors.append({"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}) - return jsonify(uuids=results) + return jsonify(uuids=results, errors=errors) @api.route("/api/v0/compose/cancel", defaults={'uuid': ""}, methods=["DELETE"]) @api.route("/api/v0/compose/cancel/", methods=["DELETE"]) @@ -1809,7 +1812,7 @@ def v0_api(api): status = uuid_status(api.config["COMPOSER_CFG"], uuid) if status is None: - return jsonify(status=False, errors=["%s is not a valid build uuid" % uuid]), 400 + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 if status["queue_status"] not in ["WAITING", "RUNNING"]: return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s is not in WAITING or RUNNING." % uuid}]) @@ -1835,7 +1838,7 @@ def v0_api(api): for uuid in [n.strip().lower() for n in uuids.split(",")]: status = uuid_status(api.config["COMPOSER_CFG"], uuid) if status is None: - errors.append("%s is not a valid build uuid" % uuid) + errors.append({"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}) elif status["queue_status"] not in ["FINISHED", "FAILED"]: errors.append({"id": BUILD_IN_WRONG_STATE, "msg": "Build %s is not in FINISHED or FAILED." % uuid}) else: @@ -1861,7 +1864,10 @@ def v0_api(api): except Exception as e: return jsonify(status=False, errors=[str(e)]), 400 - return jsonify(**info) + if info is None: + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 + else: + return jsonify(**info) @api.route("/api/v0/compose/metadata", defaults={'uuid': ""}) @api.route("/api/v0/compose/metadata/") @@ -1874,7 +1880,7 @@ def v0_api(api): status = uuid_status(api.config["COMPOSER_CFG"], uuid) if status is None: - return jsonify(status=False, errors=["%s is not a valid build uuid" % uuid]), 400 + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 if status["queue_status"] not in ["FINISHED", "FAILED"]: return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 else: @@ -1894,7 +1900,7 @@ def v0_api(api): status = uuid_status(api.config["COMPOSER_CFG"], uuid) if status is None: - return jsonify(status=False, errors=["%s is not a valid build uuid" % uuid]), 400 + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 elif status["queue_status"] not in ["FINISHED", "FAILED"]: return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 else: @@ -1914,7 +1920,7 @@ def v0_api(api): status = uuid_status(api.config["COMPOSER_CFG"], uuid) if status is None: - return jsonify(status=False, errors=["%s is not a valid build uuid" % uuid]), 400 + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 elif status["queue_status"] not in ["FINISHED", "FAILED"]: return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 else: @@ -1934,7 +1940,7 @@ def v0_api(api): status = uuid_status(api.config["COMPOSER_CFG"], uuid) if status is None: - return jsonify(status=False, errors=["%s is not a valid build uuid" % uuid]), 400 + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 elif status["queue_status"] not in ["FINISHED", "FAILED"]: return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s not in FINISHED or FAILED state." % uuid}]), 400 else: @@ -1965,7 +1971,7 @@ def v0_api(api): status = uuid_status(api.config["COMPOSER_CFG"], uuid) if status is None: - return jsonify(status=False, errors=["%s is not a valid build uuid" % uuid]), 400 + return jsonify(status=False, errors=[{"id": UNKNOWN_UUID, "msg": "%s is not a valid build uuid" % uuid}]), 400 elif status["queue_status"] == "WAITING": return jsonify(status=False, errors=[{"id": BUILD_IN_WRONG_STATE, "msg": "Build %s has not started yet. No logs to view" % uuid}]) try: diff --git a/tests/pylorax/test_server.py b/tests/pylorax/test_server.py index 9a23f534..ce092d47 100644 --- a/tests/pylorax/test_server.py +++ b/tests/pylorax/test_server.py @@ -27,6 +27,7 @@ import unittest from flask import json import pytoml as toml from pylorax.api.config import configure, make_dnf_dirs, make_queue_dirs +from pylorax.api.errors import * # pylint: disable=wildcard-import 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, DNFLock @@ -795,14 +796,15 @@ class ServerTestCase(unittest.TestCase): data = json.loads(resp.data) self.assertNotEqual(data, None) self.assertEqual(data["status"], False, "Failed to get an error for a bad uuid: %s" % data) - self.assertEqual(data["errors"], ["NO-UUID-TO-SEE-HERE is not a valid build uuid"], "Failed to get errors: %s" % data) + self.assertEqual(data["errors"], [{"id": UNKNOWN_UUID, "msg": "NO-UUID-TO-SEE-HERE is not a valid build uuid"}], + "Failed to get errors: %s" % data) def test_compose_05_delete_fail(self): """Test that requesting a delete for a bad uuid fails.""" resp = self.server.delete("/api/v0/compose/delete/NO-UUID-TO-SEE-HERE") data = json.loads(resp.data) self.assertNotEqual(data, None) - self.assertEqual(data["errors"], ["no-uuid-to-see-here is not a valid build uuid"], + self.assertEqual(data["errors"], [{"id": UNKNOWN_UUID, "msg": "no-uuid-to-see-here is not a valid build uuid"}], "Failed to get an error for a bad uuid: %s" % data) def test_compose_06_info_fail(self): @@ -811,7 +813,7 @@ class ServerTestCase(unittest.TestCase): data = json.loads(resp.data) self.assertNotEqual(data, None) self.assertEqual(data["status"], False, "Failed to get an error for a bad uuid: %s" % data) - self.assertEqual(data["errors"], ["NO-UUID-TO-SEE-HERE is not a valid build_id"], + self.assertEqual(data["errors"], [{"id": UNKNOWN_UUID, "msg": "NO-UUID-TO-SEE-HERE is not a valid build uuid"}], "Failed to get errors: %s" % data) def test_compose_07_metadata_fail(self): @@ -820,7 +822,7 @@ class ServerTestCase(unittest.TestCase): data = json.loads(resp.data) self.assertNotEqual(data, None) self.assertEqual(data["status"], False, "Failed to get an error for a bad uuid: %s" % data) - self.assertEqual(data["errors"], ["NO-UUID-TO-SEE-HERE is not a valid build uuid"], + self.assertEqual(data["errors"], [{"id": UNKNOWN_UUID, "msg": "NO-UUID-TO-SEE-HERE is not a valid build uuid"}], "Failed to get errors: %s" % data) def test_compose_08_results_fail(self): @@ -829,7 +831,8 @@ class ServerTestCase(unittest.TestCase): data = json.loads(resp.data) self.assertNotEqual(data, None) self.assertEqual(data["status"], False, "Failed to get an error for a bad uuid: %s" % data) - self.assertEqual(data["errors"], ["NO-UUID-TO-SEE-HERE is not a valid build uuid"], "Failed to get errors: %s" % data) + self.assertEqual(data["errors"], [{"id": UNKNOWN_UUID, "msg": "NO-UUID-TO-SEE-HERE is not a valid build uuid"}], + "Failed to get errors: %s" % data) def test_compose_09_logs_fail(self): """Test that requesting logs for a bad uuid fails.""" @@ -837,7 +840,7 @@ class ServerTestCase(unittest.TestCase): data = json.loads(resp.data) self.assertNotEqual(data, None) self.assertEqual(data["status"], False, "Failed to get an error for a bad uuid: %s" % data) - self.assertEqual(data["errors"], ["NO-UUID-TO-SEE-HERE is not a valid build uuid"], + self.assertEqual(data["errors"], [{"id": UNKNOWN_UUID, "msg": "NO-UUID-TO-SEE-HERE is not a valid build uuid"}], "Failed to get errors: %s" % data) def test_compose_10_log_fail(self): @@ -846,7 +849,7 @@ class ServerTestCase(unittest.TestCase): data = json.loads(resp.data) self.assertNotEqual(data, None) self.assertEqual(data["status"], False, "Failed to get an error for a bad uuid: %s" % data) - self.assertEqual(data["errors"], ["NO-UUID-TO-SEE-HERE is not a valid build uuid"], + self.assertEqual(data["errors"], [{"id": UNKNOWN_UUID, "msg": "NO-UUID-TO-SEE-HERE is not a valid build uuid"}], "Failed to get errors: %s" % data) def test_compose_11_create_failed(self):