Jenkins Credentials Manager + Active Choices
Eu quero acessar as credenciais do Jenkins para autenticar com Git antes do script do pipeline - para preencher o parâmetro Active Choices.
No pipeline, simplesmente faço isso com withCredentials. Mas durante o estágio de pré-pipeline (isto é, parâmetro Active Choices), extensões Hudson como withCredentialsou sshAgentnão estão acessíveis. Atualmente eu executo o groovy git ls-remote -h [email protected]:repo.gitcom chave não criptografada no diretório jenkins_home (o que não é uma boa ideia).
Eu sei que há alguma possibilidade de importar e construir objetos Java lendo o código-fonte de Jenkin e seus plug-ins - mas isso parece infinito.
Então: é possível de alguma forma importar e aplicar extensões Hudson ao script Groovy atual ou alguém tem alguma solução pronta para isso (aparentemente ninguém publicou nada sobre esse caso)?
Respostas
Parece-me que você já sabe disso, mas existem algumas maneiras fáceis de fazer isso e algumas maneiras difíceis de fazer isso.
As maneiras fáceis:
- Disponibilize seu repo para checkout sem chaves SSH ou credenciais de autenticação.
- Adicione manualmente um par de chaves SSH para verificação de repo ao usuário Jenkins em seu nó mestre Jenkins (já que os scripts Active Choice Groovy são executados no nó mestre) (ou seja, não use o armazenamento de credenciais).
As maneiras mais difíceis:
- Use a API Jenkins Java em seu código do Active Choices para extrair credenciais do armazenamento de credenciais. Documentos de API estão disponíveis para o armazenamento de credenciais e o tipo de credenciais ssh . Não há documentação sobre como usar as classes Java disponíveis nesses plug-ins, então é você quem decide.
- Crie um trabalho "meta" secundário para atualizar os parâmetros no trabalho original do Jenkins (incluindo scripts do Active Choices) - descrevo isso um pouco abaixo.
Se você não pode fazer nenhuma das soluções fáceis por motivos de segurança, não há uma maneira fácil e direta de atualizar os parâmetros do Active Choice com base no conteúdo de um repo git. Isto é porque:
- Como você disse, "durante o estágio de pré-pipeline (ou seja, parâmetro Active Choices), as extensões Hudson, como withCredentials ou sshAgent, não são acessíveis".
- A configuração dos parâmetros, incluindo parâmetros Active Choice, é obtida da execução anterior desse Pipeline, não da atual. O que significa que, para atualizar seus parâmetros de dentro do código do Pipeline, você precisará executar o Pipeline, o que anula o ponto do que você deseja fazer.
Existe uma solução para 1., que é usar pipelines com script em vez de declarativos, mas isso não contorna os problemas de 2.
A solução que encontrei quando me deparei com esse problema é criar um segundo trabalho do Jenkins (eu o chamo de "meta" trabalho) que atualiza os parâmetros do trabalho original, incluindo scripts do Active Choices. Este segundo meta-trabalho é acionado por um gancho git no repositório que uso para preencher as opções em meus parâmetros do Active Choices. Isso tem a vantagem de não ser necessário executar o pipeline do trabalho original para atualizar seus parâmetros, resolvendo os problemas em 2. Além disso, como ainda é um trabalho do pipeline, você pode usar as etapas normais do pipeline, permitindo acessar o armazenamento de credenciais.
Meu trabalho é (aproximadamente) assim - simplifiquei muito para que se encaixe aqui, então você precisará fazer vários ajustes para que funcione da maneira que deseja. Provavelmente há uma tonelada de erros e bugs nisso porque eu rasguei um script existente para fazer isso. Algumas coisas a serem observadas:
- Isso faz uso intenso das APIs do Jenkins, então você precisa desabilitar a sandbox do script ou colocar na lista de permissões uma tonelada de funções no gerenciador de segurança do Jenkins para que isso seja executado
- Tecnicamente, este ainda é um pipeline com script, embora se pareça muito mais com um script Groovy normal do que com um arquivo Pipeline
- Como este é um Pipeline, você pode usar etapas como
withCredentialsfazer check-out de repositórios usando o armazenamento de credenciais.
import groovy.json.JsonOutput
import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript
import org.biouno.unochoice.*
import org.biouno.unochoice.model.*
def metadataUrl = 'ssh://git@**************/metadata.git'
def metadataBranch = 'master'
def metadata = [:]
node('master') {
git(
url: metadataUrl,
branch: metadataBranch,
credentialsId: 'jenkins',
changelog: false,
)
def dataDir = "${pwd()}/myJsonFiles" // can't use File.eachFileMatch() due to: // https://wiki.jenkins.io/display/JENKINS/Pipeline+CPS+method+mismatches def files = new File(dataDir).list().findAll() { f-> FilenameUtils.getExtension(f) == 'json' } files.each() { f-> // TODO: nice error messages if files are misformatted def name = FilenameUtils.removeExtension(f) def data = readJson(file: "${dataDir}/${f}") metadata[name] = data } } // ChoiceParameterDefinition is the class name for the built-in static choice parameter. // CascadeChoiceParameter is the class name for the Active Choices dynamic choice parameter. // begin first parameter def fileParam = new ChoiceParameterDefinition( 'file', 'The JSON file to use', ) fileParam.setChoices(metadata.keySet()) // end first parameter // begin second parameter def metadataJson = JsonOutput.toJson(metadata) def scriptText = """ import groovy.json.JsonSlurper def slurper = new JsonSlurper() def metadata = slurper.parseText('${metadataJson}')
return metadata[file]['versions']
"""
def mainScript = new SecureGroovyScript(scriptText, true)
def fallbackScript = new SecureGroovyScript('return ["Error encountered - see logs"]', true)
def activeChoiceScript = new GroovyScript(mainScript, fallbackScript)
def versionParam = new CascadeChoiceParameter(
'version',
'The version to use',
activeChoiceScript,
'PT_SINGLE_SELECT',
'file',
false,
)
// end second parameter
def paramProp = new ParametersDefinitionProperty(fileParam, versionParam)
// this is the full name of the actual job which needs dynamic parameters
def job = Jenkins.instance.getItemByFullName('UNIX/deploy_to_environment/master')
// There is no "setProperty" - we need to remove and replace.
// removeProperty is safe to run even if no matching properties are set on the job.
// However, this method only removes one property per method call.
// Theoretically, this means the job could accumulate multiple conflicting
// ParametersDefinitionProperty properties.
// TODO: run removeProperty in a while loop to eliminate all matching properties for extra safety.
job.removeProperty(ParametersDefinitionProperty)
job.addProperty(paramProp)