How to update credentials of specific folder in Jenkins using Groovy script? - jenkins

I want to update a credentials object of an existing folder. How can I do that using groovy?
Here is what I have so far:
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.hudson.plugins.folder.Folder
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl
// Init
String user_name = "my_user_name"
String user_pass = "my_new_pass"
String folderName = "Projects"
Folder targetFolder = null
// Get folder:
def allJenkinsItems = Jenkins.getInstance().getItems();
for (currentJenkinsItem in allJenkinsItems)
{
if(!(currentJenkinsItem instanceof Folder)) {continue}
if(((Folder)currentJenkinsItem).getFullName().equals(folderName))
{
targetFolder = (Folder)currentJenkinsItem;
}
}
if (targetFolder == null) {println "Failed to find folder: folderName"; return}
// Get target credentials of that folder:
def credsList = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class,
targetFolder,
null,
null
);
// Get target creds out of the list - will get the first one it encounters:
def targetCreds = credsList.findResult { it.username == user_name ? it : null }
if (targetCreds == null) {println "Failed to find username: $user_name under credentials of folder: $folderName"; return}
// Gets store - how to get the folder's store??
def credentials_store = Jenkins.instance.getExtensionList(
'com.cloudbees.plugins.credentials.SystemCredentialsProvider'
)[0].getStore()
// Try to update the creds of the folder.
// **updateResult is always 'false' here**
def updateResult = credentials_store.updateCredentials(
com.cloudbees.plugins.credentials.domains.Domain.global(),
targetCreds,
new UsernamePasswordCredentialsImpl(targetCreds.scope, targetCreds.id, targetCreds.description, targetCreds.username, user_pass)
)
if (updateResult) {
println "Success changing password for ${user_name}"
} else {
println "Failed changing password for ${user_name}"
}
But when I am trying to update - I get a updateResult == false.
How can I update the credentials after they are found?

Found it myself:
/*
* Configures single (username & password) credentials for a folder in global domain
* if already exists a credentials with defined username - it will update it
* if more than one exists - the first one it encounters will be updated
*/
import java.util.logging.Logger
import jenkins.model.*
import com.cloudbees.hudson.plugins.folder.*;
import com.cloudbees.hudson.plugins.folder.properties.*;
import com.cloudbees.hudson.plugins.folder.properties.FolderCredentialsProvider.FolderCredentialsProperty;
import com.cloudbees.plugins.credentials.impl.*;
import com.cloudbees.plugins.credentials.*;
import com.cloudbees.plugins.credentials.domains.*;
// Init
def logger = Logger.getLogger("")
jenkins = Jenkins.instance
String user_name = "my_user_name"
String user_pass = "my_new_pass"
String description = "my desc"
String folderName = "Projects"
String id = java.util.UUID.randomUUID().toString()
Credentials c = new UsernamePasswordCredentialsImpl(CredentialsScope.GLOBAL, id, "description: "+id, user_name, user_pass)
logger.info("Configuring domain credentials for folder: $folderName")
for (folder in jenkins.getAllItems(Folder.class)) {
if(folder.name.equals(folderName)) {
AbstractFolder<?> folderAbs = AbstractFolder.class.cast(folder)
FolderCredentialsProperty property = folderAbs.getProperties().get(FolderCredentialsProperty.class)
// If not defined FolderCredentialsProperty yet - define and finish
if(property == null) {
logger.info("Initializing folder credentials store and add credentials in global store")
property = new FolderCredentialsProperty([c])
folderAbs.addProperty(property)
jenkins.save()
return
}
// Check for existing credentials - and update their password & description
// will update the first credentials it encounters
def credentials_store = property.getStore()
List<com.cloudbees.plugins.credentials.Credentials> folderCredentialsList = property.getCredentials()
for (creds in folderCredentialsList) {
logger.info("Checking existing credentials of folder: $folderName for user: $user_name")
if (creds.username.equals(user_name)) {
// Found username - updating it
// Try to update the creds of the folder:
def updateResult = credentials_store.updateCredentials(
com.cloudbees.plugins.credentials.domains.Domain.global(),
creds,
new UsernamePasswordCredentialsImpl(creds.scope, creds.id, description, creds.username, user_pass)
)
if (updateResult) {
println "Update successful"
} else {
println "Update failed"
}
jenkins.save()
return
}
}
logger.info("Didn't find credntials with username: $user_name - adding new one")
// If got here - then:
// 1. There is already a FolderCredentials property defined for folder: folderName
// 2. didn't find any credentials(of username & password type) with username == user_name
// so just add the new credentials
property.getStore().addCredentials(Domain.global(), c)
jenkins.save()
return
}
}

