Skip to content
Snippets Groups Projects
  • Joshua Colp's avatar
    f4c9a351
    CI: Use tmpfs option to Docker instead of mount. · f4c9a351
    Joshua Colp authored
    Some tests require Asterisk to execute scripts which
    are stored in /tmp. When mount is used for tmpfs there
    is no ability to allow scripts to be executed from
    that location.
    
    This change switches to using tmpfs which can be told
    to allow executables to be run from /tmp.
    
    Change-Id: I0e598ca2b76af1f7f2d29f0da7b1731a214a291a
    f4c9a351
    History
    CI: Use tmpfs option to Docker instead of mount.
    Joshua Colp authored
    Some tests require Asterisk to execute scripts which
    are stored in /tmp. When mount is used for tmpfs there
    is no ability to allow scripts to be executed from
    that location.
    
    This change switches to using tmpfs which can be told
    to allow executables to be run from /tmp.
    
    Change-Id: I0e598ca2b76af1f7f2d29f0da7b1731a214a291a
gates.jenkinsfile 9.18 KiB
/*
 * This pipeline is the "template" for the Asterisk Gate Tests multi-branch
 * parent job.  Jenkins will automatically scan the branches in the "asterisk"
 * or "Security-asterisk" projects in Gerrit and automatically create a branch-
 * specific job for each branch it finds this file in.
 *
 * This file starts as a declarative pipeline because with a declarative
 * pipeline, you can define the trigger in the pipeline file.  This keeps
 * everything in one place.  We transition to scripted pipeline later on because
 * we need to dynamically determine which docker image we're going to use and
 * you can't do that in a delcarative pipeline.
 */
def timeoutTime = 60
def timeoutUnits = 'MINUTES'
if (env.TIMEOUT_GATES) {
	def _timeout = env.TIMEOUT_GATES.split()
	timeoutTime = _timeout[0].toInteger()
	timeoutUnits = _timeout[1]
}

