How to use `StaplerResponse rsp` in `AsyncResourceDisposer.doStopTracking()` - jenkins

I'm trying to remove (stop tracking) trackig item from Jenkins AsyncResourceDisposer (${JENKINS_URL}/administrativeMonitor/AsyncResourceDisposer) via groovy scripts (${JENKINS_URL}/script).
According to the Javadoc and source code
// Javadoc
#Restricted(value=org.kohsuke.accmod.restrictions.DoNotUse.class)
public org.kohsuke.stapler.HttpResponse doStopTracking(#QueryParameter
int id,
org.kohsuke.stapler.StaplerResponse rsp
)
// source code
#Restricted(DoNotUse.class)
#RequirePOST
public HttpResponse doStopTracking(#QueryParameter int id, StaplerResponse rsp) {
...
}
I'd like to know how to add org.kohsuke.stapler.StaplerResponse rsp in doStopTracking(int id, org.kohsuke.stapler.StaplerResponse rsp):
import org.jenkinsci.plugins.resourcedisposer.AsyncResourceDisposer
AsyncResourceDisposer disposer = AsyncResourceDisposer.get()
disposer.backlog.each {
disposer.doStopTracking( it.id, <what should I put here> )
}
Current I can get the item id, and the other informaitons like below:
import org.jenkinsci.plugins.resourcedisposer.AsyncResourceDisposer
AsyncResourceDisposer disposer = AsyncResourceDisposer.get()
String url = Jenkins.instance.rootUrl + disposer.url
disposer.getBacklog().each { item ->
println "\n${item.id} : \t${url}/stopTracking/?id=${item.id} : \t${item.class.simpleName} : \n" +
"\t${item.getLastState().getDisplayName()} : \n" +
"\t${item.getDisposable().node} : ${item.getDisposable().path}\n" +
"\t${item.toString()}"
}
If I'm go to the url "${url}/stopTracking/?id=${item.id}" in browser (login first), the item can be removed after click RETRY USING POST (as below)

So... I'm using the API call curl -H <crumbIssues> -X POST <url> by passed the disposer.doStopTracking(int, org.kohsuke.stapler.StaplerResponse) (still really wants know how to use it)
Before running the following script, Strict Crumb Issuers Plugin is necessary to be installed and configured (or setup -Dhudson.security.csrf.DefaultCrumbIssuer.EXCLUDE_SESSION_ID=true) due to SECURITY-626 : Improved CSRF protection since:
obtain a crumb using the /crumbIssuer/api URL will now fail to perform actions protected from CSRF unless the scripts retain the web session ID in subsequent requests.
Here is details:
import org.jenkinsci.plugins.resourcedisposer.AsyncResourceDisposer
import org.jenkinsci.plugins.strictcrumbissuer.StrictCrumbIssuer
AsyncResourceDisposer disposer = AsyncResourceDisposer.get()
StrictCrumbIssuer issuer = jenkins.model.Jenkins.instance.crumbIssuer
String jenkinsCrumb = "${issuer.crumbRequestField}:${issuer.crumb}"
String url = Jenkins.instance.rootUrl + disposer.url
disposer.getBacklog().each { item ->
println "\n ~~> removeing ${item.id} : "
[ 'bash', '-c', 'curl -s ' +
'-u <user>:<token> ' +
'-X POST ' +
"-H \"Content-Type: application/json\" " +
"-H \"Accept: application/json\" " +
"-H \"${jenkinsCrumb}\" " +
"${url}/stopTracking/?id=${item.id} "
].execute().with{
def stdout = new StringBuffer()
def stderr = new StringBuffer()
it.waitForProcessOutput( stdout, stderr )
println "EXIT CODE: ${it.exitValue()}"
println "ERROR: ${stderr}"
println "OUTPUT: ${stdout}"
}
}
Although, I still have a question... As we know that if the groovy script running in ${JENKINS_URL}/script, which means the "runner" is the administrator, so, how I can remove the specific user authorication '-u <user>:<token>' (by using the jenkins administrator authorication) in curl ?

Related

From deprecated cliOnline to OnlineNodeCommand

