-#!/usr/bin/python
+#!/usr/bin/python3
+import logging
import tornado.web
+import tornado.websocket
from . import base
from . import ui_modules
+# Setup logging
+log = logging.getLogger("pakfire.buildservice.web.jobs")
+
+class APIv1QueueHandler(base.APIMixin, tornado.websocket.WebSocketHandler):
+ """
+ Builders connect to this handler which will add them to a list of connections.
+
+ For all connections, we regularly check if we have any new build jobs, and if so,
+ we will send them the job.
+ """
+
+ # Don't allow users to authenticate
+ allow_users = False
+
+ @property
+ def builder(self):
+ return self.current_user
+
+ @tornado.web.authenticated
+ async def open(self):
+ # Register a new connection
+ await self.backend.jobqueue.open(builder=self.builder, connection=self)
+
+ def on_close(self):
+ # Close the connection
+ self.backend.jobqueue.close(builder=self.builder, connection=self)
+
+ def assign_job(self, job):
+ log.debug("Sending job %s to %s" % (job, self))
+
+ # Assign this job
+ with self.db.transaction():
+ job.assign(builder=self.builder)
+
+ self.write_message({
+ "message" : "job",
+
+ # Add job information
+ "id" : job.uuid,
+ "name" : "%s" % job,
+ "arch" : job.arch,
+
+ # Is this a test job?
+ "test" : job.test,
+
+ # Send the pakfire configuration without using any mirrors
+ "conf" : "%s" % job.pakfire(mirrored=False),
+
+ # URL to the package
+ "pkg" : job.pkg.download_url,
+ })
+
+
+class APIv1DetailHandler(base.APIMixin, tornado.websocket.WebSocketHandler):
+ """
+ Builders connect to this handler when they are running a build.
+
+ We can pass information about this build around in real time.
+ """
+ # Don't allow users to authenticate
+ allow_users = False
+
+ @tornado.web.authenticated
+ def open(self, job_id):
+ self.job = self.backend.jobs.get_by_uuid(job_id)
+ if not self.job:
+ raise tornado.web.HTTPError(404, "Could not find job %s" % job_id)
+
+ # Check if the builder matches
+ if not self.current_user == self.job.builder:
+ raise tornado.web.HTTPError(403, "Job %s belongs to %s, not %s" % \
+ (self.job, self.job.builder, self.current_user))
+
+ log.debug("Connection opened for %s by %s" % (self.job, self.current_user))
+
+ async def on_message(self, message):
+ message = self._decode_json_message(message)
+
+ # Get message type
+ t = message.get("message")
+
+ # Handle status messages
+ if t == "status":
+ pass
+
+ # Handle log messages
+ elif t == "log":
+ pass
+
+ # Handle finished message
+ elif t == "finished":
+ await self._handle_finished(**message)
+
+ # Unknown message
+ else:
+ log.warning("Received a message of an unknown type: %s" % t)
+
+ async def _handle_finished(self, success=False, logfile=None, packages=[], **kwargs):
+ """
+ Called when a job has finished - whether successfully or not
+ """
+ # Fetch the log
+ if logfile:
+ logfile = self.backend.uploads.get_by_uuid(logfile)
+
+ # Fetch the packages
+ if packages:
+ packages = [self.backend.uploads.get_by_uuid(p) for p in packages]
+
+ # Mark the job as finished
+ with self.db.transaction():
+ await self.job.finished(success=success, logfile=logfile, packages=packages)
+
+ # Try to dispatch the next job
+ await self.backend.jobqueue.dispatch_jobs()
+
+
class QueueHandler(base.BaseHandler):
def get(self):
self.render("queue.html", queue=self.backend.jobqueue)