Check if build job finished before certain time - jenkins

I maintain a jenkins pipeline which has the requirement to finish before 10am in the morning.
Is there a way to detect that the job finished after 10am and print a warning for example?

Here is a sample Pipeline to achieve your requirement. Here I have used a post-build step to check the time. You can decide what you want to do after checking the time. Eg: Setting the build to unstable, sending a mail etc.
pipeline {
agent any
stages{
stage('Build') {
steps{
echo "RUNNING THE BUILD!!!!"
}
}
}
post {
always {
script{
echo 'Checking the time'
def timeToCheckBefore = [hourOfDay: 10, minute: 0, second: 0] // 10PM will be 23, 0, 0
def now = new Date()
def check = now.clone()
check.set(timeToCheckBefore)
if(now.after(check)) {
echo "Time is Passed: Current Time : $now, Should finish before: $check"
} else {
echo "Job finished timely: Current Time : $now, Should finish before: $check"
}
}
}
}
}

Related

How to create a script loop in Jenkins which continues or return success / error to pipeline based on json received by shell command?

I am using latest Jenkins in my Linux Box. I am trying to create a pipline with script block like below;
pipeline {
agent any
stages {
stage('TestStage') {
steps {
script {
sh "testfile.sh"
}
}
}
}
}
testfile.sh will return a json text like below;
{
"Worker": [
{
"Status": "running"
}
]
}
The Status can be either running or success or failure. If it is running, the code has to call testfile.sh again and check the status. If its success, pipeline has to continue to next step and if it is failure, pipeline has to terminate. Is it possible to achieve this?
Thanks.
You can achieve by creating a while loop that executes your script, reads the output and checks its value until a given timeout, when the status is no longer running you can check the result and fail the build according to the final status.
Something like:
pipeline {
agent any
stages {
stage('TestStage') {
steps {
script {
timeout(time: 1, unit: 'HOURS') { // timeout for the 'running' period
def status = sh script: 'testfile.sh', returnStdout: true
while (status == 'running') {
sleep time: 10, unit: 'SECONDS' // sleep between iterations
def output = sh script: 'testfile.sh', returnStdout: true
def dict = readJSON text: output
status = dict.Worker.Status
}
}
if(status == 'failure'){
error "Operation has ended with status 'failure'"
}
}
}
}
}
}
You can find more info on the relevant steps: sleep, timeout, error and readJSON.

killing/stopping Jenkins job with a very long list

