""" OpenStackEndpoint is Endpoint base class implementation for the OpenStack cloud service. """ from __future__ import print_function from __future__ import division from __future__ import absolute_import __RCSID__ = '29f99bbba (2021-08-20 10:44:54 +0200) Chris Burr ' import requests import json import base64 # DIRAC from DIRAC import gLogger, S_OK, S_ERROR from DIRAC.Resources.Cloud.Endpoint import Endpoint from DIRAC.Resources.Cloud.KeystoneClient import KeystoneClient from DIRAC.Core.Utilities.File import makeGuid DEBUG = False class OpenStackEndpoint(Endpoint): """ OpenStack implementation of the Cloud Endpoint interface """ def __init__(self, parameters=None, bootstrapParameters=None): super(OpenStackEndpoint, self).__init__(parameters=parameters, bootstrapParameters=bootstrapParameters) # logger self.log = gLogger.getSubLogger('OpenStackEndpoint') self.ks = None self.flavors = {} self.images = {} self.networks = {} self.computeURL = None self.imageURL = None self.networkURL = None self.network = None self.project = None self.projectID = None self.vmInfo = {} self.initialized = False result = self.initialize() if result['OK']: self.log.debug('OpenStackEndpoint created and validated') else: self.log.error(result['Message']) def initialize(self): self.caPath = self.parameters.get('CAPath', True) self.network = self.parameters.get("Network") self.project = self.parameters.get("Project") keyStoneURL = self.parameters.get("AuthURL") result = self.getProxyFileLocation() if result['OK']: self.parameters['Proxy'] = result['Value'] self.ks = KeystoneClient(keyStoneURL, self.parameters) result = self.ks.getToken() if not result['OK']: return result self.valid = True self.token = result['Value'] self.computeURL = self.ks.computeURL self.imageURL = self.ks.imageURL self.networkURL = self.ks.networkURL self.projectID = self.ks.projectID self.log.verbose("Service interfaces:\ncompute %s,\nimage %s,\nnetwork %s" % (self.computeURL, self.imageURL, self.networkURL)) result = self.getFlavors() if not result['OK']: self.valid = False result = self.getImages() if not result['OK']: self.valid = False self.getNetworks() return result def getFlavors(self): if not self.computeURL or not self.token: return S_ERROR('The endpoint object is not initialized') url = "%s/flavors/detail" % self.computeURL self.log.verbose("Getting flavors details on %s" % url) result = requests.get(url, headers={"X-Auth-Token": self.token}, verify=self.caPath) output = json.loads(result.text) for flavor in output['flavors']: self.flavors[flavor["name"]] = {"FlavorID": flavor['id'], "RAM": flavor['ram'], "NumberOfProcessors": flavor['vcpus']} return S_OK(self.flavors) def getImages(self): if not self.imageURL or not self.token: return S_ERROR('The endpoint object is not initialized') result = requests.get("%s/v2/images" % self.imageURL, headers={"X-Auth-Token": self.token}, verify=self.caPath) output = json.loads(result.text) for image in output['images']: self.images[image['name']] = {'id': image['id']} return S_OK(self.images) def getNetworks(self): """ Get a network object corresponding to the networkName :param str networkName: network name :return: S_OK|S_ERROR network object in case of S_OK """ try: result = requests.get("%s/v2.0/networks" % self.networkURL, headers={"X-Auth-Token": self.token}, verify=self.caPath) output = json.loads(result.text) except Exception as exc: return S_ERROR('Cannot get networks: %s' % str(exc)) for network in output['networks']: if network['project_id'] == self.projectID: self.networks[network["name"]] = {"NetworkID": network["id"]} return S_OK(self.networks) def createInstances(self, vmsToSubmit): outputDict = {} for nvm in range(vmsToSubmit): instanceID = makeGuid()[:8] result = self.createInstance(instanceID) if result['OK']: nodeID = result['Value'] self.log.debug('Created VM instance %s/%s' % (nodeID, instanceID)) nodeDict = {} nodeDict['InstanceID'] = instanceID nodeDict['NumberOfProcessors'] = self.parameters["NumberOfProcessors"] outputDict[nodeID] = nodeDict else: self.log.error('Failed to create OpenStack instance', '%s %s %s' % (nvm, instanceID, result['Message'])) break # We failed submission utterly if not outputDict: return S_ERROR('No VM submitted') return S_OK(outputDict) def createInstance(self, instanceID=''): """ 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. The node name has the following format: