|  | /** | 
|  | * | 
|  | * Deploy the product cluster using Jenkins master on CICD cluster | 
|  | * | 
|  | * Expected parameters: | 
|  |  | 
|  | *   IMAGE_NAME                    Name of the resulting image in the Glance or in artifacts | 
|  |  | 
|  | *   BUILD_CONFIG_DRIVE_PATH       Relative path in tcp-qa to the directory with meta-data and user-data files | 
|  | *   BUILD_PACKER_CONFIG_PATH      Relative path in tcp-qa to the file with packer config (packer.json) | 
|  | *   BASE_IMAGE_URL                Base image to build a new image, in qcow2. For example, released ubuntu cloud image | 
|  | *   BASE_IMAGE_MD5                Base image MD5 checksum. Image will be re-downloaded if not match with the local image checksum | 
|  |  | 
|  | *   PACKER_URL                    URL to the zip archive with packer binary, see https://releases.hashicorp.com/packer/ | 
|  | *   PACKER_ZIP_MD5                MD5 of the zip archive with packer binary | 
|  |  | 
|  | *   OS_AUTH_URL                   OpenStack keystone catalog URL | 
|  | *   OS_PROJECT_NAME               OpenStack project (tenant) name | 
|  | *   OS_USER_DOMAIN_NAME           OpenStack user domain name | 
|  | *   OS_CREDENTIALS                OpenStack username and password credentials ID in Jenkins | 
|  | *   UPLOAD_IMAGE_TO_GLANCE        If True: upload image to glance; if False: store as an artifact | 
|  |  | 
|  | *   TCP_QA_REFS                   Reference to the tcp-qa change on Gerrit, like refs/changes/46/418546/41 | 
|  | */ | 
|  |  | 
|  | @Library('tcp-qa')_ | 
|  |  | 
|  | def common = new com.mirantis.mk.Common() | 
|  | def shared = new com.mirantis.system_qa.SharedPipeline() | 
|  |  | 
|  | timeout(time: 6, unit: 'HOURS') { | 
|  | node () { | 
|  | try { | 
|  |  | 
|  | stage("Clean the environment and clone tcp-qa") { | 
|  | deleteDir() | 
|  | shared.run_cmd("""\ | 
|  | git clone https://gerrit.mcp.mirantis.com/mcp/tcp-qa ${WORKSPACE} | 
|  | """) | 
|  | shared.update_working_dir(false) | 
|  | sh "mkdir ./tmp" | 
|  | } | 
|  |  | 
|  | def packer_zipname = "/tmp/packer.zip" | 
|  | def configdrive_isoname = "./tmp/config-drive.iso" | 
|  |  | 
|  | stage("Prepare Packer") { | 
|  | // Check that the archive is already downloaded and has a correct checksum. Remove if not match | 
|  | if (fileExists(packer_zipname)) { | 
|  | sh(script: "bash -cex 'md5sum -c --status <(echo ${PACKER_ZIP_MD5} ${packer_zipname})' || rm -f ${packer_zipname}", returnStdout: true) | 
|  | } | 
|  | // If the file is missing or removed, then download it and check the checksum | 
|  | if (!fileExists(packer_zipname)) { | 
|  | sh(script: "wget --quiet -O ${packer_zipname} ${PACKER_URL}", returnStdout: true) | 
|  | // Should fail the job if not match | 
|  | sh(script: "bash -cex 'md5sum -c --status <(echo ${PACKER_ZIP_MD5} ${packer_zipname})'", returnStdout: true) | 
|  | } | 
|  | sh "unzip ${packer_zipname}" | 
|  | } | 
|  |  | 
|  | stage("Build the cloudinit ISO") { | 
|  | // Check that genisoimage is installed, or try to install it | 
|  | sh "which genisoimage || sudo apt-get -y install genisoimage" | 
|  | // Generate config-drive ISO | 
|  | sh "mkisofs -o ${configdrive_isoname} -V cidata -r -J --quiet ${BUILD_CONFIG_DRIVE_PATH}" | 
|  | } | 
|  |  | 
|  | stage("Build the image '${IMAGE_NAME}'") { | 
|  | // Build the image | 
|  | sh (script: """\ | 
|  | set -ex; | 
|  | export PACKER_LOG=1; | 
|  | export PACKER_CACHE_DIR='/tmp/packer_cache_${IMAGE_NAME}/'; | 
|  | mkdir -p \${PACKER_CACHE_DIR}; | 
|  | ./packer build -machine-readable -parallel=false -only='qemu' ${BUILD_PACKER_CONFIG_PATH}; | 
|  | """, returnStdout: true) | 
|  | } | 
|  |  | 
|  |  | 
|  | if (env.UPLOAD_IMAGE_TO_GLANCE) { | 
|  |  | 
|  | stage("Upload generated config drive ISO into volume on cfg01 node") { | 
|  | withCredentials([ | 
|  | [$class          : 'UsernamePasswordMultiBinding', | 
|  | credentialsId   : env.OS_CREDENTIALS, | 
|  | passwordVariable: 'OS_PASSWORD', | 
|  | usernameVariable: 'OS_USERNAME'] | 
|  | ]) { | 
|  | env.OS_IDENTITY_API_VERSION = 3 | 
|  |  | 
|  | def imagePath = "tmp/${IMAGE_NAME}/${IMAGE_NAME}.qcow2" | 
|  | shared.run_cmd("""\ | 
|  | openstack --insecure image delete ${IMAGE_NAME} || true | 
|  | sleep 3 | 
|  | openstack --insecure image create ${IMAGE_NAME} --file ${imagePath} --disk-format qcow2 --container-format bare | 
|  | """) | 
|  | } | 
|  | } | 
|  | } else { | 
|  |  | 
|  | stage("Archive artifacts") { | 
|  | archiveArtifacts artifacts: "tmp/${IMAGE_NAME}/${IMAGE_NAME}.qcow2" | 
|  | } | 
|  | } | 
|  |  | 
|  | } catch (e) { | 
|  | common.printMsg("Job is failed", "purple") | 
|  | throw e | 
|  | } finally { | 
|  | // Remove the image after job is finished | 
|  | sh "rm -f ./tmp/${IMAGE_NAME}.qcow2 || true" | 
|  | } // try | 
|  | } // node | 
|  | } // timeout |