1 import flask
2 import time
3
4 from coprs import db, app
5 from coprs import helpers
6 from coprs import models
7 from coprs.helpers import StatusEnum
8 from coprs.logic import actions_logic
9 from coprs.logic.builds_logic import BuildsLogic
10 from coprs.logic.complex_logic import ComplexLogic
11 from coprs.logic.coprs_logic import CoprChrootsLogic
12 from coprs.logic.packages_logic import PackagesLogic
13
14 from coprs.views import misc
15 from coprs.views.backend_ns import backend_ns
16 from sqlalchemy.sql import false, true
17
18 import logging
19 log = logging.getLogger(__name__)
51
52
53 @backend_ns.route("/import-completed/", methods=["POST", "PUT"])
115
116
117 @backend_ns.route("/waiting/")
118
119 -def waiting():
120 """
121 Return a single action and a single build.
122 """
123 action_record = None
124 build_record = None
125
126 action = actions_logic.ActionsLogic.get_waiting().first()
127 if action:
128 action_record = action.to_dict(options={
129 "__columns_except__": ["result", "message", "ended_on"]
130 })
131
132 task = BuildsLogic.get_build_task()
133 if task:
134 try:
135 build_record = {
136 "task_id": task.task_id,
137 "build_id": task.build.id,
138 "project_owner": task.build.copr.owner_name,
139 "project_name": task.build.copr.name,
140 "submitter": task.build.user.name if task.build.user else None,
141 "pkgs": task.build.pkgs,
142 "chroot": task.mock_chroot.name,
143
144 "repos": task.build.repos,
145 "memory_reqs": task.build.memory_reqs,
146 "timeout": task.build.timeout,
147 "enable_net": task.build.enable_net,
148 "git_repo": task.build.package.dist_git_repo,
149 "git_hash": task.git_hash,
150 "git_branch": helpers.chroot_to_branch(task.mock_chroot.name),
151 "package_name": task.build.package.name,
152 "package_version": task.build.pkg_version
153 }
154
155 copr_chroot = CoprChrootsLogic.get_by_name_safe(task.build.copr, task.mock_chroot.name)
156 if copr_chroot:
157 build_record["buildroot_pkgs"] = copr_chroot.buildroot_pkgs
158 else:
159 build_record["buildroot_pkgs"] = ""
160
161 except Exception as err:
162 app.logger.exception(err)
163
164 response_dict = {"action": action_record, "build": build_record}
165 return flask.jsonify(response_dict)
166
167
168 @backend_ns.route("/update/", methods=["POST", "PUT"])
171 result = {}
172
173 request_data = flask.request.json
174 for typ, logic_cls in [("actions", actions_logic.ActionsLogic),
175 ("builds", BuildsLogic)]:
176
177 if typ not in request_data:
178 continue
179
180 to_update = {}
181 for obj in request_data[typ]:
182 to_update[obj["id"]] = obj
183
184 existing = {}
185 for obj in logic_cls.get_by_ids(to_update.keys()).all():
186 existing[obj.id] = obj
187
188 non_existing_ids = list(set(to_update.keys()) - set(existing.keys()))
189
190 for i, obj in existing.items():
191 logic_cls.update_state_from_dict(obj, to_update[i])
192
193 db.session.commit()
194 result.update({"updated_{0}_ids".format(typ): list(existing.keys()),
195 "non_existing_{0}_ids".format(typ): non_existing_ids})
196
197 return flask.jsonify(result)
198
199
200 @backend_ns.route("/starting_build/", methods=["POST", "PUT"])
203 """
204 Check if the build is not cancelled and set it to running state
205 """
206
207 result = {"can_start": False}
208
209 if "build_id" in flask.request.json and "chroot" in flask.request.json:
210 build = ComplexLogic.get_build_safe(flask.request.json["build_id"])
211 chroot = flask.request.json.get("chroot")
212
213 if build and chroot and not build.canceled:
214 log.info("mark build {} chroot {} as starting".format(build.id, chroot))
215 BuildsLogic.update_state_from_dict(build, {
216 "chroot": chroot,
217 "status": StatusEnum("starting")
218 })
219 db.session.commit()
220 result["can_start"] = True
221
222 return flask.jsonify(result)
223
224
225 @backend_ns.route("/defer_build/", methods=["POST", "PUT"])
228 """
229 Defer build (keep it out of waiting jobs for some time).
230 """
231
232 result = {"was_deferred": False}
233
234 if "build_id" in flask.request.json and "chroot" in flask.request.json:
235 build = ComplexLogic.get_build_safe(flask.request.json["build_id"])
236 chroot = flask.request.json.get("chroot")
237
238 if build and chroot:
239 log.info("Defer build {}, chroot {}".format(build.id, chroot))
240 BuildsLogic.update_state_from_dict(build, {
241 "chroot": chroot,
242 "last_deferred": int(time.time()),
243 })
244 db.session.commit()
245 result["was_deferred"] = True
246
247 return flask.jsonify(result)
248
249
250 @backend_ns.route("/reschedule_all_running/", methods=["POST"])
268
269
270 @backend_ns.route("/reschedule_build_chroot/", methods=["POST", "PUT"])
273 response = {}
274 if "build_id" in flask.request.json and "chroot" in flask.request.json:
275 build = ComplexLogic.get_build_safe(flask.request.json["build_id"])
276 else:
277 response["result"] = "bad request"
278 response["msg"] = "Request missing `build_id` and/or `chroot`"
279 return flask.jsonify(response)
280
281 if build:
282 if build.canceled:
283 response["result"] = "noop"
284 response["msg"] = "build was cancelled, ignoring"
285 else:
286 chroot = flask.request.json["chroot"]
287 build_chroot = build.chroots_dict_by_name.get(chroot)
288 run_statuses = set([StatusEnum("starting"), StatusEnum("running")])
289 if build_chroot and build_chroot.status in run_statuses:
290 log.info("rescheduling build {} chroot: {}".format(build.id, build_chroot.name))
291 BuildsLogic.update_state_from_dict(build, {
292 "chroot": chroot,
293 "status": StatusEnum("pending")
294 })
295 db.session.commit()
296 response["result"] = "done"
297 else:
298 response["result"] = "noop"
299 response["msg"] = "build is not in running states, ignoring"
300
301 else:
302 response["result"] = "noop"
303 response["msg"] = "Build {} wasn't found".format(flask.request.json["build_id"])
304
305 return flask.jsonify(response)
306