Enterprise Java

How to update a Jenkins job posting config.xml

Recently I wanted to update a few jobs (not defined with a DSL) in Cloudbees, adding to each of them a few properties.

Well, I had some trouble making it work, here are my notes (I used Jenkins 1.651.2.1 but chances are it should work with older and more recent versions, such as jenkins 2)

No security  / no auth

This is the easy part : retrieve and re post the configuration

$ curl  http://localhost:8080/jenkins/job/pof/config.xml -o config.xml
$ curl  -X POST http://localhost:8080/jenkins/job/pof/config.xml --data-binary @config.xml

Simple security : using username and password

I assume now that your Jenkins set up has security set up (http://localhost:8080/jenkins/configureSecurity/ –> enable security)

Screen-Shot-2016-05-15-at-22.25.35-768x628

It means we now need to authenticate both our requests :

curl -X GET http://anthony:anthony@localhost:8080/jenkins/job/pof/config.xml -o config.xml
curl -X POST http://anthony:anthony@localhost:8080/jenkins/job/pof/config.xml --data-binary "@config.xml"

Simple security : with CSRF enabled (crumb)

You would also want to protect your jenkins instance against CSRF attacks (http://localhost:8080/jenkins/configureSecurity/ –> enable csrf crumb)

Screen-Shot-2016-05-15-at-22.26.20-768x195
Now, it also means your requests need to send a crumb value, either as a parameter or via a header

If you don’t :

curl -X POST http://anthony:anthony@localhost:8080/jenkins/job/pof/config.xml --data-binary "@config.xml"

You’ll get such errors :

<body><h2>HTTP ERROR 403</h2>
<p>Problem accessing /jenkins/job/pof/config.xml. Reason:
<pre>    No valid crumb was included in the request</pre></p><hr /><i><small>Powered by Jetty://</small></i><br/>

or even  :

<body><h1>HTTP Status 500 - </h1><HR size="1" noshade="noshade"><p><b>type</b> Exception report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The server encountered an internal error () that prevented it from fulfilling this request.</u></p><p><b>exception</b> <pre>java.io.IOException: Failed to persist config.xml
hudson.model.AbstractItem.updateByXml(AbstractItem.java:677)
hudson.model.AbstractItem.doConfigDotXml(AbstractItem.java:617)
…..
</pre></p><p><b>root cause</b> <pre>javax.xml.transform.TransformerException: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file.
com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:755)
com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:357)
    jenkins.util.xml.XMLUtils._transform(XMLUtils.java:96)
    jenkins.util.xml.XMLUtils.safeTransform(XMLUtils.java:63)
    hudson.model.AbstractItem.updateByXml(AbstractItem.java:674)
 hudson.model.AbstractItem.doConfigDotXml(AbstractItem.java:617)

Get the crumb value :

You can either the crumb value using a configure job page :

curl http://anthony:anthony@localhost:8080/jenkins/job/pof/configure | sed -n 's/.*\.crumb", "\(.*\)").*/\1/p' > crumb.txt

But there’s also a service dedicated to that :

curl http://anthony:anthony@localhost:8080/jenkins/crumbIssuer/api/xml | sed -n 's/.*\(.*\)<\/crumb>.*/\1/p' > crumb.txt

Use the crumb value

curl -X POST http://anthony:anthony@localhost:8080/jenkins/job/pof/config.xml --data-binary "@config.xml" -data ".crumb=6bbabc426436b72ec35e5ad4a4344687"

Oups, that did not work

Caused by: java.lang.IllegalStateException: STREAMED
    at org.eclipse.jetty.server.Request.getReader(Request.java:803)
    at javax.servlet.ServletRequestWrapper.getReader(ServletRequestWrapper.java:256)
    at hudson.model.AbstractItem.doConfigDotXml(AbstractItem.java:610)

I suggest you send the crumb using the headers :

curl -v -X POST http://anthony:anthony@localhost:8080/jenkins/job/pof/config.xml --data-binary "@config.xml" -H ".crumb: 6bbabc426436b72ec35e5ad4a4344687"

Security, based on cookies (no user / password)

In some installs, such as cloubees, you can’t pass username and password in your requests; I suggest you use the cookies instead.

To retrieve them, inspect the cookies sent by your authenticated browser, for example in chrome :

Screen-Shot-2016-05-16-at-10.11.08-768x408
And then paste this url in your shell:

curl 'http://localhost:8080/jenkins/job/pof/config.xml' -H 'Pragma: no-cache' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8,fr;q=0.6' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Referer: http://localhost:8080/jenkins/login?from=%2Fjenkins%2Fjob%2Fpof%2Fconfig.xml' -H 'Cookie: screenResolution=1440x900; JSESSIONID=XXXXX; JSESSIONID.XX=XXXX; screenResolution=1440x900' -H 'Connection: keep-alive' -H 'Cache-Control: no-cache' --compressed

Of course, you’ll still need to get the crumb value :

curl 'http://localhost:8080/jenkins/crumbIssuer/api/xml' -H 'Pragma: no-cache' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8,fr;q=0.6' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Referer: http://localhost:8080/jenkins/login?from=%2Fjenkins%2Fjob%2Fpof%2Fconfig.xml' -H 'Cookie: screenResolution=1440x900; JSESSIONID=XXXXX; JSESSIONID.XX=XXXXX; screenResolution=1440x900' -H 'Connection: keep-alive' -H 'Cache-Control: no-cache' --compressed | sed -n 's/.*<crumb>\(.*\)<\/crumb>.*/\1/p' > crumb.txt

And now you’re ready to post your updated config.xml:

curl -X POST 'http://localhost:8080/jenkins/job/pof/config.xml' -H 'Pragma: no-cache' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8,fr;q=0.6' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Referer: http://localhost:8080/jenkins/login?from=%2Fjenkins%2Fjob%2Fpof%2Fconfig.xml' -H 'Cookie: screenResolution=1440x900; JSESSIONID=XXXX; JSESSIONID.XX=XXXX; screenResolution=1440x900' -H 'Connection: keep-alive' -H 'Cache-Control: no-cache' --compressed --data-binary "@config.xml" -H ".crumb: 6bbabc426436b72ec35e5ad4a4344687"

Links

Anthony Dahanne

Anthony Dahanne is a Java software developer for 8 years, his favorite topics are Android, building tools, Continuous Integration and, of course, core Java development. Working for Terracotta, he currently implements the REST management interface for EhCache.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button