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