blob: ad70ac8b549663ff63008c127faa9ec3343f5c9f [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 os
24import sys
25import re
26from django.db import transaction
27from django.db.models import Q
28from bldcontrol.models import BuildEnvironment, BRLayer, BRVariable, BRTarget, BRBitbake
29
30# load Bitbake components
31path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
32sys.path.insert(0, path)
33import bb.server.xmlrpc
34
35class BitbakeController(object):
36 """ This is the basic class that controlls a bitbake server.
37 It is outside the scope of this class on how the server is started and aquired
38 """
39
40 def __init__(self, connection):
41 self.connection = connection
42
43 def _runCommand(self, command):
44 result, error = self.connection.connection.runCommand(command)
45 if error:
46 raise Exception(error)
47 return result
48
49 def disconnect(self):
50 return self.connection.removeClient()
51
52 def setVariable(self, name, value):
53 return self._runCommand(["setVariable", name, value])
54
55 def build(self, targets, task = None):
56 if task is None:
57 task = "build"
58 return self._runCommand(["buildTargets", targets, task])
59
60
61
62def getBuildEnvironmentController(**kwargs):
63 """ Gets you a BuildEnvironmentController that encapsulates a build environment,
64 based on the query dictionary sent in.
65
66 This is used to retrieve, for example, the currently running BE from inside
67 the toaster UI, or find a new BE to start a new build in it.
68
69 The return object MUST always be a BuildEnvironmentController.
70 """
71
72 from localhostbecontroller import LocalhostBEController
73 from sshbecontroller import SSHBEController
74
75 be = BuildEnvironment.objects.filter(Q(**kwargs))[0]
76 if be.betype == BuildEnvironment.TYPE_LOCAL:
77 return LocalhostBEController(be)
78 elif be.betype == BuildEnvironment.TYPE_SSH:
79 return SSHBEController(be)
80 else:
81 raise Exception("FIXME: Implement BEC for type %s" % str(be.betype))
82
83
84class BuildEnvironmentController(object):
85 """ BuildEnvironmentController (BEC) is the abstract class that defines the operations that MUST
86 or SHOULD be supported by a Build Environment. It is used to establish the framework, and must
87 not be instantiated directly by the user.
88
89 Use the "getBuildEnvironmentController()" function to get a working BEC for your remote.
90
91 How the BuildEnvironments are discovered is outside the scope of this class.
92
93 You must derive this class to teach Toaster how to operate in your own infrastructure.
94 We provide some specific BuildEnvironmentController classes that can be used either to
95 directly set-up Toaster infrastructure, or as a model for your own infrastructure set:
96
97 * Localhost controller will run the Toaster BE on the same account as the web server
98 (current user if you are using the the Django development web server)
99 on the local machine, with the "build/" directory under the "poky/" source checkout directory.
100 Bash is expected to be available.
101
102 * SSH controller will run the Toaster BE on a remote machine, where the current user
103 can connect without raise Exception("FIXME: implement")word (set up with either ssh-agent or raise Exception("FIXME: implement")phrase-less key authentication)
104
105 """
106 def __init__(self, be):
107 """ Takes a BuildEnvironment object as parameter that points to the settings of the BE.
108 """
109 self.be = be
110 self.connection = None
111
112 @staticmethod
113 def _updateBBLayers(bblayerconf, layerlist):
114 conflines = open(bblayerconf, "r").readlines()
115
116 bblayerconffile = open(bblayerconf, "w")
117 skip = 0
118 for i in xrange(len(conflines)):
119 if skip > 0:
120 skip =- 1
121 continue
122 if conflines[i].startswith("# line added by toaster"):
123 skip = 1
124 else:
125 bblayerconffile.write(conflines[i])
126
127 bblayerconffile.write("# line added by toaster build control\nBBLAYERS = \"" + " ".join(layerlist) + "\"")
128 bblayerconffile.close()
129
130
131 def writeConfFile(self, variable_list = None, raw = None):
132 """ Writes a configuration file in the build directory. Override with buildenv-specific implementation. """
133 raise Exception("FIXME: Must override to actually write a configuration file")
134
135
136 def startBBServer(self):
137 """ Starts a BB server with Toaster toasterui set up to record the builds, an no controlling UI.
138 After this method executes, self.be bbaddress/bbport MUST point to a running and free server,
139 and the bbstate MUST be updated to "started".
140 """
141 raise Exception("FIXME: Must override in order to actually start the BB server")
142
143 def stopBBServer(self):
144 """ Stops the currently running BB server.
145 The bbstate MUST be updated to "stopped".
146 self.connection must be none.
147 """
148 raise Exception("FIXME: Must override stoBBServer")
149
150 def setLayers(self, bbs, ls):
151 """ Checks-out bitbake executor and layers from git repositories.
152 Sets the layer variables in the config file, after validating local layer paths.
153 The bitbakes must be a 1-length list of BRBitbake
154 The layer paths must be in a list of BRLayer object
155
156 a word of attention: by convention, the first layer for any build will be poky!
157 """
158 raise Exception("FIXME: Must override setLayers")
159
160
161 def getBBController(self):
162 """ returns a BitbakeController to an already started server; this is the point where the server
163 starts if needed; or reconnects to the server if we can
164 """
165 if not self.connection:
166 self.startBBServer()
167 self.be.lock = BuildEnvironment.LOCK_RUNNING
168 self.be.save()
169
170 server = bb.server.xmlrpc.BitBakeXMLRPCClient()
171 server.initServer()
172 server.saveConnectionDetails("%s:%s" % (self.be.bbaddress, self.be.bbport))
173 self.connection = server.establishConnection([])
174
175 self.be.bbtoken = self.connection.transport.connection_token
176 self.be.save()
177
178 return BitbakeController(self.connection)
179
180 def getArtifact(self, path):
181 """ This call returns an artifact identified by the 'path'. How 'path' is interpreted as
182 up to the implementing BEC. The return MUST be a REST URL where a GET will actually return
183 the content of the artifact, e.g. for use as a "download link" in a web UI.
184 """
185 raise Exception("Must return the REST URL of the artifact")
186
187 def release(self):
188 """ This stops the server and releases any resources. After this point, all resources
189 are un-available for further reference
190 """
191 raise Exception("Must override BE release")
192
193 def triggerBuild(self, bitbake, layers, variables, targets):
194 raise Exception("Must override BE release")
195
196class ShellCmdException(Exception):
197 pass
198
199
200class BuildSetupException(Exception):
201 pass
202