""" OpenNebula Endpoint base class implementation for the OpenNebula cloud service. """ from __future__ import print_function from __future__ import division from __future__ import absolute_import __RCSID__ = "$Id" import os import base64 import ssl from requests.auth import HTTPBasicAuth try: from xmlrpc.client import ServerProxy except ImportError: # python2 compat from xmlrpclib import ServerProxy # DIRAC from DIRAC import gLogger, S_OK, S_ERROR from DIRAC.Resources.Cloud.Endpoint import Endpoint from DIRAC.Core.Utilities.File import makeGuid DEBUG = False # In case of debugging, switch class OpenNebulaEndpoint(Endpoint): """OpenNebula implementation of the Cloud Endpoint interface""" def __init__(self, parameters=None): super(OpenNebulaEndpoint, self).__init__(parameters=parameters, bootstrapParameters=parameters) self.parameters["HostCert"] = self.parameters.get("HostCert") self.parameters["HostKey"] = self.parameters.get("HostKey") self.bootstrapParameters["HostCert"] = self.parameters["HostCert"] self.bootstrapParameters["HostKey"] = self.parameters["HostKey"] self.log = gLogger.getSubLogger("OpenNebulaEndpoint") self.valid = False self.vmType = self.parameters.get("VMType") self.site = self.parameters.get("Site") # Prepare the authentication request parameters self.session = None self.authArgs = {} self.user = self.parameters.get("User") self.password = self.parameters.get("Password") self.loginMode = False if self.user and self.password: # we have the login/password case self.authArgs["auth"] = HTTPBasicAuth(self.user, self.password) self.authArgs["verify"] = False self.loginMode = True self.oneauth = self.user + ":" + self.password else: # we have the user proxy case # TODO: test self.userProxy = os.environ.get("X509_USER_PROXY") self.userProxy = self.parameters.get("Proxy", self.userProxy) if self.userProxy is None: self.log.error("User proxy is not defined") self.valid = False return self.authArgs["cert"] = self.userProxy self.caPath = self.parameters.get("CAPath") self.authArgs["verify"] = self.caPath if self.parameters.get("Auth") == "voms": self.authArgs["data"] = '{"auth":{"voms": true}}' self.serviceUrl = self.parameters.get("EndpointUrl") result = self.initialize() if result["OK"]: self.log.debug("OpenNebulaEndpoint created and validated") self.valid = True def initialize(self): self.log.info("INITIALIZE") ssl_ctx = ssl.create_default_context() ssl_ctx.check_hostname = False ssl_ctx.verify_mode = ssl.CERT_NONE self.rpcproxy = ServerProxy(self.serviceUrl, context=ssl_ctx) return S_OK() def createInstances(self, vmsToSubmit): outputDict = {} message = "" self.log.debug("vmsToSubmit " + str(vmsToSubmit)) for nvm in range(vmsToSubmit): instanceID = makeGuid()[:8] createPublicIP = "ipPool" in self.parameters result = self.createInstance(instanceID, createPublicIP) if result["OK"]: nodeID, publicIP = result["Value"] self.log.debug("Created VM instance %s/%s with publicIP %s" % (nodeID, instanceID, publicIP)) nodeDict = {} nodeDict["PublicIP"] = publicIP nodeDict["InstanceID"] = instanceID nodeDict["NumberOfProcessors"] = self.parameters.get("NumberOfProcessors", 1) outputDict[nodeID] = nodeDict else: message = result["Message"] break # We failed submission utterly if not outputDict: return S_ERROR("No VM submitted: %s" % message) return S_OK(outputDict) def createInstance(self, instanceID="", createPublicIP=True): """ Creates VM in OpenNebula cloud. one.template.instantiate XML-RPC method is called with the following parameters This creates a VM instance for the given boot image and creates a context script, taken the given parameters. Successful creation returns instance VM Boots a new node on the OpenStack server defined by self.endpointConfig. The 'personality' of the node is done by self.imageConfig. Both variables are defined on initialization phase. * template ID is obtained from Endpoint's `TemplateID` constructor parameter * VM name equals to `instanceID` method argument * onhold flag is obtained from Endpoint's `Onhold` constructor parameter * template string contains userdata scripts encoded in base64 and DNS servers adresses The node name has the following format: