]> git.ipfire.org Git - pbs.git/blobdiff - src/web/jobs.py
Merge Pakfire Hub into the main webapp
[pbs.git] / src / web / jobs.py
index 83e85d7e1ad0b19f47f649481c1da6df9117abf7..510ca937daa6c8be63a94934b41fc189995a05c9 100644 (file)
-#!/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)