Пример #1
0
 def __startListenning(self):
     """
     Creates the control connection
     Args:
         None
     Returns:
         Nothing
     """    
     networkInterface = self.__parser.getConfigurationParameter("vncNetworkInterface")
     listenningPort = self.__parser.getConfigurationParameter("listenningPort")
     try :
         self.__vncServerIP = get_ip_address(networkInterface)
     except Exception :
         raise Exception("Error: the network interface '{0}' is not ready. Exiting now".format(networkInterface))    
     self.__ftpTimeout = self.__parser.getConfigurationParameter("FTPTimeout")
     self.__listenningPort = listenningPort
     self.__networkManager = NetworkManager(self.__parser.getConfigurationParameter("certificatePath"))
     self.__networkManager.startNetworkService()
     self.__useSSL = self.__parser.getConfigurationParameter("useSSL")
     self.__packetManager = VMServerPacketHandler(self.__networkManager)            
     self.__connectToDatabases("VMServerDB", self.__parser.getConfigurationParameter("databaseUserName"), self.__parser.getConfigurationParameter("databasePassword"))
         
     self.__domainHandler = DomainHandler(self.__commandsDBConnector, self.__vncServerIP, self.__networkManager, self.__packetManager, self.__listenningPort, 
                                              self.__parser.getConfigurationParameter("useQEMUWebsockets"),
                                              self.__parser.getConfigurationParameter("websockifyPath"),
                                              self.__parser.getConfigurationParameter("configFilePath"),
                                              self.__parser.getConfigurationParameter("sourceImagePath"), self.__parser.getConfigurationParameter("executionImagePath"),
                                              self.__parser.getConfigurationParameter("passwordLength"))
     self.__domainHandler.connectToLibvirt(self.__parser.getConfigurationParameter("vncNetworkInterface"), 
                                               self.__parser.getConfigurationParameter("vnName"), self.__parser.getConfigurationParameter("gatewayIP"), 
                                               self.__parser.getConfigurationParameter("netMask"), self.__parser.getConfigurationParameter("dhcpStartIP"), 
                                               self.__parser.getConfigurationParameter("dhcpEndIP"), self.__parser.getConfigurationParameter("createVirtualNetworkAsRoot"))
         
     self.__domainHandler.doInitialCleanup()
     self.__deleteTemporaryZipFiles()
     self.__fileTransferThread = FileTransferThread(self.__networkManager, self.__listenningPort, self.__packetManager,
                                                    self.__parser.getConfigurationParameter("TransferDirectory"),
                                                    self.__parser.getConfigurationParameter("FTPTimeout"), 
                                                    self.__parser.getConfigurationParameter("MaxTransferAttempts"), self.__commandsDBConnector, self.__useSSL)
     self.__compressionThread = CompressionThread(self.__parser.getConfigurationParameter("TransferDirectory"), self.__parser.getConfigurationParameter("sourceImagePath"),
                                                  self.__parser.getConfigurationParameter("configFilePath"),
                                                  self.__commandsDBConnector, self.__domainHandler, self.__networkManager, self.__listenningPort, self.__packetManager)
     self.__fileTransferThread.start()
     self.__compressionThread.start()
     self.__networkManager.listenIn(self.__listenningPort, self, self.__useSSL)
