Browse code

Code Refactoring

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>

Rui Gu authored on 2017/10/31 08:16:03
Showing 4 changed files
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()