xref: /OK3568_Linux_fs/yocto/poky/bitbake/lib/toaster/bldcontrol/models.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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