So I created this groovy script but read that the cliOnline() command is deprecated.
But I can't seem to figure out how to actually change my code to use hudson.model.Hudson.instance.OnlineNodeCommand()?
deprecated cliOnline
def nodes_checklist = ["PD100069", "PD100070", "PD100090", "PD10756"]; // List of nodes which should be turned online
def jenkinsNodes = jenkins.model.Jenkins.instance.getNodes() // Get all existing nodes on this Jenkins URL
for(def node_checker: nodes_checklist) {
for(def node: jenkinsNodes) {
if(node.getNodeName().contains(node_checker)) {
println "The node " + node.getNodeName() + "'s offline status: " + node.toComputer().isOffline()
if (node.toComputer().isOffline()){
println "Turning " + node.getNodeName() + " online"
node.toComputer().cliOnline() // If node is offline, turn it online
println node.getNodeName() + "'s online status: " node.toComputer().isOnline()
}
}
}
}
Does anyone know how to rewrite this to use the non-deprecated version?
If you look at this depricated method, it simply calls a non depricated method setTemporarilyOffline(boolean temporarilyOffline, OfflineCause cause). So not sure why this was depricated. Anyway instead of using cliOnline() you can use setTemporarilyOffline. Check the following.
node.getComputer().setTemporarilyOffline(false, null)
Some proper code with a proper cause. Cause is not really needed when setting the node online though.
import hudson.slaves.OfflineCause.UserCause
def jenkinsNodes = Jenkins.instance.getNodes()
for(def node: jenkinsNodes) {
if (node.getComputer().isTemporarilyOffline()){
node.getComputer().setTemporarilyOffline(false, null)
}
}
Setting to temporarily offline
UserCause cause = new UserCause(User.current(), "This is a automated process!!")
node.getComputer().setTemporarilyOffline(true, cause)

Executing CURL in Shared Library Jenkins Pipeline Using `Process`

