blob: 8ef434baf598476dbbfe130f429d7fb70e54c937 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# BitBake Toaster Implementation
6#
7# Copyright (C) 2014 Intel Corporation
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 2 as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
22
23import sys
24import re
25from django.db import transaction
26from django.db.models import Q
27from bldcontrol.models import BuildEnvironment, BRLayer, BRVariable, BRTarget, BRBitbake
28import subprocess
29
30from toastermain import settings
31
32from bbcontroller import BuildEnvironmentController, ShellCmdException, BuildSetupException
33
34class NotImplementedException(Exception):
35 pass
36
37def DN(path):
38 return "/".join(path.split("/")[0:-1])
39
40class SSHBEController(BuildEnvironmentController):
41 """ Implementation of the BuildEnvironmentController for the localhost;
42 this controller manages the default build directory,
43 the server setup and system start and stop for the localhost-type build environment
44
45 """
46
47 def __init__(self, be):
48 super(SSHBEController, self).__init__(be)
49 self.dburl = settings.getDATABASE_URL()
50 self.pokydirname = None
51 self.islayerset = False
52
53 def _shellcmd(self, command, cwd = None):
54 if cwd is None:
55 cwd = self.be.sourcedir
56
57 p = subprocess.Popen("ssh %s 'cd %s && %s'" % (self.be.address, cwd, command), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
58 (out,err) = p.communicate()
59 if p.returncode:
60 if len(err) == 0:
61 err = "command: %s \n%s" % (command, out)
62 else:
63 err = "command: %s \n%s" % (command, err)
64 raise ShellCmdException(err)
65 else:
66 return out.strip()
67
68 def _pathexists(self, path):
69 try:
70 self._shellcmd("test -e \"%s\"" % path)
71 return True
72 except ShellCmdException as e:
73 return False
74
75 def _pathcreate(self, path):
76 self._shellcmd("mkdir -p \"%s\"" % path)
77
78 def _setupBE(self):
79 assert self.pokydirname and self._pathexists(self.pokydirname)
80 self._pathcreate(self.be.builddir)
81 self._shellcmd("bash -c \"source %s/oe-init-build-env %s\"" % (self.pokydirname, self.be.builddir))
82
83 def startBBServer(self, brbe):
84 assert self.pokydirname and self._pathexists(self.pokydirname)
85 assert self.islayerset
86 cmd = self._shellcmd("bash -c \"source %s/oe-init-build-env %s && DATABASE_URL=%s source toaster start noweb brbe=%s\"" % (self.pokydirname, self.be.builddir, self.dburl, brbe))
87
88 port = "-1"
89 for i in cmd.split("\n"):
90 if i.startswith("Bitbake server address"):
91 port = i.split(" ")[-1]
92 print "Found bitbake server port ", port
93
94
95 assert self.be.sourcedir and self._pathexists(self.be.builddir)
96 self.be.bbaddress = self.be.address.split("@")[-1]
97 self.be.bbport = port
98 self.be.bbstate = BuildEnvironment.SERVER_STARTED
99 self.be.save()
100
101 def stopBBServer(self):
102 assert self.pokydirname and self._pathexists(self.pokydirname)
103 assert self.islayerset
104 print self._shellcmd("bash -c \"source %s/oe-init-build-env %s && %s source toaster stop\"" %
105 (self.pokydirname, self.be.builddir, (lambda: "" if self.be.bbtoken is None else "BBTOKEN=%s" % self.be.bbtoken)()))
106 self.be.bbstate = BuildEnvironment.SERVER_STOPPED
107 self.be.save()
108 print "Stopped server"
109
110
111 def _copyFile(self, filepath1, filepath2):
112 p = subprocess.Popen("scp '%s' '%s'" % (filepath1, filepath2), stdout=subprocess.PIPE, stderr = subprocess.PIPE, shell=True)
113 (out, err) = p.communicate()
114 if p.returncode:
115 raise ShellCmdException(err)
116
117 def pullFile(self, local_filename, remote_filename):
118 _copyFile(local_filename, "%s:%s" % (self.be.address, remote_filename))
119
120 def pushFile(self, local_filename, remote_filename):
121 _copyFile("%s:%s" % (self.be.address, remote_filename), local_filename)
122
123 def setLayers(self, bitbakes, layers):
124 """ a word of attention: by convention, the first layer for any build will be poky! """
125
126 assert self.be.sourcedir is not None
127 assert len(bitbakes) == 1
128 # set layers in the layersource
129
130
131 raise NotImplementedException("Not implemented: SSH setLayers")
132 # 3. configure the build environment, so we have a conf/bblayers.conf
133 assert self.pokydirname is not None
134 self._setupBE()
135
136 # 4. update the bblayers.conf
137 bblayerconf = os.path.join(self.be.builddir, "conf/bblayers.conf")
138 if not self._pathexists(bblayerconf):
139 raise BuildSetupException("BE is not consistent: bblayers.conf file missing at %s" % bblayerconf)
140
141 import uuid
142 local_bblayerconf = "/tmp/" + uuid.uuid4() + "-bblayer.conf"
143
144 self.pullFile(bblayerconf, local_bblayerconf)
145
146 BuildEnvironmentController._updateBBLayers(local_bblayerconf, layerlist)
147 self.pushFile(local_bblayerconf, bblayerconf)
148
149 os.unlink(local_bblayerconf)
150
151 self.islayerset = True
152 return True
153
154 def release(self):
155 assert self.be.sourcedir and self._pathexists(self.be.builddir)
156 import shutil
157 shutil.rmtree(os.path.join(self.be.sourcedir, "build"))
158 assert not self._pathexists(self.be.builddir)
159
160 def triggerBuild(self, bitbake, layers, variables, targets):
161 # set up the buid environment with the needed layers
162 self.setLayers(bitbake, layers)
163 self.writeConfFile("conf/toaster-pre.conf", )
164 self.writeConfFile("conf/toaster.conf", raw = "INHERIT+=\"toaster buildhistory\"")
165
166 # get the bb server running with the build req id and build env id
167 bbctrl = self.getBBController()
168
169 # trigger the build command
170 task = reduce(lambda x, y: x if len(y)== 0 else y, map(lambda y: y.task, targets))
171 if len(task) == 0:
172 task = None
173
174 bbctrl.build(list(map(lambda x:x.target, targets)), task)
175
176 logger.debug("localhostbecontroller: Build launched, exiting. Follow build logs at %s/toaster_ui.log" % self.be.builddir)
177
178 # disconnect from the server
179 bbctrl.disconnect()