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