Пример #2
0
class VMServerReactor(NetworkCallback):
    """
    Virtual machine server packet reactor
    """
    def __init__(self, configurationFileParser):
        """
        Initializes the reactor's state, establishes the connection with the database
        and creates the control connection
        Args:
            configurationFileParser: the virtual machine server's configuration file parser
        """        
        self.__finished = False
        self.__emergencyStop = False
        self.__fileTransferThread = None
        self.__compressionThread = None
        self.__networkManager = None
        self.__parser = configurationFileParser
        self.__domainHandler = None
        self.__domainTimeout = 0
        try :
            self.__connectToDatabases("VMServerDB", self.__parser.getConfigurationParameter("databaseUserName"), 
                                      self.__parser.getConfigurationParameter("databasePassword"))
            self.__startListenning()
        except Exception as e:
            print e.message
            self.__emergencyStop = True
            self.__finished = True
        
    def __connectToDatabases(self, databaseName, user, password) :
        """
        Establishes the connection with the database
        Args:
            databaseName: a database name
            user: a SQL username
            password: the user's password
        Returns:
            Nothing
        """
        self.__commandsDBConnector = VMServerDBConnector(user, password, databaseName)  
            
    def __startListenning(self):
        """
        Creates the control connection
        Args:
            None
        Returns:
            Nothing
        """    
        networkInterface = self.__parser.getConfigurationParameter("vncNetworkInterface")
        listenningPort = self.__parser.getConfigurationParameter("listenningPort")
        try :
            self.__vncServerIP = get_ip_address(networkInterface)
        except Exception :
            raise Exception("Error: the network interface '{0}' is not ready. Exiting now".format(networkInterface))    
        self.__ftpTimeout = self.__parser.getConfigurationParameter("FTPTimeout")
        self.__listenningPort = listenningPort
        self.__networkManager = NetworkManager(self.__parser.getConfigurationParameter("certificatePath"))
        self.__networkManager.startNetworkService()
        self.__useSSL = self.__parser.getConfigurationParameter("useSSL")
        self.__packetManager = VMServerPacketHandler(self.__networkManager)            
        self.__connectToDatabases("VMServerDB", self.__parser.getConfigurationParameter("databaseUserName"), self.__parser.getConfigurationParameter("databasePassword"))
            
        self.__domainHandler = DomainHandler(self.__commandsDBConnector, self.__vncServerIP, self.__networkManager, self.__packetManager, self.__listenningPort, 
                                                 self.__parser.getConfigurationParameter("useQEMUWebsockets"),
                                                 self.__parser.getConfigurationParameter("websockifyPath"),
                                                 self.__parser.getConfigurationParameter("configFilePath"),
                                                 self.__parser.getConfigurationParameter("sourceImagePath"), self.__parser.getConfigurationParameter("executionImagePath"),
                                                 self.__parser.getConfigurationParameter("passwordLength"))
        self.__domainHandler.connectToLibvirt(self.__parser.getConfigurationParameter("vncNetworkInterface"), 
                                                  self.__parser.getConfigurationParameter("vnName"), self.__parser.getConfigurationParameter("gatewayIP"), 
                                                  self.__parser.getConfigurationParameter("netMask"), self.__parser.getConfigurationParameter("dhcpStartIP"), 
                                                  self.__parser.getConfigurationParameter("dhcpEndIP"), self.__parser.getConfigurationParameter("createVirtualNetworkAsRoot"))
            
        self.__domainHandler.doInitialCleanup()
        self.__deleteTemporaryZipFiles()
        self.__fileTransferThread = FileTransferThread(self.__networkManager, self.__listenningPort, self.__packetManager,
                                                       self.__parser.getConfigurationParameter("TransferDirectory"),
                                                       self.__parser.getConfigurationParameter("FTPTimeout"), 
                                                       self.__parser.getConfigurationParameter("MaxTransferAttempts"), self.__commandsDBConnector, self.__useSSL)
        self.__compressionThread = CompressionThread(self.__parser.getConfigurationParameter("TransferDirectory"), self.__parser.getConfigurationParameter("sourceImagePath"),
                                                     self.__parser.getConfigurationParameter("configFilePath"),
                                                     self.__commandsDBConnector, self.__domainHandler, self.__networkManager, self.__listenningPort, self.__packetManager)
        self.__fileTransferThread.start()
        self.__compressionThread.start()
        self.__networkManager.listenIn(self.__listenningPort, self, self.__useSSL)
        
    def __deleteTemporaryZipFiles(self):
        """
        Deletes the temporary zip files
        Args:
            None
        Returns:
            Nothing
        """
        transfer_dir_path = self.__parser.getConfigurationParameter("TransferDirectory")
        for filePath in os.listdir(transfer_dir_path) :
            fileName = os.path.splitext(filePath)[0]
            if re.match("[^0-9]", fileName):
                # The non-temporary zip files only have numbers on their names
                os.remove(os.path.join(transfer_dir_path, filePath))
    
    def shutdown(self):
        """
        Shuts down the virtual machine server
        Args:
            None
        Returns:
            Nothing
        """                
            
        if (self.__emergencyStop) :            
            self.__domainTimeout = 0
            
        self.__domainHandler.shutdown(self.__domainTimeout)                   
        
        if (self.__fileTransferThread != None) :
            self.__fileTransferThread.stop()
            self.__fileTransferThread.join()
        if (self.__compressionThread != None) :
            self.__compressionThread.stop()
            self.__compressionThread.join()
            
        if (self.__networkManager != None) :
            self.__networkManager.stopNetworkService() # Dejar de atender peticiones inmediatamente
        sys.exit()              
        
    def processPacket(self, packet):
        """
        Processes a packet sent from the cluster server
        Args:
            packet: the packet to process
        Returns:
            Nothing
        """
        data = self.__packetManager.readPacket(packet)
        if (data["packet_type"] == VM_SERVER_PACKET_T.CREATE_DOMAIN) :
            self.__domainHandler.createDomain(data["MachineID"], data["UserID"], data["CommandID"])
        elif (data["packet_type"] == VM_SERVER_PACKET_T.SERVER_STATUS_REQUEST) :
            self.__sendStatusData()
        elif (data["packet_type"] == VM_SERVER_PACKET_T.USER_FRIENDLY_SHUTDOWN) :
            self.__domainTimeout = data["Timeout"]
            self.__finished = True
        elif (data["packet_type"] == VM_SERVER_PACKET_T.HALT) :
            self.__domainTimeout = 0
            self.__finished = True
        elif (data['packet_type'] == VM_SERVER_PACKET_T.QUERY_ACTIVE_VM_DATA) :
            self.__sendDomainsVNCConnectionData()
        elif (data['packet_type'] == VM_SERVER_PACKET_T.DESTROY_DOMAIN) :
            self.__domainHandler.destroyDomain(data["DomainID"])
        elif (data['packet_type'] == VM_SERVER_PACKET_T.REBOOT_DOMAIN) :
            self.__domainHandler.rebootDomain(data["DomainID"])
        elif (data['packet_type'] == VM_SERVER_PACKET_T.QUERY_ACTIVE_DOMAIN_UIDS) :
            self.__sendActiveDomainUIDs()
        elif (data['packet_type'] == VM_SERVER_PACKET_T.IMAGE_EDITION) :
            self.__processImageEditionPacket(data)
        elif (data['packet_type'] == VM_SERVER_PACKET_T.DEPLOY_IMAGE) :
            self.__processDeployImagePacket(data)
        elif (data['packet_type'] == VM_SERVER_PACKET_T.DELETE_IMAGE) :
            self.__processDeleteImagePacket(data)
            
    def __processDeployImagePacket(self, data):
        """
        Processes an image deployment packet
        Args:
            data: a dictionary containing the packet to process' data
        Returns:
            Nothing
        """
        data.pop("packet_type")
        data["Transfer_Type"] = TRANSFER_T.DEPLOY_IMAGE
        self.__commandsDBConnector.addToTransferQueue(data)
        
    def __processDeleteImagePacket(self, data):
        
        isBootable = self.__commandsDBConnector.getBootableFlag(data["ImageID"])
        
        if(isBootable):            
            osImagePath = os.path.join(self.__parser.getConfigurationParameter("sourceImagePath") 
                                   ,self.__commandsDBConnector.getOSImagePath(data["ImageID"]))
            definitionFilePath = os.path.join(self.__parser.getConfigurationParameter("configFilePath") 
                                   ,self.__commandsDBConnector.getDefinitionFilePath(data["ImageID"]))
            
            try :
                
                self.__commandsDBConnector.deleteImage(data["ImageID"])                
                ChildProcessManager.runCommandInForeground("rm -rf " + os.path.dirname(osImagePath), VMServerException)                
                ChildProcessManager.runCommandInForeground("rm -rf " + os.path.dirname(definitionFilePath), VMServerException)
                p = self.__packetManager.createConfirmationPacket(VM_SERVER_PACKET_T.IMAGE_DELETED, data["ImageID"], data["CommandID"])
            except Exception:
                p = self.__packetManager.createErrorPacket(VM_SERVER_PACKET_T.IMAGE_DELETION_ERROR, ERROR_DESC_T.VM_SRVR_INTERNAL_ERROR, 
                                                            data["CommandID"])                
            
        else:
            if (isBootable != None) :
                errorCode = ERROR_DESC_T.VMSRVR_LOCKED_IMAGE
            else :
                errorCode = ERROR_DESC_T.VMSRVR_UNKNOWN_IMAGE
            
            p = self.__packetManager.createErrorPacket(VM_SERVER_PACKET_T.IMAGE_DELETION_ERROR, errorCode, 
                                                       data["CommandID"])
        
        self.__networkManager.sendPacket('', self.__listenningPort, p)
            
        
        
    def __processImageEditionPacket(self, data):
        """
        Processes an image edition packet
        Args:
            data: a dictionary containing the packet to process' data
        Returns:
            Nothing
        """
        data.pop("packet_type")
        if (data["Modify"]) :
            data["Transfer_Type"] = TRANSFER_T.EDIT_IMAGE
        else :
            data["Transfer_Type"] = TRANSFER_T.CREATE_IMAGE
        data.pop("Modify")
        self.__commandsDBConnector.addToTransferQueue(data)

    def __sendDomainsVNCConnectionData(self):
        '''
        Sends the domains' VNC connection data to the cluster server
        Args:
            None
        Returns:
            Nothing
        '''
        vncConnectionData = self.__commandsDBConnector.getDomainsConnectionData()
        segmentSize = 150
        segmentCounter = 1
        outgoingData = []
        if (len(vncConnectionData) == 0):
            segmentCounter = 0
        segmentNumber = (len(vncConnectionData) / segmentSize)
        if (len(vncConnectionData) % segmentSize != 0) :
            segmentNumber += 1
            sendLastSegment = True
        else :
            sendLastSegment = segmentNumber == 0 
        for connectionParameters in vncConnectionData :
            outgoingData.append(connectionParameters)
            if (len(outgoingData) >= segmentSize) :
                # Flush
                packet = self.__packetManager.createActiveVMsVNCDataPacket(self.__vncServerIP, segmentCounter, segmentNumber, outgoingData)
                self.__networkManager.sendPacket('', self.__listenningPort, packet)
                outgoingData = []
                segmentCounter += 1
        # Send the last segment
        if (sendLastSegment) :
            packet = self.__packetManager.createActiveVMsVNCDataPacket(self.__vncServerIP, segmentCounter, segmentNumber, outgoingData)
            self.__networkManager.sendPacket('', self.__listenningPort, packet)         
    
    def __sendStatusData(self):
        """
        Sends the server's status data to the cluster server
        Args:
            None
        Returns:
            Nothing
        """
        info = self.__domainHandler.getLibvirtStatusData()
        realCPUNumber = multiprocessing.cpu_count()
        freeOutput = ChildProcessManager.runCommandInForeground("free -k", VMServerException)
        
        # free's output contains the following lines and collumns:
        #              total       used       free     shared    buffers     cached
        # Mem:    4146708480 3939934208  206774272          0  224706560 1117671424
        # -/+ buffers/cache: 2597556224 1549152256
        # Swap:   2046816256   42455040 2004361216
        #
        # We must get the third line
           
        availableMemory = int(freeOutput.split("\n")[1].split()[1])
        freeMemory = int(freeOutput.split("\n")[2].split()[2])
        
        freeStorageSpace, availableStorageSpace, freeTemporaryStorage, availableTemporaryStorage = self.__generateDiskStats()
        packet = self.__packetManager.createVMServerStatusPacket(self.__vncServerIP, info["#domains"], freeMemory, availableMemory, 
                                                                 freeStorageSpace, availableStorageSpace, 
                                                                 freeTemporaryStorage, availableTemporaryStorage,
                                                                 info["#vcpus"], realCPUNumber)
        self.__networkManager.sendPacket('', self.__listenningPort, packet) 
        
    def __generateDiskStats(self):
        """
        Generates the hard disk usage statistics
        Args:
            None
        Returns:
            the free and available storage and temporary space
        """
        diskStats_storage = os.statvfs(self.__parser.getConfigurationParameter("sourceImagePath"))
        diskStats_temporaryData = os.statvfs(self.__parser.getConfigurationParameter("executionImagePath"))
        allocatedStorageSpace, allocatedTemporaryStorageSpace = self.__checkDiskImagesSpace()
        freeStorageSpace = diskStats_storage.f_bfree * diskStats_storage.f_frsize / 1024 - allocatedStorageSpace
        availableStorageSpace = diskStats_storage.f_blocks * diskStats_storage.f_frsize / 1024
        freeTemporaryStorageSpace = diskStats_temporaryData.f_bfree * diskStats_temporaryData.f_frsize / 1024 - allocatedTemporaryStorageSpace
        availableTemporaryStorageSpace = diskStats_temporaryData.f_blocks * diskStats_temporaryData.f_frsize / 1024
        return freeStorageSpace, availableStorageSpace, freeTemporaryStorageSpace, availableTemporaryStorageSpace
    
    def __checkDiskImagesSpace(self):
        """
        Checks how much disk space must be allocated for the active virtual machines' disk images
        Args:
            None
        Returns:
            the storage and temporary storage space that must be allocated.
        """
        activeDomainNames = self.__commandsDBConnector.getRegisteredDomainNames()
        allocatedStorageSpace = 0
        allocatedTemporaryStorageSpace = 0
        for domainName in activeDomainNames:            
            imageID = self.__commandsDBConnector.getDomainImageID(domainName)
            if (imageID == None) :
                return 0, 0
            dataImagePath = self.__commandsDBConnector.getDomainDataImagePath(domainName)
            if (dataImagePath == None) :
                return 0, 0
            osImagePath = self.__commandsDBConnector.getDomainOSImagePath(domainName)          
            if (osImagePath == None):
                return 0, 0
            isEditedImage = self.__commandsDBConnector.getBootableFlag(imageID)      
            if (isEditedImage == None):
                return 0, 0
            dataSpace = self.__getAllocatedSpace(dataImagePath)
            if (isEditedImage) :
                osSpace = self.__getAllocatedSpace(osImagePath)
                allocatedStorageSpace += osSpace + dataSpace
            else :
                allocatedTemporaryStorageSpace += dataSpace
                
        return allocatedStorageSpace, allocatedTemporaryStorageSpace
            
    def __getAllocatedSpace(self, imagePath):
        """
        Returns the disk space that must be allocated for a disk image
        Args:
            imagePath: the disk image's path
        Returns:
            Nothing
        """
        try :
            output = ChildProcessManager.runCommandInForeground("qemu-img info " + imagePath, Exception)
            lines = output.split("\n")
            virtualSize = VMServerReactor.__extractImageSize(lines[2].split(":")[1].split("(")[0])
            usedSpace = VMServerReactor.__extractImageSize(lines[3].split(":")[1])            
            return virtualSize - usedSpace
        except Exception as e:
            print e
            return 0
            
    @staticmethod
    def __extractImageSize(string):
        """
        Extracts an image size from a quemu-img command output.
        Args:
            string: the qemu-img command's image size
        Returns:
            the disk image size (in kilobytes)
        """
        if ("G" in string) :
            power = 2
        elif ("M" in string):
            power = 1
        else:
            power = 0                                
        string = string.replace("G", "")
        string = string.replace("M", "")
        string = string.replace("K", "")
        return int(ceil(float(string))) * 1024 ** power        
    
    def __sendActiveDomainUIDs(self):
        """
        Sends domains' UUIDs to the cluster server
        Args:
            None
        Returns:
            Nothing
        """
        activeDomainUIDs = self.__commandsDBConnector.getActiveDomainUIDs()
        packet = self.__packetManager.createActiveDomainUIDsPacket(self.__vncServerIP, activeDomainUIDs)
        self.__networkManager.sendPacket('', self.__listenningPort, packet)
    
    def has_finished(self):
        """
        Checks if the virtual machine server has been shut down or not
        Args:
            None
        Returns:
            Nothing
        """
        return self.__finished   
