blob: 1c5e4afc623f5f0c85802fd8e463a9350cb8ee8b [file] [log] [blame]
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){
def imageDir = imageQemu.substring(0, imageQemu.lastIndexOf("/") + 1);
def moveResult = sh(script: "mv ${imageQemu}.qcow2 ${imageDir}..", returnStatus: true)
if(moveResult == 0){
sh "rm -rf ${imageDir}"
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 %s.md5",imageName, imageName))
}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]
sh "curl -f -X DELETE ${UPLOAD_URL}" + cleanupImages[j] + ".md5"
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.replaceAll(/\./,"-"))
def remoteImagesSameType = remoteImages.findAll { it ->
it =~ /${imageTypeForRegex}$/
}
return remoteImagesSameType.toSorted().findAll { it ->
it =~ /^${osImageForRegex}-/
}
}