Hi everyone,
We're trying to create a Jenkins pipeline that installs a custom Jira plugin JAR file to our Jira instance using the UPM REST APIs.
Our process thus far is as follows:
- Make a DELETE call to '/rest/plugins/latest/com.fanniemae.atlassian.jira.<plugin>-key' to uninstall the current version.
- Make a call to GET call to '/rest/plugins/latest/?os_authType=basic' to get the value for the 'upm-token' header.
- Make a POST call to '/rest/plugins/latest/?token={{upm_token}}' and pass the file system path to the JAR file as form data
The above calls work in Postman. However, Jenkins always fails in #3 with a 403 status code and
<textarea>{"errorMessage":"invalid token","subCode":"upm.error.invalid.token"}</textarea>
Our Jenkins pipeline is as follows:
stage("Deploy to Devl and Test") {
when {
expression { env.GIT_BRANCH != 'master'}
}
steps {
script {
logInfo("Download jar file from Nexus")
downloadArtifact(PLUGIN_NEXUS_URL: "atlassian/jira/releases/fmrelease",
PLUGIN_VERSION: env.BUILD_VERSION,
PLUGIN_JAR_FILE: "fmrelease")
logInfo("Uninstall the existing version of the plugin")
pluginUninstall(URL: "https://jira-devl:8443",
PLUGIN: "fmrelease",
PLUGIN_KEY: env.PLUGIN_KEY,
CREDENTIAL_ID: "grk_devl_internal_nuid")
logInfo("Get UPM for Jira Devl")
def UPM_TOKEN = upmToken(URL: "https://jira-devl:8443",
CREDENTIAL_ID: "grk_devl_internal_nuid")
logInfo(UPM_TOKEN)
pluginInstall(URL: "https://jira-devl:8443",
CREDENTIAL_ID: "grk_devl_internal_nuid",
UPM_TOKEN: UPM_TOKEN,
JAR_FILE: "fmrelease-${env.BUILD_VERSION}.jar",
PLUGIN: "fmrelease",
PLUGIN_VERSION: env.BUILD_VERSION)
}
}
}
Here is how we're getting the UPM token in Jenkins:
def call (Map params) {
def credentialId = required(params, "CREDENTIAL_ID")
def url = required(params, "URL")
withCredentials([string(credentialsId: credentialId, variable: 'SECRET')]) {
logInfo("Get UPM Token....")
def upmToken = sh(script:"""
set +x
curl -skIX GET \
'${url}/rest/plugins/latest/?os_authType=basic' \
-H 'Authorization: Basic ${SECRET}' | grep upm-token | cut -d: -f2- | tr -d '[[:space:]]'
set -x
""", returnStdout: true).trim()
return upmToken
}
}
return this
We then pass the output to the pluginInstall Groovy script:
def call (Map params) {
def url = required(params, "URL")
def upmToken = required(params, "UPM_TOKEN")
def credentialId = required(params, "CREDENTIAL_ID")
def jarFile = required(params, "JAR_FILE")
def plugin = required(params, 'PLUGIN')
def pluginVersion = required(params, "PLUGIN_VERSION")
def successStatusCode = 200
withCredentials([string(credentialsId: credentialId, variable: 'SECRET')]) {
logInfo("Install ${plugin} plugin Started...")
def output
echo """curl -kvX POST "${url}/rest/plugins/latest/?token=${upmToken}" -H 'Authorization: Basic ${SECRET}' -F 'plugin=@${jarFile}'"""
try {
output = sh(script: """
set +x
curl -kvX POST \
"${url}/rest/plugins/latest/?token=${upmToken.trim()}" \
-H 'Authorization: Basic ${SECRET}' \
-F 'plugin=@${jarFile}'
set -x
""", returnStdout: true)
} catch (Exception e) {
error("Failed to install ${plugin} plugin: ${e.toString()}")
}
logInfo("Installation output: ${output.toString()}")
def jsonOutput = readJSON text: output
def installationStatus = jsonOutput["status"]["done"]
def httpStatusCode = jsonOutput["status"]["statusCode"]
if (!installationStatus && httpStatusCode == successStatusCode) {
logInfo("Installtion of ${plugin} is intiated but not completed")
def apiEndpoint = jsonOutput["links"]["self"]
logInfo("Validation endpoint: ${apiEndpoint.toString()}")
def validationOutput
sh "sleep 30"
try {
validationOutput = sh(script: """
set +x
curl -kL GET \
"${url}${apiEndpoint}" \
-H 'Authorization: Basic ${SECRET}' \
""", returnStdout: true)
} catch (Exception e) {
error("Failed to validate the ${plugin} plugin installation: ${e.toString()}")
}
logInfo("Plugin install validation output: ${validationOutput.toString()}")
def validationJsonOutput = readJSON text: validationOutput
def pluginEnable = validationJsonOutput["enabled"]
def pluginInstallVersion = validationJsonOutput["version"]
if (pluginInstallVersion == PLUGIN_VERSION && pluginEnable) {
logInfo("Installtion of ${plugin} is Successfull")
}
} else if (httpStatusCode != successStatusCode) {
println(httpStatusCode)
error("Installation Failed...Please check the api output: ${output}")
} else {
error("Invalid Installation call: ${output}")
}
}
}
return this