blob: 3ca638a9745ae3999f000d84da1e279a540a107e [file] [log] [blame]
Jakub Josef6ee6f992017-01-27 16:16:04 +01001import java.util.regex.Pattern
2/**
3 *
4 * Images build pipeline
5 *
6 * Expected parameters:
7 * BUILD_OS
8 * BUILD_ONLY
9 * PACKER_DEBUG
10 * PACKER_URL
11 * PACKER_ZIP
12 * PACKER_ZIP_MD5
13 * PACKER_ARGS
14 * UPLOAD_URL
15 * SKIP_UPLOAD
16 * CLEANUP_OLD
17 * CLEANUP_KEEP
18 * PIPELINE_LIBS_URL
19 * PIPELINE_LIBS_BRANCH
20 * PIPELINE_LIBS_CREDENTIALS_ID
21 */
22
23
24// Load shared libs
25def common
26fileLoader.withGit(PIPELINE_LIBS_URL, PIPELINE_LIBS_BRANCH, PIPELINE_LIBS_CREDENTIALS_ID, '') {
27 common = fileLoader.load("common");
28}
29
30node('qemu') {
31 // Define global variables
32 def workspace = common.getWorkspace()
33 def buildTypes = BUILD_ONLY.tokenize(" ")
34 checkout scm
35 try {
36 stage("prepare") {
37 if (!fileExists("${workspace}/tmp")) {
38 sh "mkdir -p ${workspace}/tmp"
39 }
40 if (!fileExists("${workspace}/images")) {
41 sh "mkdir ${workspace}/images"
42 }
43 }
44 if (!fileExists("bin")) {
45 println("Downloading packer")
46 sh "mkdir bin"
47 dir("bin") {
48 sh "wget -O ${PACKER_ZIP} ${PACKER_URL}"
49 sh "echo \"${PACKER_ZIP_MD5} ${PACKER_ZIP}\" >> md5sum"
50 sh "md5sum -c --status md5sum"
51 sh "unzip ${PACKER_ZIP}"
52 }
53 }
54 stage("build") {
55 dir(BUILD_OS) {
56 withEnv([String.format("PATH=%s:%s/bin", env.PATH, workspace),
57 "PACKER_LOG_PATH=${workspace}/packer.log",
58 "PACKER_LOG=1",
59 "TMPDIR=${workspace}/tmp"
60 ]) {
61 if (PACKER_DEBUG == 'true') {
62 PACKER_ARGS = "${PACKER_ARGS} -debug"
63 }
64 sh "packer build -only=${BUILD_ONLY} ${PACKER_ARGS} -parallel=false template.json"
65 def packerStatus = sh(script: "grep \"Some builds didn't complete successfully and had errors\" ${PACKER_LOG_PATH}", returnStatus: true)
66 // grep returns 0 if find something
67 if (packerStatus != 0) {
68 if (buildTypes.contains("qemu")) {
69 def imageQemu = sh(script: "find images/ | grep -- '-qemu-' | tail -1", returnStdout: true).trim()
70 if (imageQemu != null && imageQemu != "") {
71 def qemuConvertStatus = sh(script: "qemu-img convert -c -O qcow2 ${imageQemu} ${imageQemu}.qcow2", returnStatus:true)
72 if(qemuConvertStatus == 0){
73 sh "mv ${imageQemu}/${imageQemu}.qcow2 .."
74 sh "rm -f ${imageQemu}"
75 }else{
76 throw new Exception("Qemu image convert failed")
77 }
78 }
79 }
80 if (buildTypes.contains("docker")) {
81 def imageDocker = sh(script: "find images/ | grep -- '-docker-' | grep '.tar\$' | tail -1", returnStdout: true).trim()
82 if (imageDocker != null && imageDocker != "") {
83 def pbZip2Status = sh(script: "pbzip2 ${imageDocker}", returnStatus: true)
84 if(pbZip2Status == 0){
85 sh "rm -f ${imageDocker}"
86 }else{
87 throw new Exception("pbzip2 image convert failed")
88 }
89 }
90 }
91 } else {
92 throw new Exception("Packer build failed")
93 }
94 }
95 }
96 }
97 stage("upload"){
98 dir(BUILD_OS + "/images") {
99 def images = findFiles(glob: "*.*")
100 def uploadedImages=[]
101 def cleanedImages=[]
102 def imageBuilds = [:]
103 for (int i = 0; i < images.size(); i++) {
104 def imageName = images[i].name
105 def imageNameList = imageName.tokenize(".")
106 def imageType = "." + imageNameList[imageNameList.size() - 1]
107 if(imageType.equals(".md5")){
108 continue;
109 }
110 imageBuilds["build${i}"]={
111 if (SKIP_UPLOAD != 'true') {
112 sh "md5sum ${imageName} > ${imageName}.md5"
113 println("Uploading image " + imageName)
114 def uploadImageStatus = sh(script: "curl -f -T ${imageName} ${UPLOAD_URL}", returnStatus: true)
115 def uploadMd5Status = sh(script: "curl -f -T ${imageName}.md5 ${UPLOAD_URL}", returnStatus: true)
116 if(uploadImageStatus==0 && uploadMd5Status == 0){
117 uploadedImages.add(imageName)
118 sh(String.format("rm -r *%s*", BUILD_OS.replaceAll(/\./,"-")))
119 }else{
120 throw new Exception("Image upload failed")
121 }
122 }
123 if (CLEANUP_OLD == 'true') {
124 def remoteImages = sh(script: "curl -f -sss ${UPLOAD_URL} | grep -Eo '>.*\\.(qcow2|box|tar\\.bz2)</a>' | sed -e 's,>,,g' -e 's,</a,,g'", returnStdout: true)
125 if (remoteImages != "") {
126 def cleanupImages = getCleanupImageList(remoteImages, imageType, BUILD_OS)
127 def deleteCount = cleanupImages.size() - Integer.parseInt(CLEANUP_KEEP)
128 if (deleteCount > 0) {
129 for (int j = 0; j < deleteCount; j++) {
130 println(String.format("Deleting image %s from aptly", cleanupImages[j]))
131 sh "curl -f -X DELETE ${UPLOAD_URL}/" + cleanupImages[j]
132 def imageTypeForRegex = Pattern.quote(imageType)
133 def imageMd5 = cleanupImages[j].replaceAll(/${imageTypeForRegex}$/, ".md5")
134 sh "curl -f -X DELETE ${UPLOAD_URL}/" + imageMd5
135
136 sh "curl -f -X DELETE ${UPLOAD_URL}/${cleanupImages[j]} || true"
137 sh "curl -f -X DELETE ${UPLOAD_URL}/${imageMd5} || true"
138 cleanedImages.add(cleanupImages[j])
139 }
140 }
141 }
142 }
143 }
144 }
145 parallel imageBuilds
146 println(String.format("Uploaded %s images with names %s", uploadedImages.size(), uploadedImages.toString()))
147 println(String.format("Cleaned %s images with names %s", cleanedImages.size(), cleanedImages.toString()))
148 }
149 }
150 } catch (Throwable e) {
151 // If there was an error or exception thrown, the build failed
152 currentBuild.result = "FAILURE"
153 throw e
154 } finally {
155 common.sendNotification(currentBuild.result, "", ["slack"])
156 if (buildTypes.contains("docker")) {
157 withEnv(["PACKER_LOG_PATH=${workspace}/packer.log"]) {
158 sh "docker rmi --force \$(grep \"docker: Image ID:\" ${PACKER_LOG_PATH} | cut -d : -f 6 | head -1 | sed s,\\ ,,g) || true"
159 }
160 }
161 }
162}
163
164@NonCPS
165def getCleanupImageList(remoteImagesString, imageType, osImage) {
166 def remoteImages = remoteImagesString.tokenize("\n")
167 def imageTypeForRegex = Pattern.quote(imageType)
168 def osImageForRegex = Pattern.quote(osImage)
169 def remoteImagesSameType = remoteImages.findAll {
170 it = ~/${imageTypeForRegex}$/
171 }
172 return remoteImagesSameType.toSorted().findAll {
173 it = ~/^${osImageForRegex}-/
174 }
175}