Related

How to minimize the complexity of this code ,by avoiding it to traverse all the jenkins job(lets say 5000 jobs?)

I'm changing my jenkins job's SCM url from, lets say gitlab to github by using Groovy script. Is there any way to minimize the complexity of this code ?
I have used Jenkins.instance.items.each {} which traverses through all the jobs in my jenkins
import hudson.plugins.git.*
import jenkins.*
import jenkins.model.*
def modifyGitUrl(url) {
def newurl = url.replace("source", "destination")
return newurl
}
def modifyGitID(credentialsId) {
def newID = ("Jenkins User ID")
return newID
}
Jenkins.instance.items.each {
if(it.name == "expected name"){
if (it.scm instanceof GitSCM) {
def oldScm = it.scm
def newUserRemoteConfigs = oldScm.userRemoteConfigs.collect {
new UserRemoteConfig(modifyGitUrl(it.url), it.name, it.refspec, modifyGitID(it.credentialsId))
}
def newScm = new GitSCM(newUserRemoteConfigs, oldScm.branches, oldScm.doGenerateSubmoduleConfigurations,
oldScm.submoduleCfg, oldScm.browser, oldScm.gitTool, oldScm.extensions)
it.scm = newScm
it.save()
}
}
}

How to map the Groovy script to Nexus script API and pass the Argument in JSON

I have a script which will add the nexus role to the LDAP user.
import org.sonatype.nexus.security.role.RoleIdentifier;
import org.sonatype.nexus.security.user.User;
import org.sonatype.nexus.security.user.UserManager;
String userId = 'NA12345';
String newRoleId = 'dot-maven'
String realm = 'LDAP'
String role_realm = 'default'
User user = security.securitySystem.getUser(userId, realm)
authManager = security.getSecuritySystem().getAuthorizationManager(UserManager.DEFAULT_SOURCE)
def existingRole = authManager.getRole(newRoleId)
if(user != null) {
RoleIdentifier newRole = new RoleIdentifier(role_realm, existingRole.roleId);
user.addRole(newRole)
security.securitySystem.setUsersRoles(user.getUserId(), realm, user.getRoles());
} else {
log.warn("No user with ID of $userId found.")
}
Now I need to add this script in the NExus Script API and pass the username and role id as argrument in JSON format.
How can i achieve this?

Downloading content from URL without prompting for authentication in Grails

