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 rcFile = "" |
| 29 | def openstackEnv = "" |
Richard Felkl | 802e446 | 2017-12-06 10:08:05 +0100 | [diff] [blame] | 30 | def uploadImageStatus = "" |
| 31 | def uploadMd5Status = "" |
Richard Felkl | 3e93eeb | 2018-03-06 14:51:45 +0100 | [diff] [blame] | 32 | def creds |
| 33 | ArrayList extra_vars = EXTRA_VARIABLES.readLines() |
| 34 | IMAGE_NAME = IMAGE_NAME + "-" + 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") { |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 43 | if (!fileExists("${workspace}/tmp")) { |
| 44 | sh "mkdir -p ${workspace}/tmp" |
Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 45 | } |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 46 | if (!fileExists("${workspace}/images")) { |
| 47 | sh "mkdir ${workspace}/images" |
| 48 | } |
| 49 | if (!fileExists("bin")) { |
| 50 | common.infoMsg("Downloading packer") |
| 51 | sh "mkdir -p bin" |
| 52 | dir("bin") { |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 53 | sh "wget --quiet -O ${PACKER_ZIP} ${PACKER_URL}" |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 54 | sh "echo \"${PACKER_ZIP_MD5} ${PACKER_ZIP}\" >> md5sum" |
| 55 | sh "md5sum -c --status md5sum" |
| 56 | sh "unzip ${PACKER_ZIP}" |
| 57 | } |
| 58 | } |
| 59 | // clean images dir before building |
| 60 | sh(script: "rm -rf ${BUILD_OS}/images/*", returnStatus: true) |
| 61 | // clean virtualenv is exists |
| 62 | sh(script: "rm -rf ${workspace}/venv", returnStatus: true) |
| 63 | |
| 64 | openstack.setupOpenstackVirtualenv(openstackEnv, OS_VERSION) |
| 65 | git.checkoutGitRepository(PACKER_TEMPLATES_REPO_NAME, PACKER_TEMPLATES_REPO_URL, PACKER_TEMPLATES_BRANCH) |
Richard Felkl | 3e93eeb | 2018-03-06 14:51:45 +0100 | [diff] [blame] | 66 | creds = common.getPasswordCredentials(OS_CREDENTIALS_ID) |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 67 | } |
| 68 | |
| 69 | stage("Build Instance") { |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 70 | dir("${workspace}/${PACKER_TEMPLATES_REPO_NAME}/${BUILD_OS}/") { |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 71 | withEnv(extra_vars + ["PATH=${env.PATH}:${workspace}/bin", |
| 72 | "PACKER_LOG_PATH=${workspace}/packer.log", |
| 73 | "PACKER_LOG=1", |
Richard Felkl | 3e93eeb | 2018-03-06 14:51:45 +0100 | [diff] [blame] | 74 | "TMPDIR=${workspace}/tmp", |
azvyagintsev | 4ece5a7 | 2018-03-07 15:11:59 +0200 | [diff] [blame] | 75 | "IMAGE_NAME=${IMAGE_NAME}", |
Richard Felkl | 3e93eeb | 2018-03-06 14:51:45 +0100 | [diff] [blame] | 76 | "OS_USERNAME=${creds.username}", |
| 77 | "OS_PASSWORD=${creds.password.toString()}"]) { |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 78 | if (PACKER_DEBUG.toBoolean()) { |
| 79 | PACKER_ARGS = "${PACKER_ARGS} -debug" |
| 80 | } |
| 81 | |
Richard Felkl | 3e93eeb | 2018-03-06 14:51:45 +0100 | [diff] [blame] | 82 | sh "packer build -only=${BUILD_ONLY} ${PACKER_ARGS} -parallel=false template.json" |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 83 | |
| 84 | def packerStatus = sh(script: "grep \"Some builds didn't complete successfully and had errors\" ${PACKER_LOG_PATH}", returnStatus: true) |
| 85 | // grep returns 0 if find something |
| 86 | if (packerStatus != 0) { |
Richard Felkl | 3e93eeb | 2018-03-06 14:51:45 +0100 | [diff] [blame] | 87 | common.infoMsg("Openstack instance complete") |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 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}") |
Richard Felkl | 3e93eeb | 2018-03-06 14:51:45 +0100 | [diff] [blame] | 97 | rcFile = openstack.createOpenstackEnv(workspace, OS_URL, OS_CREDENTIALS_ID, OS_PROJECT, "default", "", "default", "2", "") |
| 98 | |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 99 | common.retry(3, 5) { |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 100 | openstack.runOpenstackCommand("openstack image save --file ${IMAGE_NAME}.qcow2 ${IMAGE_NAME}", rcFile, openstackEnv) |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 101 | } |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 102 | sh "md5sum ${IMAGE_NAME}.qcow2 > ${IMAGE_NAME}.qcow2.md5" |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 103 | |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 104 | common.infoMsg("Uploading image ${IMAGE_NAME}") |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 105 | common.retry(3, 5) { |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 106 | uploadImageStatus = sh(script: "curl -f -T ${IMAGE_NAME}.qcow2 ${UPLOAD_URL}", returnStatus: true) |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 107 | if (uploadImageStatus != 0) { |
| 108 | throw new Exception("Image upload failed") |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | common.retry(3, 5) { |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 113 | 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] | 114 | if (uploadMd5Status != 0) { |
| 115 | throw new Exception("MD5 sum upload failed") |
| 116 | } |
| 117 | } |
azvyagintsev | a0bc614 | 2018-03-02 21:24:30 +0200 | [diff] [blame] | 118 | 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] | 119 | } |
| 120 | |
| 121 | } catch (Throwable e) { |
| 122 | // If there was an error or exception thrown, the build failed |
| 123 | currentBuild.result = "FAILURE" |
| 124 | throw e |
| 125 | } finally { |
| 126 | if (CLEANUP_AFTER) { |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 127 | dir(workspace) { |
| 128 | sh "rm -rf ./*" |
| 129 | } |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 130 | } else { |
| 131 | common.infoMsg("Env has not been cleanup!") |
| 132 | common.infoMsg("Packer private key:") |
| 133 | dir("${workspace}/${PACKER_TEMPLATES_REPO_NAME}/${BUILD_OS}/") { |
| 134 | sh "cat os_${BUILD_OS}.pem" |
| 135 | } |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 136 | } |
Richard Felkl | 2e9e545 | 2017-10-16 09:52:10 +0200 | [diff] [blame] | 137 | } |
azvyagintsev | 1c79f4d | 2018-03-02 14:25:37 +0200 | [diff] [blame] | 138 | } |
Jakub Josef | 88aaf83 | 2018-01-18 16:18:28 +0100 | [diff] [blame] | 139 | } |