Add Jenkins file for pipeline testing
Change-Id: Iff703121d77e09b2b7ade81d092a1b3f60f05209
diff --git a/Jenkinsfile b/Jenkinsfile
new file mode 100755
index 0000000..3ca638a
--- /dev/null
+++ b/Jenkinsfile
@@ -0,0 +1,175 @@
+import java.util.regex.Pattern
+/**
+ *
+ * Images build pipeline
+ *
+ * Expected parameters:
+ * BUILD_OS
+ * BUILD_ONLY
+ * PACKER_DEBUG
+ * PACKER_URL
+ * PACKER_ZIP
+ * PACKER_ZIP_MD5
+ * PACKER_ARGS
+ * UPLOAD_URL
+ * SKIP_UPLOAD
+ * CLEANUP_OLD
+ * CLEANUP_KEEP
+ * PIPELINE_LIBS_URL
+ * PIPELINE_LIBS_BRANCH
+ * PIPELINE_LIBS_CREDENTIALS_ID
+ */
+
+
+// Load shared libs
+def common
+fileLoader.withGit(PIPELINE_LIBS_URL, PIPELINE_LIBS_BRANCH, PIPELINE_LIBS_CREDENTIALS_ID, '') {
+ common = fileLoader.load("common");
+}
+
+node('qemu') {
+ // Define global variables
+ def workspace = common.getWorkspace()
+ def buildTypes = BUILD_ONLY.tokenize(" ")
+ checkout scm
+ try {
+ stage("prepare") {
+ if (!fileExists("${workspace}/tmp")) {
+ sh "mkdir -p ${workspace}/tmp"
+ }
+ if (!fileExists("${workspace}/images")) {
+ sh "mkdir ${workspace}/images"
+ }
+ }
+ if (!fileExists("bin")) {
+ println("Downloading packer")
+ sh "mkdir bin"
+ dir("bin") {
+ sh "wget -O ${PACKER_ZIP} ${PACKER_URL}"
+ sh "echo \"${PACKER_ZIP_MD5} ${PACKER_ZIP}\" >> md5sum"
+ sh "md5sum -c --status md5sum"
+ sh "unzip ${PACKER_ZIP}"
+ }
+ }
+ stage("build") {
+ dir(BUILD_OS) {
+ withEnv([String.format("PATH=%s:%s/bin", env.PATH, workspace),
+ "PACKER_LOG_PATH=${workspace}/packer.log",
+ "PACKER_LOG=1",
+ "TMPDIR=${workspace}/tmp"
+ ]) {
+ if (PACKER_DEBUG == 'true') {
+ PACKER_ARGS = "${PACKER_ARGS} -debug"
+ }
+ sh "packer build -only=${BUILD_ONLY} ${PACKER_ARGS} -parallel=false template.json"
+ def packerStatus = sh(script: "grep \"Some builds didn't complete successfully and had errors\" ${PACKER_LOG_PATH}", returnStatus: true)
+ // grep returns 0 if find something
+ if (packerStatus != 0) {
+ if (buildTypes.contains("qemu")) {
+ def imageQemu = sh(script: "find images/ | grep -- '-qemu-' | tail -1", returnStdout: true).trim()
+ if (imageQemu != null && imageQemu != "") {
+ def qemuConvertStatus = sh(script: "qemu-img convert -c -O qcow2 ${imageQemu} ${imageQemu}.qcow2", returnStatus:true)
+ if(qemuConvertStatus == 0){
+ sh "mv ${imageQemu}/${imageQemu}.qcow2 .."
+ sh "rm -f ${imageQemu}"
+ }else{
+ throw new Exception("Qemu image convert failed")
+ }
+ }
+ }
+ if (buildTypes.contains("docker")) {
+ def imageDocker = sh(script: "find images/ | grep -- '-docker-' | grep '.tar\$' | tail -1", returnStdout: true).trim()
+ if (imageDocker != null && imageDocker != "") {
+ def pbZip2Status = sh(script: "pbzip2 ${imageDocker}", returnStatus: true)
+ if(pbZip2Status == 0){
+ sh "rm -f ${imageDocker}"
+ }else{
+ throw new Exception("pbzip2 image convert failed")
+ }
+ }
+ }
+ } else {
+ throw new Exception("Packer build failed")
+ }
+ }
+ }
+ }
+ stage("upload"){
+ dir(BUILD_OS + "/images") {
+ def images = findFiles(glob: "*.*")
+ def uploadedImages=[]
+ def cleanedImages=[]
+ def imageBuilds = [:]
+ for (int i = 0; i < images.size(); i++) {
+ def imageName = images[i].name
+ def imageNameList = imageName.tokenize(".")
+ def imageType = "." + imageNameList[imageNameList.size() - 1]
+ if(imageType.equals(".md5")){
+ continue;
+ }
+ imageBuilds["build${i}"]={
+ if (SKIP_UPLOAD != 'true') {
+ sh "md5sum ${imageName} > ${imageName}.md5"
+ println("Uploading image " + imageName)
+ def uploadImageStatus = sh(script: "curl -f -T ${imageName} ${UPLOAD_URL}", returnStatus: true)
+ def uploadMd5Status = sh(script: "curl -f -T ${imageName}.md5 ${UPLOAD_URL}", returnStatus: true)
+ if(uploadImageStatus==0 && uploadMd5Status == 0){
+ uploadedImages.add(imageName)
+ sh(String.format("rm -r *%s*", BUILD_OS.replaceAll(/\./,"-")))
+ }else{
+ throw new Exception("Image upload failed")
+ }
+ }
+ if (CLEANUP_OLD == 'true') {
+ 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)
+ if (remoteImages != "") {
+ def cleanupImages = getCleanupImageList(remoteImages, imageType, BUILD_OS)
+ def deleteCount = cleanupImages.size() - Integer.parseInt(CLEANUP_KEEP)
+ if (deleteCount > 0) {
+ for (int j = 0; j < deleteCount; j++) {
+ println(String.format("Deleting image %s from aptly", cleanupImages[j]))
+ sh "curl -f -X DELETE ${UPLOAD_URL}/" + cleanupImages[j]
+ def imageTypeForRegex = Pattern.quote(imageType)
+ def imageMd5 = cleanupImages[j].replaceAll(/${imageTypeForRegex}$/, ".md5")
+ sh "curl -f -X DELETE ${UPLOAD_URL}/" + imageMd5
+
+ sh "curl -f -X DELETE ${UPLOAD_URL}/${cleanupImages[j]} || true"
+ sh "curl -f -X DELETE ${UPLOAD_URL}/${imageMd5} || true"
+ cleanedImages.add(cleanupImages[j])
+ }
+ }
+ }
+ }
+ }
+ }
+ parallel imageBuilds
+ println(String.format("Uploaded %s images with names %s", uploadedImages.size(), uploadedImages.toString()))
+ println(String.format("Cleaned %s images with names %s", cleanedImages.size(), cleanedImages.toString()))
+ }
+ }
+ } catch (Throwable e) {
+ // If there was an error or exception thrown, the build failed
+ currentBuild.result = "FAILURE"
+ throw e
+ } finally {
+ common.sendNotification(currentBuild.result, "", ["slack"])
+ if (buildTypes.contains("docker")) {
+ withEnv(["PACKER_LOG_PATH=${workspace}/packer.log"]) {
+ sh "docker rmi --force \$(grep \"docker: Image ID:\" ${PACKER_LOG_PATH} | cut -d : -f 6 | head -1 | sed s,\\ ,,g) || true"
+ }
+ }
+ }
+}
+
+@NonCPS
+def getCleanupImageList(remoteImagesString, imageType, osImage) {
+ def remoteImages = remoteImagesString.tokenize("\n")
+ def imageTypeForRegex = Pattern.quote(imageType)
+ def osImageForRegex = Pattern.quote(osImage)
+ def remoteImagesSameType = remoteImages.findAll {
+ it = ~/${imageTypeForRegex}$/
+ }
+ return remoteImagesSameType.toSorted().findAll {
+ it = ~/^${osImageForRegex}-/
+ }
+}
\ No newline at end of file