Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 1 | /** |
| 2 | * |
Richard Felkl | 859f4dd | 2018-01-04 23:03:27 +0100 | [diff] [blame] | 3 | * Build mirror image pipeline |
Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 4 | * |
| 5 | * Expected parameters: |
Richard Felkl | 859f4dd | 2018-01-04 23:03:27 +0100 | [diff] [blame] | 6 | * IMAGE_NAME - Name of the result image. |
| 7 | * OS_CREDENTIALS_ID - ID of credentials for OpenStack API stored in Jenkins. |
| 8 | * OS_PROJECT - Project in OpenStack under the VM will be spawned. |
| 9 | * OS_URL - Keystone auth endpoint of the OpenStack. |
| 10 | * OS_VERSION - OpenStack version |
Richard Felkl | 859f4dd | 2018-01-04 23:03:27 +0100 | [diff] [blame] | 11 | * UPLOAD_URL - URL of an WebDAV used to upload the image after creating. |
| 12 | * VM_AVAILABILITY_ZONE - Availability zone in OpenStack in the VM will be spawned. |
Richard Felkl | 859f4dd | 2018-01-04 23:03:27 +0100 | [diff] [blame] | 13 | * VM_FLAVOR - Flavor to be used for VM in OpenStack. |
| 14 | * VM_FLOATING_IP_POOL - Floating IP pool to be used to assign floating IP to the VM. |
| 15 | * VM_IMAGE - Name of the image to be used for VM in OpenStack. |
| 16 | * VM_IP - Static IP that is assigned to the VM which belongs to the network used. |
Richard Felkl | 859f4dd | 2018-01-04 23:03:27 +0100 | [diff] [blame] | 17 | * VM_NETWORK_ID - ID of the network that VM connects to. |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 18 | * EXTRA_VARIABLES - list of key:value variables required by template.json |
Richard Felkl | 859f4dd | 2018-01-04 23:03:27 +0100 | [diff] [blame] | 19 | * |
Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 20 | */ |
| 21 | |
| 22 | // Load shared libs |
Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 23 | def common = new com.mirantis.mk.Common() |
Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 24 | def openstack = new com.mirantis.mk.Openstack() |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 25 | def git = new com.mirantis.mk.Git() |
Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 26 | def date = new Date() |
| 27 | def dateTime = date.format("ddMMyyyy-HHmmss") |
Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 28 | def openstackServer = "" |
| 29 | def rcFile = "" |
| 30 | def openstackEnv = "" |
Richard Felkl | 802e446 | 2017-12-06 10:08:05 +0100 | [diff] [blame] | 31 | def uploadImageStatus = "" |
| 32 | def uploadMd5Status = "" |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 33 | ArrayList extra_vars = job_env.get('EXTRA_VARIABLES', '').readLines() |
| 34 | def IMAGE_NAME = job_env.get('IMAGE_NAME', "packer-image") + "-" + dateTime |
Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 35 | |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 36 | timeout(time: 8, unit: 'HOURS') { |
| 37 | node("python&&disk-xl") { |
| 38 | try { |
| 39 | def workspace = common.getWorkspace() |
| 40 | openstackEnv = "${workspace}/venv" |
Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 41 | |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 42 | stage("Prepare env") { |
| 43 | checkout scm |
| 44 | if (!fileExists("${workspace}/tmp")) { |
| 45 | sh "mkdir -p ${workspace}/tmp" |
Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 46 | } |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 47 | if (!fileExists("${workspace}/images")) { |
| 48 | sh "mkdir ${workspace}/images" |
| 49 | } |
| 50 | if (!fileExists("bin")) { |
| 51 | common.infoMsg("Downloading packer") |
| 52 | sh "mkdir -p bin" |
| 53 | dir("bin") { |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 54 | sh "wget --quiet -O ${PACKER_ZIP} ${PACKER_URL}" |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 55 | sh "echo \"${PACKER_ZIP_MD5} ${PACKER_ZIP}\" >> md5sum" |
| 56 | sh "md5sum -c --status md5sum" |
| 57 | sh "unzip ${PACKER_ZIP}" |
| 58 | } |
| 59 | } |
| 60 | // clean images dir before building |
| 61 | sh(script: "rm -rf ${BUILD_OS}/images/*", returnStatus: true) |
| 62 | // clean virtualenv is exists |
| 63 | sh(script: "rm -rf ${workspace}/venv", returnStatus: true) |
| 64 | |
| 65 | openstack.setupOpenstackVirtualenv(openstackEnv, OS_VERSION) |
| 66 | git.checkoutGitRepository(PACKER_TEMPLATES_REPO_NAME, PACKER_TEMPLATES_REPO_URL, PACKER_TEMPLATES_BRANCH) |
| 67 | } |
| 68 | |
| 69 | stage("Build Instance") { |
| 70 | rcFile = openstack.createOpenstackEnv(OS_URL, OS_CREDENTIALS_ID, OS_PROJECT, "default", "", "default", "2", "") |
| 71 | dir("${workspace}/${PACKER_TEMPLATES_REPO_NAME}/${BUILD_OS}/") { |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 72 | withEnv(extra_vars + ["PATH=${env.PATH}:${workspace}/bin", |
| 73 | "PACKER_LOG_PATH=${workspace}/packer.log", |
| 74 | "PACKER_LOG=1", |
| 75 | "TMPDIR=${workspace}/tmp"]) { |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 76 | if (PACKER_DEBUG.toBoolean()) { |
| 77 | PACKER_ARGS = "${PACKER_ARGS} -debug" |
| 78 | } |
| 79 | |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 80 | sh "source extra.vars ; packer build -only=${BUILD_ONLY} ${PACKER_ARGS} -parallel=false template.json" |
| 81 | |
| 82 | def packerStatus = sh(script: "grep \"Some builds didn't complete successfully and had errors\" ${PACKER_LOG_PATH}", returnStatus: true) |
| 83 | // grep returns 0 if find something |
| 84 | if (packerStatus != 0) { |
| 85 | if (buildTypes.contains("openstack")) { |
| 86 | common.infoMsg("Openstack instance complete") |
| 87 | } |
| 88 | } else { |
| 89 | throw new Exception("Packer build failed") |
| 90 | } |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | stage("Publish image") { |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 96 | common.infoMsg("Saving image ${IMAGE_NAME}") |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 97 | common.retry(3, 5) { |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 98 | openstack.runOpenstackCommand("openstack image save --file ${IMAGE_NAME}.qcow2 ${IMAGE_NAME}", rcFile, openstackEnv) |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 99 | } |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 100 | sh "md5sum ${IMAGE_NAME}.qcow2 > ${IMAGE_NAME}.qcow2.md5" |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 101 | |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 102 | common.infoMsg("Uploading image ${IMAGE_NAME}") |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 103 | common.retry(3, 5) { |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 104 | uploadImageStatus = sh(script: "curl -f -T ${IMAGE_NAME}.qcow2 ${UPLOAD_URL}", returnStatus: true) |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 105 | if (uploadImageStatus != 0) { |
| 106 | throw new Exception("Image upload failed") |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | common.retry(3, 5) { |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 111 | uploadMd5Status = sh(script: "curl -f -T ${IMAGE_NAME}.qcow2.md5 ${UPLOAD_URL}", returnStatus: true) |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 112 | if (uploadMd5Status != 0) { |
| 113 | throw new Exception("MD5 sum upload failed") |
| 114 | } |
| 115 | } |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 116 | currentBuild.description = "<a href='http://ci.mcp.mirantis.net:8085/images/${IMAGE_NAME}.qcow2'>${IMAGE_NAME}.qcow2</a>" |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 117 | } |
| 118 | |
| 119 | } catch (Throwable e) { |
| 120 | // If there was an error or exception thrown, the build failed |
| 121 | currentBuild.result = "FAILURE" |
| 122 | throw e |
| 123 | } finally { |
| 124 | if (CLEANUP_AFTER) { |
| 125 | stage("Cleanup") { |
| 126 | if (openstackServer != "") { |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 127 | openstack.runOpenstackCommand("openstack server delete ${IMAGE_NAME}", rcFile, openstackEnv) |
| 128 | openstack.runOpenstackCommand("openstack image delete ${IMAGE_NAME}", rcFile, openstackEnv) |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 129 | } |
| 130 | dir(workspace) { |
| 131 | sh "rm -rf ./*" |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | } else { |
| 136 | common.infoMsg("Env has not been cleanup!") |
| 137 | common.infoMsg("Packer private key:") |
| 138 | dir("${workspace}/${PACKER_TEMPLATES_REPO_NAME}/${BUILD_OS}/") { |
| 139 | sh "cat os_${BUILD_OS}.pem" |
| 140 | } |
| 141 | |
| 142 | } |
Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 143 | } |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 144 | |
| 145 | } |
Jakub Josef | 88aaf83 | 2018-01-18 16:18:28 +0100 | [diff] [blame] | 146 | } |