I have a Jenkins job in which at the end of the job (maybe around post actions or in the last stage of that job I want to find how much time has been elapsed since the job started.
How can find that? Is there any easy straightforward way of knowing it ?
Sample pipeline script
pipeline {
agent any
stages {
stage('Hello') {
steps {
echo 'Hello World'
sleep 10
}
}
}
post {
always {
println "${currentBuild.durationString}"
}
}
}
Output:
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Hello)
[Pipeline] echo
Hello World
[Pipeline] sleep
Sleeping for 10 sec
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Declarative: Post Actions)
[Pipeline] echo
14 sec and counting
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
if you don't like the and counting part you can always do
"${currentBuild.durationString}".replaceAll(' and counting', "")
Install Timestamper plugin.
The Timestamper plugin adds timestamps to the console output of Jenkins jobs. For example:
21:51:15 Started by user anonymous
21:51:15 Building on master
21:51:17 Finished: SUCCESS
/timestamps/ By default, display the elapsed time in seconds with three places after the decimal point.
/timestamps/?time=HH:mm:ss&appendLog Display the system clock time and append the line from the log.
/timestamps/?elapsed=HH:mm:ss.S&appendLog Display the elapsed time and append the line from the log.
/timestamps/?time=HH:mm:ss&elapsed=HH:mm:ss.S Display both the system clock time and the elapsed time.
/timestamps/?currentTime&time=HH:mm:ss Display the current time on the Jenkins controller.
Apart from all the answers above there is a very nice way of doing it:
import hudson.Util
.
.
.
String time = Util.getTimeSpanString(System.currentTimeMillis() - currentBuild.startTimeInMillis)
If you display time it will come in this format:
2 hr 15 min 47 sec
which is pretty neat and does not require any extra variable to be setup initially, also less editing needed (in my case I wanted in this exact way).
Related
Jenkins version: 2.319.3
Lockable Resources plugin version: 2.18
I have a simple Jenkins pipeline that runs based on a webhook. This pipeline runs very frequently, so we have a lock on one stage so that it won't run on multiple builds at the same time. The problem is, we noticed that infrequently, multiple builds will run at the same time, despite the lock. Here's the code:
node("Windows_Server") {
properties([disableConcurrentBuilds()])
stage("Setup") {
some stuff...
} // end 'Setup' stage
stage("Stage 1") {
lock("Stage 1") {
withCredentials(some stuff...)
} // end lock
} // end stage
} // end node
Both builds ran at almost the same time (maybe 0.5 seconds apart), and it appears that the first build didn't set a lock:
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Stage 1)
[Pipeline] withCredentials
some stuff...
This is the second build:
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Stage 1)
[Pipeline] lock
Trying to acquire lock on [Stage 1]
Resource [Stage 1] did not exist. Created.
Lock acquired on [Stage 1]
[Pipeline] {
[Pipeline] withCredentials
some stuff...
Then in Blue Ocean, the output shows that the stage for those builds ran within a few milliseconds of each other; one started at [2023-01-25T21:39:34.917Z], the other at [2023-01-25T21:39:35.040Z].
So my question is, why would the first one not put a lock on that stage, or if it did why did the second one not see the lock?
I'm trying to set up a Jenkins pipeline (using the declarative syntax) that runs unit and feature tests on two separate, on-demand AWS EC2 instances. The pipeline works perfectly when run on a single instance and without the parallel stages. As soon as I switch to parallel stages, any shell script fails with this cryptic message:
process apparently never started in
/home/admin/workspace/GSWebRuby_Test#tmp/durable-b0d8c4b4 (running
Jenkins temporarily with
-Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true
might make the problem clearer)
I've googled extensively and came across several bug reports of the Durable Task plugin that appears to be responsible for this message. I'm using the latest version of the plugin v. 1.33 and none of the problems seem to apply to my case, e.g. failures on unusual architectures or when running Docker containers. I've also down- and re-upgaded the plugin (toggling between versions 1.30 and 1.33). Also, to re-iterate, sh commands work without issue when I don't use the parallel stages.
I've created a simplified pipeline to debug the problem. Note that the shell commands are also simple, e.g. "env | sort", or "pwd".
pipeline {
agent none
environment {
DB_USER = credentials('db-user')
DB_PASS = credentials('db-pass')
}
stages {
stage('Setup'){
failFast false
parallel {
stage('foo') {
agent {
label 'jenkins-slave-ondemand'
}
steps {
echo 'In stage foo'
sh 'env|sort'
}
}
stage('bar') {
agent {
label 'jenkins-slave-ondemand'
}
steps {
echo 'In stage bar'
sh 'pwd'
}
}
}
}
}
}
This is the console output:
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] withCredentials
Masking supported pattern matches of $DB_PASS or $DB_USER
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Setup)
[Pipeline] parallel
[Pipeline] { (Branch: foo)
[Pipeline] { (Branch: bar)
[Pipeline] stage
[Pipeline] { (foo)
[Pipeline] stage
[Pipeline] { (bar)
[Pipeline] node
[Pipeline] node
Still waiting to schedule task
All nodes of label ‘jenkins-slave-ondemand’ are offline
Still waiting to schedule task
All nodes of label ‘jenkins-slave-ondemand’ are offline
Running on EC2 (Jenkins AWS EC2) - Jenkins slave (i-0982299c572100c71) in /home/admin/workspace/GSWebRuby_Test
[Pipeline] {
[Pipeline] echo
In stage foo
[Pipeline] sh
Running on EC2 (Jenkins AWS EC2) - Jenkins slave (i-092ecac8e6c257270) in /home/admin/workspace/GSWebRuby_Test
[Pipeline] {
[Pipeline] echo
In stage bar
[Pipeline] sh
process apparently never started in /home/admin/workspace/GSWebRuby_Test#tmp/durable-b0d8c4b4
(running Jenkins temporarily with -Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true might make the problem clearer)
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
Failed in branch foo
process apparently never started in /home/admin/workspace/GSWebRuby_Test#tmp/durable-b6cfcff9
(running Jenkins temporarily with -Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true might make the problem clearer)
[Pipeline] }
[Pipeline] // node
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
Failed in branch bar
[Pipeline] // parallel
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] End of Pipeline
ERROR: script returned exit code -2
Finished: FAILURE
Am I doing something wrong in the way I've set up the pipeline? Any pointers would be greatly appreciated.
Edit:
After setting this JENKINS_JAVA_OPTIONS org.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true, I see this additional output:
In stage bar
[Pipeline] sh
nohup: failed to run command 'sh': No such file or directory
process apparently never started in /home/admin/workspace/GSWebRuby_Test#tmp/durable-099a2e56
I have found a strange issue with Groovy code in Jenkinsfile:
#NonCPS
def test() {
println "Start"
sleep(10)
println "Stop"
}
Thing is, that after sleeping for 10s code never gets to println "Stop".
It just seems, that sleep returns after 10 seconds and runs next pipeline steps.
Output is just:
[Pipieline] echo
Start
[Pipeline] sleep
Sleeping for 10 sec
[Pipeline] }
... next pipeline steps
Did anyone had same problem?
When you call sleep(10) inside your Groovy script, Workflow CPS plugin executes SleepStep instead of DefaultGroovyStaticMethods.sleep(Object self, long time). The problem in your case is caused #NonCPS function (thanks mkobit for a suggestion!). Consider following example:
node {
stage("Test") {
test()
}
}
#NonCPS
def test() {
echo "Start"
sleep(5)
echo "Stop"
}
Output:
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/test-pipeline
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Test)
[Pipeline] echo
Start
[Pipeline] sleep
Sleeping for 5 sec
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
There is no Stop echoed from the pipeline run. Now, if we only remove #NonCPS annotation from the function we call in the pipeline:
node {
stage("Test") {
test()
}
}
def test() {
echo "Start"
sleep(5)
echo "Stop"
}
Things get change and Stop gets echoed as expected:
Started by user admin
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/test-pipeline
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Test)
[Pipeline] echo
Start
[Pipeline] sleep
Sleeping for 5 sec
[Pipeline] echo
Stop
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
For more information about usage of #NonCPS please read following Best Practices For Pipeline Code article.
This issue is well documented in https://wiki.jenkins.io/display/JENKINS/Pipeline+CPS+method+mismatches
Use of Pipeline steps from #NonCPS
Sometimes users will apply the #NonCPS annotation to a method definition, which bypasses the CPS transform inside that method. This can be done to work around limitations in Groovy language coverage (since the body of the method will execute using the native Groovy semantics), or to get better performance (the interpreter imposes a substantial overhead). However such methods must not call CPS-transformed code such as Pipeline steps.
As suggested by Szymon removing the #NonCPS tag will indeed solve the issue,
however if you can't remove the #NonCPS tag because it is needed (to solve serialization issues for example) you can overcome this by using the Thread.sleep(long millis) Java method instead.
Notice - an administrator will need to approve this signature if running in sandbox.
In a #NonCPS annotated function, only code up to the very first jenkins build step is executed. Does anyone have the same problem? Am I missing something? I am using Jenkins LTS... just sayin' (2.73.2).
This is my code:
#NonCPS
def hello() {
println 'Output "hello":'
sh 'echo Hello'
println 'Output "World":'
sh 'echo World'
}
node {
stage('Test') {
hello()
}
}
I would expect this code to run properly, but the output is the following:
[Pipeline] node
Running on Jenkins in /var/lib/jenkins/workspace/Sandbox/pipeline-test
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Test)
[Pipeline] echo
Output "hello":
[Pipeline] sh
[pipeline-test] Running shell script
+ echo Hello
Hello
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
You cannot run build steps inside #NonCPS methods. Pipeline scripts are considered "serializable", allowing them to be durable across system failures etc. Only a subset of the capabilities of groovy used by pipeline scripts is serializable - for anything that is not, you use #NonCPS to execute it.
Essentially, your #NonCPS method needs to do its business and return data back to the "safe", serialized execution stack.
In your particular example code I see no reason why hello() has to be #NonCPS at all - I can only assume your real function is doing something more complex.
(Edit)
Having just looked at your question history and the original script; I don't know if this is still the case with the latest versions but when I was writing our scripts ~6 months ago, each { thing -> iteration was not serializable.
I'm not a Jenkins guru so please be patient. :-)
I have a pipeline, something nearly as simple as this:
def hash = ''
node {
stage('Checkout') {
…
}
stage('Build') {
…
}
stage('Tests') {
…
}
}
stage('Ask deploy') {
input 'Deploy?'
}
node {
stage('Deploy') {
}
}
I want to set the value of the hash variable in the first node and read it in the next if the manual input is positive. Is this possible and safe? Is this the correct approach?
Note that there are multiple executors and manual input involved. In the Jenkins docs it is hinted for a node that:
As soon as an executor is free on a node, the steps will run.
This means that the two nodes may run in different executors, correct? Do they still share the same global variables? Thanks in advance for any clarifications!
If you have multiple slaves in Jenkins, the pipeline will be launch in one of this slaves. Every slave is different.
Every stage in you pipeline will be launch in the same slave so if you have the variable "hash" at the first line of your pipeline you wouldn't have problem to read it in all your pipeline but if you have to access to this variable value from a different build you can not access.
If you need a global variable to read it in different builds you can define a global variable using the Global Variables String Parameter Plugin
The hash variable is global and its value is available in the different executors which seems logical to me. So it looks like what I do is OK and it will work this way unless I miss something.
Here is how I've verified that (details skipped for brevity):
I've created a similar pipeline and killed the executor which ran the first node:
def gitHash;
node {
withCredentials(...) {
//Step 1:
//Check out from the SCM
stage('Prepare') {
echo "Checking out the project from source control.."
scmInfo = checkout scm
gitHash = scmInfo.GIT_COMMIT
echo "Project checked out, the GIT hash of the last commit is: ${gitHash}"
}
}
}
stage('Ask deploy') {
input 'Deploy?'
}
node {
withCredentials(...) {
stage('Deploy') {
echo "TODO, hash ${gitHash}"
}
}
}
The output from Jenkins is the following (details skipped):
Obtained Jenkinsfile from 7adc4bb98524b31de93e0c1ae16bf967ca3df47c
Running on jnlp-13775fa128a47 in /root/workspace/...
[Pipeline] {
[Pipeline] withCredentials
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Prepare)
[Pipeline] echo
Project checked out, the GIT hash of the last commit is: 7adc4bb98524b31de93e0c1ae16bf967ca3df47c
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] stage
[Pipeline] { (Ask deploy)
[Pipeline] input
Deploy?
Proceed or Abort
Approved by admin
[Pipeline] }
[Pipeline] // stage
[Pipeline] node
Running on jnlp-1383bdf520c9d in /root/workspace/...
[Pipeline] {
[Pipeline] withCredentials
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Deploy)
[Pipeline] echo
TODO, hash 7adc4bb98524b31de93e0c1ae16bf967ca3df47c
[Pipeline] End of Pipeline
Finished: SUCCESS
As seen the first node runs on executor jnlp-13775fa128a47 the second is on jnlp-1383bdf520c9d but the value of the globally scoped variable can be read there.