def __init__(self, imageElementName, endpointElementName): """ Creates an instance that will manage appliances of a given type on a specific cloud infrastructure. Separate instances must be created for different cloud infrastructures and different appliances. The configuration is validated only when the connect() method is called. This method MUST be called before any of the other methods. :Parameters: **imageElementName** - `string` element name in CS:/Resources/VirtualMachines/Images describing the type of appliance (image) to instantiate **endpointElementName** - `string` element name in CS:/Resources/VirtualMachines/CloudEndpoint giving the configuration parameters for the StratusLab cloud endpoint """ self.log = gLogger.getSubLogger('StratusLabImage_%s_%s: ' % (endpointElementName, imageElementName)) self._imageConfig = ImageConfiguration(imageElementName) self._endpointConfig = StratusLabEndpointConfiguration(endpointElementName) self._impl = None
def __init__( self, imageName, endPoint ): """ Constructor: uses NovaConfiguration to parse the endPoint CS configuration and ImageConfiguration to parse the imageName CS configuration. :Parameters: **imageName** - `string` imageName as defined on CS:/Resources/VirtualMachines/Images **endPoint** - `string` endPoint as defined on CS:/Resources/VirtualMachines/CloudEndpoint """ # logger self.log = gLogger.getSubLogger( 'NovaImage %s: ' % imageName ) self.imageName = imageName self.endPoint = endPoint # their config() method returns a dictionary with the parsed configuration # they also provide a validate() method to make sure it is correct self.__imageConfig = ImageConfiguration( imageName ) self.__novaConfig = NovaConfiguration( endPoint ) # this object will connect to the server. Better keep it private. self.__clinova = None
def __init__( self, imageName, endPoint ): """ Constructor: uses AmazonConfiguration to parse the endPoint CS configuration and ImageConfiguration to parse the imageName CS configuration. :Parameters: **imageName** - `string` imageName as defined on CS:/Resources/VirtualMachines/Images **endPoint** - `string` endPoint as defined on CS:/Resources/VirtualMachines/CloudEndpoint """ # logger self.log = gLogger.getSubLogger( 'AmazonImage %s: ' % imageName ) self.imageName = imageName self.endPoint = endPoint # their config() method returns a dictionary with the parsed configuration # they also provide a validate() method to make sure it is correct self.__imageConfig = ImageConfiguration( imageName, endPoint ) self.__amazonConfig = AmazonConfiguration( endPoint ) self.__cliamazon = None
def __init__( self, imageName, endPoint): """ The OCCI Image Interface provides the functionality required to use a standard occi cloud infrastructure. Constructor: uses OcciConfiguration to parse the endPoint CS configuration and ImageConfiguration to parse the imageName CS configuration. :Parameters: **imageName** - `string` imageName as defined on CS:/Resources/VirtualMachines/Images **endPoint** - `string` endPoint as defined on CS:/Resources/VirtualMachines/CloudEndpoint """ # logger self.log = gLogger.getSubLogger( 'OcciImage %s: ' % imageName ) self.imageName = imageName self.endPoint = endPoint # their config() method returns a dictionary with the parsed configuration # they also provide a validate() method to make sure it is correct self.__imageConfig = ImageConfiguration( imageName ) self.__occiConfig = OcciConfiguration( endPoint ) # this object will connect to the server. Better keep it private. self.__cliocci = None # error status of the image with the asociated context (endpoing + image), basically for check_connction propagation self.__errorStatus = None
class NovaImage: """ NovaImage class. """ def __init__( self, imageName, endPoint ): """ Constructor: uses NovaConfiguration to parse the endPoint CS configuration and ImageConfiguration to parse the imageName CS configuration. :Parameters: **imageName** - `string` imageName as defined on CS:/Resources/VirtualMachines/Images **endPoint** - `string` endPoint as defined on CS:/Resources/VirtualMachines/CloudEndpoint """ # logger self.log = gLogger.getSubLogger( 'NovaImage %s: ' % imageName ) self.imageName = imageName self.endPoint = endPoint # their config() method returns a dictionary with the parsed configuration # they also provide a validate() method to make sure it is correct self.__imageConfig = ImageConfiguration( imageName ) self.__novaConfig = NovaConfiguration( endPoint ) # this object will connect to the server. Better keep it private. self.__clinova = None def connectNova( self ): """ Method that issues the connection with the OpenStack server. In order to do it, validates the CS configurations. auth user/password or x509 proxy :return: S_OK | S_ERROR """ # Before doing anything, make sure the configurations make sense # ImageConfiguration validImage = self.__imageConfig.validate() if not validImage[ 'OK' ]: return validImage # EndpointConfiguration validNova = self.__novaConfig.validate() if not validNova[ 'OK' ]: return validNova # Get authentication configuration auth, u, p = self.__novaConfig.authConfig() if auth == 'userpasswd': user = u secret = p elif auth == 'proxy': proxyPath = u else: self.__errorStatus = "auth not supported (userpasswd/proxy)" self.log.error( self.__errorStatus ) return # Create the libcloud and novaclient objects in NovaClient.Nova11 if auth == 'userpasswd': self.__clinova = NovaClient( user=user, secret=secret, endpointConfig=self.__novaConfig.config(), imageConfig=self.__imageConfig.config() ) else: self.__clinova = NovaClient( user=proxyPath, secret=None, endpointConfig=self.__novaConfig.config(), imageConfig=self.__imageConfig.config() ) # Check connection to the server result = self.__clinova.check_connection() if not result[ 'OK' ]: self.log.error( "connectNova" ) self.log.error( result[ 'Message' ] ) else: self.log.info( "Successful connection check" ) return result def startNewInstance( self, vmdiracInstanceID, runningPodRequirements ): """ Once the connection is stablished using the `connectNova` method, we can boot nodes. To do so, the config in __imageConfig and __novaConfig applied to NovaClient initialization is applied. :return: S_OK | S_ERROR """ self.log.info( "Booting %s / %s" % ( self.__imageConfig.config()[ 'bootImageName' ], self.__novaConfig.config()[ 'ex_force_auth_url' ] ) ) result = self.__clinova.create_VMInstance( vmdiracInstanceID, runningPodRequirements ) if not result[ 'OK' ]: self.log.error( "startNewInstance" ) self.log.error( result[ 'Message' ] ) return result def getInstanceStatus( self, uniqueId ): """ Given the node ID, returns the status. Bear in mind, is the translation of the status done by libcloud and then reversed to a string. Its possible values are: RUNNING, REBOOTING, TERMINATED, PENDING, UNKNOWN. :Parameters: **uniqueId** - `string` node ID, given by the OpenStack service :return: S_OK | S_ERROR """ result = self.__clinova.getStatus_VMInstance( uniqueId ) if not result[ 'OK' ]: self.log.error( "getInstanceStatus: %s" % uniqueId ) self.log.error( result[ 'Message' ] ) return result def stopInstance( self, uniqueId, public_ip ): """ Method that destroys the node and if using floating IPs and frees the floating IPs if any. :Parameters: **uniqueId** - `string` node ID, given by the OpenStack service **public_ip** - `string` public IP of the VM, needed for some setups ( floating IP ). :return: S_OK | S_ERROR """ # FIXME: maybe it makes sense to get the public_ip in Nova11 and encapsulate it. # FIXME: after all, is an implementation detail. result = self.__clinova.terminate_VMinstance( uniqueId, public_ip ) if not result[ 'OK' ]: self.log.error( "stopInstance: %s, %s" % ( uniqueId, public_ip ) ) self.log.error( result[ 'Message' ] ) return result def contextualizeInstance( self, uniqueId, public_ip, cpuTime, submitPool ): """ This method is not a regular method in the sense that is not generic at all. It will be called only of those VMs which need after-booting contextualisation, for the time being, just ssh contextualisation. On the other hand, one can say this is the most generic method because you don't need any particular "golden" image, like HEPiX, just whatever linux image with available ssh connectivity :Parameters: **uniqueId** - `string` node ID, given by the OpenStack service **public_ip** - `string` public IP of the VM, needed for asynchronous contextualisation :return: S_OK | S_ERROR """ # FIXME: maybe is worth hiding the public_ip attribute and getting it on # FIXME: the contextualize step. result = self.__clinova.contextualize_VMInstance( uniqueId, public_ip, cpuTime, submitPool ) if not result[ 'OK' ]: self.log.error( "contextualizeInstance: %s, %s" % ( uniqueId, public_ip ) ) self.log.error( result[ 'Message' ] ) return result return S_OK( uniqueId )
class AmazonImage: """ AmazonImage class. """ def __init__( self, imageName, endPoint ): """ Constructor: uses AmazonConfiguration to parse the endPoint CS configuration and ImageConfiguration to parse the imageName CS configuration. :Parameters: **imageName** - `string` imageName as defined on CS:/Resources/VirtualMachines/Images **endPoint** - `string` endPoint as defined on CS:/Resources/VirtualMachines/CloudEndpoint """ # logger self.log = gLogger.getSubLogger( 'AmazonImage %s: ' % imageName ) self.imageName = imageName self.endPoint = endPoint # their config() method returns a dictionary with the parsed configuration # they also provide a validate() method to make sure it is correct self.__imageConfig = ImageConfiguration( imageName, endPoint ) self.__amazonConfig = AmazonConfiguration( endPoint ) self.__cliamazon = None def connectAmazon( self ): """ Method that issues the connection with Amazon. In order to do it, validates the CS configurations. auth secretaccesskey :return: S_OK | S_ERROR """ # Before doing anything, make sure the configurations make sense # ImageConfiguration validImage = self.__imageConfig.validate() if not validImage[ 'OK' ]: return validImage # EndpointConfiguration validAmazon = self.__amazonConfig.validate() if not validAmazon[ 'OK' ]: return validAmazon # Get authentication configuration # not needed jet, only secretaccesskey method #if not auth == 'secretaccesskey': # self.__errorStatus = "auth not supported (currently secretaccesskey)" # self.log.error( self.__errorStatus ) # return # this object will connect to the Amazon server. Better keep it private. self.__cliamazon = AmazonClient( endpointConfig=self.__amazonConfig.config(), imageConfig=self.__imageConfig.config() ) # Check connection to the server result = self.__cliamazon.check_connection() if not result[ 'OK' ]: self.log.error( "connectAmazon" ) self.log.error( result[ 'Message' ] ) else: self.log.info( "Successful connection check" ) return result def startNewInstance( self, runningPodRequirements ): """ Once the connection is stablished using the `connectAmazon` method, we can boot nodes. To do so, the config in __imageConfig and __amazonConfig applied to AmazonClient initialization is applied. :return: S_OK | S_ERROR """ self.log.info( "Booting %s / %s" % ( self.__imageConfig.config()[ 'bootImageName' ], self.__amazonConfig.config()[ 'endpointURL' ] ) ) result = self.__cliamazon.create_VMInstance( runningPodRequirements ) if not result[ 'OK' ]: self.log.error( "startNewInstance" ) self.log.error( result[ 'Message' ] ) return result def getInstanceStatus( self, uniqueId ): """ Given the node ID and the current instanceName (AMI in Amazon terms), returns the status. :Parameters: **uniqueId** - `string` node ID, given by the OpenStack service :return: S_OK | S_ERROR """ result = self.__cliamazon.getStatus_VMInstance( uniqueId, self.imageName ) if not result[ 'OK' ]: self.log.error( "getInstanceStatus: %s" % uniqueId ) self.log.error( result[ 'Message' ] ) return result def stopInstance( self, uniqueId ): """ Method that destroys the instance :Parameters: **uniqueId** - `string` :return: S_OK | S_ERROR """ result = self.__cliamazon.terminate_VMinstance( uniqueId ) if not result[ 'OK' ]: self.log.error( "stopInstance: %s " % ( uniqueId ) ) self.log.error( result[ 'Message' ] ) return result
class OcciImage: def __init__( self, imageName, endPoint): """ The OCCI Image Interface provides the functionality required to use a standard occi cloud infrastructure. Constructor: uses OcciConfiguration to parse the endPoint CS configuration and ImageConfiguration to parse the imageName CS configuration. :Parameters: **imageName** - `string` imageName as defined on CS:/Resources/VirtualMachines/Images **endPoint** - `string` endPoint as defined on CS:/Resources/VirtualMachines/CloudEndpoint """ # logger self.log = gLogger.getSubLogger( 'OcciImage %s: ' % imageName ) self.imageName = imageName self.endPoint = endPoint # their config() method returns a dictionary with the parsed configuration # they also provide a validate() method to make sure it is correct self.__imageConfig = ImageConfiguration( imageName ) self.__occiConfig = OcciConfiguration( endPoint ) # this object will connect to the server. Better keep it private. self.__cliocci = None # error status of the image with the asociated context (endpoing + image), basically for check_connction propagation self.__errorStatus = None def connectOcci( self ): """ Method that issues the connection with the OpenNebula server. In order to do it, validates the CS configurations. OcciClient which will check the connection. :return: S_OK | S_ERROR """ # Before doing anything, make sure the configurations make sense # ImageConfiguration validImage = self.__imageConfig.validate() if not validImage[ 'OK' ]: return validImage # EndpointConfiguration validOcci = self.__occiConfig.validate() if not validOcci[ 'OK' ]: return validOcci # Get authentication configuration auth, u, p = self.__occiConfig.authConfig() if auth == 'userpasswd': user = u secret = p elif auth == 'proxy': userCredPath = u else: self.__errorStatus = "auth not supported (userpasswd/proxy)" self.log.error( self.__errorStatus ) return # Create the occiclient objects in OcciClient: if self.__occiConfig.cloudDriver() == 'occi-0.8': if auth == 'userpasswd': from VMDIRAC.WorkloadManagementSystem.Client.Occi08 import OcciClient self.__cliocci = OcciClient(user, secret, self.__occiConfig.config(), self.__imageConfig.config()) else: self.__errorStatus = "%s is not supported auth method for %s driver" % (auth,self.__occiConfig.cloudDriver()) self.log.error( self.__errorStatus ) return S_ERROR( self.__errorStatus ) elif self.__occiConfig.cloudDriver() == 'occi-0.9': if auth == 'userpasswd': from VMDIRAC.WorkloadManagementSystem.Client.Occi09 import OcciClient self.__cliocci = OcciClient(user, secret, self.__occiConfig.config(), self.__imageConfig.config()) else: self.__errorStatus = "%s is not supported auth method for %s driver" % (auth,self.__occiConfig.cloudDriver()) self.log.error( self.__errorStatus ) return S_ERROR( self.__errorStatus ) elif self.__occiConfig.cloudDriver() == 'rocci-1.1': if auth == 'proxy': from VMDIRAC.WorkloadManagementSystem.Client.Rocci11 import OcciClient self.__cliocci = OcciClient(userCredPath, None, None, self.__occiConfig.config(), self.__imageConfig.config()) elif auth == 'userpasswd': from VMDIRAC.WorkloadManagementSystem.Client.Rocci11 import OcciClient self.__cliocci = OcciClient(None, user, secret, self.__occiConfig.config(), self.__imageConfig.config()) else: self.__errorStatus = "%s is not supported auth method for %s driver" % (auth,self.__occiConfig.cloudDriver()) self.log.error( self.__errorStatus ) return S_ERROR( self.__errorStatus ) else: self.__errorStatus = "Driver %s not supported" % self.__cloudDriver self.log.error( self.__errorStatus ) return S_ERROR( self.__errorStatus ) # Check connection to the server request = self.__cliocci.check_connection() if request.returncode != 0: self.__errorStatus = "Can't connect to OCCI URI %s\n%s" % (self.__occiConfig.occiURI(), request.stdout) self.log.error( self.__errorStatus ) return S_ERROR( self.__errorStatus ) else: self.log.info( "Successful connection check to %s" % (self.__occiConfig.occiURI()) ) return S_OK( request.stdout ) def startNewInstance( self, cpuTime = None, submitPool = None, runningPodRequirements = None, instanceID = None ): """ Prior to use, virtual machine images are uploaded to the OCCI cloud manager assigned an id (OII in a URI). cpuTime and submitPool have been scheck ad VMDIRECTOR level, used for maintenance ONE 0.8 drivers """ if self.__errorStatus: return S_ERROR( self.__errorStatus ) self.log.info( "Starting new instance for DIRAC image: %s; to endpoint %s" % ( self.imageName, self.endPoint) ) request = self.__cliocci.create_VMInstance(cpuTime,submitPool,runningPodRequirements,instanceID) if request.returncode != 0: self.__errorStatus = "Can't create instance for DIRAC image: %s; to endpoint %s" % ( self.imageName, self.endPoint) self.log.error( self.__errorStatus ) return S_ERROR( self.__errorStatus ) if self.__occiConfig.cloudDriver() == 'rocci-1.1': firstcoma = request.stdout.find(",") idVM = request.stdout[0:firstcoma] last = len(request.stdout) firstcoma += 1 publicIP = request.stdout[firstcoma:last] return S_OK( ( idVM, publicIP ) ) return S_OK( request.stdout ) def stopInstance( self, VMinstanceId ): """ Simple call to terminate a VM based on its id """ request = self.__cliocci.terminate_VMinstance( VMinstanceId ) if request.returncode != 0: self.__errorStatus = "Can't delete VM instance ide %s from endpoint URL %s\n%s" % (VMinstanceId, self.__occiConfig.occiURI(), request.stdout) self.log.error( self.__errorStatus ) return S_ERROR( self.__errorStatus ) return S_OK( request.stdout ) def getInstanceStatus( self, uniqueId ): """ Given the node ID, returns the status. :Parameters: **uniqueId** - `string` node ID, given by the OpenNebula service :return: S_OK | S_ERROR """ request = self.__cliocci.getStatus_VMInstance( uniqueId ) if request.returncode != 0: self.__errorStatus = "getInstanceStatus: %s, msg: %s" % (uniqueId, request.stderr) self.log.error( self.__errorStatus ) return S_ERROR( self.__errorStatus ) return S_OK( request.stdout ) def contextualizeInstance( self, uniqueId, public_ip, cpuTime, submitPool ): """ This method is not a regular method in the sense that is not generic at all. It will be called only of those VMs which need after-booting contextualisation, for the time being, just ssh contextualisation. On the other hand, one can say this is the most generic method because you don't need any particular "golden" image, like HEPiX, just whatever linux image with available ssh connectivity :Parameters: **uniqueId** - `string` node ID, given by the OpenNebula service **public_ip** - `string` public IP of the VM, needed for asynchronous contextualisation :return: S_OK | S_ERROR """ return self.__cliocci.contextualize_VMInstance( uniqueId, public_ip, cpuTime, submitPool )
class StratusLabImage: """ Provides interface for managing virtual machine instances of a particular appliance on a StratusLab cloud infrastructure. """ def __init__(self, imageElementName, endpointElementName): """ Creates an instance that will manage appliances of a given type on a specific cloud infrastructure. Separate instances must be created for different cloud infrastructures and different appliances. The configuration is validated only when the connect() method is called. This method MUST be called before any of the other methods. :Parameters: **imageElementName** - `string` element name in CS:/Resources/VirtualMachines/Images describing the type of appliance (image) to instantiate **endpointElementName** - `string` element name in CS:/Resources/VirtualMachines/CloudEndpoint giving the configuration parameters for the StratusLab cloud endpoint """ self.log = gLogger.getSubLogger('StratusLabImage_%s_%s: ' % (endpointElementName, imageElementName)) self._imageConfig = ImageConfiguration(imageElementName) self._endpointConfig = StratusLabEndpointConfiguration(endpointElementName) self._impl = None def connect(self): """ Tests the connection to the StratusLab cloud infrastructure. Validates the configuration and then makes a request to list active virtual machine instances to ensure that the connection works. :return: S_OK | S_ERROR """ result = self._imageConfig.validate() self._logResult(result, 'image configuration check') if not result['OK']: return result result = self._endpointConfig.validate() self._logResult(result, 'endpoint configuration check') if not result['OK']: return result try: self._impl = StratusLabClient(self._endpointConfig, self._imageConfig) except Exception, e: return S_ERROR(e) result = self._impl.check_connection() return self._logResult(result, 'connect')