zuul/zuul/lib/result_data.py
James E. Blair f0c313fb7d Handle zuul_return format errors
This change does two things:

First, it corrects an error in the zuul_return schema validation
which would, in a job where someone returned an artifact with a
missing required attribute such as "url", cause an exception in
the SQL reporter (which would lead to incomplete build results in
the db, and possibly other pipeline-related errors).

This change is made by correcting the voluptuous schema so that
the "Required" flag is on the key, not the value.

Secondly, it performs schema validation within the zuul_return
module itself.  This will cause such errors to become user-visible
at the time they occur (during the job) rather than post-facto.
To accomplish this, the schema definition is moved into the
shared zuul/ansible module, and a dependency on voluptuous within
the in-job ansible virtualenvs is added.

The first fix is still needed even with the second because users
can return data to Zuul without using the zuul_return plugin.

Change-Id: I6991863b2b5986b8067124b92c141c3c59240d18
2024-08-26 14:35:49 -07:00

70 lines
2.3 KiB
Python

# Copyright 2018-2019 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import urllib.parse
from zuul.ansible.schema import (
artifact_schema,
warning_schema,
)
def validate_schema(data, schema):
try:
schema(data)
except Exception:
return False
return True
def get_artifacts_from_result_data(result_data, logger=None):
ret = []
if validate_schema(result_data, artifact_schema):
artifacts = result_data.get('zuul', {}).get(
'artifacts', [])
default_url = result_data.get('zuul', {}).get(
'log_url')
if default_url:
if default_url[-1] != '/':
default_url += '/'
for artifact in artifacts:
url = artifact['url']
if default_url:
# If the artifact url is relative, it will be combined
# with the log_url; if it is absolute, it will replace
# it.
try:
url = urllib.parse.urljoin(default_url, url)
except Exception:
if logger:
logger.debug("Error parsing URL:",
exc_info=1)
d = artifact.copy()
d['url'] = url
ret.append(d)
else:
if logger:
logger.debug("Result data did not pass artifact schema "
"validation: %s", result_data)
return ret
def get_warnings_from_result_data(result_data, logger=None):
if validate_schema(result_data, warning_schema):
return result_data.get('zuul', {}).get('warnings', [])
else:
if logger:
logger.debug("Result data did not pass warnings schema "
"validation: %s", result_data)