Remove redundent code between docker build and chroot build
Change-Id: Ib2352eb848476007900e00f23f36a7e9b8452899
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/4154
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: Xiaolin Li <xiaolinl@vmware.com>
Reviewed-by: Vinay Kulkarni <kulkarniv@vmware.com>
1 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,250 +0,0 @@ |
1 |
-from PackageUtils import PackageUtils |
|
2 |
-from Logger import Logger |
|
3 |
-from ToolChainUtils import ToolChainUtils |
|
4 |
-from CommandUtils import CommandUtils |
|
5 |
-from ChrootUtils import ChrootUtils |
|
6 |
-import os.path |
|
7 |
-import sys |
|
8 |
-from constants import constants |
|
9 |
-import shutil |
|
10 |
-import docker |
|
11 |
-from SpecData import SPECS |
|
12 |
- |
|
13 |
-class BuildContainer(object): |
|
14 |
- |
|
15 |
- def __init__(self, mapPackageToCycles, listAvailableCyclicPackages, listBuildOptionPackages, pkgBuildOptionFile, logName=None, logPath=None): |
|
16 |
- if logName is None: |
|
17 |
- logName = "BuildContainer" |
|
18 |
- if logPath is None: |
|
19 |
- logPath = constants.logPath |
|
20 |
- self.logName = logName |
|
21 |
- self.logPath = logPath |
|
22 |
- self.logger = Logger.getLogger(logName, logPath, True) |
|
23 |
- self.buildContainerImage = "photon_build_container:latest" |
|
24 |
- self.dockerClient = docker.from_env(version="auto") |
|
25 |
- self.mapPackageToCycles = mapPackageToCycles |
|
26 |
- self.listAvailableCyclicPackages = listAvailableCyclicPackages |
|
27 |
- self.listNodepsPackages = ["glibc","gmp","zlib","file","binutils","mpfr","mpc","gcc","ncurses","util-linux","groff","perl","texinfo","rpm","openssl","openssl-devel","go"] |
|
28 |
- self.listBuildOptionPackages = listBuildOptionPackages |
|
29 |
- self.pkgBuildOptionFile = pkgBuildOptionFile |
|
30 |
- |
|
31 |
- def prepareBuildContainer(self, containerTaskName, packageName, isToolChainPackage=False): |
|
32 |
- # Prepare an empty chroot environment to let docker use the BUILD folder. |
|
33 |
- # This avoids docker using overlayFS which will cause make check failure. |
|
34 |
- chrootName="build-"+packageName |
|
35 |
- chrUtils = ChrootUtils(self.logName,self.logPath) |
|
36 |
- returnVal,chrootID = chrUtils.createChroot(chrootName) |
|
37 |
- if not returnVal: |
|
38 |
- raise Exception("Unable to prepare build root") |
|
39 |
- cmdUtils = CommandUtils() |
|
40 |
- cmdUtils.runCommandInShell("mkdir -p " + chrootID + constants.topDirPath) |
|
41 |
- cmdUtils.runCommandInShell("mkdir -p " + chrootID + constants.topDirPath + "/BUILD") |
|
42 |
- |
|
43 |
- containerID = None |
|
44 |
- mountVols = { |
|
45 |
- constants.prevPublishRPMRepo: {'bind': '/publishrpms', 'mode': 'ro'}, |
|
46 |
- constants.prevPublishXRPMRepo: {'bind': '/publishxrpms', 'mode': 'ro'}, |
|
47 |
- constants.tmpDirPath: {'bind': '/tmp', 'mode': 'rw'}, |
|
48 |
- constants.rpmPath: {'bind': constants.topDirPath + "/RPMS", 'mode': 'rw'}, |
|
49 |
- constants.sourceRpmPath: {'bind': constants.topDirPath + "/SRPMS", 'mode': 'rw'}, |
|
50 |
- constants.logPath + "/" + self.logName: {'bind': constants.topDirPath + "/LOGS", 'mode': 'rw'}, |
|
51 |
- chrootID + constants.topDirPath + "/BUILD": {'bind': constants.topDirPath + "/BUILD", 'mode': 'rw'} |
|
52 |
- } |
|
53 |
- |
|
54 |
- containerName = containerTaskName |
|
55 |
- containerName = containerName.replace("+", "p") |
|
56 |
- try: |
|
57 |
- oldContainerID = self.dockerClient.containers.get(containerName) |
|
58 |
- if oldContainerID is not None: |
|
59 |
- oldContainerID.remove(force=True) |
|
60 |
- except docker.errors.NotFound: |
|
61 |
- sys.exc_clear() |
|
62 |
- |
|
63 |
- try: |
|
64 |
- self.logger.info("BuildContainer-prepareBuildContainer: Starting build container: " + containerName) |
|
65 |
- #TODO: Is init=True equivalent of --sig-proxy? |
|
66 |
- privilegedDocker = False |
|
67 |
- cap_list = ['SYS_PTRACE'] |
|
68 |
- if packageName in constants.listReqPrivilegedDockerForTest: |
|
69 |
- privilegedDocker = True |
|
70 |
- |
|
71 |
- containerID = self.dockerClient.containers.run(self.buildContainerImage, |
|
72 |
- detach=True, |
|
73 |
- cap_add=cap_list, |
|
74 |
- privileged=privilegedDocker, |
|
75 |
- name=containerName, |
|
76 |
- network_mode="host", |
|
77 |
- volumes=mountVols, |
|
78 |
- command="/bin/bash -l -c /wait.sh") |
|
79 |
- |
|
80 |
- self.logger.debug("Started Photon build container for task " + containerTaskName |
|
81 |
- + " ID: " + containerID.short_id) |
|
82 |
- if not containerID: |
|
83 |
- raise Exception("Unable to start Photon build container for task " + containerTaskName) |
|
84 |
- except Exception as e: |
|
85 |
- self.logger.debug("Unable to start Photon build container for task " + containerTaskName) |
|
86 |
- raise e |
|
87 |
- return containerID, chrootID |
|
88 |
- |
|
89 |
- def findPackageNameFromRPMFile(self, rpmfile): |
|
90 |
- rpmfile = os.path.basename(rpmfile) |
|
91 |
- releaseindex = rpmfile.rfind("-") |
|
92 |
- if releaseindex == -1: |
|
93 |
- self.logger.error("Invalid rpm file:" + rpmfile) |
|
94 |
- return None |
|
95 |
- versionindex=rpmfile[0:releaseindex].rfind("-") |
|
96 |
- if versionindex == -1: |
|
97 |
- self.logger.error("Invalid rpm file:" + rpmfile) |
|
98 |
- return None |
|
99 |
- packageName = rpmfile[0:versionindex] |
|
100 |
- return packageName |
|
101 |
- |
|
102 |
- def findInstalledPackages(self, containerID): |
|
103 |
- pkgUtils = PackageUtils(self.logName, self.logPath) |
|
104 |
- listInstalledRPMs = pkgUtils.findInstalledRPMPackagesInContainer(containerID) |
|
105 |
- listInstalledPackages = [] |
|
106 |
- for installedRPM in listInstalledRPMs: |
|
107 |
- packageName = self.findPackageNameFromRPMFile(installedRPM) |
|
108 |
- if packageName is not None: |
|
109 |
- listInstalledPackages.append(packageName) |
|
110 |
- return listInstalledPackages, listInstalledRPMs |
|
111 |
- |
|
112 |
- def buildPackageThreadAPI(self, package, outputMap, threadName,): |
|
113 |
- try: |
|
114 |
- self.buildPackage(package) |
|
115 |
- outputMap[threadName] = True |
|
116 |
- except Exception as e: |
|
117 |
- self.logger.error(e) |
|
118 |
- outputMap[threadName] = False |
|
119 |
- |
|
120 |
- def checkIfPackageIsAlreadyBuilt(self, package): |
|
121 |
- basePkg = SPECS.getData().getSpecName(package) |
|
122 |
- listRPMPackages = SPECS.getData().getRPMPackages(basePkg) |
|
123 |
- packageIsAlreadyBuilt = True |
|
124 |
- pkgUtils = PackageUtils(self.logName,self.logPath) |
|
125 |
- for pkg in listRPMPackages: |
|
126 |
- if pkgUtils.findRPMFileForGivenPackage(pkg) is None: |
|
127 |
- packageIsAlreadyBuilt = False |
|
128 |
- break |
|
129 |
- return packageIsAlreadyBuilt |
|
130 |
- |
|
131 |
- def buildPackage(self, package): |
|
132 |
- #do not build if RPM is already built |
|
133 |
- #test only if the package is in the testForceRPMS with rpmCheck |
|
134 |
- #build only if the package is not in the testForceRPMS with rpmCheck |
|
135 |
- if self.checkIfPackageIsAlreadyBuilt(package): |
|
136 |
- if not constants.rpmCheck: |
|
137 |
- self.logger.info("Skipping building the package:"+package) |
|
138 |
- return |
|
139 |
- elif constants.rpmCheck and package not in constants.testForceRPMS: |
|
140 |
- self.logger.info("Skipping testing the package:"+package) |
|
141 |
- return |
|
142 |
- |
|
143 |
- #should initialize a logger based on package name |
|
144 |
- containerTaskName = "build-" + package |
|
145 |
- containerID = None |
|
146 |
- chrootID = None |
|
147 |
- isToolChainPackage = False |
|
148 |
- if package in constants.listToolChainPackages: |
|
149 |
- isToolChainPackage = True |
|
150 |
- destLogPath = constants.logPath + "/build-"+package |
|
151 |
- try: |
|
152 |
- containerID, chrootID = self.prepareBuildContainer(containerTaskName, package, isToolChainPackage) |
|
153 |
- if not os.path.isdir(destLogPath): |
|
154 |
- cmdUtils = CommandUtils() |
|
155 |
- cmdUtils.runCommandInShell("mkdir -p "+destLogPath) |
|
156 |
- |
|
157 |
- tcUtils = ToolChainUtils(self.logName, self.logPath) |
|
158 |
- if package in constants.perPackageToolChain: |
|
159 |
- self.logger.debug(constants.perPackageToolChain[package]) |
|
160 |
- tcUtils.installCustomToolChainRPMSinContainer(containerID, constants.perPackageToolChain[package], package); |
|
161 |
- |
|
162 |
- listInstalledPackages, listInstalledRPMs = self.findInstalledPackages(containerID) |
|
163 |
- self.logger.info(listInstalledPackages) |
|
164 |
- listDependentPackages = self.findBuildTimeRequiredPackages(package) |
|
165 |
- if constants.rpmCheck and package in constants.testForceRPMS: |
|
166 |
- listDependentPackages.extend(self.findBuildTimeCheckRequiredPackages(package)) |
|
167 |
- testPackages=set(constants.listMakeCheckRPMPkgtoInstall)-set(listInstalledPackages)-set([package]) |
|
168 |
- listDependentPackages.extend(testPackages) |
|
169 |
- listDependentPackages=list(set(listDependentPackages)) |
|
170 |
- |
|
171 |
- pkgUtils = PackageUtils(self.logName,self.logPath) |
|
172 |
- if len(listDependentPackages) != 0: |
|
173 |
- self.logger.info("BuildContainer-buildPackage: Installing dependent packages..") |
|
174 |
- self.logger.info(listDependentPackages) |
|
175 |
- for pkg in listDependentPackages: |
|
176 |
- self.installPackage(pkgUtils, pkg, containerID, destLogPath, listInstalledPackages, listInstalledRPMs) |
|
177 |
- # Special case sqlite due to package renamed from sqlite-autoconf to sqlite |
|
178 |
- if "sqlite" in listInstalledPackages or "sqlite-devel" in listInstalledPackages or "sqlite-libs" in listInstalledPackages: |
|
179 |
- if "sqlite" not in listInstalledPackages: |
|
180 |
- self.installPackage(pkgUtils, "sqlite", containerID, destLogPath, listInstalledPackages, listInstalledRPMs) |
|
181 |
- if "sqlite-devel" not in listInstalledPackages: |
|
182 |
- self.installPackage(pkgUtils, "sqlite-devel", containerID, destLogPath, listInstalledPackages, listInstalledRPMs) |
|
183 |
- if "sqlite-libs" not in listInstalledPackages: |
|
184 |
- self.installPackage(pkgUtils, "sqlite-libs", containerID, destLogPath, listInstalledPackages, listInstalledRPMs) |
|
185 |
- pkgUtils.installRPMSInAOneShotInContainer(containerID, destLogPath) |
|
186 |
- |
|
187 |
- pkgUtils.adjustGCCSpecsInContainer(package, containerID, destLogPath) |
|
188 |
- |
|
189 |
- pkgUtils.buildRPMSForGivenPackageInContainer( |
|
190 |
- package, |
|
191 |
- containerID, |
|
192 |
- self.listBuildOptionPackages, |
|
193 |
- self.pkgBuildOptionFile, |
|
194 |
- destLogPath) |
|
195 |
- self.logger.info("BuildContainer-buildPackage: Successfully built the package: " + package) |
|
196 |
- except Exception as e: |
|
197 |
- self.logger.error("Failed while building package:" + package) |
|
198 |
- if containerID is not None: |
|
199 |
- self.logger.debug("Container " + containerID.short_id + " retained for debugging.") |
|
200 |
- logFileName = os.path.join(destLogPath, package + ".log") |
|
201 |
- fileLog = os.popen('tail -n 20 ' + logFileName).read() |
|
202 |
- self.logger.debug(fileLog) |
|
203 |
- raise e |
|
204 |
- |
|
205 |
- # Remove the container |
|
206 |
- if containerID is not None: |
|
207 |
- containerID.remove(force=True) |
|
208 |
- # Remove the dummy chroot |
|
209 |
- if chrootID is not None: |
|
210 |
- chrUtils = ChrootUtils(self.logName,self.logPath) |
|
211 |
- chrUtils.destroyChroot(chrootID) |
|
212 |
- |
|
213 |
- def findRunTimeRequiredRPMPackages(self, rpmPackage): |
|
214 |
- listRequiredPackages = SPECS.getData().getRequiresForPackage(rpmPackage) |
|
215 |
- return listRequiredPackages |
|
216 |
- |
|
217 |
- def findBuildTimeRequiredPackages(self, package): |
|
218 |
- listRequiredPackages = SPECS.getData().getBuildRequiresForPackage(package) |
|
219 |
- return listRequiredPackages |
|
220 |
- |
|
221 |
- def findBuildTimeCheckRequiredPackages(self,package): |
|
222 |
- listRequiredPackages=SPECS.getData().getCheckBuildRequiresForPackage(package) |
|
223 |
- return listRequiredPackages |
|
224 |
- |
|
225 |
- def installPackage(self, pkgUtils, package, containerID, destLogPath, listInstalledPackages, listInstalledRPMs): |
|
226 |
- latestRPM = os.path.basename(pkgUtils.findRPMFileForGivenPackage(package)).replace(".rpm", "") |
|
227 |
- if package in listInstalledPackages and latestRPM in listInstalledRPMs: |
|
228 |
- return |
|
229 |
- self.installDependentRunTimePackages(pkgUtils, package, containerID, destLogPath, listInstalledPackages, listInstalledRPMs) |
|
230 |
- noDeps = False |
|
231 |
- if self.mapPackageToCycles.has_key(package): |
|
232 |
- noDeps = True |
|
233 |
- if package in self.listNodepsPackages: |
|
234 |
- noDeps = True |
|
235 |
- if package in constants.noDepsPackageList: |
|
236 |
- noDeps = True |
|
237 |
- pkgUtils.prepRPMforInstallInContainer(package, containerID, noDeps, destLogPath) |
|
238 |
- listInstalledPackages.append(package) |
|
239 |
- listInstalledRPMs.append(latestRPM) |
|
240 |
- |
|
241 |
- def installDependentRunTimePackages(self, pkgUtils, package, containerID, destLogPath, listInstalledPackages, listInstalledRPMs): |
|
242 |
- listRunTimeDependentPackages = self.findRunTimeRequiredRPMPackages(package) |
|
243 |
- if len(listRunTimeDependentPackages) != 0: |
|
244 |
- for pkg in listRunTimeDependentPackages: |
|
245 |
- if self.mapPackageToCycles.has_key(pkg) and pkg not in self.listAvailableCyclicPackages: |
|
246 |
- continue |
|
247 |
- latestPkgRPM = os.path.basename(pkgUtils.findRPMFileForGivenPackage(pkg)).replace(".rpm", "") |
|
248 |
- if pkg in listInstalledPackages and latestPkgRPM in listInstalledRPMs: |
|
249 |
- continue |
|
250 |
- self.installPackage(pkgUtils, pkg, containerID, destLogPath, listInstalledPackages, listInstalledRPMs) |
... | ... |
@@ -7,10 +7,11 @@ import os.path |
7 | 7 |
from constants import constants |
8 | 8 |
import shutil |
9 | 9 |
from SpecData import SPECS |
10 |
+import docker |
|
11 |
+import sys |
|
10 | 12 |
|
11 |
-class PackageBuilder(object): |
|
12 |
- |
|
13 |
- def __init__(self,mapPackageToCycles,listAvailableCyclicPackages,listBuildOptionPackages,pkgBuildOptionFile): |
|
13 |
+class PackageBuilderBase(object): |
|
14 |
+ def __init__(self,mapPackageToCycles,listAvailableCyclicPackages,listBuildOptionPackages,pkgBuildOptionFile, pkgBuildType): |
|
14 | 15 |
# will be initialized in buildPackageThreadAPI() |
15 | 16 |
self.logName=None |
16 | 17 |
self.logPath=None |
... | ... |
@@ -21,24 +22,16 @@ class PackageBuilder(object): |
21 | 21 |
self.listNodepsPackages = ["glibc","gmp","zlib","file","binutils","mpfr","mpc","gcc","ncurses","util-linux","groff","perl","texinfo","rpm","openssl","go"] |
22 | 22 |
self.listBuildOptionPackages=listBuildOptionPackages |
23 | 23 |
self.pkgBuildOptionFile=pkgBuildOptionFile |
24 |
+ self.pkgBuildType = pkgBuildType |
|
24 | 25 |
|
25 |
- def prepareBuildRoot(self): |
|
26 |
- chrootID=None |
|
27 |
- chrootName="build-"+self.package |
|
28 |
- try: |
|
29 |
- chrUtils = ChrootUtils(self.logName,self.logPath) |
|
30 |
- returnVal,chrootID = chrUtils.createChroot(chrootName) |
|
31 |
- self.logger.debug("Created new chroot: " + chrootID) |
|
32 |
- if not returnVal: |
|
33 |
- raise Exception("Unable to prepare build root") |
|
34 |
- tUtils=ToolChainUtils(self.logName,self.logPath) |
|
35 |
- tUtils.installToolChainRPMS(chrootID, self.package, self.logPath) |
|
36 |
- except Exception as e: |
|
37 |
- if chrootID is not None: |
|
38 |
- self.logger.debug("Deleting chroot: " + chrootID) |
|
39 |
- chrUtils.destroyChroot(chrootID) |
|
40 |
- raise e |
|
41 |
- return chrootID |
|
26 |
+ def buildPackageThreadAPIPrepare(self,package,outputMap, threadName): |
|
27 |
+ self.package=package |
|
28 |
+ self.logName="build-"+package |
|
29 |
+ self.logPath=constants.logPath+"/build-"+package |
|
30 |
+ if not os.path.isdir(self.logPath): |
|
31 |
+ cmdUtils = CommandUtils() |
|
32 |
+ cmdUtils.runCommandInShell("mkdir -p "+self.logPath) |
|
33 |
+ self.logger=Logger.getLogger(self.logName,self.logPath) |
|
42 | 34 |
|
43 | 35 |
def findPackageNameFromRPMFile(self,rpmfile): |
44 | 36 |
rpmfile=os.path.basename(rpmfile) |
... | ... |
@@ -53,33 +46,18 @@ class PackageBuilder(object): |
53 | 53 |
packageName=rpmfile[0:versionindex] |
54 | 54 |
return packageName |
55 | 55 |
|
56 |
- def findInstalledPackages(self,chrootID): |
|
57 |
- pkgUtils = PackageUtils(self.logName,self.logPath) |
|
58 |
- listInstalledRPMs=pkgUtils.findInstalledRPMPackages(chrootID) |
|
56 |
+ def findInstalledPackages(self, instanceID): |
|
57 |
+ pkgUtils = PackageUtils(self.logName, self.logPath) |
|
58 |
+ if self.pkgBuildType == "chroot": |
|
59 |
+ listInstalledRPMs = pkgUtils.findInstalledRPMPackages(instanceID) |
|
60 |
+ elif self.pkgBuildType == "container": |
|
61 |
+ listInstalledRPMs = pkgUtils.findInstalledRPMPackagesInContainer(instanceID) |
|
59 | 62 |
listInstalledPackages=[] |
60 | 63 |
for installedRPM in listInstalledRPMs: |
61 | 64 |
packageName=self.findPackageNameFromRPMFile(installedRPM) |
62 | 65 |
if packageName is not None: |
63 | 66 |
listInstalledPackages.append(packageName) |
64 |
- return listInstalledPackages |
|
65 |
- |
|
66 |
- def buildPackageThreadAPI(self,package,outputMap, threadName,): |
|
67 |
- self.package=package |
|
68 |
- self.logName="build-"+package |
|
69 |
- self.logPath=constants.logPath+"/build-"+package |
|
70 |
- if not os.path.isdir(self.logPath): |
|
71 |
- cmdUtils = CommandUtils() |
|
72 |
- cmdUtils.runCommandInShell("mkdir -p "+self.logPath) |
|
73 |
- self.logger=Logger.getLogger(self.logName,self.logPath) |
|
74 |
- |
|
75 |
- try: |
|
76 |
- self.buildPackage() |
|
77 |
- outputMap[threadName]=True |
|
78 |
- except Exception as e: |
|
79 |
- # TODO: self.logger might be None |
|
80 |
- self.logger.error(e) |
|
81 |
- outputMap[threadName]=False |
|
82 |
- raise e |
|
67 |
+ return listInstalledPackages, listInstalledRPMs |
|
83 | 68 |
|
84 | 69 |
def checkIfPackageIsAlreadyBuilt(self): |
85 | 70 |
basePkg=SPECS.getData().getSpecName(self.package) |
... | ... |
@@ -92,52 +70,6 @@ class PackageBuilder(object): |
92 | 92 |
break |
93 | 93 |
return packageIsAlreadyBuilt |
94 | 94 |
|
95 |
- def buildPackage(self): |
|
96 |
- #do not build if RPM is already built |
|
97 |
- #test only if the package is in the testForceRPMS with rpmCheck |
|
98 |
- #build only if the package is not in the testForceRPMS with rpmCheck |
|
99 |
- if self.checkIfPackageIsAlreadyBuilt(): |
|
100 |
- if not constants.rpmCheck: |
|
101 |
- self.logger.info("Skipping building the package:"+self.package) |
|
102 |
- return |
|
103 |
- elif constants.rpmCheck and self.package not in constants.testForceRPMS: |
|
104 |
- self.logger.info("Skipping testing the package:"+self.package) |
|
105 |
- return |
|
106 |
- |
|
107 |
- chrUtils = ChrootUtils(self.logName,self.logPath) |
|
108 |
- chrootID=None |
|
109 |
- try: |
|
110 |
- chrootID = self.prepareBuildRoot() |
|
111 |
- listInstalledPackages=self.findInstalledPackages(chrootID) |
|
112 |
- listDependentPackages=self.findBuildTimeRequiredPackages() |
|
113 |
- if constants.rpmCheck and self.package in constants.testForceRPMS: |
|
114 |
- listDependentPackages.extend(self.findBuildTimeCheckRequiredPackages()) |
|
115 |
- testPackages=set(constants.listMakeCheckRPMPkgtoInstall)-set(listInstalledPackages)-set([self.package]) |
|
116 |
- listDependentPackages.extend(testPackages) |
|
117 |
- listDependentPackages=list(set(listDependentPackages)) |
|
118 |
- |
|
119 |
- pkgUtils = PackageUtils(self.logName,self.logPath) |
|
120 |
- if len(listDependentPackages) != 0: |
|
121 |
- self.logger.info("Installing the build time dependent packages......") |
|
122 |
- for pkg in listDependentPackages: |
|
123 |
- self.installPackage(pkgUtils, pkg,chrootID,self.logPath,listInstalledPackages) |
|
124 |
- pkgUtils.installRPMSInAOneShot(chrootID,self.logPath) |
|
125 |
- self.logger.info("Finished installing the build time dependent packages......") |
|
126 |
- |
|
127 |
- pkgUtils.adjustGCCSpecs(self.package, chrootID, self.logPath) |
|
128 |
- pkgUtils.buildRPMSForGivenPackage(self.package,chrootID,self.listBuildOptionPackages,self.pkgBuildOptionFile,self.logPath) |
|
129 |
- self.logger.info("Successfully built the package:"+self.package) |
|
130 |
- except Exception as e: |
|
131 |
- self.logger.error("Failed while building package:" + self.package) |
|
132 |
- self.logger.debug("Chroot with ID: " + chrootID + " not deleted for debugging.") |
|
133 |
- logFileName = os.path.join(self.logPath, self.package + ".log") |
|
134 |
- fileLog = os.popen('tail -n 100 ' + logFileName).read() |
|
135 |
- self.logger.debug(fileLog) |
|
136 |
- raise e |
|
137 |
- if chrootID is not None: |
|
138 |
- chrUtils.destroyChroot(chrootID) |
|
139 |
- |
|
140 |
- |
|
141 | 95 |
def findRunTimeRequiredRPMPackages(self,rpmPackage): |
142 | 96 |
listRequiredPackages=SPECS.getData().getRequiresForPackage(rpmPackage) |
143 | 97 |
return listRequiredPackages |
... | ... |
@@ -150,12 +82,14 @@ class PackageBuilder(object): |
150 | 150 |
listRequiredPackages=SPECS.getData().getCheckBuildRequiresForPackage(self.package) |
151 | 151 |
return listRequiredPackages |
152 | 152 |
|
153 |
- def installPackage(self,pkgUtils,package,chrootID,destLogPath,listInstalledPackages): |
|
154 |
- if package in listInstalledPackages: |
|
153 |
+ def installPackage(self, pkgUtils, package, instanceID, destLogPath, listInstalledPackages, listInstalledRPMs): |
|
154 |
+ latestRPM = os.path.basename(pkgUtils.findRPMFileForGivenPackage(package)).replace(".rpm", "") |
|
155 |
+ if package in listInstalledPackages and latestRPM in listInstalledRPMs: |
|
155 | 156 |
return |
156 | 157 |
# mark it as installed - to avoid cyclic recursion |
157 | 158 |
listInstalledPackages.append(package) |
158 |
- self.installDependentRunTimePackages(pkgUtils,package,chrootID,destLogPath,listInstalledPackages) |
|
159 |
+ listInstalledRPMs.append(latestRPM) |
|
160 |
+ self.installDependentRunTimePackages(pkgUtils,package,instanceID,destLogPath,listInstalledPackages, listInstalledRPMs) |
|
159 | 161 |
noDeps=False |
160 | 162 |
if self.mapPackageToCycles.has_key(package): |
161 | 163 |
noDeps = True |
... | ... |
@@ -163,15 +97,249 @@ class PackageBuilder(object): |
163 | 163 |
noDeps=True |
164 | 164 |
if package in constants.noDepsPackageList: |
165 | 165 |
noDeps=True |
166 |
- pkgUtils.installRPM(package,chrootID,noDeps,destLogPath) |
|
166 |
+ if self.pkgBuildType == "chroot": |
|
167 |
+ pkgUtils.installRPM(package,instanceID,noDeps,destLogPath) |
|
168 |
+ elif self.pkgBuildType == "container": |
|
169 |
+ pkgUtils.prepRPMforInstallInContainer(package, instanceID, noDeps, destLogPath) |
|
167 | 170 |
|
168 |
- def installDependentRunTimePackages(self,pkgUtils,package,chrootID,destLogPath,listInstalledPackages): |
|
171 |
+ def installDependentRunTimePackages(self,pkgUtils,package,instanceID,destLogPath,listInstalledPackages, listInstalledRPMs): |
|
169 | 172 |
listRunTimeDependentPackages=self.findRunTimeRequiredRPMPackages(package) |
170 | 173 |
if len(listRunTimeDependentPackages) != 0: |
171 | 174 |
for pkg in listRunTimeDependentPackages: |
172 | 175 |
if self.mapPackageToCycles.has_key(pkg) and pkg not in self.listAvailableCyclicPackages: |
173 | 176 |
continue |
174 |
- if pkg in listInstalledPackages: |
|
177 |
+ latestPkgRPM = os.path.basename(pkgUtils.findRPMFileForGivenPackage(pkg)).replace(".rpm", "") |
|
178 |
+ if pkg in listInstalledPackages and latestPkgRPM in listInstalledRPMs: |
|
175 | 179 |
continue |
176 |
- self.installPackage(pkgUtils,pkg,chrootID,destLogPath,listInstalledPackages) |
|
180 |
+ self.installPackage(pkgUtils, pkg, instanceID, destLogPath, listInstalledPackages, listInstalledRPMs) |
|
181 |
+ |
|
182 |
+class PackageBuilderContainer(object): |
|
183 |
+ def __init__(self, mapPackageToCycles, listAvailableCyclicPackages, listBuildOptionPackages, pkgBuildOptionFile, pkgBuildType): |
|
184 |
+ self.buildContainerImage = "photon_build_container:latest" |
|
185 |
+ self.dockerClient = docker.from_env(version="auto") |
|
186 |
+ |
|
187 |
+ self.base = PackageBuilderBase(mapPackageToCycles, listAvailableCyclicPackages, |
|
188 |
+ listBuildOptionPackages, pkgBuildOptionFile, pkgBuildType) |
|
189 |
+ |
|
190 |
+ def buildPackageThreadAPI(self, package, outputMap, threadName): |
|
191 |
+ self.base.buildPackageThreadAPIPrepare(package, outputMap, threadName) |
|
192 |
+ try: |
|
193 |
+ self.buildPackage() |
|
194 |
+ outputMap[threadName]=True |
|
195 |
+ except Exception as e: |
|
196 |
+ # TODO: self.logger might be None |
|
197 |
+ self.base.logger.error(e) |
|
198 |
+ outputMap[threadName]=False |
|
199 |
+ raise e |
|
200 |
+ |
|
201 |
+ def prepareBuildContainer(self, containerTaskName, packageName, isToolChainPackage=False): |
|
202 |
+ # Prepare an empty chroot environment to let docker use the BUILD folder. |
|
203 |
+ # This avoids docker using overlayFS which will cause make check failure. |
|
204 |
+ chrootName="build-"+packageName |
|
205 |
+ chrUtils = ChrootUtils(self.base.logName, self.base.logPath) |
|
206 |
+ returnVal,chrootID = chrUtils.createChroot(chrootName) |
|
207 |
+ if not returnVal: |
|
208 |
+ raise Exception("Unable to prepare build root") |
|
209 |
+ cmdUtils = CommandUtils() |
|
210 |
+ cmdUtils.runCommandInShell("mkdir -p " + chrootID + constants.topDirPath) |
|
211 |
+ cmdUtils.runCommandInShell("mkdir -p " + chrootID + constants.topDirPath + "/BUILD") |
|
212 |
+ |
|
213 |
+ containerID = None |
|
214 |
+ mountVols = { |
|
215 |
+ constants.prevPublishRPMRepo: {'bind': '/publishrpms', 'mode': 'ro'}, |
|
216 |
+ constants.prevPublishXRPMRepo: {'bind': '/publishxrpms', 'mode': 'ro'}, |
|
217 |
+ constants.tmpDirPath: {'bind': '/tmp', 'mode': 'rw'}, |
|
218 |
+ constants.rpmPath: {'bind': constants.topDirPath + "/RPMS", 'mode': 'rw'}, |
|
219 |
+ constants.sourceRpmPath: {'bind': constants.topDirPath + "/SRPMS", 'mode': 'rw'}, |
|
220 |
+ constants.logPath + "/" + self.base.logName: {'bind': constants.topDirPath + "/LOGS", 'mode': 'rw'}, |
|
221 |
+ chrootID + constants.topDirPath + "/BUILD": {'bind': constants.topDirPath + "/BUILD", 'mode': 'rw'} |
|
222 |
+ } |
|
223 |
+ |
|
224 |
+ containerName = containerTaskName |
|
225 |
+ containerName = containerName.replace("+", "p") |
|
226 |
+ try: |
|
227 |
+ oldContainerID = self.dockerClient.containers.get(containerName) |
|
228 |
+ if oldContainerID is not None: |
|
229 |
+ oldContainerID.remove(force=True) |
|
230 |
+ except docker.errors.NotFound: |
|
231 |
+ sys.exc_clear() |
|
232 |
+ |
|
233 |
+ try: |
|
234 |
+ self.base.logger.info("BuildContainer-prepareBuildContainer: Starting build container: " + containerName) |
|
235 |
+ #TODO: Is init=True equivalent of --sig-proxy? |
|
236 |
+ privilegedDocker = False |
|
237 |
+ cap_list = ['SYS_PTRACE'] |
|
238 |
+ if packageName in constants.listReqPrivilegedDockerForTest: |
|
239 |
+ privilegedDocker = True |
|
240 |
+ |
|
241 |
+ containerID = self.dockerClient.containers.run(self.buildContainerImage, |
|
242 |
+ detach=True, |
|
243 |
+ cap_add=cap_list, |
|
244 |
+ privileged=privilegedDocker, |
|
245 |
+ name=containerName, |
|
246 |
+ network_mode="host", |
|
247 |
+ volumes=mountVols, |
|
248 |
+ command="/bin/bash -l -c /wait.sh") |
|
249 |
+ |
|
250 |
+ self.base.logger.debug("Started Photon build container for task " + containerTaskName |
|
251 |
+ + " ID: " + containerID.short_id) |
|
252 |
+ if not containerID: |
|
253 |
+ raise Exception("Unable to start Photon build container for task " + containerTaskName) |
|
254 |
+ except Exception as e: |
|
255 |
+ self.base.logger.debug("Unable to start Photon build container for task " + containerTaskName) |
|
256 |
+ raise e |
|
257 |
+ return containerID, chrootID |
|
177 | 258 |
|
259 |
+ def buildPackage(self): |
|
260 |
+ #do not build if RPM is already built |
|
261 |
+ #test only if the package is in the testForceRPMS with rpmCheck |
|
262 |
+ #build only if the package is not in the testForceRPMS with rpmCheck |
|
263 |
+ if self.base.checkIfPackageIsAlreadyBuilt(): |
|
264 |
+ if not constants.rpmCheck: |
|
265 |
+ self.base.logger.info("Skipping building the package:" + self.base.package) |
|
266 |
+ return |
|
267 |
+ elif constants.rpmCheck and self.base.package not in constants.testForceRPMS: |
|
268 |
+ self.base.logger.info("Skipping testing the package:" + self.base.package) |
|
269 |
+ return |
|
270 |
+ |
|
271 |
+ #should initialize a logger based on package name |
|
272 |
+ containerTaskName = "build-" + self.base.package |
|
273 |
+ containerID = None |
|
274 |
+ chrootID = None |
|
275 |
+ isToolChainPackage = False |
|
276 |
+ if self.base.package in constants.listToolChainPackages: |
|
277 |
+ isToolChainPackage = True |
|
278 |
+ destLogPath = constants.logPath + "/build-" + self.base.package |
|
279 |
+ try: |
|
280 |
+ containerID, chrootID = self.prepareBuildContainer(containerTaskName, self.base.package, isToolChainPackage) |
|
281 |
+ |
|
282 |
+ tcUtils = ToolChainUtils(self.base.logName, self.base.logPath) |
|
283 |
+ if self.base.package in constants.perPackageToolChain: |
|
284 |
+ self.base.logger.debug(constants.perPackageToolChain[self.base.package]) |
|
285 |
+ tcUtils.installCustomToolChainRPMSinContainer(containerID, |
|
286 |
+ constants.perPackageToolChain[self.base.package], |
|
287 |
+ self.base.package); |
|
288 |
+ |
|
289 |
+ listInstalledPackages, listInstalledRPMs = self.base.findInstalledPackages(containerID) |
|
290 |
+ self.base.logger.info(listInstalledPackages) |
|
291 |
+ listDependentPackages = self.base.findBuildTimeRequiredPackages() |
|
292 |
+ if constants.rpmCheck and self.base.package in constants.testForceRPMS: |
|
293 |
+ listDependentPackages.extend(self.base.findBuildTimeCheckRequiredPackages()) |
|
294 |
+ testPackages=set(constants.listMakeCheckRPMPkgtoInstall)-set(listInstalledPackages)-set([self.base.package]) |
|
295 |
+ listDependentPackages.extend(testPackages) |
|
296 |
+ listDependentPackages=list(set(listDependentPackages)) |
|
297 |
+ |
|
298 |
+ pkgUtils = PackageUtils(self.base.logName, self.base.logPath) |
|
299 |
+ if len(listDependentPackages) != 0: |
|
300 |
+ self.base.logger.info("BuildContainer-buildPackage: Installing dependent packages..") |
|
301 |
+ self.base.logger.info(listDependentPackages) |
|
302 |
+ for pkg in listDependentPackages: |
|
303 |
+ self.base.installPackage(pkgUtils, pkg, containerID, destLogPath, listInstalledPackages, listInstalledRPMs) |
|
304 |
+ pkgUtils.installRPMSInAOneShotInContainer(containerID, destLogPath) |
|
305 |
+ self.base.logger.info("Finished installing the build time dependent packages......") |
|
306 |
+ |
|
307 |
+ self.base.logger.info("BuildContainer-buildPackage: Start building the package: " + self.base.package) |
|
308 |
+ pkgUtils.adjustGCCSpecsInContainer(self.base.package, containerID, destLogPath) |
|
309 |
+ pkgUtils.buildRPMSForGivenPackageInContainer( |
|
310 |
+ self.base.package, |
|
311 |
+ containerID, |
|
312 |
+ self.base.listBuildOptionPackages, |
|
313 |
+ self.base.pkgBuildOptionFile, |
|
314 |
+ destLogPath) |
|
315 |
+ self.base.logger.info("BuildContainer-buildPackage: Successfully built the package: " + self.base.package) |
|
316 |
+ except Exception as e: |
|
317 |
+ self.base.logger.error("Failed while building package:" + self.base.package) |
|
318 |
+ if containerID is not None: |
|
319 |
+ self.base.logger.debug("Container " + containerID.short_id + " retained for debugging.") |
|
320 |
+ logFileName = os.path.join(destLogPath, self.base.package + ".log") |
|
321 |
+ fileLog = os.popen('tail -n 20 ' + logFileName).read() |
|
322 |
+ self.base.logger.debug(fileLog) |
|
323 |
+ raise e |
|
324 |
+ |
|
325 |
+ # Remove the container |
|
326 |
+ if containerID is not None: |
|
327 |
+ containerID.remove(force=True) |
|
328 |
+ # Remove the dummy chroot |
|
329 |
+ if chrootID is not None: |
|
330 |
+ chrUtils = ChrootUtils(self.base.logName, self.base.logPath) |
|
331 |
+ chrUtils.destroyChroot(chrootID) |
|
332 |
+ |
|
333 |
+class PackageBuilderChroot(object): |
|
334 |
+ def __init__(self, mapPackageToCycles, listAvailableCyclicPackages, listBuildOptionPackages, pkgBuildOptionFile, pkgBuildType): |
|
335 |
+ self.base = PackageBuilderBase(mapPackageToCycles, listAvailableCyclicPackages, |
|
336 |
+ listBuildOptionPackages, pkgBuildOptionFile, pkgBuildType) |
|
337 |
+ |
|
338 |
+ def buildPackageThreadAPI(self, package, outputMap, threadName): |
|
339 |
+ self.base.buildPackageThreadAPIPrepare(package,outputMap, threadName) |
|
340 |
+ try: |
|
341 |
+ self.buildPackage() |
|
342 |
+ outputMap[threadName]=True |
|
343 |
+ except Exception as e: |
|
344 |
+ # TODO: self.logger might be None |
|
345 |
+ self.base.logger.error(e) |
|
346 |
+ outputMap[threadName]=False |
|
347 |
+ raise e |
|
348 |
+ |
|
349 |
+ def prepareBuildRoot(self): |
|
350 |
+ chrootID=None |
|
351 |
+ chrootName="build-"+self.base.package |
|
352 |
+ try: |
|
353 |
+ chrUtils = ChrootUtils(self.base.logName,self.base.logPath) |
|
354 |
+ returnVal,chrootID = chrUtils.createChroot(chrootName) |
|
355 |
+ self.base.logger.debug("Created new chroot: " + chrootID) |
|
356 |
+ if not returnVal: |
|
357 |
+ raise Exception("Unable to prepare build root") |
|
358 |
+ tUtils=ToolChainUtils(self.base.logName,self.base.logPath) |
|
359 |
+ tUtils.installToolChainRPMS(chrootID, self.base.package, self.base.logPath) |
|
360 |
+ except Exception as e: |
|
361 |
+ if chrootID is not None: |
|
362 |
+ self.base.logger.debug("Deleting chroot: " + chrootID) |
|
363 |
+ chrUtils.destroyChroot(chrootID) |
|
364 |
+ raise e |
|
365 |
+ return chrootID |
|
366 |
+ |
|
367 |
+ def buildPackage(self): |
|
368 |
+ #do not build if RPM is already built |
|
369 |
+ #test only if the package is in the testForceRPMS with rpmCheck |
|
370 |
+ #build only if the package is not in the testForceRPMS with rpmCheck |
|
371 |
+ if self.base.checkIfPackageIsAlreadyBuilt(): |
|
372 |
+ if not constants.rpmCheck: |
|
373 |
+ self.base.logger.info("Skipping building the package:" + self.base.package) |
|
374 |
+ return |
|
375 |
+ elif constants.rpmCheck and self.base.package not in constants.testForceRPMS: |
|
376 |
+ self.base.logger.info("Skipping testing the package:" + self.base.package) |
|
377 |
+ return |
|
378 |
+ |
|
379 |
+ chrUtils = ChrootUtils(self.base.logName,self.base.logPath) |
|
380 |
+ chrootID=None |
|
381 |
+ try: |
|
382 |
+ chrootID = self.prepareBuildRoot() |
|
383 |
+ listInstalledPackages, listInstalledRPMs = self.base.findInstalledPackages(chrootID) |
|
384 |
+ listDependentPackages=self.base.findBuildTimeRequiredPackages() |
|
385 |
+ if constants.rpmCheck and self.base.package in constants.testForceRPMS: |
|
386 |
+ listDependentPackages.extend(self.base.findBuildTimeCheckRequiredPackages()) |
|
387 |
+ testPackages=set(constants.listMakeCheckRPMPkgtoInstall)-set(listInstalledPackages)-set([self.base.package]) |
|
388 |
+ listDependentPackages.extend(testPackages) |
|
389 |
+ listDependentPackages=list(set(listDependentPackages)) |
|
390 |
+ |
|
391 |
+ pkgUtils = PackageUtils(self.base.logName,self.base.logPath) |
|
392 |
+ if len(listDependentPackages) != 0: |
|
393 |
+ self.base.logger.info("Installing the build time dependent packages......") |
|
394 |
+ for pkg in listDependentPackages: |
|
395 |
+ self.base.installPackage(pkgUtils, pkg, chrootID, self.base.logPath, listInstalledPackages, listInstalledRPMs) |
|
396 |
+ pkgUtils.installRPMSInAOneShot(chrootID, self.base.logPath) |
|
397 |
+ self.base.logger.info("Finished installing the build time dependent packages......") |
|
398 |
+ |
|
399 |
+ pkgUtils.adjustGCCSpecs(self.base.package, chrootID, self.base.logPath) |
|
400 |
+ pkgUtils.buildRPMSForGivenPackage(self.base.package, chrootID,self.base.listBuildOptionPackages, |
|
401 |
+ self.base.pkgBuildOptionFile, self.base.logPath) |
|
402 |
+ self.base.logger.info("Successfully built the package:" + self.base.package) |
|
403 |
+ except Exception as e: |
|
404 |
+ self.base.logger.error("Failed while building package:" + self.base.package) |
|
405 |
+ self.base.logger.debug("Chroot with ID: " + chrootID + " not deleted for debugging.") |
|
406 |
+ logFileName = os.path.join(self.base.logPath, self.base.package + ".log") |
|
407 |
+ fileLog = os.popen('tail -n 100 ' + logFileName).read() |
|
408 |
+ self.base.logger.debug(fileLog) |
|
409 |
+ raise e |
|
410 |
+ if chrootID is not None: |
|
411 |
+ chrUtils.destroyChroot(chrootID) |
... | ... |
@@ -533,8 +533,8 @@ class PackageUtils(object): |
533 | 533 |
self.logger.error("Error copying source SPEC file to container") |
534 | 534 |
raise Exception("Failed copying source SPEC to container") |
535 | 535 |
|
536 |
-# FIXME: some sources are located in SPECS/.. how to mount? |
|
537 |
-# if os.geteuid()==0: |
|
536 |
+ #FIXME: some sources are located in SPECS/.. how to mount? |
|
537 |
+ # if os.geteuid()==0: |
|
538 | 538 |
#TODO: mount it in, don't copy |
539 | 539 |
macros = [] |
540 | 540 |
self.copySourcesToContainer(listSourcesFiles, package, containerID, sourcePath) |
... | ... |
@@ -1,5 +1,5 @@ |
1 |
-from BuildContainer import BuildContainer |
|
2 |
-from PackageBuilder import PackageBuilder |
|
1 |
+from PackageBuilder import PackageBuilderChroot |
|
2 |
+from PackageBuilder import PackageBuilderContainer |
|
3 | 3 |
import threading |
4 | 4 |
import Scheduler |
5 | 5 |
import ThreadPool |
... | ... |
@@ -28,9 +28,17 @@ class WorkerThread(threading.Thread): |
28 | 28 |
break |
29 | 29 |
self.logger.info("Thread "+self.name+" is building package:"+ pkg) |
30 | 30 |
if self.pkgBuildType == "chroot": |
31 |
- pkgBuilder = PackageBuilder(self.mapPackageToCycle,self.listAvailableCyclicPackages,self.listBuildOptionPackages,self.pkgBuildOptionFile) |
|
31 |
+ pkgBuilder = PackageBuilderChroot(self.mapPackageToCycle, |
|
32 |
+ self.listAvailableCyclicPackages, |
|
33 |
+ self.listBuildOptionPackages, |
|
34 |
+ self.pkgBuildOptionFile, |
|
35 |
+ self.pkgBuildType) |
|
32 | 36 |
elif self.pkgBuildType == "container": |
33 |
- pkgBuilder = BuildContainer(self.mapPackageToCycle,self.listAvailableCyclicPackages,self.listBuildOptionPackages,self.pkgBuildOptionFile,"build-"+pkg) |
|
37 |
+ pkgBuilder = PackageBuilderContainer(self.mapPackageToCycle, |
|
38 |
+ self.listAvailableCyclicPackages, |
|
39 |
+ self.listBuildOptionPackages, |
|
40 |
+ self.pkgBuildOptionFile, |
|
41 |
+ self.pkgBuildType) |
|
34 | 42 |
t = threading.Thread(target=pkgBuilder.buildPackageThreadAPI,args=(pkg,outputMap,pkg)) |
35 | 43 |
t.start() |
36 | 44 |
t.join() |