I am working on a web app programmed in Grails. I have a page used to display a certain report and these reports can contain attachments. The attachment is stored in documentum and currently, when the user clicks on it, it is only a link to the location in documentum where the attachment is stored and prompts the user for his credentials. My app has documentum credentials stored in the configuration file therefore I want to use those rather than forcing the user to enter his own credentials. I am using RESTful services to retrieve link but I am trying to find a way to use the link to download directly to the users computer.
private def getFileInfo(def id, def subject) {
// product show view needs the following four lists to display the document information correctly
def ATRReportInstance = ATRReport.findByTrackingNumber(id)
def linkList = []
def nameList = []
def formatList = []
def idList = []
// open up a connection to the documentum server
def doc = connectToDocumentum()
if (!doc) return
def rest = doc.rest
def response = doc.response
if (response.status == 200) {
// retrieve the folder for this product (the name of this folder is the product's ID)
def rObjectId = rest.get(documentumServer + "/repositories/" + documentumfilestore + "?dql=select r_object_id from dm_folder where any r_folder_path='" + atrreportfolderpath + "/" + id + "'") {
auth authuser, authpass
}
// get the folder's ID from the folder object retrieved above
def folderObjectID
rObjectId.json.entries.each {
entry - >
folderObjectID = entry.content.properties.r_object_id
}
// get all of the documents in the product's MSDS folder using the folder ID retrieved above
def resp = rest.get(documentumServer + "/repositories/" + documentumfilestore + "?dql=select r_object_id, object_name, a_content_type, subject from cbs_document where any i_folder_id= '" + folderObjectID + "'") {
auth authuser, authpass
}
// cycle through the documents above to populate the four MSDS document information lists
def x = 0
resp.json.entries.each {
entry - >
if (entry.content.properties.subject == subject) {
// get the document's content object from the document's ID
def content = rest.get(documentumServer + "/repositories/" + documentumfilestore + "/objects/" + entry.content.properties.r_object_id + "/contents/content" + "?media-url-policy=local") {
auth authuser, authpass
}
if (entry.content.properties.r_object_id != null && ATRReportInstance.inactiveFiles != null && ATRReportInstance.inactiveFiles.contains(entry.content.properties.r_object_id.toString())) {} else {
linkList[x] = getLink(content.json.links, "enclosure")
if (linkList[x].contains("format=msg"))
linkList[x] = linkList[x].toString().substring(0, linkList[x].toString().indexOf("content-media")) + "content-media.msg"
formatList[x] = entry.content.properties.a_content_type
nameList[x] = entry.content.properties.object_name
idList[x] = entry.content.properties.r_object_id
x++
}
}
}
return [linkList: linkList, nameList: nameList, formatList: formatList, idList: idList]
} else {
// return null if documentum is unavailable
flash.message = message(code: 'error.documentum.unavailable')
return null
}
}
I'm thinking writing another function that can take in a URL and download the document to the user might work, but I can't figure how to retrieve that document within Grails.
If you want to bypass login you could either setup a SSO solution (requires some work for DCTM) or do a function as you suggest. However you should consider the licensing terms when doing this.
Here is the solution I implemented and that worked. It is a method that downloads a file in documentum using authentication credentials found in a configuration file.
def exportAttachment() {
//uses parameters from gsp file
def url = params.url
def name = params.name
def format = params.format
def extension
//find proper extension
for (s in documentumExtMap) {
if (s.value.equals(format)) {
extension = s.key
}
}
def connection = new URL(url).openConnection()
def remoteAuth = "Basic " + "${authuser}:${authpass}".bytes.encodeBase64()
connection.setRequestProperty("Authorization", remoteAuth)
def dataStream = connection.inputStream
response.setContentType("application/octet-stream")
response.setHeader('Content-disposition', 'Attachment; filename=' + name + '.' + extension)
response.outputStream << dataStream
response.outputStream.flush()
}
The method has three parameters: url, name, format.
Url is the location of the file in documentum.
Name is the name of the download client side
Format is the type of file that is being downloaded. In my case, I had to use this to get the proper extension needed for the file.

Jenkins [Dynamic Choice Parameter (Scriptler)] failing when querying credentials information

