Jenkins Credentials Manager + Active Choices
ฉันต้องการเข้าถึง Jenkins Credentials เพื่อพิสูจน์ตัวตนกับ Git ก่อนสคริปต์ไปป์ไลน์ - เพื่อเติมพารามิเตอร์ Active Choices
withCredentialsในท่อฉันก็ทำมันด้วย แต่ในระหว่างขั้นตอนก่อนไปป์ไลน์ (เช่นพารามิเตอร์ Active Choices) ส่วนขยายของฮัดสันเช่นwithCredentialsหรือsshAgentไม่สามารถเข้าถึงได้ ขณะนี้ฉันดำเนินการ groovy git ls-remote -h [email protected]:repo.gitด้วยคีย์ที่ไม่ได้เข้ารหัสในไดเร็กทอรี jenkins_home (ซึ่งไม่ใช่ความคิดที่ดี)
ฉันรู้ว่ามีความเป็นไปได้ที่จะนำเข้าและสร้างวัตถุ Java โดยการอ่านซอร์สโค้ดของ Jenkin และปลั๊กอิน - แต่ดูเหมือนจะไม่มีที่สิ้นสุด
ดังนั้น: เป็นไปได้หรือไม่ที่จะนำเข้าและใช้ส่วนขยายของฮัดสันกับสคริปต์ Groovy ปัจจุบันได้อย่างง่ายดายหรือใครมีโซลูชันที่พร้อมสำหรับสิ่งนี้ (ดูเหมือนไม่มีใครเผยแพร่อะไรเกี่ยวกับกรณีดังกล่าว)
คำตอบ
สำหรับฉันดูเหมือนว่าคุณจะรู้เรื่องนี้แล้ว แต่มีวิธีง่ายๆสองสามวิธีในการทำเช่นนี้และสองวิธีที่ยากในการทำเช่นนี้
วิธีง่ายๆ:
- ทำให้ repo ของคุณพร้อมสำหรับการชำระเงินโดยไม่มีคีย์ SSH หรือข้อมูลรับรองการตรวจสอบสิทธิ์
- เพิ่มคีย์คู่ SSH ด้วยตนเองสำหรับการชำระเงิน repo ให้กับผู้ใช้ Jenkins บนโหนดหลักของ Jenkins ของคุณ (เนื่องจากสคริปต์ Active Choice Groovy ทำงานบนโหนดหลัก) (เช่นอย่าใช้ที่เก็บข้อมูลรับรอง)
วิธีที่ยาก:
- ใช้ Jenkins Java API ในโค้ด Active Choices ของคุณเพื่อแยกข้อมูลรับรองจากที่เก็บหนังสือรับรอง เอกสาร API ที่มีอยู่สำหรับการจัดเก็บข้อมูลประจำตัวและประเภทข้อมูลประจำตัวของ SSH ไม่มีเอกสารเกี่ยวกับวิธีใช้คลาส Java ที่มีอยู่ในปลั๊กอินเหล่านี้ดังนั้นคุณจึงต้องคิดออกด้วยตัวเอง
- สร้างงาน "เมตา" รองเพื่ออัปเดตพารามิเตอร์ในงาน Jenkins ดั้งเดิม (รวมถึงสคริปต์ Active Choices) - ฉันอธิบายสิ่งนี้ไว้ด้านล่างเล็กน้อย
หากคุณไม่สามารถทำวิธีแก้ปัญหาง่ายๆด้วยเหตุผลด้านความปลอดภัยไม่มีวิธีที่ง่ายและตรงไปตรงมาในการอัปเดตพารามิเตอร์ Active Choice ตามเนื้อหาของ git repo นี้เป็นเพราะ:
- เช่นเดียวกับที่คุณกล่าวว่า "ในช่วงก่อนไปป์ไลน์ (เช่นพารามิเตอร์ Active Choices) ส่วนขยายของฮัดสันเช่น withCredentials หรือ sshAgent ไม่สามารถเข้าถึงได้"
- การกำหนดค่าสำหรับพารามิเตอร์รวมถึงพารามิเตอร์ Active Choice นำมาจากการเรียกใช้ Pipeline ก่อนหน้านั้นไม่ใช่พารามิเตอร์ปัจจุบัน หมายความว่าในการอัปเดตพารามิเตอร์ของคุณจากภายในรหัสไปป์ไลน์คุณจะต้องเรียกใช้ไปป์ไลน์ซึ่งเอาชนะจุดที่คุณต้องการทำ
มีวิธีแก้ไขสำหรับ 1. ซึ่งก็คือการใช้ Scripted Pipelines แทน Declarative แต่จะไม่สามารถแก้ไขปัญหาของ 2 ได้
วิธีแก้ปัญหาที่ฉันคิดขึ้นเมื่อฉันพบปัญหานี้คือการสร้างงานเจนกินส์ที่สอง (ฉันเรียกว่างาน "เมตา") ซึ่งอัปเดตพารามิเตอร์ของงานดั้งเดิมรวมถึงสคริปต์ Active Choices งานเมตาที่สองนี้ถูกทริกเกอร์โดย git hook บนที่เก็บที่ฉันใช้เพื่อเติมตัวเลือกในพารามิเตอร์ Active Choices ของฉัน สิ่งนี้มีข้อดีที่คุณไม่จำเป็นต้องเรียกใช้ Pipeline ของงานเดิมเพื่ออัปเดตพารามิเตอร์แก้ปัญหาในข้อ 2 นอกจากนี้เนื่องจากยังคงเป็นงาน Pipeline คุณจึงสามารถใช้ขั้นตอน Pipeline ตามปกติได้จึงช่วยให้คุณเข้าถึง การจัดเก็บข้อมูลรับรอง
งานของฉันมีลักษณะ (โดยประมาณ) แบบนี้ - ฉันทำให้มันง่ายขึ้นมากเพื่อให้พอดีกับที่นี่ดังนั้นคุณจะต้องปรับแต่งหลายอย่างเพื่อให้มันทำงานได้ตามที่คุณต้องการ อาจมีข้อผิดพลาดและข้อบกพร่องมากมายในเรื่องนี้เนื่องจากฉันฉีกสคริปต์ที่มีอยู่ออกจากกันเพื่อสร้างสิ่งนี้ สิ่งที่ควรทราบ:
- สิ่งนี้ใช้ประโยชน์จาก Jenkins APIs เป็นจำนวนมากดังนั้นคุณจะต้องปิดการใช้งานแซนด์บ็อกซ์ของสคริปต์หรือรายการฟังก์ชันที่อนุญาตพิเศษมากมายในตัวจัดการความปลอดภัยของเจนกินส์เพื่อให้สิ่งนี้ทำงานได้
- นี่ยังคงเป็นไปในทางเทคนิคของ Scripted Pipeline แม้ว่าจะดูเหมือนสคริปต์ Groovy ปกติมากกว่าไฟล์ Pipeline ก็ตาม
- เนื่องจากนี่คือไปป์ไลน์คุณสามารถใช้ขั้นตอนต่างๆเช่น
withCredentialsการตรวจสอบที่เก็บโดยใช้ที่เก็บหนังสือรับรอง
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)