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