blob: 27289be5fd5a25db8280c289258a06fb79ee8100 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001from django.core.management.base import NoArgsCommand, CommandError
2from django.db import transaction
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05003from django.db.models import Q
4
5from bldcontrol.bbcontroller import getBuildEnvironmentController
6from bldcontrol.bbcontroller import ShellCmdException, BuildSetupException
7from bldcontrol.models import BuildRequest, BuildEnvironment
8from bldcontrol.models import BRError, BRVariable
9
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010from orm.models import Build, ToasterSetting, LogMessage, Target
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050011
Patrick Williamsc124f4f2015-09-15 14:41:29 -050012import os
13import logging
Patrick Williamsf1e5d692016-03-30 15:21:19 -050014import time
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050015import sys
16import traceback
Patrick Williamsc124f4f2015-09-15 14:41:29 -050017
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050018logger = logging.getLogger("toaster")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050019
20class Command(NoArgsCommand):
21 args = ""
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050022 help = "Schedules and executes build requests as possible."
23 "Does not return (interrupt with Ctrl-C)"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050024
25
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050026 @transaction.atomic
Patrick Williamsc124f4f2015-09-15 14:41:29 -050027 def _selectBuildEnvironment(self):
28 bec = getBuildEnvironmentController(lock = BuildEnvironment.LOCK_FREE)
29 bec.be.lock = BuildEnvironment.LOCK_LOCK
30 bec.be.save()
31 return bec
32
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050033 @transaction.atomic
Patrick Williamsc124f4f2015-09-15 14:41:29 -050034 def _selectBuildRequest(self):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050035 br = BuildRequest.objects.filter(state=BuildRequest.REQ_QUEUED).first()
Patrick Williamsc124f4f2015-09-15 14:41:29 -050036 return br
37
38 def schedule(self):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050039 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050040 # select the build environment and the request to build
41 br = self._selectBuildRequest()
42 if br:
43 br.state = BuildRequest.REQ_INPROGRESS
44 br.save()
45 else:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046 return
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050047
Patrick Williamsc124f4f2015-09-15 14:41:29 -050048 try:
49 bec = self._selectBuildEnvironment()
50 except IndexError as e:
51 # we could not find a BEC; postpone the BR
52 br.state = BuildRequest.REQ_QUEUED
53 br.save()
54 logger.debug("runbuilds: No build env")
55 return
56
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050057 logger.debug("runbuilds: starting build %s, environment %s" % \
58 (str(br).decode('utf-8'), bec.be))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050059
60 # let the build request know where it is being executed
61 br.environment = bec.be
62 br.save()
63
64 # this triggers an async build
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050065 bec.triggerBuild(br.brbitbake, br.brlayer_set.all(),
66 br.brvariable_set.all(), br.brtarget_set.all(),
67 "%d:%d" % (br.pk, bec.be.pk))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050068
69 except Exception as e:
70 logger.error("runbuilds: Error launching build %s" % e)
71 traceback.print_exc(e)
72 if "[Errno 111] Connection refused" in str(e):
73 # Connection refused, read toaster_server.out
74 errmsg = bec.readServerLogFile()
75 else:
76 errmsg = str(e)
77
78 BRError.objects.create(req = br,
79 errtype = str(type(e)),
80 errmsg = errmsg,
81 traceback = traceback.format_exc(e))
82 br.state = BuildRequest.REQ_FAILED
83 br.save()
84 bec.be.lock = BuildEnvironment.LOCK_FREE
85 bec.be.save()
86
87 def archive(self):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050088 for br in BuildRequest.objects.filter(state = BuildRequest.REQ_ARCHIVE):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050089 if br.build == None:
90 br.state = BuildRequest.REQ_FAILED
Patrick Williamsd7e96312015-09-22 08:09:05 -050091 else:
92 br.state = BuildRequest.REQ_COMPLETED
Patrick Williamsc124f4f2015-09-15 14:41:29 -050093 br.save()
94
95 def cleanup(self):
96 from django.utils import timezone
97 from datetime import timedelta
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050098 # environments locked for more than 30 seconds
99 # they should be unlocked
100 BuildEnvironment.objects.filter(
101 Q(buildrequest__state__in=[BuildRequest.REQ_FAILED,
102 BuildRequest.REQ_COMPLETED,
103 BuildRequest.REQ_CANCELLING]) &
104 Q(lock=BuildEnvironment.LOCK_LOCK) &
105 Q(updated__lt=timezone.now() - timedelta(seconds = 30))
106 ).update(lock=BuildEnvironment.LOCK_FREE)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500107
108
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500109 # update all Builds that were in progress and failed to start
110 for br in BuildRequest.objects.filter(
111 state=BuildRequest.REQ_FAILED,
112 build__outcome=Build.IN_PROGRESS):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500113 # transpose the launch errors in ToasterExceptions
114 br.build.outcome = Build.FAILED
115 for brerror in br.brerror_set.all():
116 logger.debug("Saving error %s" % brerror)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500117 LogMessage.objects.create(build=br.build,
118 level=LogMessage.EXCEPTION,
119 message=brerror.errmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500120 br.build.save()
121
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500122 # we don't have a true build object here; hence, toasterui
123 # didn't have a change to release the BE lock
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500124 br.environment.lock = BuildEnvironment.LOCK_FREE
125 br.environment.save()
126
127
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500128 # update all BuildRequests without a build created
129 for br in BuildRequest.objects.filter(build = None):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500130 br.build = Build.objects.create(project=br.project,
131 completed_on=br.updated,
132 started_on=br.created)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500133 br.build.outcome = Build.FAILED
134 try:
135 br.build.machine = br.brvariable_set.get(name='MACHINE').value
136 except BRVariable.DoesNotExist:
137 pass
138 br.save()
139 # transpose target information
140 for brtarget in br.brtarget_set.all():
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500141 Target.objects.create(build=br.build,
142 target=brtarget.target,
143 task=brtarget.task)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500144 # transpose the launch errors in ToasterExceptions
145 for brerror in br.brerror_set.all():
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500146 LogMessage.objects.create(build=br.build,
147 level=LogMessage.EXCEPTION,
148 message=brerror.errmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500149
150 br.build.save()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500151
152 # Make sure the LOCK is removed for builds which have been fully
153 # cancelled
154 for br in BuildRequest.objects.filter(
155 Q(build__outcome=Build.CANCELLED) &
156 Q(state=BuildRequest.REQ_CANCELLING) &
157 ~Q(environment=None)):
158 br.environment.lock = BuildEnvironment.LOCK_FREE
159 br.environment.save()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500160
161
162 def handle_noargs(self, **options):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500163 while True:
164 try:
165 self.cleanup()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500166 except Exception as e:
167 logger.warn("runbuilds: cleanup exception %s" % str(e))
168
169 try:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500170 self.archive()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500171 except Exception as e:
172 logger.warn("runbuilds: archive exception %s" % str(e))
173
174 try:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500175 self.schedule()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500176 except Exception as e:
177 logger.warn("runbuilds: schedule exception %s" % str(e))
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500178
179 time.sleep(1)