mirror of
https://pagure.io/fm-orchestrator.git
synced 2026-04-02 10:20:31 +08:00
Greenwave query class and configuration update
Signed-off-by: Valerij Maljulin <vmaljuli@redhat.com>
This commit is contained in:
@@ -120,7 +120,11 @@ class TestConfiguration(BaseConfiguration):
|
||||
RESOLVER = "db"
|
||||
|
||||
ALLOWED_GROUPS_TO_IMPORT_MODULE = set(["mbs-import-module"])
|
||||
GREENWAVE_DECISION_CONTEXT = "osci_compose_gate_modules"
|
||||
|
||||
# Greenwave configuration
|
||||
GREENWAVE_URL = "https://greenwave.example.local/api/v1.0/"
|
||||
GREENWAVE_DECISION_CONTEXT = "test_dec_context"
|
||||
GREENWAVE_SUBJECT_TYPE = "some-module"
|
||||
|
||||
STREAM_SUFFIXES = {r"^el\d+\.\d+\.\d+\.z$": 0.1}
|
||||
|
||||
|
||||
@@ -295,14 +295,9 @@ class KojiContentGenerator(object):
|
||||
return rpms
|
||||
|
||||
def _get_build(self):
|
||||
ret = {}
|
||||
ret[u"name"] = self.module.name
|
||||
ret = self.module.nvr
|
||||
if self.devel:
|
||||
ret["name"] += "-devel"
|
||||
ret[u"version"] = self.module.stream.replace("-", "_")
|
||||
# Append the context to the version to make NVRs of modules unique in the event of
|
||||
# module stream expansion
|
||||
ret[u"release"] = "{0}.{1}".format(self.module.version, self.module.context)
|
||||
ret[u"source"] = self.module.scmurl
|
||||
ret[u"start_time"] = calendar.timegm(self.module.time_submitted.utctimetuple())
|
||||
ret[u"end_time"] = calendar.timegm(self.module.time_completed.utctimetuple())
|
||||
|
||||
@@ -603,6 +603,22 @@ class Config(object):
|
||||
"corresponding suffix added to formatted stream version. "
|
||||
'For example, {r"regexp": 0.1, ...}',
|
||||
},
|
||||
"greenwave_url": {
|
||||
"type": str,
|
||||
"default": "",
|
||||
"desc": "The URL of the server where Greenwave is running (should include "
|
||||
"the root of the API)"
|
||||
},
|
||||
"greenwave_subject_type": {
|
||||
"type": str,
|
||||
"default": "",
|
||||
"desc": "Subject type for Greenwave requests"
|
||||
},
|
||||
"greenwave_timeout": {
|
||||
"type": int,
|
||||
"default": 60,
|
||||
"desc": "Greenwave response timeout"
|
||||
}
|
||||
}
|
||||
|
||||
def __init__(self, conf_section_obj):
|
||||
|
||||
@@ -55,6 +55,10 @@ class StreamAmbigous(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
class GreenwaveError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def json_error(status, error, message):
|
||||
response = jsonify({"status": status, "error": error, "message": message})
|
||||
response.status_code = status
|
||||
|
||||
@@ -34,6 +34,7 @@ from collections import OrderedDict
|
||||
from datetime import datetime
|
||||
|
||||
import sqlalchemy
|
||||
import kobo.rpmlib
|
||||
from flask import has_app_context
|
||||
from sqlalchemy import func, and_
|
||||
from sqlalchemy.orm import lazyload
|
||||
@@ -601,6 +602,18 @@ class ModuleBuild(MBSBase):
|
||||
)
|
||||
return [build.id for build in query.all()]
|
||||
|
||||
@property
|
||||
def nvr(self):
|
||||
return {
|
||||
u"name": self.name,
|
||||
u"version": self.stream.replace("-", "_"),
|
||||
u"release": "{0}.{1}".format(self.version, self.context)
|
||||
}
|
||||
|
||||
@property
|
||||
def nvr_string(self):
|
||||
return kobo.rpmlib.make_nvr(self.nvr)
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
cls,
|
||||
|
||||
116
module_build_service/utils/greenwave.py
Normal file
116
module_build_service/utils/greenwave.py
Normal file
@@ -0,0 +1,116 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2019 Red Hat, Inc.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
#
|
||||
# Written by Valerij Maljulin <vmaljuli@redhat.com>
|
||||
|
||||
|
||||
import requests
|
||||
import json
|
||||
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
|
||||
if not self.url:
|
||||
raise GreenwaveError("No Greenwave URL set")
|
||||
self._decision_context = conf.greenwave_decision_context
|
||||
if not self.decision_context:
|
||||
raise GreenwaveError("No Greenwave decision context set")
|
||||
self._subj_type = conf.greenwave_subject_type
|
||||
self._gw_timeout = conf.greenwave_timeout
|
||||
|
||||
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
|
||||
}
|
||||
url = "{0}/decision".format(self.url)
|
||||
headers = {"Content-Type": "application/json"}
|
||||
try:
|
||||
response = requests.post(
|
||||
url=url, headers=headers, data=json.dumps(payload), timeout=self.timeout)
|
||||
except requests.exceptions.Timeout:
|
||||
raise GreenwaveError("Greenwave request timed out")
|
||||
except Exception as exc:
|
||||
log.exception(str(exc))
|
||||
raise GreenwaveError("Greenwave request error")
|
||||
|
||||
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 result: status=%d, content="%s"',
|
||||
(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))
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
return self._url
|
||||
|
||||
@url.setter
|
||||
def url(self, value):
|
||||
value = value.rstrip("/")
|
||||
if value:
|
||||
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
|
||||
@@ -98,14 +98,14 @@ class TestDecisionUpdateHandler:
|
||||
log.debug.assert_called_once_with(
|
||||
'Skip Greenwave message %s as MBS only handles messages with the decision context "%s"',
|
||||
"msg-id-1",
|
||||
"osci_compose_gate_modules",
|
||||
"test_dec_context"
|
||||
)
|
||||
|
||||
@patch("module_build_service.scheduler.handlers.greenwave.log")
|
||||
def test_not_satisfy_policies(self, log):
|
||||
msg = Mock(
|
||||
msg_id="msg-id-1",
|
||||
decision_context="osci_compose_gate_modules",
|
||||
decision_context="test_dec_context",
|
||||
policies_satisfied=False,
|
||||
subject_identifier="pkg-0.1-1.c1",
|
||||
)
|
||||
@@ -144,7 +144,7 @@ class TestDecisionUpdateHandler:
|
||||
"msg_id": "msg-id-1",
|
||||
"topic": "org.fedoraproject.prod.greenwave.decision.update",
|
||||
"msg": {
|
||||
"decision_context": "osci_compose_gate_modules",
|
||||
"decision_context": "test_dec_context",
|
||||
"policies_satisfied": True,
|
||||
"subject_identifier": "pkg-0.1-1.c1",
|
||||
},
|
||||
|
||||
70
tests/test_utils/test_greenwave.py
Normal file
70
tests/test_utils/test_greenwave.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# Copyright (c) 2019 Red Hat, Inc.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
#
|
||||
# Written by Valerij Maljulin <vmaljuli@redhat.com>
|
||||
|
||||
|
||||
import json
|
||||
from mock import patch, Mock
|
||||
import module_build_service.utils.greenwave
|
||||
from tests import make_module
|
||||
|
||||
|
||||
class TestGreenwaveQuery():
|
||||
@patch("module_build_service.utils.greenwave.requests")
|
||||
def test_greenwave_decision(self, mock_requests):
|
||||
resp_status = 200
|
||||
resp_content = {
|
||||
"applicable_policies": ["osci_compose_modules"],
|
||||
"policies_satisfied": True,
|
||||
"satisfied_requirements": [
|
||||
{
|
||||
"result_id": 7336633,
|
||||
"testcase": "test-ci.test-module.tier1",
|
||||
"type": "test-result-passed"
|
||||
},
|
||||
{
|
||||
"result_id": 7336650,
|
||||
"testcase": "test-ci.test-module.tier2",
|
||||
"type": "test-result-passed"
|
||||
}
|
||||
],
|
||||
"summary": "All required tests passed",
|
||||
"unsatisfied_requirements": []
|
||||
}
|
||||
response = Mock()
|
||||
response.json.return_value = resp_content
|
||||
response.status_code = resp_status
|
||||
mock_requests.post.return_value = response
|
||||
|
||||
fake_build = make_module("pkg:0.1:1:c1", requires_list={"platform": "el8"})
|
||||
|
||||
gw = module_build_service.utils.greenwave.Greenwave()
|
||||
got_response = gw.query_decision(fake_build, prod_version="xxxx-8")
|
||||
|
||||
assert got_response == resp_content
|
||||
assert json.loads(mock_requests.post.call_args_list[0][1]["data"]) == {
|
||||
"decision_context": "test_dec_context",
|
||||
"product_version": "xxxx-8", "subject_type": "some-module",
|
||||
"subject_identifier": "pkg-0.1-1.c1"}
|
||||
assert mock_requests.post.call_args_list[0][1]["headers"] == {
|
||||
"Content-Type": "application/json"}
|
||||
assert mock_requests.post.call_args_list[0][1]["url"] == \
|
||||
"https://greenwave.example.local/api/v1.0/decision"
|
||||
Reference in New Issue
Block a user