I'm new to Jenkins so I hope my terms are correct:
I have a Jenkins job that triggers another job. This second job tests a very long list of items (maybe 2000) it gets from the trigger.
Because it's such a long list, I pass it to the second job in groups of 20.
Unfortunately, this list turned out to take an extremely long time, and I can't stop it.
No matter what I tried, stop/kill only stop the current group of 20, and proceeds to the group.
Waiting for it to finish, or doing this manually for each group is not an option.
I guess the entire list was already passed to the second job, and it's loading the next group whenever the current one ends.
What I tried:
Clicking the "stop" button next to the build on the trigger and the second job
Using purge build queue add on
Using the following script in script console:
def jobname = "Trigger Job"
def buildnum = 123
def job = Jenkins.instance.getItemByFullName(jobname)
for (build in job.builds) {
if (buildnum == build.getNumber().toInteger()){
if (build.isBuilding()){
build.doStop();
build.doKill();
}
}
}
Using the following script in script console:
String job = 'Job name';
List<Integer> build_list = [];
def result = jenkins.model.Jenkins.instance.getItem(job).getBuilds().findAll{
it.isBuilding() == true && (!build_list || build_list.contains(it.id.toInteger()))}.each{it.doStop()}.collect{it.id};
println new groovy.json.JsonBuilder(result).toPrettyString(); ```
This is my groovy part of the code that splits it into groups of 20. Maybe I should put the parallel part outside the sub list loop?
Is there a better way to divide into sub lists for future use?
stages {
stage('Execute tests') {
steps {
script {
// Limit number of items to run
def shortList = IDs.take(IDs.size()) // For testing purpose, can be removed if not needed
println(Arrays.toString(shortList))
// devide the list of items into small, equal,sub-lists
def colList = shortList.toList().collate(20)
for (subList in colList) {
testStepsForParallel = subList.collectEntries {
["Testing on ${it}": {
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
stage(it) {
def buildWrapper = build job: "Job name",
parameters: [
string(name: 'param1', value: it.trim()),
string(name: 'param2', value: "")
],
propagate: false
remoteBuildResult = buildWrapper.result
println("Remote build results: ${remoteBuildResult}")
if (remoteBuildResult == "FAILURE") {
currentBuild.result = "FAILURE"
}
catchError(stageResult: 'UNSTABLE') {
copyArtifacts projectName: "Job name", selector: specific("${buildWrapper.number}")
}
}
}
}]
}
parallel testStepsForParallel
}
}
}
}
}
Thanks for your help!
Don't know what else to do to stop this run.

Jenkins - set timeout to Stage and continue with next stage

I have a stage which runs one shell script at remote node. If the script takes very long time to execute, the stage should wait for sometime and should move to next stage without aborting the subsequent stages.
Could you please let me know the required syntax to achieve this.
in a declarative pipeline, add this stage:
stage ("do-and-skip-for-timeout") {
steps {
script {
try {
timeout (time: 10, unit: 'MINUTES') {
echo "do something here, that can take some time" // replace this line with your code
}
}
catch (error) {
def user = error.getCauses()[0].getUser()
if('SYSTEM' == user.toString()) { // SYSTEM means timeout.
echo "Timeout reached, continue to next stage"
}
else {
throw new Exception("[ERROR] stage failed!")
}
}
}
}

Jenkins Triggering of a Build Step/Stage(not the entire job) at a given interval

I am trying to build a pipeline where i would need to chain multiple jobs and some of them has to start at a certain time.
Ex: Job1(starts at Midnight) -> Job2 -> Job3 ->Job4(starts at 4 PM)
Using Declarative Syntax:
pipeline {
agent any
stages{
stage('Fetch Latest Code-1') {
steps{
build job: 'Get Latest - All Nodes', quietPeriod: 60
}
}
stage('CI Day - 1') {
parallel {
stage('ANZ CI'){
steps{
build job: 'ANZ - CI', quietPeriod: 120
}
}
stage('BRZ CI'){
steps{
build job: 'BRZ_CI', quietPeriod: 120
}
}
stage('NAM CI'){
steps{
build job: 'NAM - CI', quietPeriod: 120
}
}
}
}
stage('BEP Part 2') {
steps{
build job: 'BEP_CI_Verification_Job', quietPeriod: 180
}
}
stage('Intermediate Results') {
steps{
build job: 'CI Automation Results', parameters: [string(name: 'Files', value: '_CI_')], quietPeriod: 300
}
}
}
}
As I create this job, I had configured the Job to start at 12 Midnight. Therefore, the 1st job automatically gets started at midnight.
But, I would also need the second job(CI Day - 1) to begin at 1 AM & the last Job 'Intermediate results' to start at 6 PM.
As these jobs are Multi-Configuration Jobs(already tried setting them individually at the desired timings but they get overwritten when called through pipeline).
Also, did try triggers{ cron(0 1 * * 6) } within the stage/steps. No luck!
Here is a quick idea for launching another job at a given time of day. Using Groovy code, calculate the difference in seconds between the desired launch time and the current time and use it as argument for the quietPeriod parameter.
If you get an error "Scripts not permitted to use method", you have to approve the methods using "Manage Jenkins" > "In-process script approval".
import groovy.time.*
pipeline {
agent any
stages{
stage('Stage 1') {
steps{
script {
def secs = secondsUntil hourOfDay: 15, minute: 30, second: 0
echo "anotherjob will be triggered in $secs seconds"
build job: 'anotherjob', quietPeriod: secs
}
}
}
}
}
long secondsUntil( Map dateProperties ) {
def now = new Date()
def to = now.clone()
to.set( dateProperties )
long duration = TimeCategory.minus( to, now ).toMilliseconds() / 1000
return duration > 0 ? duration : 0
}

Pipeline with nightly deploy, deploys twice

I want my pipeline to continuously build and run unit test during the day and automatically deploy the latest build at midnight. Also need to be able to manually force deploy if needed. My problem is that the first build of the day is not cancelled, so the pipeline will deploy twice.
Maybe if I create a separate job that locks the deploy resource just before midnight and releases it some time after just to make sure that all builds are in queue for lock so that 'inversePrecedence' prunes all older builds. Is there a simpler solution?
stage('build')
node('myNode') {
sh 'build.ksh'
sh 'runtest.ksh'
stash includes: 'Builds/', name: 'Builds'
}
// Wait for midnight to deploy
milestone 1
stage('wait for midnight')
if (!isMidnight()) {
waitForMidnightOrManualTrigger()
}
milestone 2
stage('deploy')
lock(resource: 'deploy-server', inversePrecedence: true) {
node('myNode') {
unstash 'Builds'
sh "deploy.ksh"
}
}
milestone 3
def isMidnight() {
int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
return hour < 1
}
def waitForMidnightOrManualTrigger() {
echo 'Wait until midnight. Or Force deploy. Or abort.'
try {
waitTime = getMillisToMidnight()
timeout(time: waitTime, unit: 'MILLISECONDS') {
input 'Click Proceed to force deploy now. Or wait till midnight for automatic deploy.'
}
} catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e){
if (isAborted(e)) {
echo "The job was aborted by user"
throw e
} else {
echo "Timeout reached, proceed!"
}
}
}
def getMillisToMidnight() {
Calendar c = Calendar.getInstance();
c.add(Calendar.DAY_OF_MONTH, 1);
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
return c.getTimeInMillis() - System.currentTimeMillis();
}
// There might be an easier way to differ between if the timeout throws the
// exception or if it is the user that has aborted the build...
def isAborted(e) {
def stackTrace = e.getStackTrace()
for (int i=0; i<stackTrace.size(); ++i) {
if (stackTrace[i].toString().contains("InputStepExecution.stop")) {
return false
}
}
return true
}

Resources