Пример #3
0
class VMServerReactor(NetworkCallback):
    """
    Virtual machine server packet reactor
    """
    def __init__(self, configurationFileParser):
        """
        Initializes the reactor's state, establishes the connection with the database
        and creates the control connection
        Args:
            configurationFileParser: the virtual machine server's configuration file parser
        """
        self.__finished = False
        self.__emergencyStop = False
        self.__fileTransferThread = None
        self.__compressionThread = None
        self.__networkManager = None
        self.__parser = configurationFileParser
        self.__domainHandler = None
        self.__domainTimeout = 0
        try:
            self.__connectToDatabases(
                "VMServerDB",
                self.__parser.getConfigurationParameter("databaseUserName"),
                self.__parser.getConfigurationParameter("databasePassword"))
            self.__startListenning()
        except Exception as e:
            print e.message
            self.__emergencyStop = True
            self.__finished = True

    def __connectToDatabases(self, databaseName, user, password):
        """
        Establishes the connection with the database
        Args:
            databaseName: a database name
            user: a SQL username
            password: the user's password
        Returns:
            Nothing
        """
        self.__commandsDBConnector = VMServerDBConnector(
            user, password, databaseName)

    def __startListenning(self):
        """
        Creates the control connection
        Args:
            None
        Returns:
            Nothing
        """
        networkInterface = self.__parser.getConfigurationParameter(
            "vncNetworkInterface")
        listenningPort = self.__parser.getConfigurationParameter(
            "listenningPort")
        try:
            self.__vncServerIP = get_ip_address(networkInterface)
        except Exception:
            raise Exception(
                "Error: the network interface '{0}' is not ready. Exiting now".
                format(networkInterface))
        self.__ftpTimeout = self.__parser.getConfigurationParameter(
            "FTPTimeout")
        self.__listenningPort = listenningPort
        self.__networkManager = NetworkManager(
            self.__parser.getConfigurationParameter("certificatePath"))
        self.__networkManager.startNetworkService()
        self.__useSSL = self.__parser.getConfigurationParameter("useSSL")
        self.__packetManager = VMServerPacketHandler(self.__networkManager)
        self.__connectToDatabases(
            "VMServerDB",
            self.__parser.getConfigurationParameter("databaseUserName"),
            self.__parser.getConfigurationParameter("databasePassword"))

        self.__domainHandler = DomainHandler(
            self.__commandsDBConnector, self.__vncServerIP,
            self.__networkManager, self.__packetManager, self.__listenningPort,
            self.__parser.getConfigurationParameter("useQEMUWebsockets"),
            self.__parser.getConfigurationParameter("websockifyPath"),
            self.__parser.getConfigurationParameter("configFilePath"),
            self.__parser.getConfigurationParameter("sourceImagePath"),
            self.__parser.getConfigurationParameter("executionImagePath"),
            self.__parser.getConfigurationParameter("passwordLength"))
        self.__domainHandler.connectToLibvirt(
            self.__parser.getConfigurationParameter("vncNetworkInterface"),
            self.__parser.getConfigurationParameter("vnName"),
            self.__parser.getConfigurationParameter("gatewayIP"),
            self.__parser.getConfigurationParameter("netMask"),
            self.__parser.getConfigurationParameter("dhcpStartIP"),
            self.__parser.getConfigurationParameter("dhcpEndIP"),
            self.__parser.getConfigurationParameter(
                "createVirtualNetworkAsRoot"))

        self.__domainHandler.doInitialCleanup()
        self.__deleteTemporaryZipFiles()
        self.__fileTransferThread = FileTransferThread(
            self.__networkManager, self.__listenningPort, self.__packetManager,
            self.__parser.getConfigurationParameter("TransferDirectory"),
            self.__parser.getConfigurationParameter("FTPTimeout"),
            self.__parser.getConfigurationParameter("MaxTransferAttempts"),
            self.__commandsDBConnector, self.__useSSL)
        self.__compressionThread = CompressionThread(
            self.__parser.getConfigurationParameter("TransferDirectory"),
            self.__parser.getConfigurationParameter("sourceImagePath"),
            self.__parser.getConfigurationParameter("configFilePath"),
            self.__commandsDBConnector, self.__domainHandler,
            self.__networkManager, self.__listenningPort, self.__packetManager)
        self.__fileTransferThread.start()
        self.__compressionThread.start()
        self.__networkManager.listenIn(self.__listenningPort, self,
                                       self.__useSSL)

    def __deleteTemporaryZipFiles(self):
        """
        Deletes the temporary zip files
        Args:
            None
        Returns:
            Nothing
        """
        transfer_dir_path = self.__parser.getConfigurationParameter(
            "TransferDirectory")
        for filePath in os.listdir(transfer_dir_path):
            fileName = os.path.splitext(filePath)[0]
            if re.match("[^0-9]", fileName):
                # The non-temporary zip files only have numbers on their names
                os.remove(os.path.join(transfer_dir_path, filePath))

    def shutdown(self):
        """
        Shuts down the virtual machine server
        Args:
            None
        Returns:
            Nothing
        """

        if (self.__emergencyStop):
            self.__domainTimeout = 0

        self.__domainHandler.shutdown(self.__domainTimeout)

        if (self.__fileTransferThread != None):
            self.__fileTransferThread.stop()
            self.__fileTransferThread.join()
        if (self.__compressionThread != None):
            self.__compressionThread.stop()
            self.__compressionThread.join()

        if (self.__networkManager != None):
            self.__networkManager.stopNetworkService(
            )  # Dejar de atender peticiones inmediatamente
        sys.exit()

    def processPacket(self, packet):
        """
        Processes a packet sent from the cluster server
        Args:
            packet: the packet to process
        Returns:
            Nothing
        """
        data = self.__packetManager.readPacket(packet)
        if (data["packet_type"] == VM_SERVER_PACKET_T.CREATE_DOMAIN):
            self.__domainHandler.createDomain(data["MachineID"],
                                              data["UserID"],
                                              data["CommandID"])
        elif (data["packet_type"] == VM_SERVER_PACKET_T.SERVER_STATUS_REQUEST):
            self.__sendStatusData()
        elif (data["packet_type"] == VM_SERVER_PACKET_T.USER_FRIENDLY_SHUTDOWN
              ):
            self.__domainTimeout = data["Timeout"]
            self.__finished = True
        elif (data["packet_type"] == VM_SERVER_PACKET_T.HALT):
            self.__domainTimeout = 0
            self.__finished = True
        elif (data['packet_type'] == VM_SERVER_PACKET_T.QUERY_ACTIVE_VM_DATA):
            self.__sendDomainsVNCConnectionData()
        elif (data['packet_type'] == VM_SERVER_PACKET_T.DESTROY_DOMAIN):
            self.__domainHandler.destroyDomain(data["DomainID"])
        elif (data['packet_type'] == VM_SERVER_PACKET_T.REBOOT_DOMAIN):
            self.__domainHandler.rebootDomain(data["DomainID"])
        elif (data['packet_type'] ==
              VM_SERVER_PACKET_T.QUERY_ACTIVE_DOMAIN_UIDS):
            self.__sendActiveDomainUIDs()
        elif (data['packet_type'] == VM_SERVER_PACKET_T.IMAGE_EDITION):
            self.__processImageEditionPacket(data)
        elif (data['packet_type'] == VM_SERVER_PACKET_T.DEPLOY_IMAGE):
            self.__processDeployImagePacket(data)
        elif (data['packet_type'] == VM_SERVER_PACKET_T.DELETE_IMAGE):
            self.__processDeleteImagePacket(data)

    def __processDeployImagePacket(self, data):
        """
        Processes an image deployment packet
        Args:
            data: a dictionary containing the packet to process' data
        Returns:
            Nothing
        """
        data.pop("packet_type")
        data["Transfer_Type"] = TRANSFER_T.DEPLOY_IMAGE
        self.__commandsDBConnector.addToTransferQueue(data)

    def __processDeleteImagePacket(self, data):

        isBootable = self.__commandsDBConnector.getBootableFlag(
            data["ImageID"])

        if (isBootable):
            osImagePath = os.path.join(
                self.__parser.getConfigurationParameter("sourceImagePath"),
                self.__commandsDBConnector.getOSImagePath(data["ImageID"]))
            definitionFilePath = os.path.join(
                self.__parser.getConfigurationParameter("configFilePath"),
                self.__commandsDBConnector.getDefinitionFilePath(
                    data["ImageID"]))

            try:

                self.__commandsDBConnector.deleteImage(data["ImageID"])
                ChildProcessManager.runCommandInForeground(
                    "rm -rf " + os.path.dirname(osImagePath),
                    VMServerException)
                ChildProcessManager.runCommandInForeground(
                    "rm -rf " + os.path.dirname(definitionFilePath),
                    VMServerException)
                p = self.__packetManager.createConfirmationPacket(
                    VM_SERVER_PACKET_T.IMAGE_DELETED, data["ImageID"],
                    data["CommandID"])
            except Exception:
                p = self.__packetManager.createErrorPacket(
                    VM_SERVER_PACKET_T.IMAGE_DELETION_ERROR,
                    ERROR_DESC_T.VM_SRVR_INTERNAL_ERROR, data["CommandID"])

        else:
            if (isBootable != None):
                errorCode = ERROR_DESC_T.VMSRVR_LOCKED_IMAGE
            else:
                errorCode = ERROR_DESC_T.VMSRVR_UNKNOWN_IMAGE

            p = self.__packetManager.createErrorPacket(
                VM_SERVER_PACKET_T.IMAGE_DELETION_ERROR, errorCode,
                data["CommandID"])

        self.__networkManager.sendPacket('', self.__listenningPort, p)

    def __processImageEditionPacket(self, data):
        """
        Processes an image edition packet
        Args:
            data: a dictionary containing the packet to process' data
        Returns:
            Nothing
        """
        data.pop("packet_type")
        if (data["Modify"]):
            data["Transfer_Type"] = TRANSFER_T.EDIT_IMAGE
        else:
            data["Transfer_Type"] = TRANSFER_T.CREATE_IMAGE
        data.pop("Modify")
        self.__commandsDBConnector.addToTransferQueue(data)

    def __sendDomainsVNCConnectionData(self):
        '''
        Sends the domains' VNC connection data to the cluster server
        Args:
            None
        Returns:
            Nothing
        '''
        vncConnectionData = self.__commandsDBConnector.getDomainsConnectionData(
        )
        segmentSize = 150
        segmentCounter = 1
        outgoingData = []
        if (len(vncConnectionData) == 0):
            segmentCounter = 0
        segmentNumber = (len(vncConnectionData) / segmentSize)
        if (len(vncConnectionData) % segmentSize != 0):
            segmentNumber += 1
            sendLastSegment = True
        else:
            sendLastSegment = segmentNumber == 0
        for connectionParameters in vncConnectionData:
            outgoingData.append(connectionParameters)
            if (len(outgoingData) >= segmentSize):
                # Flush
                packet = self.__packetManager.createActiveVMsVNCDataPacket(
                    self.__vncServerIP, segmentCounter, segmentNumber,
                    outgoingData)
                self.__networkManager.sendPacket('', self.__listenningPort,
                                                 packet)
                outgoingData = []
                segmentCounter += 1
        # Send the last segment
        if (sendLastSegment):
            packet = self.__packetManager.createActiveVMsVNCDataPacket(
                self.__vncServerIP, segmentCounter, segmentNumber,
                outgoingData)
            self.__networkManager.sendPacket('', self.__listenningPort, packet)

    def __sendStatusData(self):
        """
        Sends the server's status data to the cluster server
        Args:
            None
        Returns:
            Nothing
        """
        info = self.__domainHandler.getLibvirtStatusData()
        realCPUNumber = multiprocessing.cpu_count()
        freeOutput = ChildProcessManager.runCommandInForeground(
            "free -k", VMServerException)

        # free's output contains the following lines and collumns:
        #              total       used       free     shared    buffers     cached
        # Mem:    4146708480 3939934208  206774272          0  224706560 1117671424
        # -/+ buffers/cache: 2597556224 1549152256
        # Swap:   2046816256   42455040 2004361216
        #
        # We must get the third line

        availableMemory = int(freeOutput.split("\n")[1].split()[1])
        freeMemory = int(freeOutput.split("\n")[2].split()[2])

        freeStorageSpace, availableStorageSpace, freeTemporaryStorage, availableTemporaryStorage = self.__generateDiskStats(
        )
        packet = self.__packetManager.createVMServerStatusPacket(
            self.__vncServerIP, info["#domains"], freeMemory, availableMemory,
            freeStorageSpace, availableStorageSpace, freeTemporaryStorage,
            availableTemporaryStorage, info["#vcpus"], realCPUNumber)
        self.__networkManager.sendPacket('', self.__listenningPort, packet)

    def __generateDiskStats(self):
        """
        Generates the hard disk usage statistics
        Args:
            None
        Returns:
            the free and available storage and temporary space
        """
        diskStats_storage = os.statvfs(
            self.__parser.getConfigurationParameter("sourceImagePath"))
        diskStats_temporaryData = os.statvfs(
            self.__parser.getConfigurationParameter("executionImagePath"))
        allocatedStorageSpace, allocatedTemporaryStorageSpace = self.__checkDiskImagesSpace(
        )
        freeStorageSpace = diskStats_storage.f_bfree * diskStats_storage.f_frsize / 1024 - allocatedStorageSpace
        availableStorageSpace = diskStats_storage.f_blocks * diskStats_storage.f_frsize / 1024
        freeTemporaryStorageSpace = diskStats_temporaryData.f_bfree * diskStats_temporaryData.f_frsize / 1024 - allocatedTemporaryStorageSpace
        availableTemporaryStorageSpace = diskStats_temporaryData.f_blocks * diskStats_temporaryData.f_frsize / 1024
        return freeStorageSpace, availableStorageSpace, freeTemporaryStorageSpace, availableTemporaryStorageSpace

    def __checkDiskImagesSpace(self):
        """
        Checks how much disk space must be allocated for the active virtual machines' disk images
        Args:
            None
        Returns:
            the storage and temporary storage space that must be allocated.
        """
        activeDomainNames = self.__commandsDBConnector.getRegisteredDomainNames(
        )
        allocatedStorageSpace = 0
        allocatedTemporaryStorageSpace = 0
        for domainName in activeDomainNames:
            imageID = self.__commandsDBConnector.getDomainImageID(domainName)
            if (imageID == None):
                return 0, 0
            dataImagePath = self.__commandsDBConnector.getDomainDataImagePath(
                domainName)
            if (dataImagePath == None):
                return 0, 0
            osImagePath = self.__commandsDBConnector.getDomainOSImagePath(
                domainName)
            if (osImagePath == None):
                return 0, 0
            isEditedImage = self.__commandsDBConnector.getBootableFlag(imageID)
            if (isEditedImage == None):
                return 0, 0
            dataSpace = self.__getAllocatedSpace(dataImagePath)
            if (isEditedImage):
                osSpace = self.__getAllocatedSpace(osImagePath)
                allocatedStorageSpace += osSpace + dataSpace
            else:
                allocatedTemporaryStorageSpace += dataSpace

        return allocatedStorageSpace, allocatedTemporaryStorageSpace

    def __getAllocatedSpace(self, imagePath):
        """
        Returns the disk space that must be allocated for a disk image
        Args:
            imagePath: the disk image's path
        Returns:
            Nothing
        """
        try:
            output = ChildProcessManager.runCommandInForeground(
                "qemu-img info " + imagePath, Exception)
            lines = output.split("\n")
            virtualSize = VMServerReactor.__extractImageSize(
                lines[2].split(":")[1].split("(")[0])
            usedSpace = VMServerReactor.__extractImageSize(
                lines[3].split(":")[1])
            return virtualSize - usedSpace
        except Exception as e:
            print e
            return 0

    @staticmethod
    def __extractImageSize(string):
        """
        Extracts an image size from a quemu-img command output.
        Args:
            string: the qemu-img command's image size
        Returns:
            the disk image size (in kilobytes)
        """
        if ("G" in string):
            power = 2
        elif ("M" in string):
            power = 1
        else:
            power = 0
        string = string.replace("G", "")
        string = string.replace("M", "")
        string = string.replace("K", "")
        return int(ceil(float(string))) * 1024**power

    def __sendActiveDomainUIDs(self):
        """
        Sends domains' UUIDs to the cluster server
        Args:
            None
        Returns:
            Nothing
        """
        activeDomainUIDs = self.__commandsDBConnector.getActiveDomainUIDs()
        packet = self.__packetManager.createActiveDomainUIDsPacket(
            self.__vncServerIP, activeDomainUIDs)
        self.__networkManager.sendPacket('', self.__listenningPort, packet)

    def has_finished(self):
        """
        Checks if the virtual machine server has been shut down or not
        Args:
            None
        Returns:
            Nothing
        """
        return self.__finished
