Jenkins/vars/nebula.groovy

195 líneas
6.6 KiB
Groovy

@Grab('org.codehaus.groovy:groovy-xmlrpc:0.8')
import groovy.net.xmlrpc.*
import groovy.util.XmlSlurper
import groovy.util.slurpersupport.GPathResult
import groovy.util.slurpersupport.NodeChild
import groovy.xml.XmlUtil
import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
class Client {
String oneAuth
String url
Script script
// Voir http://groovy-lang.org/processing-xml.html pour plus d'informations
// sur le traitement du XML en Groovy
// OpenNebula RPC API
@NonCPS
XMLRPCServerProxy createProxy() {
return new XMLRPCServerProxy(url, true)
}
// Voir https://docs.opennebula.org/5.6/integration/system_interfaces/api.html#one-templatepool-info
@NonCPS
GPathResult templatepoolInfo(int filter = -2, int start = -1, int end = -1) {
def proxy = createProxy()
def results = proxy."one.templatepool.info"(oneAuth, filter, start, end)
assert results[0] : results[1]
return new XmlSlurper().parseText(results[1])
}
// Voir https://docs.opennebula.org/5.6/integration/system_interfaces/api.html#one-vm-allocate
@NonCPS
Integer vmAllocate(String template, Boolean hold = false) {
def proxy = createProxy()
def results = proxy."one.vm.allocate"(oneAuth, template, hold)
assert results[0] : results[1]
return results[1]
}
// Voir https://docs.opennebula.org/5.6/integration/system_interfaces/api.html#one-vm-action
@NonCPS
Integer vmAction(String actionName, Integer objectId) {
def proxy = createProxy()
def results = proxy."one.vm.action"(oneAuth, actionName, objectId)
assert results[0] : results[1]
return results[1]
}
// Voir https://docs.opennebula.org/5.6/integration/system_interfaces/api.html#one-vm-info
@NonCPS
GPathResult vmInfo(Integer objectId) {
def proxy = createProxy()
def results = proxy."one.vm.info"(oneAuth, objectId)
assert results[0] : results[1]
return new XmlSlurper().parseText(results[1])
}
// Utilitaires de haut niveau pour les pipelines Jenkins
// Retrouve un template de VM via son nom
@NonCPS
NodeChild findVMTemplate(String name) {
def templates = templatepoolInfo()
def result = null
templates.'*'.each {
if (it.NAME.text().trim() == name) {
result = it
}
}
return result
}
// Démarre une VM, exécute les étapes passées en paramètres
// puis supprime la VM
@NonCPS
void withNewVM(String templateName, Boolean terminateOnExit = true, Closure body) {
def tmpl = findVMTemplate(templateName)
def id = vmAllocate(XmlUtil.serialize(tmpl.TEMPLATE))
tmpl = null
script.println("Démarrage de la VM '${id}'...")
def info = vmInfo(id)
script.println("En attente du démarrage de la VM...")
while(info.STATE.toInteger() != 3 || info.LCM_STATE.toInteger() != 3) {
sleep(5000)
info = vmInfo(id)
}
script.println("VM démarrée.")
def ip = info.TEMPLATE.NIC.IP.text()
info = null
runThenTerminate(id, ip, terminateOnExit, body)
}
void runThenTerminate(Integer id, String ip, Boolean terminateOnExit, Closure body) {
try {
body(ip)
} finally {
if (terminateOnExit) {
script.println("Suppression de la VM '${id}'...")
vmAction("terminate", id)
}
}
}
}
@NonCPS
def init(String url, String username, String password, Closure body) {
def oneAuth = "${username}:${password}"
def client = new Client(oneAuth: oneAuth, url: url, script: this)
proxy = null
body.call(client)
}
def initWithCredentials(String urlCredentialsId, String userCredentialsId, Closure body) {
withCredentials([
string(credentialsId: urlCredentialsId, variable: 'NEBULA_URL'),
usernamePassword(credentialsId: userCredentialsId, usernameVariable: 'NEBULA_USERNAME', passwordVariable: 'NEBULA_PASSWORD')
]) {
init(env.NEBULA_URL, env.NEBULA_USERNAME, env.NEBULA_PASSWORD, body)
}
}
def runScriptInNewVM(Map args) {
def script = args.get("script", "")
runInNewVM(args) { shell ->
shell(script)
}
}
def runInNewVM(Map args, Closure body) {
def urlCredentialsId = args.get('urlCredentialsId', 'opennebula-dev-url')
def userCredentialsId = args.get('userCredentialsId', 'kipp-credentials')
def sshCredentialsId = args.get('sshCredentialsId', 'kipp-opennebula-dev-ssh-keypair')
def vmTemplate = args.get('vmTemplate', '')
def terminateOnExit = args.get('terminateOnExit', true)
def shell = args.get("shell", "/bin/sh")
def connectionTimeout = args.get('connectionTimeout', 10)
// On récupère les identifiants de connexion SSH pour la VM
withCredentials([
sshUserPrivateKey(credentialsId: sshCredentialsId, keyFileVariable: 'VM_SSH_KEY')
]) {
initWithCredentials(urlCredentialsId, userCredentialsId) { client ->
client.withNewVM(vmTemplate, terminateOnExit) { host ->
def sshArgs = "-i '${VM_SSH_KEY}' -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
// On attend que la connexion SSH soit disponible
println "En attente de l'accès SSH sur la machine ${host}..."
timeout(connectionTimeout) {
while(true) {
def status = sh script: "nc -zv ${host} 22", returnStatus: true
if (status == 0) {
break;
}
sleep(5)
}
}
def remoteShell = { script ->
// On créait un script temporaire à exécuter sur la machine distante
def now = System.currentTimeMillis()
def tempScriptFile = "script_${env.BUILD_ID}_${now}.sh"
writeFile(file: tempScriptFile, text: """
#!${shell}
${script.stripIndent()}
""")
// On transfère le script sur la machine distante et on l'exécute
sh """
scp ${sshArgs} '${tempScriptFile}' 'root@${host}:/tmp/${tempScriptFile}'
ssh ${sshArgs} root@${host} 'chmod +x /tmp/${tempScriptFile}; /tmp/${tempScriptFile}'
"""
}
body(remoteShell)
}
}
}
}