2019-02-18 16:05:33 +01:00
|
|
|
@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
|
2019-03-01 10:41:41 +01:00
|
|
|
import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
|
2019-02-18 16:05:33 +01:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-03-01 15:27:08 +01:00
|
|
|
def runScriptInNewVM(Map args) {
|
|
|
|
def script = args.get("script", "")
|
|
|
|
runInNewVM(args) { shell ->
|
|
|
|
shell(script)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def runInNewVM(Map args, Closure body) {
|
2019-02-18 16:05:33 +01:00
|
|
|
|
|
|
|
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")
|
|
|
|
|
|
|
|
// 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 ->
|
|
|
|
|
2019-03-01 10:41:41 +01:00
|
|
|
def sshArgs = "-i '${VM_SSH_KEY}' -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
|
2019-02-18 16:05:33 +01:00
|
|
|
|
|
|
|
// On attend que la connexion SSH soit disponible
|
2019-03-01 10:41:41 +01:00
|
|
|
println "En attente de l'accès SSH sur la machine ${host}..."
|
|
|
|
while(true) {
|
|
|
|
def status = sh script: "nc -zv ${host} 22", returnStatus: true
|
|
|
|
if (status == 0) {
|
|
|
|
break;
|
2019-02-18 16:05:33 +01:00
|
|
|
}
|
2019-03-01 10:41:41 +01:00
|
|
|
sleep(5)
|
2019-02-18 16:05:33 +01:00
|
|
|
}
|
|
|
|
|
2019-03-01 15:27:08 +01:00
|
|
|
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)
|
|
|
|
|
2019-02-18 16:05:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-01 15:27:08 +01:00
|
|
|
}
|