pipeline {
	options {
		timestamps()
		timeout(time: timeoutTime, unit: timeoutUnits)
	}
	triggers {
		/*
		 * This trigger will match either the "asterisk" or "Security-asterisk"
		 * projects.  The branch is taken from the branch this job was created
		 * for.
		 */
		gerrit customUrl: '',
			commentTextParameterMode: 'PLAIN',
			commitMessageParameterMode: 'PLAIN',
			gerritBuildSuccessfulVerifiedValue: 2,
			gerritBuildFailedVerifiedValue: -1,
			gerritBuildUnstableVerifiedValue: -1,
			gerritProjects: [
				[branches: [[compareType: 'PLAIN', pattern: "${BRANCH_NAME}"]],
					compareType: 'REG_EXP',
					disableStrictForbiddenFileVerification: false,
					pattern: '^(Security-)?asterisk.*'
				]
			],
			silentMode: false,
			triggerOnEvents: [
				commentAddedContains('^regate$'),
				commentAdded(commentAddedTriggerApprovalValue: '+2', verdictCategory: 'Code-Review'),
			],
			skipVote: [
				onFailed: false,
				onNotBuilt: true,
				onSuccessful: false,
				onUnstable: false
			]
	}
	
	agent {
		/* All of the stages need to be performed on a docker host */
		label "swdev-docker"
	}

	stages {
		stage ("->") {
			/*
			 * Jenkins will try to automatically rebuild this job when
			 * the jenkinsfile changes but since this job is dependent on
			 * Gerrit, we really don't want to do anything in that case.
			 */
			when {
				not { environment name: 'GERRIT_CHANGE_NUMBER', value: '' }
				not { environment name: 'GERRIT_EVENT_ACCOUNT_NAME', value: 'Jenkins2' }
			}
			steps {
				/* Here's where we switch to scripted pipeline */
				script {
					manager.build.displayName = "${env.GERRIT_CHANGE_NUMBER}"
					manager.createSummary("/plugin/workflow-job/images/48x48/pipelinejob.png").appendText("Docker Host: ${NODE_NAME}", false)

					stage ("Checkout") {
						sh "sudo chown -R jenkins:users ."  
						env.GERRIT_PROJECT_URL = env.GERRIT_CHANGE_URL.replaceAll(/\/[0-9]+$/, "/${env.GERRIT_PROJECT}")
					
						/*
						 * Jenkins has already automatically checked out the base branch
						 * for this change but we now need to check out the change itself
						 * and rebase it on the current base branch.  If the rebase fails,
						 * that's an indication to the user that they'll need to sort their
						 * change out.
						 *
						 * The Gerrit Trigger provides all the URLs and refspecs to
						 * check out the change.
						 *
						 * We need to retrieve the jenkins2 gerrit https credentials
						 * in case this review is in a restricted project.
						 */
						withCredentials([usernamePassword(credentialsId: "${JENKINS_GERRIT_CREDS}",
							passwordVariable: 'GERRIT_USER_PW', usernameVariable: 'GERRIT_USER_NAME')]) {

							sh "printenv | sort"

							checkout scm: [$class: 'GitSCM',
								branches: [[name: env.GERRIT_BRANCH ]],
								extensions: [
									[$class: 'ScmName', name: 'gerrit-public'],
									[$class: 'CleanBeforeCheckout'],
									[$class: 'PreBuildMerge', options: [
										mergeRemote: 'gerrit-public',
										fastForwardMode: 'NO_FF',
										mergeStrategy: 'RECURSIVE',
										mergeTarget: env.GERRIT_BRANCH]],
									[$class: 'CloneOption',
										honorRefspec: true,
										noTags: true,
										depth: 10,
										shallow: true
									],
									[$class: 'PruneStaleBranch'],
									[$class: 'BuildChooserSetting',
										buildChooser: [$class: 'GerritTriggerBuildChooser']
									]
								],
								userRemoteConfigs: [
									[
									credentialsId: env.JENKINS_GERRIT_CREDS,
									name: env.GERRIT_NAME,
									refspec: env.GERRIT_REFSPEC,
									url: env.GERRIT_PROJECT_URL.replaceAll("http(s)?://", "http\$1://${GERRIT_USER_NAME}@")
									]
								]
							]
						}
						sh "sudo tests/CI/setupJenkinsEnvironment.sh"
					}

					def images = env.DOCKER_IMAGES.split(' ')
					def r = currentBuild.startTimeInMillis % images.length
					def ri = images[(int)r]
					def randomImage = env.DOCKER_REGISTRY + "/" + ri
					/* FYI... Jenkins takes care of mouting the workspace for the container */
					def dockerOptions = "--privileged --ulimit core=0 --ulimit nofile=10240 " +
						" --tmpfs /tmp:exec,size=1G -v /srv/jenkins:/srv/jenkins:rw -v /srv/cache:/srv/cache:rw " +
						" --entrypoint=''"
					def bt = env.BUILD_TAG.replaceAll(/[^a-zA-Z0-9_.-]/, '-')
					def outputdir = "tests/CI/output/Testsuite"

					manager.createSummary("/plugin/workflow-job/images/48x48/pipelinejob.png").appendText("Docker Image: ${randomImage}", false)
					def img = docker.image(randomImage)
					img.pull()

					stage ("Build") {
						img.inside(dockerOptions + " --name ${bt}-build") {
							echo 'Building..'
							env.CCACHE_DIR = "/srv/cache/ccache"
							sh "./tests/CI/buildAsterisk.sh --branch-name=${BRANCH_NAME} --output-dir=${outputdir} --cache-dir=/srv/cache"

							archiveArtifacts allowEmptyArchive: true, defaultExcludes: false, fingerprint: false,
								artifacts: "${outputdir}/*"
						}
					}

					def testGroups = readJSON file: "tests/CI/gateTestGroups.json"
					def parallelTasks = [ : ]

					for (def testGroup in testGroups) {
						/*
						 * Because each task is a Groovy closure, we need to
						 * keep local references to some variables.
						 */
						def groupName = testGroup.name
						def groupDir = testGroup.dir
						def groupTestcmd = testGroup.testcmd
						def testsuiteUrl = env.GERRIT_PROJECT_URL.replaceAll(/\/(Security-)?[^\/]+$/, "/\$1testsuite")

						parallelTasks[groupName] = {
							stage (groupName) {

								img.inside("${dockerOptions} --name ${bt}-${groupName}") {

									lock("${JOB_NAME}.${NODE_NAME}.installer") {
										sh "sudo ./tests/CI/installAsterisk.sh --uninstall-all --branch-name=${BRANCH_NAME} --user-group=jenkins:users"
									}

									sh "sudo rm -rf ${groupDir} || : "
									
									withCredentials([usernamePassword(credentialsId: "${JENKINS_GERRIT_CREDS}",
										passwordVariable: 'GERRIT_USER_PW', usernameVariable: 'GERRIT_USER_NAME')]) {
										checkout scm: [$class: 'GitSCM',
											branches: [[name: "${BRANCH_NAME}"]],
											extensions: [
												[$class: 'RelativeTargetDirectory', relativeTargetDir: groupDir],
												[$class: 'CloneOption',
													noTags: true,
													depth: 10,
													honorRefspec: true,
													shallow: true
												],
											],
											userRemoteConfigs: [
												[
												credentialsId: env.JENKINS_GERRIT_CREDS,
												name: env.GERRIT_NAME,
												url: testsuiteUrl.replaceAll("http(s)?://", "http\$1://${GERRIT_USER_NAME}@")
												]
											]
										]
									}

									sh "sudo tests/CI/runTestsuite.sh --testsuite-dir='${groupDir}' --testsuite-command='${groupTestcmd}'"
									archiveArtifacts allowEmptyArchive: true, defaultExcludes: false, fingerprint: true,
										artifacts: "${groupDir}/asterisk-test-suite-report.xml, ${groupDir}/logs/**, ${groupDir}/core*.txt"

									junit testResults: "${groupDir}/asterisk-test-suite-report.xml",
										healthScaleFactor: 1.0,
										keepLongStdio: true

									echo "Group result d: ${currentBuild.currentResult}"
								}
								echo "Group result s: ${currentBuild.currentResult}"
							}
						}
					}
					parallel parallelTasks
				}
			}
		}
	}
	post {
		cleanup {
			sh "sudo make distclean >/dev/null 2>&1 || : "
			sh "sudo rm -rf tests/CI/output >/dev/null 2>&1 || : "
		}
		/*
		 * The Gerrit Trigger will automatically post the "Verified" results back
		 * to Gerrit but the verification publisher publishes extra stuff in the
		 * "Code Review" section of the review.
		 */
		always {
			script {
				def cat
				def comment
				def rvalue
				switch (currentBuild.currentResult) {
					case ~/^SUCCESS$/:
						cat = "Passed"
						comment = ""
						rvalue = 2
						break
					case ~/^FAILURE$/:
						cat = "Failed"
						comment = "Fatal Error"
						rvalue = -1
						break
					case ~/^UNSTABLE$/:
						cat = "Failed"
						comment = "Tests Failed"
						rvalue = -1
						break
				}

				gerritverificationpublisher verifyStatusValue: rvalue,
					verifyStatusCategory: cat, verifyStatusURL: '',
					verifyStatusComment: comment, verifyStatusName: '',
					verifyStatusReporter: 'Jenkins2', verifyStatusRerun: 'regate'
			}
		}
		success {
			echo "Reporting ${currentBuild.currentResult} Passed"
		}
		failure {
			echo "Reporting ${currentBuild.currentResult}: Failed: Fatal Error"
		}
		unstable {
			echo "Reporting ${currentBuild.currentResult}: Failed: Tests Failed"
		}
	}
}