Librairie utilitaire pour Jenkins
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

nebula.groovy 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. @Grab('org.codehaus.groovy:groovy-xmlrpc:0.8')
  2. import groovy.net.xmlrpc.*
  3. import groovy.util.XmlSlurper
  4. import groovy.util.slurpersupport.GPathResult
  5. import groovy.util.slurpersupport.NodeChild
  6. import groovy.xml.XmlUtil
  7. import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
  8. class Client {
  9. String oneAuth
  10. String url
  11. Script script
  12. // Voir http://groovy-lang.org/processing-xml.html pour plus d'informations
  13. // sur le traitement du XML en Groovy
  14. // OpenNebula RPC API
  15. @NonCPS
  16. XMLRPCServerProxy createProxy() {
  17. return new XMLRPCServerProxy(url, true)
  18. }
  19. // Voir https://docs.opennebula.org/5.6/integration/system_interfaces/api.html#one-templatepool-info
  20. @NonCPS
  21. GPathResult templatepoolInfo(int filter = -2, int start = -1, int end = -1) {
  22. def proxy = createProxy()
  23. def results = proxy."one.templatepool.info"(oneAuth, filter, start, end)
  24. assert results[0] : results[1]
  25. return new XmlSlurper().parseText(results[1])
  26. }
  27. // Voir https://docs.opennebula.org/5.6/integration/system_interfaces/api.html#one-vm-allocate
  28. @NonCPS
  29. Integer vmAllocate(String template, Boolean hold = false) {
  30. def proxy = createProxy()
  31. def results = proxy."one.vm.allocate"(oneAuth, template, hold)
  32. assert results[0] : results[1]
  33. return results[1]
  34. }
  35. // Voir https://docs.opennebula.org/5.6/integration/system_interfaces/api.html#one-vm-action
  36. @NonCPS
  37. Integer vmAction(String actionName, Integer objectId) {
  38. def proxy = createProxy()
  39. def results = proxy."one.vm.action"(oneAuth, actionName, objectId)
  40. assert results[0] : results[1]
  41. return results[1]
  42. }
  43. // Voir https://docs.opennebula.org/5.6/integration/system_interfaces/api.html#one-vm-info
  44. @NonCPS
  45. GPathResult vmInfo(Integer objectId) {
  46. def proxy = createProxy()
  47. def results = proxy."one.vm.info"(oneAuth, objectId)
  48. assert results[0] : results[1]
  49. return new XmlSlurper().parseText(results[1])
  50. }
  51. // Utilitaires de haut niveau pour les pipelines Jenkins
  52. // Retrouve un template de VM via son nom
  53. @NonCPS
  54. NodeChild findVMTemplate(String name) {
  55. def templates = templatepoolInfo()
  56. def result = null
  57. templates.'*'.each {
  58. if (it.NAME.text().trim() == name) {
  59. result = it
  60. }
  61. }
  62. return result
  63. }
  64. // Démarre une VM, exécute les étapes passées en paramètres
  65. // puis supprime la VM
  66. @NonCPS
  67. void withNewVM(String templateName, Boolean terminateOnExit = true, Closure body) {
  68. def tmpl = findVMTemplate(templateName)
  69. def id = vmAllocate(XmlUtil.serialize(tmpl.TEMPLATE))
  70. tmpl = null
  71. script.println("Démarrage de la VM '${id}'...")
  72. def info = vmInfo(id)
  73. script.println("En attente du démarrage de la VM...")
  74. while(info.STATE.toInteger() != 3 || info.LCM_STATE.toInteger() != 3) {
  75. sleep(5000)
  76. info = vmInfo(id)
  77. }
  78. script.println("VM démarrée.")
  79. def ip = info.TEMPLATE.NIC.IP.text()
  80. info = null
  81. runThenTerminate(id, ip, terminateOnExit, body)
  82. }
  83. void runThenTerminate(Integer id, String ip, Boolean terminateOnExit, Closure body) {
  84. try {
  85. body(ip)
  86. } finally {
  87. if (terminateOnExit) {
  88. script.println("Suppression de la VM '${id}'...")
  89. vmAction("terminate", id)
  90. }
  91. }
  92. }
  93. }
  94. @NonCPS
  95. def init(String url, String username, String password, Closure body) {
  96. def oneAuth = "${username}:${password}"
  97. def client = new Client(oneAuth: oneAuth, url: url, script: this)
  98. proxy = null
  99. body.call(client)
  100. }
  101. def initWithCredentials(String urlCredentialsId, String userCredentialsId, Closure body) {
  102. withCredentials([
  103. string(credentialsId: urlCredentialsId, variable: 'NEBULA_URL'),
  104. usernamePassword(credentialsId: userCredentialsId, usernameVariable: 'NEBULA_USERNAME', passwordVariable: 'NEBULA_PASSWORD')
  105. ]) {
  106. init(env.NEBULA_URL, env.NEBULA_USERNAME, env.NEBULA_PASSWORD, body)
  107. }
  108. }
  109. def runScriptInNewVM(Map args) {
  110. def script = args.get("script", "")
  111. runInNewVM(args) { shell ->
  112. shell(script)
  113. }
  114. }
  115. def runInNewVM(Map args, Closure body) {
  116. def urlCredentialsId = args.get('urlCredentialsId', 'opennebula-dev-url')
  117. def userCredentialsId = args.get('userCredentialsId', 'kipp-credentials')
  118. def sshCredentialsId = args.get('sshCredentialsId', 'kipp-opennebula-dev-ssh-keypair')
  119. def vmTemplate = args.get('vmTemplate', '')
  120. def terminateOnExit = args.get('terminateOnExit', true)
  121. def shell = args.get("shell", "/bin/sh")
  122. def connectionTimeout = args.get('connectionTimeout', 10)
  123. // On récupère les identifiants de connexion SSH pour la VM
  124. withCredentials([
  125. sshUserPrivateKey(credentialsId: sshCredentialsId, keyFileVariable: 'VM_SSH_KEY')
  126. ]) {
  127. initWithCredentials(urlCredentialsId, userCredentialsId) { client ->
  128. client.withNewVM(vmTemplate, terminateOnExit) { host ->
  129. def sshArgs = "-i '${VM_SSH_KEY}' -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
  130. // On attend que la connexion SSH soit disponible
  131. println "En attente de l'accès SSH sur la machine ${host}..."
  132. timeout(connectionTimeout) {
  133. while(true) {
  134. def status = sh script: "nc -zv ${host} 22", returnStatus: true
  135. if (status == 0) {
  136. break;
  137. }
  138. sleep(5)
  139. }
  140. }
  141. def remoteShell = { script ->
  142. // On créait un script temporaire à exécuter sur la machine distante
  143. def now = System.currentTimeMillis()
  144. def tempScriptFile = "script_${env.BUILD_ID}_${now}.sh"
  145. writeFile(file: tempScriptFile, text: """
  146. #!${shell}
  147. ${script.stripIndent()}
  148. """)
  149. // On transfère le script sur la machine distante et on l'exécute
  150. sh """
  151. scp ${sshArgs} '${tempScriptFile}' 'root@${host}:/tmp/${tempScriptFile}'
  152. ssh ${sshArgs} root@${host} 'chmod +x /tmp/${tempScriptFile}; /tmp/${tempScriptFile}'
  153. """
  154. }
  155. body(remoteShell)
  156. }
  157. }
  158. }
  159. }