I am bit stuck on why when I run the following script in Jenkins Scriptler and the Script Console it works, yet when used in the Dynamic Choice Parameter (Scriptler), it fails with the error:
Error: groovy.lang.MissingPropertyException: No such property: com for class: Script1
I can only assume that it is to do with the used class com.cloudbees.plugins.credentials.CredentialsProvider is called.
Here is the script:
/*** BEGIN META {
"name" : "GetRemoteNasFolderList",
"comment" : "Retrieve a list of folder names (in reverse order) from a remote NAS location.",
"parameters" : [ 'ENVIRONMENT', 'SHARE_PATH', 'FOLDER_PATH' ],
"core": "1.565",
"authors" : [{
name : "Authors Name"
}]
} END META**/
import jenkins.model.Jenkins
try {
// params
def env = ENVIRONMENT // 'DEV" or 'TEST' or 'PROD'
def share_path = SHARE_PATH
def folder_path = FOLDER_PATH
String user_domain = ''
String nas_path = ''
switch (env) {
case 'DEV':
user_domain = 'dev';
nas_path = 'nas_host.dev.company.com.au';
break;
case 'TEST':
user_domain = 'test';
nas_path = 'nas_host.test.company.com.au';
break;
case 'PROD':
default:
user_domain = 'prod';
nas_path = 'nas_host.prod.company.com.au';
}
String user_name = 'myUserName'
def full_name = user_domain + '\\' + user_name
String pass_word = ''
def found = false
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class,
Jenkins.instance,
null,
null
);
for (c in creds) {
if (c.username == full_name) {
pass_word = c.password
found = true
}
}
if (found == true) {
url = "smb://" + nas_path + "/" + share_path + "/" + folder_path;
println("Url: "+url)
// println(user_domain+"\\"+user_name+", "+pass_word)
auth = new jcifs.smb.NtlmPasswordAuthentication(user_domain, user_name, pass_word);
dir = new jcifs.smb.SmbFile(url, auth);
folders = []
for (jcifs.smb.SmbFile f : dir.listFiles())
{
folders.push(f.getName().replace('/',''))
}
return folders.sort().reverse()
} else {
print("Credential entry not found for ( " + full_name + " )")
}
} catch (e) {
return ["Error: "+e]
} finally {
}
Any thoughts, anyone.
Error: groovy.lang.MissingPropertyException: No such property: xx for class: yy
Typical error message if your missing an import reference, have you tried referencing everything?
import jenkins.model.*
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.common.*
import com.cloudbees.plugins.credentials.domains.*;
Perhaps this is what the Jenkins Scriptler and the Script Console do by default, where as the Dynamic Choice Parameter (Scriptler) doesn't.
Ref: https://github.com/chef-cookbooks/jenkins/issues/174
Switched to using a different plugin (Active Choices Parameter) that makes use of Scriptler scripts and is now working.

Trying to delete a uploaded file from directory file system

I have a web app that uploads files to file system and show them in a list. I am trying to delete the item with a button. I know I need to get the path of the directory file to be able to delete it and I believe this is where I am stuck:
def delete = {
def doc = Document.get(params.id)
def path = Document.get(path.id)
doc.delete(path)
redirect( action:'list' )
}
error I am getting: No such property: path for class: file_down.DocumentController Possible solutions: flash
It seems to me def path = Document.get(path.id) is wrong, in that case how do we find the path of a document ?
This is my upload method where I upload the files, assign it to a specific filesize, date, and fullPath( which is the uploaded folder)
def upload() {
def file = request.getFile('file')
if(file.empty) {
flash.message = "File cannot be empty"
} else {
def documentInstance = new Document()
documentInstance.filename = file.originalFilename
documentInstance.fullPath = grailsApplication.config.uploadFolder + documentInstance.filename
documentInstance.fileSize = file.getSize() / (1024 * 1024)
documentInstance.company = Company.findByName(params.company)
if (documentInstance.company == null) {
flash.message = "Company doesn't exist"
redirect (action: 'admin')
}
else {
file.transferTo(new File(documentInstance.fullPath))
documentInstance.save()
redirect (action:'list', params: ['company': params.company])
}
}
}
I think you have an error in this line:
def path = Document.get(path.id)
You try to get path.id from the path variable you are just declaring.
I'm pretty sure that you mean
def path = new File(doc.fullPath)
path.delete() // Remove the file from the file-system
doc.delete() // Remote the domain instance in DB
Alternative:
class Document {
// Add this to your Document domain
def beforeDelete = {
new File(fullPath).delete()
}
}
and then you could just do this in your controller:
def delete = {
def doc = Document.get(params.id)
doc.delete() // Delete the domain instance in DB
redirect( action:'list' )
}

Resources