from __future__ import unicode_literals from django.db import models from django.core.validators import MaxValueValidator, MinValueValidator from django.utils.encoding import force_bytes from orm.models import Project, ProjectLayer, ProjectVariable, ProjectTarget, Build, Layer_Version import logging logger = logging.getLogger("toaster") # a BuildEnvironment is the equivalent of the "build/" directory on the localhost class BuildEnvironment(models.Model): SERVER_STOPPED = 0 SERVER_STARTED = 1 SERVER_STATE = ( (SERVER_STOPPED, "stopped"), (SERVER_STARTED, "started"), ) TYPE_LOCAL = 0 TYPE = ( (TYPE_LOCAL, "local"), ) LOCK_FREE = 0 LOCK_LOCK = 1 LOCK_RUNNING = 2 LOCK_STATE = ( (LOCK_FREE, "free"), (LOCK_LOCK, "lock"), (LOCK_RUNNING, "running"), ) address = models.CharField(max_length = 254) betype = models.IntegerField(choices = TYPE) bbaddress = models.CharField(max_length = 254, blank = True) bbport = models.IntegerField(default = -1) bbtoken = models.CharField(max_length = 126, blank = True) bbstate = models.IntegerField(choices = SERVER_STATE, default = SERVER_STOPPED) sourcedir = models.CharField(max_length = 512, blank = True) builddir = models.CharField(max_length = 512, blank = True) lock = models.IntegerField(choices = LOCK_STATE, default = LOCK_FREE) created = models.DateTimeField(auto_now_add = True) updated = models.DateTimeField(auto_now = True) def get_artifact(self, path): if self.betype == BuildEnvironment.TYPE_LOCAL: return open(path, "r") raise NotImplementedError("FIXME: artifact download not implemented "\ "for build environment type %s" % \ self.get_betype_display()) def has_artifact(self, path): import os if self.betype == BuildEnvironment.TYPE_LOCAL: return os.path.exists(path) raise NotImplementedError("FIXME: has artifact not implemented for "\ "build environment type %s" % \ self.get_betype_display()) # a BuildRequest is a request that the scheduler will build using a BuildEnvironment # the build request queue is the table itself, ordered by state class BuildRequest(models.Model): REQ_CREATED = 0 REQ_QUEUED = 1 REQ_INPROGRESS = 2 REQ_COMPLETED = 3 REQ_FAILED = 4 REQ_DELETED = 5 REQ_CANCELLING = 6 REQ_ARCHIVE = 7 REQUEST_STATE = ( (REQ_CREATED, "created"), (REQ_QUEUED, "queued"), (REQ_INPROGRESS, "in progress"), (REQ_COMPLETED, "completed"), (REQ_FAILED, "failed"), (REQ_DELETED, "deleted"), (REQ_CANCELLING, "cancelling"), (REQ_ARCHIVE, "archive"), ) search_allowed_fields = ("brtarget__target", "build__project__name") project = models.ForeignKey(Project) build = models.OneToOneField(Build, null = True) # TODO: toasterui should set this when Build is created environment = models.ForeignKey(BuildEnvironment, null = True) state = models.IntegerField(choices = REQUEST_STATE, default = REQ_CREATED) created = models.DateTimeField(auto_now_add = True) updated = models.DateTimeField(auto_now = True) def __init__(self, *args, **kwargs): super(BuildRequest, self).__init__(*args, **kwargs) # Save the old state incase it's about to be modified self.old_state = self.state def save(self, *args, **kwargs): # Check that the state we're trying to set is not going backwards # e.g. from REQ_FAILED to REQ_INPROGRESS if self.old_state != self.state and self.old_state > self.state: logger.warning("Invalid state change requested: " "Cannot go from %s to %s - ignoring request" % (BuildRequest.REQUEST_STATE[self.old_state][1], BuildRequest.REQUEST_STATE[self.state][1]) ) # Set property back to the old value self.state = self.old_state return super(BuildRequest, self).save(*args, **kwargs) def get_duration(self): return (self.updated - self.created).total_seconds() def get_sorted_target_list(self): tgts = self.brtarget_set.order_by( 'target' ); return( tgts ); def get_machine(self): return self.brvariable_set.get(name="MACHINE").value def __str__(self): return force_bytes('%s %s' % (self.project, self.get_state_display())) # These tables specify the settings for running an actual build. # They MUST be kept in sync with the tables in orm.models.Project* class BRLayer(models.Model): req = models.ForeignKey(BuildRequest) name = models.CharField(max_length = 100) giturl = models.CharField(max_length = 254) commit = models.CharField(max_length = 254) dirpath = models.CharField(max_length = 254) layer_version = models.ForeignKey(Layer_Version, null=True) class BRBitbake(models.Model): req = models.OneToOneField(BuildRequest) # only one bitbake for a request giturl = models.CharField(max_length =254) commit = models.CharField(max_length = 254) dirpath = models.CharField(max_length = 254) class BRVariable(models.Model): req = models.ForeignKey(BuildRequest) name = models.CharField(max_length=100) value = models.TextField(blank = True) class BRTarget(models.Model): req = models.ForeignKey(BuildRequest) target = models.CharField(max_length=100) task = models.CharField(max_length=100, null=True) class BRError(models.Model): req = models.ForeignKey(BuildRequest) errtype = models.CharField(max_length=100) errmsg = models.TextField() traceback = models.TextField() def __str__(self): return "%s (%s)" % (self.errmsg, self.req)