Пример #4
0
    def __startListenning(self):
        """
        Creates the control connection
        Args:
            None
        Returns:
            Nothing
        """
        networkInterface = self.__parser.getConfigurationParameter(
            "vncNetworkInterface")
        listenningPort = self.__parser.getConfigurationParameter(
            "listenningPort")
        try:
            self.__vncServerIP = get_ip_address(networkInterface)
        except Exception:
            raise Exception(
                "Error: the network interface '{0}' is not ready. Exiting now".
                format(networkInterface))
        self.__ftpTimeout = self.__parser.getConfigurationParameter(
            "FTPTimeout")
        self.__listenningPort = listenningPort
        self.__networkManager = NetworkManager(
            self.__parser.getConfigurationParameter("certificatePath"))
        self.__networkManager.startNetworkService()
        self.__useSSL = self.__parser.getConfigurationParameter("useSSL")
        self.__packetManager = VMServerPacketHandler(self.__networkManager)
        self.__connectToDatabases(
            "VMServerDB",
            self.__parser.getConfigurationParameter("databaseUserName"),
            self.__parser.getConfigurationParameter("databasePassword"))

        self.__domainHandler = DomainHandler(
            self.__commandsDBConnector, self.__vncServerIP,
            self.__networkManager, self.__packetManager, self.__listenningPort,
            self.__parser.getConfigurationParameter("useQEMUWebsockets"),
            self.__parser.getConfigurationParameter("websockifyPath"),
            self.__parser.getConfigurationParameter("configFilePath"),
            self.__parser.getConfigurationParameter("sourceImagePath"),
            self.__parser.getConfigurationParameter("executionImagePath"),
            self.__parser.getConfigurationParameter("passwordLength"))
        self.__domainHandler.connectToLibvirt(
            self.__parser.getConfigurationParameter("vncNetworkInterface"),
            self.__parser.getConfigurationParameter("vnName"),
            self.__parser.getConfigurationParameter("gatewayIP"),
            self.__parser.getConfigurationParameter("netMask"),
            self.__parser.getConfigurationParameter("dhcpStartIP"),
            self.__parser.getConfigurationParameter("dhcpEndIP"),
            self.__parser.getConfigurationParameter(
                "createVirtualNetworkAsRoot"))

        self.__domainHandler.doInitialCleanup()
        self.__deleteTemporaryZipFiles()
        self.__fileTransferThread = FileTransferThread(
            self.__networkManager, self.__listenningPort, self.__packetManager,
            self.__parser.getConfigurationParameter("TransferDirectory"),
            self.__parser.getConfigurationParameter("FTPTimeout"),
            self.__parser.getConfigurationParameter("MaxTransferAttempts"),
            self.__commandsDBConnector, self.__useSSL)
        self.__compressionThread = CompressionThread(
            self.__parser.getConfigurationParameter("TransferDirectory"),
            self.__parser.getConfigurationParameter("sourceImagePath"),
            self.__parser.getConfigurationParameter("configFilePath"),
            self.__commandsDBConnector, self.__domainHandler,
            self.__networkManager, self.__listenningPort, self.__packetManager)
        self.__fileTransferThread.start()
        self.__compressionThread.start()
        self.__networkManager.listenIn(self.__listenningPort, self,
                                       self.__useSSL)
    def startListenning(self, useSSL, certificatePath, listenningPort,
                        repositoryIP, repositoryPort,
                        vmServerStatusUpdateInterval):
        """
        Creates the control connection
        Args:
            useSSL: indicates if SSL encryption must be used in the control connection or not
            certificatePath: the directory where the server.crt and server.key files are
            listenningPort: the control connection's port
            repositoryIP: the image repository IP address
            repositoryPort: the image repository's port
            vmServerStatusUpdateInterval: the virtual machine server status database interval
        Returns:
            Nothing
        """

        self.__networkManager = NetworkManager(certificatePath)
        self.__networkManager.startNetworkService()
        self.__listenningPort = listenningPort
        self.__packetHandler = ClusterServerPacketHandler(
            self.__networkManager)
        self.__useSSL = useSSL
        imageRepositoryPacketHandler = ImageRepositoryPacketHandler(
            self.__networkManager)
        vmServerPacketHandler = VMServerPacketHandler(self.__networkManager)
        networkEventsReactor = NetworkEventsReactor(self.__dbConnector,
                                                    repositoryIP,
                                                    repositoryPort)

        imageRepositoryPacketReactor = ImageRepositoryPacketReactor(
            self.__dbConnector, self.__networkManager, listenningPort,
            repositoryIP, repositoryPort, self.__packetHandler,
            vmServerPacketHandler, imageRepositoryPacketHandler)
        try:
            imageRepositoryCallback = ImageRepositoryCallback(
                imageRepositoryPacketReactor, networkEventsReactor)
            self.__networkManager.connectTo(repositoryIP, repositoryPort, 10,
                                            imageRepositoryCallback,
                                            self.__useSSL, True)
            self.__dbConnector.addImageRepository(repositoryIP, repositoryPort,
                                                  SERVER_STATE_T.READY)
        except Exception as e:
            print "Can't connect to the image repository: " + e.message
            self.__exit = True
            return

        vmServerPacketReactor = VMServerPacketReactor(self.__dbConnector,
                                                      self.__networkManager,
                                                      listenningPort,
                                                      vmServerPacketHandler,
                                                      self.__packetHandler)

        self.__endpointPacketReactor = EndpointPacketReactor(
            self.__dbConnector, self.__networkManager, vmServerPacketHandler,
            self.__packetHandler, imageRepositoryPacketHandler,
            VMServerCallback(vmServerPacketReactor,
                             networkEventsReactor), listenningPort,
            repositoryIP, repositoryPort, self.__loadBalancerSettings,
            self.__averageCompressionRatio, self.__useSSL)
        clusterEndpointCallback = ClusterEndpointCallback(
            self.__endpointPacketReactor)
        self.__networkManager.listenIn(listenningPort, clusterEndpointCallback,
                                       self.__useSSL)

        self.__statusMonitoringThread = ClusterStatusMonitoringThread(
            vmServerStatusUpdateInterval, self.__dbConnector,
            self.__networkManager, repositoryIP, repositoryPort,
            vmServerPacketHandler, imageRepositoryPacketHandler)
        self.__statusMonitoringThread.start()