Files
fm-orchestrator/module_build_service/utils/greenwave.py
mprahl 8c6cfb702d Use small license headers in the Python files
This also removes the outdated comments around authorship of each
file. If there is still interest in this information, one can just
look at the git history.
2019-10-03 08:47:24 -04:00

190 lines
6.0 KiB
Python

# -*- coding: utf-8 -*-
# SPDX-License-Identifier: MIT
import requests
import json
from functools import reduce
from module_build_service import log, conf
from module_build_service.errors import GreenwaveError
class Greenwave(object):
def __init__(self):
"""
Initialize greenwave instance with config
"""
self.url = conf.greenwave_url
self._decision_context = conf.greenwave_decision_context
if not self.decision_context:
raise RuntimeError("No Greenwave decision context set")
self._subj_type = conf.greenwave_subject_type
self._gw_timeout = conf.greenwave_timeout
self.error_occurred = False
def _greenwave_query(self, query_type, payload=None):
"""
Make a query to greenwave
:param query_type: will be part of url
:type query_type: str
:param payload: request payload used in 'decision' query
:type payload: str
:return: response
:rtype: dict
"""
query_func = requests.post if payload else requests.get
kwargs = {"url": "{0}/{1}".format(self.url, query_type), "timeout": self.timeout}
if payload:
kwargs["headers"] = {"Content-Type": "application/json"}
kwargs["data"] = payload
try:
response = query_func(**kwargs)
except requests.exceptions.Timeout:
raise GreenwaveError("Greenwave request timed out")
except Exception as exc:
error_message = "Unspecified greenwave request error " \
'(original exception was: "{0}")'.format(str(exc))
log.exception(error_message)
raise GreenwaveError(error_message)
try:
resp_json = response.json()
except ValueError:
log.debug("Greenwave response content (status {0}): {1}".format(
response.status_code, response.text
))
raise GreenwaveError("Greenwave returned invalid JSON.")
log.debug(
'Query to Greenwave (%s) result: status=%d, content="%s"',
kwargs["url"], response.status_code, resp_json
)
if response.status_code == 200:
return resp_json
try:
err_msg = resp_json["message"]
except KeyError:
err_msg = response.text
raise GreenwaveError("Greenwave returned {0} status code. Message: {1}".format(
response.status_code, err_msg
))
def query_decision(self, build, prod_version):
"""
Query decision to greenwave
:param build: build object
:type build: module_build_service.models.ModuleBuild
:param prod_version: The product version string used for querying WaiverDB
:type prod_version: str
:return: response
:rtype: dict
"""
payload = {
"decision_context": self.decision_context,
"product_version": prod_version,
"subject_type": self.subject_type,
"subject_identifier": build.nvr_string
}
return self._greenwave_query('decision', json.dumps(payload))
def query_policies(self, return_all=False):
"""
Query policies to greenwave
:param return_all: Return all policies, if False select by subject_type and decision_context
:type return_all: bool
:return: response
:rtype: dict
"""
response = self._greenwave_query('policies')
if return_all:
return response
try:
selective_resp = {
"policies": [
pol for pol in response["policies"]
if pol["decision_context"] == self.decision_context
and pol["subject_type"] == self.subject_type
]
}
except KeyError:
log.exception("Incorrect greenwave response (Mandatory key is missing)")
raise GreenwaveError("Incorrect greenwave response (Mandatory key is missing)")
return selective_resp
def get_product_versions(self):
"""
Return a set of product versions according to decision_context and subject_type
:return: product versions
:rtype: set
"""
return reduce(
lambda old, new: old.union(new),
[pol["product_versions"] for pol in self.query_policies()["policies"]],
set()
)
def check_gating(self, build):
"""
Query decision to greenwave
:param build: build object
:type build: module_build_service.models.ModuleBuild
:return: True if at least one GW response contains policies_satisfied set to true
:rtype: bool
"""
self.error_occurred = False
try:
versions = self.get_product_versions()
except GreenwaveError:
log.warning('An error occured while getting a product versions')
self.error_occurred = True
return False
for ver in versions:
try:
if self.query_decision(build, ver)["policies_satisfied"]:
# at least one positive result is enough
return True
except (KeyError, GreenwaveError) as exc:
self.error_occurred = True
log.warning('Incorrect greenwave result "%s", ignoring', str(exc))
return False
@property
def url(self):
return self._url
@url.setter
def url(self, value):
value = value.rstrip("/")
if not value:
raise RuntimeError("No Greenwave URL set")
self._url = value
@property
def decision_context(self):
return self._decision_context
@property
def subject_type(self):
return self._subj_type
@property
def timeout(self):
return self._gw_timeout
@timeout.setter
def timeout(self, value):
self._gw_timeout = value
try:
greenwave = Greenwave()
except RuntimeError:
log.warning('Greenwave is not configured or configured improperly')
greenwave = None