1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun 5*4882a593Smuzhiyunfrom __future__ import unicode_literals 6*4882a593Smuzhiyunfrom django.db import models 7*4882a593Smuzhiyunfrom django.utils.encoding import force_text 8*4882a593Smuzhiyunfrom orm.models import Project, Build, Layer_Version 9*4882a593Smuzhiyun 10*4882a593Smuzhiyunimport logging 11*4882a593Smuzhiyunlogger = logging.getLogger("toaster") 12*4882a593Smuzhiyun# a BuildEnvironment is the equivalent of the "build/" directory on the localhost 13*4882a593Smuzhiyunclass BuildEnvironment(models.Model): 14*4882a593Smuzhiyun SERVER_STOPPED = 0 15*4882a593Smuzhiyun SERVER_STARTED = 1 16*4882a593Smuzhiyun SERVER_STATE = ( 17*4882a593Smuzhiyun (SERVER_STOPPED, "stopped"), 18*4882a593Smuzhiyun (SERVER_STARTED, "started"), 19*4882a593Smuzhiyun ) 20*4882a593Smuzhiyun 21*4882a593Smuzhiyun TYPE_LOCAL = 0 22*4882a593Smuzhiyun TYPE = ( 23*4882a593Smuzhiyun (TYPE_LOCAL, "local"), 24*4882a593Smuzhiyun ) 25*4882a593Smuzhiyun 26*4882a593Smuzhiyun LOCK_FREE = 0 27*4882a593Smuzhiyun LOCK_LOCK = 1 28*4882a593Smuzhiyun LOCK_RUNNING = 2 29*4882a593Smuzhiyun LOCK_STATE = ( 30*4882a593Smuzhiyun (LOCK_FREE, "free"), 31*4882a593Smuzhiyun (LOCK_LOCK, "lock"), 32*4882a593Smuzhiyun (LOCK_RUNNING, "running"), 33*4882a593Smuzhiyun ) 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun address = models.CharField(max_length = 254) 36*4882a593Smuzhiyun betype = models.IntegerField(choices = TYPE) 37*4882a593Smuzhiyun bbaddress = models.CharField(max_length = 254, blank = True) 38*4882a593Smuzhiyun bbport = models.IntegerField(default = -1) 39*4882a593Smuzhiyun bbtoken = models.CharField(max_length = 126, blank = True) 40*4882a593Smuzhiyun bbstate = models.IntegerField(choices = SERVER_STATE, default = SERVER_STOPPED) 41*4882a593Smuzhiyun sourcedir = models.CharField(max_length = 512, blank = True) 42*4882a593Smuzhiyun builddir = models.CharField(max_length = 512, blank = True) 43*4882a593Smuzhiyun lock = models.IntegerField(choices = LOCK_STATE, default = LOCK_FREE) 44*4882a593Smuzhiyun created = models.DateTimeField(auto_now_add = True) 45*4882a593Smuzhiyun updated = models.DateTimeField(auto_now = True) 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun def get_artifact(self, path): 48*4882a593Smuzhiyun if self.betype == BuildEnvironment.TYPE_LOCAL: 49*4882a593Smuzhiyun return open(path, "r") 50*4882a593Smuzhiyun raise NotImplementedError("FIXME: artifact download not implemented "\ 51*4882a593Smuzhiyun "for build environment type %s" % \ 52*4882a593Smuzhiyun self.get_betype_display()) 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun def has_artifact(self, path): 55*4882a593Smuzhiyun import os 56*4882a593Smuzhiyun if self.betype == BuildEnvironment.TYPE_LOCAL: 57*4882a593Smuzhiyun return os.path.exists(path) 58*4882a593Smuzhiyun raise NotImplementedError("FIXME: has artifact not implemented for "\ 59*4882a593Smuzhiyun "build environment type %s" % \ 60*4882a593Smuzhiyun self.get_betype_display()) 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun# a BuildRequest is a request that the scheduler will build using a BuildEnvironment 63*4882a593Smuzhiyun# the build request queue is the table itself, ordered by state 64*4882a593Smuzhiyun 65*4882a593Smuzhiyunclass BuildRequest(models.Model): 66*4882a593Smuzhiyun REQ_CREATED = 0 67*4882a593Smuzhiyun REQ_QUEUED = 1 68*4882a593Smuzhiyun REQ_INPROGRESS = 2 69*4882a593Smuzhiyun REQ_FAILED = 3 70*4882a593Smuzhiyun REQ_DELETED = 4 71*4882a593Smuzhiyun REQ_CANCELLING = 5 72*4882a593Smuzhiyun REQ_COMPLETED = 6 73*4882a593Smuzhiyun REQ_ARCHIVE = 7 74*4882a593Smuzhiyun 75*4882a593Smuzhiyun REQUEST_STATE = ( 76*4882a593Smuzhiyun (REQ_CREATED, "created"), 77*4882a593Smuzhiyun (REQ_QUEUED, "queued"), 78*4882a593Smuzhiyun (REQ_INPROGRESS, "in progress"), 79*4882a593Smuzhiyun (REQ_FAILED, "failed"), 80*4882a593Smuzhiyun (REQ_DELETED, "deleted"), 81*4882a593Smuzhiyun (REQ_CANCELLING, "cancelling"), 82*4882a593Smuzhiyun (REQ_COMPLETED, "completed"), 83*4882a593Smuzhiyun (REQ_ARCHIVE, "archive"), 84*4882a593Smuzhiyun ) 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun search_allowed_fields = ("brtarget__target", "build__project__name") 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun project = models.ForeignKey(Project, on_delete=models.CASCADE) 89*4882a593Smuzhiyun build = models.OneToOneField(Build, on_delete=models.CASCADE, null = True) # TODO: toasterui should set this when Build is created 90*4882a593Smuzhiyun environment = models.ForeignKey(BuildEnvironment, on_delete=models.CASCADE, null = True) 91*4882a593Smuzhiyun state = models.IntegerField(choices = REQUEST_STATE, default = REQ_CREATED) 92*4882a593Smuzhiyun created = models.DateTimeField(auto_now_add = True) 93*4882a593Smuzhiyun updated = models.DateTimeField(auto_now = True) 94*4882a593Smuzhiyun 95*4882a593Smuzhiyun def __init__(self, *args, **kwargs): 96*4882a593Smuzhiyun super(BuildRequest, self).__init__(*args, **kwargs) 97*4882a593Smuzhiyun # Save the old state in case it's about to be modified 98*4882a593Smuzhiyun self.old_state = self.state 99*4882a593Smuzhiyun 100*4882a593Smuzhiyun def save(self, *args, **kwargs): 101*4882a593Smuzhiyun # Check that the state we're trying to set is not going backwards 102*4882a593Smuzhiyun # e.g. from REQ_FAILED to REQ_INPROGRESS 103*4882a593Smuzhiyun if self.old_state != self.state and self.old_state > self.state: 104*4882a593Smuzhiyun logger.warning("Invalid state change requested: " 105*4882a593Smuzhiyun "Cannot go from %s to %s - ignoring request" % 106*4882a593Smuzhiyun (BuildRequest.REQUEST_STATE[self.old_state][1], 107*4882a593Smuzhiyun BuildRequest.REQUEST_STATE[self.state][1]) 108*4882a593Smuzhiyun ) 109*4882a593Smuzhiyun # Set property back to the old value 110*4882a593Smuzhiyun self.state = self.old_state 111*4882a593Smuzhiyun return 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun super(BuildRequest, self).save(*args, **kwargs) 114*4882a593Smuzhiyun 115*4882a593Smuzhiyun 116*4882a593Smuzhiyun def get_duration(self): 117*4882a593Smuzhiyun return (self.updated - self.created).total_seconds() 118*4882a593Smuzhiyun 119*4882a593Smuzhiyun def get_sorted_target_list(self): 120*4882a593Smuzhiyun tgts = self.brtarget_set.order_by( 'target' ); 121*4882a593Smuzhiyun return( tgts ); 122*4882a593Smuzhiyun 123*4882a593Smuzhiyun def get_machine(self): 124*4882a593Smuzhiyun return self.brvariable_set.get(name="MACHINE").value 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun def __str__(self): 127*4882a593Smuzhiyun return force_text('%s %s' % (self.project, self.get_state_display())) 128*4882a593Smuzhiyun 129*4882a593Smuzhiyun# These tables specify the settings for running an actual build. 130*4882a593Smuzhiyun# They MUST be kept in sync with the tables in orm.models.Project* 131*4882a593Smuzhiyun 132*4882a593Smuzhiyun 133*4882a593Smuzhiyunclass BRLayer(models.Model): 134*4882a593Smuzhiyun req = models.ForeignKey(BuildRequest, on_delete=models.CASCADE) 135*4882a593Smuzhiyun name = models.CharField(max_length=100) 136*4882a593Smuzhiyun giturl = models.CharField(max_length=254, null=True) 137*4882a593Smuzhiyun local_source_dir = models.CharField(max_length=254, null=True) 138*4882a593Smuzhiyun commit = models.CharField(max_length=254, null=True) 139*4882a593Smuzhiyun dirpath = models.CharField(max_length=254, null=True) 140*4882a593Smuzhiyun layer_version = models.ForeignKey(Layer_Version, on_delete=models.CASCADE, null=True) 141*4882a593Smuzhiyun 142*4882a593Smuzhiyunclass BRBitbake(models.Model): 143*4882a593Smuzhiyun req = models.OneToOneField(BuildRequest, on_delete=models.CASCADE) # only one bitbake for a request 144*4882a593Smuzhiyun giturl = models.CharField(max_length =254) 145*4882a593Smuzhiyun commit = models.CharField(max_length = 254) 146*4882a593Smuzhiyun dirpath = models.CharField(max_length = 254) 147*4882a593Smuzhiyun 148*4882a593Smuzhiyunclass BRVariable(models.Model): 149*4882a593Smuzhiyun req = models.ForeignKey(BuildRequest, on_delete=models.CASCADE) 150*4882a593Smuzhiyun name = models.CharField(max_length=100) 151*4882a593Smuzhiyun value = models.TextField(blank = True) 152*4882a593Smuzhiyun 153*4882a593Smuzhiyunclass BRTarget(models.Model): 154*4882a593Smuzhiyun req = models.ForeignKey(BuildRequest, on_delete=models.CASCADE) 155*4882a593Smuzhiyun target = models.CharField(max_length=100) 156*4882a593Smuzhiyun task = models.CharField(max_length=100, null=True) 157*4882a593Smuzhiyun 158*4882a593Smuzhiyunclass BRError(models.Model): 159*4882a593Smuzhiyun req = models.ForeignKey(BuildRequest, on_delete=models.CASCADE) 160*4882a593Smuzhiyun errtype = models.CharField(max_length=100) 161*4882a593Smuzhiyun errmsg = models.TextField() 162*4882a593Smuzhiyun traceback = models.TextField() 163*4882a593Smuzhiyun 164*4882a593Smuzhiyun def __str__(self): 165*4882a593Smuzhiyun return "%s (%s)" % (self.errmsg, self.req) 166