I have a method in a shared library in my Jenkins pipeline. The idea is to use this library and upload files to a remote host. The library is imported in a singleton library.
import com.package.jobutil.UploadFile
def uploadFunc() {
def uploader = new UploadFile(this)
withCredentials ([usernamePassword(credentialsId: 'user', userNameVariable: 'username', passwordVariable:'password)]) {
uploader.uploadArtifact("${username}", "${password}", file.txt, location)
}
}
def call() {
uploadFunc()
}
The class that is instantiated looks like this:
class UploadFile {
def steps
UploadFile (steps) {
this.steps = steps
}
pulic uploadArtifct (String user, String password, String file, String location) {
Process proc
def cred = "${user}:${pass}"
def cmd = ["curl", "-v", "-u", cred, "--upload-file", file, location]
steps.println "CURL: ${cmd}"
proc = cmd.execute()
}
}
Even though I see the println line in the logs. I do not see the curl command being executed.
Is there something I am missing that does not invoke the cmd.execute to work?
EDIT
When I use the curl directly in the library, it works.
pulic uploadArtifct (String user, String password, String file, String
location) {
def cred = "${user}:${password}"
def cmd = "curl -v -u ${cred} --upload-file ${file} ${nexusLocation}/${file}"
try {
steps.sh cmd
} catch (Exception e) {
throw new RuntimeExceptipon("Cannot execute curl, exception: [${e.getClass().getName()} - '${e.getMessage()}']")
}
}
However, when trying to use the Process it does not work.
pulic uploadArtifct (String user, String password, String file, String
location) {
def cred = "${user}:${password}"
def cmd = ["curl", "-v", "-u", cred, "--upload-file", ${file}, ${location}]
try {
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = cmd.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println sout
} catch (Exception e) {
throw new RuntimeExceptipon("Cannot execute curl, exception: [${e.getClass().getName()} - '${e.getMessage()}']")
}
}
The exception I get is:
java.lang.RuntimeException: Cannot execute curl, exception: [groovy.lang.MissingMethodException - 'No signature of method: java.lang.String.div() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [file.txt]
As explained here, you need to capture stdout/stderr to see anything.
At the very least:
def outputStream = new StringBuffer();
proc.waitForProcessOutput(outputStream, System.err)
//proc.waitForProcessOutput(System.out, System.err)
Or, as in this gist:
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = cmd.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println sout
An example of blocking call would be:
println new ProcessBuilder( 'sh', '-c', 'du -h --max-depth=1 /var/foo/bar/folder\\ with\\ spaces | sort -hr').redirectErrorStream(true).start().text
def cmd = ["curl", "-v", "-u", cred, "--upload-file", ${file}, ${location}/${file}]
No signature of method: java.lang.String.div() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [file.txt]
The '/' in '${location}/${file}' is interpreted as an '/ (div) operation instead of a string.
Try instead for that curl command argument:
${location}+"/"+${file}
As noted in your subsequent question, the all path needs to be between double-quotes.

function lines after httpRequest are not executed in groovy jenkins pipeline

None of the lines after making httpRequest are getting executed. Everything else works fine in this function. What could be going wrong here?
However, network request is going fine and I am able to see the response in the console. httpRequest is being made via plugin
I've even tried CURL - but lines after curl are not executed.
#NonCPS
def doPRCommentBasedTesting() {
def causes = currentBuild.rawBuild.getCauses()
def commentURL
for(cause in causes) {
if (cause.class.toString().contains("GitHubPullRequestCommentCause")) {
commentURL = cause.getCommentUrl()
commentURL = commentURL.substring(commentURL.lastIndexOf("-") + 1)
println "This job was caused by job " + commentURL
def url1 = "https://<git_url>/api/v3/repos/<owner>/<repo>/issues/comments/" + commentURL
def commentText = httpRequest authentication: '<auth_cred>', url: url1, consoleLogResponseBody: true
println commentText
println commentText.getClass()
println "hello world, how are you doing today?"
}
else {
println "Root cause : " + cause.toString()
}
}
println "==============================="
return 0
}
A non cps function does not have the ability to pause in between because it runs in a go. You need to put network call into a different function that is not marked as nonCPS and then it will work. In general the nonCPS block should be very small and limited to code that cannot be serialised

Jenkins lockable resource - lock without unlocking

I'm using the "Locable Resources Plugin" together with the Jenkins multipipeline functionality:
lock('my-resource-name') {
}
I have a situation where I need to lock a resource in one pipeline and unlock it in another. I have workarounds, but I would prefer using the lock plugin, if possible.
I imagagine something like this
lock("my-resource-name")
.....
unlock("my-resource-name)
The why of it
I'm implementing canary releases, and there are three different paths through my pipeline (I considered other solutions, like pausing the pipeline with the input plugin - providing me with more is out of scope for this question).
I would like to lock/halt the pipeline while the canary is evaluated, and then, when the promotion or rollback is done, unlock it again.
Omitting the body for the lock statement just gives me java.lang.IllegalStateException: There is no body to invoke
One way of doing it is this:
curl -XGET https://your-jenkins/lockable-resources/reserve?resource=myresource
curl -XGET https://your-jenkins/lockable-resources/unreserve?resource=myresource
The GET is not a mistake, it really is GET.
To wait for a lock
lock("my-resource-name") {}
I also know Jenkins support something called "milestones" apparently is something used to communicate between builds. But I have no idea if it can be used to solve this problem in any meaningful way.
The lock can be done this way
import org.jenkins.plugins.lockableresources.LockableResource
import org.jenkins.plugins.lockableresources.LockableResourcesManager
...
LockableResourcesManager lockableResourcesManager = LockableResourcesManager.get()
LockableResource lockableResource = lockableResourcesManager.fromName(resourceName)
// if the resource doesn't exists, create it
if (lockableResource == null) {
lockableResourcesManager.createResource(resourceName)
lockableResource = lockableResourcesManager.fromName(resourceName)
}
// wait until lock is successful
waitUntil { lockableResourcesManager.lock([lockableResource].toSet(), currentBuild.rawBuild, null) }
The unlock is much simpler because you know the resource exists (if it doesn't there is no reason to try to unlock it)
LockableResourcesManager lockableResourcesManager = LockableResourcesManager.get()
LockableResource lockableResource = lockableResourcesManager.fromName(resourceName)
// do not pass currentBuild.rawBuild as in your case is not the build that locked this resource
// so I am passing null instead
lockableResourcesManager.unlock([lockableResource], null)
Note that I used to test this org.6wind.jenkins:lockable-resources:2.7, the implementation details may vary depending on the version used.
<dependency>
<groupId>org.6wind.jenkins</groupId>
<artifactId>lockable-resources</artifactId>
<version>2.7</version>
<scope>provided</scope>
</dependency>
from LockableResourcesManager get each lock, then
foreach lock do if lock.getName matches then do lock.reset() to release the lock
e.g. some groovy to find locked locks not owned by any builds and clean them up:
print "START\n"
def all_lockable_resources = org.jenkins.plugins.lockableresources.LockableResourcesManager.get().resources
all_lockable_resources.each { r->
if (r.isLocked() || r.isReserved()) {
println "Lock " + r + " is locked or reserved by " + r.getBuild() + " B CARSE " + r.getLockCause()
b = r.getBuild()
if (b) {
if (b.isBuilding()) { println "build:" + b + " is building" }
if (b.getResult().equals(null)) { println "build:" + b + " result is not in yet" }
if ( ! b.isBuilding() && ! b.getResult().equals(null)) {
println "build:" + b + " is not building and result is " + b.getResult() + " yet the lock " + r + " is locked."
println "ACTION RELEASE LOCK " + r
println "getLockCause:" + r.getLockCause()
println "getDescription:" + r.getDescription()
println "getReservedBy:" + r.getReservedBy()
println "isReserved:" + r.isReserved()
println "isLocked:" + r.isLocked()
println "isQueued:" + r.isQueued()
//release the lock
r.reset()
println "getLockCause:" + r.getLockCause()
println "getDescription:" + r.getDescription()
println "getReservedBy:" + r.getReservedBy()
println "isReserved:" + r.isReserved()
println "isLocked:" + r.isLocked()
println "isQueued:" + r.isQueued()
}
}
}
}
API: http://javadoc.jenkins.io/plugin/lockable-resources/org/jenkins/plugins/lockableresources/LockableResource.html
or navigate to https://jenkins-host/lockable-resources/ page. here we can find list of all the lockable resources. we can manually lock or reserve these.

Remove user from Jenkins via groovy script when role based strategy is used

I am trying to automate Jenkins user deletion. Groovy script which I tried is as below.
import hudson.model.User
User u = User.get('rh54')
u.delete()
Mentioned groovy script does not delete when user is LDAP integrated. Also Security realm which is being used is Role-based Strategy.
Please suggest
The below groovy script should create a new instance of RoleBasedAuthorizationStrategy excluding the given user from all roles.
Please note that I've not tested it thoroughly and make sure to take a backup of your Jenkins instance before testing this script.
import hudson.model.*
import com.michelin.cio.hudson.plugins.rolestrategy.*
String removeRolesFromUser="test"
def roleBasedAuthorizationStrategy = Jenkins.getInstance().getAuthorizationStrategy()
if(roleBasedAuthorizationStrategy instanceof RoleBasedAuthorizationStrategy){
boolean changed=false
Map<String, RoleMap> roleMaps = roleBasedAuthorizationStrategy.getRoleMaps()
RoleBasedAuthorizationStrategy updatedRoleBasedAuthorizationStrategy = new RoleBasedAuthorizationStrategy()
for(Map.Entry<String, RoleMap> roleMapEntry : roleMaps.entrySet()){
Set<Role> roleSet = roleMapEntry.getValue().getRoles()
for(Role role : roleSet){
updatedRoleBasedAuthorizationStrategy.addRole(roleMapEntry.getKey(),role);
for(String addUserAgain : roleMapEntry.getValue().getSidsForRole(role.getName())){
if(!addUserAgain.equals(removeRolesFromUser)){
updatedRoleBasedAuthorizationStrategy.assignRole(roleMapEntry.getKey(),role,addUserAgain)
}else{
println("User : " + removeRolesFromUser + " excluded from role : " + role.getName())
changed=true
}
}
}
}
if(changed){
Jenkins.getInstance().setAuthorizationStrategy(updatedRoleBasedAuthorizationStrategy)
println("INFO: Authorization strategy updated, user " + removeRolesFromUser + " removed from all roles.")
Jenkins.getInstance().save();
println("INFO: Authorization strategy saved to disk.")
}else{
println("INFO: No changes made to Authorization strategy since user : " + removeRolesFromUser + " does not belong to any role!")
}
}else{
println("ERROR : This script works only for RoleBasedAuthorizationStrategy!")
}

Resources