-
Notifications
You must be signed in to change notification settings - Fork 56
/
frontend.py
103 lines (84 loc) · 3.75 KB
/
frontend.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
"""
The logic behind contacting Copr Frontend from Backend. All the requests to
the /backend/ Flask blueprint should go through this FrontendClient API.
"""
import logging
from copr_common.request import SafeRequest, RequestError
from copr_backend.exceptions import FrontendClientException
# The frontend counterpart is in `backend_general:send_frontend_version`
MIN_FE_BE_API = 6
class FrontendClient:
"""
Object to send data back to fronted
"""
# do we block the main daemon process?
try_indefinitely = False
def __init__(self, opts, logger=None, try_indefinitely=False):
self.frontend_url = "{}/backend".format(opts.frontend_base_url)
self.frontend_auth = opts.frontend_auth
self.try_indefinitely = try_indefinitely
self.msg = None
self.logger = logger
@property
def log(self):
'return configured logger object, or no-op logger'
if not self.logger:
self.logger = logging.getLogger(__name__)
self.logger.addHandler(logging.NullHandler())
return self.logger
def get(self, url_path):
'Issue relentless GET request to Frontend'
return self.send(url_path, method='get')
def post(self, url_path, data):
'Issue relentless POST request to Frontend'
return self.send(url_path, data=data)
def put(self, url_path, data):
'Issue relentless POST request to Frontend'
return self.send(url_path, data=data, method='put')
def send(self, url_path, method='post', data=None, authenticate=True):
""" Repeat the request until it succeeds. """
while True:
response = self._send_attempt(url_path, method, data, authenticate)
fe_be_api_version = response.headers.get("Copr-FE-BE-API-Version", 0)
if int(fe_be_api_version) >= MIN_FE_BE_API:
return response
msg = "Copr FE/BE API is too old on Frontend side, %s < %s"
if self.try_indefinitely:
self.logger.error(msg, fe_be_api_version, MIN_FE_BE_API)
continue
raise FrontendClientException(msg % (fe_be_api_version, MIN_FE_BE_API))
def _send_attempt(self, url_path, method='post', data=None, authenticate=True):
# """
# Repeat the request until it succeeds, or timeout is reached.
# """
url = "{}/{}/".format(self.frontend_url, url_path)
auth = self.frontend_auth if authenticate else None
self.log.info("Sending %s request to frontend URL - %s",
method.upper(), url)
try:
request = SafeRequest(auth=auth, log=self.log,
try_indefinitely=self.try_indefinitely)
response = request.send(url, method=method, data=data)
return response
except RequestError as ex:
raise FrontendClientException(str(ex)) from ex
def update(self, data):
"""
Send data to be updated in the frontend
"""
self.post("update", data)
def starting_build(self, data):
"""
Announce to the frontend that a build is starting.
:return: True if the build can start or False if the build can not start (can be cancelled or deleted).
"""
response = self.post("starting_build", data)
if "can_start" not in response.json():
raise FrontendClientException("Bad response from the frontend")
return response.json()["can_start"]
def reschedule_build(self, build_id, task_id, chroot_name):
"""
Announce to the frontend that a build should be rescheduled (set pending state).
"""
data = {"build_id": build_id, "task_id": task_id, "chroot": chroot_name}
self.post("reschedule_build_chroot", data)