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