def __freeDomainResources(self, domainName, deleteDiskImages=True): """ Free the resources assigned to a domain Args: domainName: a domain name deleteDiskImages: indicates wether the disk images must be deleted or not Returns: Nothing """ dataImagePath = self.__commandsDBConnector.getDomainDataImagePath( domainName) osImagePath = self.__commandsDBConnector.getDomainOSImagePath( domainName) imageID = self.__commandsDBConnector.getDomainImageID(domainName) websockify_pid = self.__commandsDBConnector.getWebsockifyDaemonPID( domainName) isBootable = self.__commandsDBConnector.getBootableFlag(imageID) commandID = self.__commandsDBConnector.getVMBootCommand(domainName) self.__commandsDBConnector.unregisterDomainResources(domainName) if (websockify_pid != -1): ChildProcessManager.runCommandInForeground( "kill -s TERM " + str(websockify_pid), None) if isBootable: # If the domain was manually stopped, libvirt has already got rid of the disk images. # ==> we don't have to complain if we can't find them ChildProcessManager.runCommandInForeground("rm " + dataImagePath, None) ChildProcessManager.runCommandInForeground("rm " + osImagePath, None) dataDirectory = path.dirname(dataImagePath) osDirectory = path.dirname(osImagePath) if (path.exists(dataDirectory) and listdir(dataDirectory) == []): ChildProcessManager.runCommandInForeground( "rm -rf " + dataDirectory, None) if (osDirectory != dataDirectory and path.exists(osDirectory) and listdir(osDirectory) == []): ChildProcessManager.runCommandInForeground( "rm -rf " + osDirectory, None) else: data = dict() connectionData = self.__commandsDBConnector.getImageRepositoryConnectionData( commandID) data["Transfer_Type"] = TRANSFER_T.STORE_IMAGE data["DataImagePath"] = dataImagePath data["OSImagePath"] = osImagePath data[ "DefinitionFilePath"] = self.__commandsDBConnector.getDefinitionFilePath( imageID) data["RepositoryIP"] = connectionData["RepositoryIP"] data["RepositoryPort"] = connectionData["RepositoryPort"] data["CommandID"] = commandID data["TargetImageID"] = imageID self.__commandsDBConnector.addToCompressionQueue(data) self.__commandsDBConnector.removeImageRepositoryConnectionData( commandID) self.__commandsDBConnector.deleteImage(imageID)
def createVirtualNetwork(self, networkName, gatewayIPAddress, netmask, dhcpStartIPAddress, dhcpEndIPAddress, bridgeName=None): """ Creates a virtual network. Args: networkName: the virtual network's name gatewayIPAddress: the gateway's IPv4 address netmask: the gateway's netmask dhcpStartIPAddress: the DHCP server start address dhcpStopIPAddress: the DHCP server stop address bridgeName: bridge name. If it's none, it will be named after the virtual network. Returns: Nothing """ # Check errors if (self.__networksByIP.has_key(gatewayIPAddress) != 0): raise VirtualNetworkManagerException("The gateway IP address " + \ gatewayIPAddress + " is already in use") if (self.__networksByName.has_key(networkName)): raise VirtualNetworkManagerException("The virtual network name " + networkName + \ " is already in use") xmlFilePath = "/tmp/networkConfig.xml" # Build the definition file self.__generateConfigurationFile(xmlFilePath, networkName, bridgeName,\ gatewayIPAddress, netmask, dhcpStartIPAddress, dhcpEndIPAddress) # Create the virtual network. If it exists, it will be previously destroyed if (self.__runAsRoot): runMethod = ChildProcessManager.runCommandInForegroundAsRoot else: runMethod = ChildProcessManager.runCommandInForeground try: runMethod("virsh net-destroy " + networkName, Exception) except Exception: pass try: runMethod("virsh net-undefine " + networkName, Exception) except Exception: pass runMethod("virsh net-define " + xmlFilePath, VirtualNetworkManagerException) # Enable the virtual network runMethod("virsh net-start " + networkName, VirtualNetworkManagerException) # Delete the definition file ChildProcessManager.runCommandInForeground( "rm " + xmlFilePath, VirtualNetworkManagerException) # Start the virtual network self.__networksByIP[gatewayIPAddress] = networkName self.__networksByName[networkName] = gatewayIPAddress
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 __deleteImage(self, data): """ Handles an image deletion request Args: data: the received packet's content Returns: Nothing """ imageData = self.__dbConnector.getImageData(data["imageID"]) if (imageData == None): p = self.__repositoryPacketHandler.createImageDeletionErrorPacket( data["imageID"], ERROR_DESC_T.IR_UNKNOWN_IMAGE) self.__networkManager.sendPacket('', self.__commandsListenningPort, p, data['clientIP'], data['clientPort']) elif (imageData["imageStatus"] == IMAGE_STATUS_T.EDITION): p = self.__repositoryPacketHandler.createImageDeletionErrorPacket( data["imageID"], ERROR_DESC_T.IR_IMAGE_EDITED) self.__networkManager.sendPacket('', self.__commandsListenningPort, p, data['clientIP'], data['clientPort']) else: if (not "undefined" in imageData["compressedFilePath"]): imageDirectory = path.dirname(imageData["compressedFilePath"]) ChildProcessManager.runCommandInForeground( "rm -rf " + imageDirectory, Exception) self.__dbConnector.deleteImage( data["imageID"]) # TODO: poner encima del if p = self.__repositoryPacketHandler.createDeleteRequestReceivedPacket( data["imageID"]) self.__networkManager.sendPacket('', self.__commandsListenningPort, p, data['clientIP'], data['clientPort'])
def on_incomplete_f_received(self, f): """ Handles a file partially received event Args: f: a filename Returns: Nothing """ remove(f) ChildProcessManager.runCommandInForeground("rm -rf " + path.dirname(f), Exception)
def createVirtualNetwork(self, networkName, gatewayIPAddress, netmask, dhcpStartIPAddress, dhcpEndIPAddress, bridgeName=None): """ Creates a virtual network. Args: networkName: the virtual network's name gatewayIPAddress: the gateway's IPv4 address netmask: the gateway's netmask dhcpStartIPAddress: the DHCP server start address dhcpStopIPAddress: the DHCP server stop address bridgeName: bridge name. If it's none, it will be named after the virtual network. Returns: Nothing """ # Check errors if (self.__networksByIP.has_key(gatewayIPAddress) != 0) : raise VirtualNetworkManagerException("The gateway IP address " + \ gatewayIPAddress + " is already in use") if (self.__networksByName.has_key(networkName)): raise VirtualNetworkManagerException("The virtual network name " + networkName + \ " is already in use") xmlFilePath = "/tmp/networkConfig.xml" # Build the definition file self.__generateConfigurationFile(xmlFilePath, networkName, bridgeName,\ gatewayIPAddress, netmask, dhcpStartIPAddress, dhcpEndIPAddress) # Create the virtual network. If it exists, it will be previously destroyed if (self.__runAsRoot) : runMethod = ChildProcessManager.runCommandInForegroundAsRoot else : runMethod = ChildProcessManager.runCommandInForeground try : runMethod("virsh net-destroy " + networkName, Exception) except Exception : pass try : runMethod("virsh net-undefine " + networkName, Exception) except Exception : pass runMethod("virsh net-define " + xmlFilePath, VirtualNetworkManagerException) # Enable the virtual network runMethod("virsh net-start " + networkName, VirtualNetworkManagerException) # Delete the definition file ChildProcessManager.runCommandInForeground("rm " + xmlFilePath, VirtualNetworkManagerException) # Start the virtual network self.__networksByIP[gatewayIPAddress] = networkName self.__networksByName[networkName] = gatewayIPAddress
def runSQLScript(self, database, sqlFilePath, username="******", password=None): ''' Runs a SQL script Args: databaseName: the MySQL database to use sqlFilePath: the SQL script path username: a MySQL user name. password: the user's password ''' passwordCommand = "" if (password != None and len(password) != 0) : passwordCommand = "-p" + str(password) filePath = os.path.abspath(sqlFilePath) command = "mysql -uroot {0} -e \"source {1}\"".format(passwordCommand, filePath) ChildProcessManager.runCommandInForeground(command, Exception)
def extractFile(self, path, outputDirectory): ''' Extracts a .zip file. Args: path: the .zip file path to extract outputDirectory: the directory where the .zip file content will be extracted. Returns: Nothing Raises: Exception When the compressed file cannot be extracted, an exception will be raised. ''' if (outputDirectory == None) : outputDirectory = path.dirname(path) ChildProcessManager.runCommandInForeground("unzip " + path + " -d " + outputDirectory, Exception)
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 extractFile(self, path, outputDirectory): ''' Extracts a .zip file. Args: path: the .zip file path to extract outputDirectory: the directory where the .zip file content will be extracted. Returns: Nothing Raises: Exception When the compressed file cannot be extracted, an exception will be raised. ''' if (outputDirectory == None): outputDirectory = path.dirname(path) ChildProcessManager.runCommandInForeground( "unzip " + path + " -d " + outputDirectory, Exception)
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 __freeDomainResources(self, domainName, deleteDiskImages=True): """ Free the resources assigned to a domain Args: domainName: a domain name deleteDiskImages: indicates wether the disk images must be deleted or not Returns: Nothing """ dataImagePath = self.__commandsDBConnector.getDomainDataImagePath(domainName) osImagePath = self.__commandsDBConnector.getDomainOSImagePath(domainName) imageID = self.__commandsDBConnector.getDomainImageID(domainName) websockify_pid = self.__commandsDBConnector.getWebsockifyDaemonPID(domainName) isBootable = self.__commandsDBConnector.getBootableFlag(imageID) commandID = self.__commandsDBConnector.getVMBootCommand(domainName) self.__commandsDBConnector.unregisterDomainResources(domainName) if (websockify_pid != -1) : ChildProcessManager.runCommandInForeground("kill -s TERM " + str(websockify_pid), None) if isBootable : # If the domain was manually stopped, libvirt has already got rid of the disk images. # ==> we don't have to complain if we can't find them ChildProcessManager.runCommandInForeground("rm " + dataImagePath, None) ChildProcessManager.runCommandInForeground("rm " + osImagePath, None) dataDirectory = path.dirname(dataImagePath) osDirectory = path.dirname(osImagePath) if (path.exists(dataDirectory) and listdir(dataDirectory) == []) : ChildProcessManager.runCommandInForeground("rm -rf " + dataDirectory, None) if (osDirectory != dataDirectory and path.exists(osDirectory) and listdir(osDirectory) == []) : ChildProcessManager.runCommandInForeground("rm -rf " + osDirectory, None) else : data = dict() connectionData = self.__commandsDBConnector.getImageRepositoryConnectionData(commandID) data["Transfer_Type"] = TRANSFER_T.STORE_IMAGE data["DataImagePath"] = dataImagePath data["OSImagePath"] = osImagePath data["DefinitionFilePath"] = self.__commandsDBConnector.getDefinitionFilePath(imageID) data["RepositoryIP"] = connectionData["RepositoryIP"] data["RepositoryPort"] = connectionData["RepositoryPort"] data["CommandID"] = commandID data["TargetImageID"] = imageID self.__commandsDBConnector.addToCompressionQueue(data) self.__commandsDBConnector.removeImageRepositoryConnectionData(commandID) self.__commandsDBConnector.deleteImage(imageID)
def __generateVNCPassword(self): """ Generates a VNC random password Args: None Returns: a string containing the generated password """ return ChildProcessManager.runCommandInForeground("openssl rand -base64 " + str(self.__vncPasswordLength), VMServerException)
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 runSQLScript(self, database, sqlFilePath, username="******", password=None): ''' Runs a SQL script Args: databaseName: the MySQL database to use sqlFilePath: the SQL script path username: a MySQL user name. password: the user's password ''' passwordCommand = "" if (password != None and len(password) != 0): passwordCommand = "-p" + str(password) filePath = os.path.abspath(sqlFilePath) command = "mysql -uroot {0} -e \"source {1}\"".format( passwordCommand, filePath) ChildProcessManager.runCommandInForeground(command, Exception)
def __generateVNCPassword(self): """ Generates a VNC random password Args: None Returns: a string containing the generated password """ return ChildProcessManager.runCommandInForeground( "openssl rand -base64 " + str(self.__vncPasswordLength), VMServerException)
def __deleteImage(self, data): """ Handles an image deletion request Args: data: the received packet's content Returns: Nothing """ imageData = self.__dbConnector.getImageData(data["imageID"]) if (imageData == None) : p = self.__repositoryPacketHandler.createImageDeletionErrorPacket(data["imageID"], ERROR_DESC_T.IR_UNKNOWN_IMAGE) self.__networkManager.sendPacket('', self.__commandsListenningPort, p, data['clientIP'], data['clientPort']) elif (imageData["imageStatus"] == IMAGE_STATUS_T.EDITION): p = self.__repositoryPacketHandler.createImageDeletionErrorPacket(data["imageID"], ERROR_DESC_T.IR_IMAGE_EDITED) self.__networkManager.sendPacket('', self.__commandsListenningPort, p, data['clientIP'], data['clientPort']) else : if (not "undefined" in imageData["compressedFilePath"]) : imageDirectory = path.dirname(imageData["compressedFilePath"]) ChildProcessManager.runCommandInForeground("rm -rf " + imageDirectory, Exception) self.__dbConnector.deleteImage(data["imageID"]) # TODO: poner encima del if p = self.__repositoryPacketHandler.createDeleteRequestReceivedPacket(data["imageID"]) self.__networkManager.sendPacket('', self.__commandsListenningPort, p, data['clientIP'], data['clientPort'])
def createCompressedFile(self, filePath, fileNameList): ''' Generates a .zip file. Args: filePath: the new .zip file path fileNameList: the files that will be added to the .zip file. Returns: Nothing Raises: Exception When the compressed file cannot be created, an exception will be raised. ''' args = filePath + " " for fileName in fileNameList : args += fileName + " " try : ChildProcessManager.runCommandInForeground("zip -j " + args, Exception) except Exception as e: if ("Nothing to do" in e.message) : pass else : raise e
def createCompressedFile(self, filePath, fileNameList): ''' Generates a .zip file. Args: filePath: the new .zip file path fileNameList: the files that will be added to the .zip file. Returns: Nothing Raises: Exception When the compressed file cannot be created, an exception will be raised. ''' args = filePath + " " for fileName in fileNameList: args += fileName + " " try: ChildProcessManager.runCommandInForeground("zip -j " + args, Exception) except Exception as e: if ("Nothing to do" in e.message): pass else: raise e
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
def startListenning(self, networkInterface, useSSL, certificatesDirectory, commandsListenningPort, ftpListenningPort, maxConnections, maxConnectionsPerIP, uploadBandwidthRatio, downloadBandwidthRatio, ftpUsername, ftpPasswordLength): """ Boots up the FTP server and creates the control connection. Args: networkInterface: the network interface that will be used by the FTP server useSSL: indicates if SSL encryption must be used in the control connection or not certificatesDirectory: the directory where the files server.crt and server.key are commandsListenningPort: the control connection's port ftpListenningPort: the FTP server listenning port maxConnections: maximum FTP connections maxConnectionsPerIP: maximum FTP connections per IP address uploadBandwidthRatio: maximum download bandwidth fraction downloadBandwidthRatio: maximum upload bandwidth fraction ftpUsername: the FTP user that the virtual machine servers will use ftpPasswordLength: the random FTP password length Returns: Nothing @attention: The FTP password will be randomly generated at every boot. """ try : self.__maxConnections = maxConnections self.__commandsListenningPort = commandsListenningPort self.__FTPListenningPort = ftpListenningPort self.__networkManager = NetworkManager(certificatesDirectory) self.__repositoryPacketHandler = ImageRepositoryPacketHandler(self.__networkManager) self.__commandsCallback = CommandsCallback(self.__networkManager, self.__repositoryPacketHandler, commandsListenningPort, self.__dbConnector, self.__retrieveQueue, self.__storeQueue, self.__diskImagesDirectory) self.__networkManager.startNetworkService() self.__networkManager.listenIn(commandsListenningPort, self.__commandsCallback, useSSL) dataCallback = FTPServerCallback(self.__slotCounter, self.__dbConnector) self.__ftpUsername = ftpUsername self.__ftpPassword = ChildProcessManager.runCommandInForeground("openssl rand -base64 {0}".format(ftpPasswordLength), Exception) self.__ftpServer = ConfigurableFTPServer("Image repository FTP Server") self.__ftpServer.startListenning(networkInterface, ftpListenningPort, maxConnections, maxConnectionsPerIP, dataCallback, downloadBandwidthRatio, uploadBandwidthRatio) self.__ftpServer.addUser(self.__ftpUsername, self.__ftpPassword, self.__diskImagesDirectory, "eramw") except Exception as e: print "Error: " + e.message self.__finish = True
def startListenning(self, networkInterface, port, maxConnections, maxConnectionsPerIP, ftpCallback=None, downloadBandwidthRatio=0.8, uploadBandwitdhRatio=0.8): """ Starts the FTP server Args: networkInterface: the network interface that will be used to perform the FTP transfers port: a listenning port maxConnections: maximum connection number maxConnectionsPerIP: maximum connection number per IP address ftpCallback: the callback that will handle the events. If it's none, almost nothing will be done to handle them. downloadBandwidthRatio: maximum download bandwidth fraction uploadBandwidthRatio: maximum upload bandwidth fraction Returns: Nothing """ ip_address = get_ip_address(networkInterface) handler = CygnusCloudFTPHandler handler.ftpCallback = ftpCallback handler.authorizer = self.__authorizer handler.banner = self.__banner link_bandwidth = ChildProcessManager.runCommandInForeground( "/sbin/ethtool eth0 | grep -i Speed | cut -b 9-", Exception) if ("Mb/s" in link_bandwidth): power = 1024**2 else: power = 1024**3 link_bandwidth = int(sub('[^0-9]', '', link_bandwidth)) dtp_handler = ThrottledDTPHandler dtp_handler.read_limit = link_bandwidth * downloadBandwidthRatio * power dtp_handler.write_limit = link_bandwidth * uploadBandwitdhRatio * power handler.dtp_handler = dtp_handler address = (ip_address, port) self.__ftpServer = FTPServer(address, handler) self.__ftpServer.max_cons = maxConnections self.__ftpServer.max_cons_per_ip = maxConnectionsPerIP self.__thread = FTPServerThread(self.__ftpServer) self.__thread.start()
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
def startListenning(self, networkInterface, port, maxConnections, maxConnectionsPerIP, ftpCallback = None, downloadBandwidthRatio=0.8, uploadBandwitdhRatio=0.8): """ Starts the FTP server Args: networkInterface: the network interface that will be used to perform the FTP transfers port: a listenning port maxConnections: maximum connection number maxConnectionsPerIP: maximum connection number per IP address ftpCallback: the callback that will handle the events. If it's none, almost nothing will be done to handle them. downloadBandwidthRatio: maximum download bandwidth fraction uploadBandwidthRatio: maximum upload bandwidth fraction Returns: Nothing """ ip_address = get_ip_address(networkInterface) handler = CygnusCloudFTPHandler handler.ftpCallback = ftpCallback handler.authorizer = self.__authorizer handler.banner = self.__banner link_bandwidth = ChildProcessManager.runCommandInForeground("/sbin/ethtool eth0 | grep -i Speed | cut -b 9-", Exception) if ("Mb/s" in link_bandwidth) : power = 1024 ** 2 else : power = 1024 ** 3 link_bandwidth = int(sub('[^0-9]', '', link_bandwidth)) dtp_handler = ThrottledDTPHandler dtp_handler.read_limit = link_bandwidth * downloadBandwidthRatio * power dtp_handler.write_limit = link_bandwidth * uploadBandwitdhRatio * power handler.dtp_handler = dtp_handler address = (ip_address, port) self.__ftpServer = FTPServer(address, handler) self.__ftpServer.max_cons = maxConnections self.__ftpServer.max_cons_per_ip = maxConnectionsPerIP self.__thread = FTPServerThread(self.__ftpServer) self.__thread.start()
def createDomain(self, imageID, userID, commandID): """ Creates a domain Args: imageID: the image to use's ID userID: the domain owner's ID commandID: the domain boot command's ID Returns: Nothing """ try: diskImagesCreated = False websockifyPID = -1 imageFound = False newUUID = None newMAC = None definitionFile = self.__definitionFileDirectory + self.__commandsDBConnector.getDefinitionFilePath( imageID) originalName = "{0}_".format(imageID) dataImagePath = self.__commandsDBConnector.getDataImagePath( imageID) osImagePath = self.__commandsDBConnector.getOSImagePath(imageID) isBootable = self.__commandsDBConnector.getBootableFlag(imageID) imageFound = True # Generate the configuration parameters newUUID, newMAC = self.__commandsDBConnector.extractFreeMACAndUUID( ) newPort = self.__commandsDBConnector.extractFreeVNCPort() newName = originalName + str(newPort) newPassword = self.__generateVNCPassword() sourceOSDisk = self.__sourceImagePath + osImagePath if (isBootable): # Create the disk images in copy-on-write mode trimmedDataImagePath = dataImagePath try: trimmedDataImagePath = dataImagePath[0:dataImagePath. index(".qcow2")] except: pass trimmedOSImagePath = osImagePath try: trimmedOSImagePath = osImagePath[0:osImagePath. index(".qcow2")] except: pass newDataDisk = self.__executionImagePath + trimmedDataImagePath + str( newPort) + ".qcow2" newOSDisk = self.__executionImagePath + trimmedOSImagePath + str( newPort) + ".qcow2" # If one of the files already exist, we'll get rid of it. if (path.exists(newDataDisk)): print("Warning: the file " + newDataDisk + " already exists") ChildProcessManager.runCommandInForeground( "rm " + newDataDisk, VMServerException) if (path.exists(newOSDisk)): print("Warning: the file " + newOSDisk + " already exists") ChildProcessManager.runCommandInForeground( "rm " + newOSDisk, VMServerException) try: ChildProcessManager.runCommandInForeground( "cd " + self.__sourceImagePath + ";" + "cp --parents " + dataImagePath + " " + self.__executionImagePath, VMServerException) ChildProcessManager.runCommandInForeground( "mv " + self.__executionImagePath + dataImagePath + " " + newDataDisk, VMServerException) ChildProcessManager.runCommandInForeground( "qemu-img create -b " + sourceOSDisk + " -f qcow2 " + newOSDisk, VMServerException) diskImagesCreated = True except Exception as e: diskImagesCreated = False raise e else: # The images will not be created in copy-on-write mode. In fact, their stored copies will be # modified (we're editing them) newDataDisk = path.join(self.__sourceImagePath, dataImagePath) newOSDisk = path.join(self.__sourceImagePath, osImagePath) # Build dthe definition file xmlFile = DefinitionFileEditor(definitionFile) xmlFile.setDomainIdentifiers(newName, newUUID) xmlFile.setImagePaths(newOSDisk, newDataDisk) xmlFile.setVirtualNetworkConfiguration(self.__virtualNetworkName, newMAC) xmlFile.setVNCServerConfiguration(self.__vncServerIP, newPort, newPassword, self.__useQEMUWebsockets) string = xmlFile.generateConfigurationString() # Start the domain self.__libvirtConnection.startDomain(string) if (not self.__useQEMUWebsockets): websockifyPID = self.__childProcessManager.runCommandInBackground( [ self.__websockifyPath, self.__vncServerIP + ":" + str(newPort + 1), self.__vncServerIP + ":" + str(newPort) ]) # Everything went OK => register the resources on the database self.__commandsDBConnector.registerVMResources( newName, imageID, newPort, newPassword, userID, websockifyPID, newOSDisk, newDataDisk, newMAC, newUUID) self.__commandsDBConnector.addVMBootCommand(newName, commandID) except Exception as e: print e # Free the allocated resources, generate an error packet and send it. if (imageFound and not isBootable): self.__commandsDBConnector.deleteImage(imageID) if (newUUID != None): self.__commandsDBConnector.freeMACAndUUID(newUUID, newMAC) if (diskImagesCreated): ChildProcessManager.runCommandInForeground( "rm " + newOSDisk, None) ChildProcessManager.runCommandInForeground( "rm " + newDataDisk, None) directoryName = path.dirname(newOSDisk) if (listdir(directoryName) == []): ChildProcessManager.runCommandInForeground("rm -rf " + directoryName) if (websockifyPID != -1): ChildProcessManager.runCommandInForeground( "kill " + websockifyPID, None) p = self.__packetManager.createInternalErrorPacket(commandID) self.__networkManager.sendPacket('', self.__listenningPort, p)
def createDomain(self, imageID, userID, commandID): """ Creates a domain Args: imageID: the image to use's ID userID: the domain owner's ID commandID: the domain boot command's ID Returns: Nothing """ try : diskImagesCreated = False websockifyPID = -1 imageFound = False newUUID = None newMAC = None definitionFile = self.__definitionFileDirectory + self.__commandsDBConnector.getDefinitionFilePath(imageID) originalName = "{0}_".format(imageID) dataImagePath = self.__commandsDBConnector.getDataImagePath(imageID) osImagePath = self.__commandsDBConnector.getOSImagePath(imageID) isBootable = self.__commandsDBConnector.getBootableFlag(imageID) imageFound = True # Generate the configuration parameters newUUID, newMAC = self.__commandsDBConnector.extractFreeMACAndUUID() newPort = self.__commandsDBConnector.extractFreeVNCPort() newName = originalName + str(newPort) newPassword = self.__generateVNCPassword() sourceOSDisk = self.__sourceImagePath + osImagePath if(isBootable): # Create the disk images in copy-on-write mode trimmedDataImagePath = dataImagePath try: trimmedDataImagePath = dataImagePath[0:dataImagePath.index(".qcow2")] except: pass trimmedOSImagePath = osImagePath try: trimmedOSImagePath = osImagePath[0:osImagePath.index(".qcow2")] except: pass newDataDisk = self.__executionImagePath + trimmedDataImagePath + str(newPort) + ".qcow2" newOSDisk = self.__executionImagePath + trimmedOSImagePath + str(newPort) + ".qcow2" # If one of the files already exist, we'll get rid of it. if (path.exists(newDataDisk)): print("Warning: the file " + newDataDisk + " already exists") ChildProcessManager.runCommandInForeground("rm " + newDataDisk, VMServerException) if (path.exists(newOSDisk)): print("Warning: the file " + newOSDisk + " already exists") ChildProcessManager.runCommandInForeground("rm " + newOSDisk, VMServerException) try : ChildProcessManager.runCommandInForeground("cd " + self.__sourceImagePath + ";" + "cp --parents "+ dataImagePath + " " + self.__executionImagePath, VMServerException) ChildProcessManager.runCommandInForeground("mv " + self.__executionImagePath + dataImagePath +" " + newDataDisk, VMServerException) ChildProcessManager.runCommandInForeground("qemu-img create -b " + sourceOSDisk + " -f qcow2 " + newOSDisk, VMServerException) diskImagesCreated = True except Exception as e: diskImagesCreated = False raise e else : # The images will not be created in copy-on-write mode. In fact, their stored copies will be # modified (we're editing them) newDataDisk = path.join(self.__sourceImagePath, dataImagePath) newOSDisk = path.join(self.__sourceImagePath, osImagePath) # Build dthe definition file xmlFile = DefinitionFileEditor(definitionFile) xmlFile.setDomainIdentifiers(newName, newUUID) xmlFile.setImagePaths(newOSDisk, newDataDisk) xmlFile.setVirtualNetworkConfiguration(self.__virtualNetworkName, newMAC) xmlFile.setVNCServerConfiguration(self.__vncServerIP, newPort, newPassword, self.__useQEMUWebsockets) string = xmlFile.generateConfigurationString() # Start the domain self.__libvirtConnection.startDomain(string) if (not self.__useQEMUWebsockets) : websockifyPID = self.__childProcessManager.runCommandInBackground([self.__websockifyPath, self.__vncServerIP + ":" + str(newPort + 1), self.__vncServerIP + ":" + str(newPort)]) # Everything went OK => register the resources on the database self.__commandsDBConnector.registerVMResources(newName, imageID, newPort, newPassword, userID, websockifyPID, newOSDisk, newDataDisk, newMAC, newUUID) self.__commandsDBConnector.addVMBootCommand(newName, commandID) except Exception as e: print e # Free the allocated resources, generate an error packet and send it. if (imageFound and not isBootable) : self.__commandsDBConnector.deleteImage(imageID) if (newUUID != None) : self.__commandsDBConnector.freeMACAndUUID(newUUID, newMAC) if (diskImagesCreated) : ChildProcessManager.runCommandInForeground("rm " + newOSDisk, None) ChildProcessManager.runCommandInForeground("rm " + newDataDisk, None) directoryName = path.dirname(newOSDisk) if (listdir(directoryName) == []) : ChildProcessManager.runCommandInForeground("rm -rf " + directoryName) if (websockifyPID != -1) : ChildProcessManager.runCommandInForeground("kill " + websockifyPID, None) p = self.__packetManager.createInternalErrorPacket(commandID) self.__networkManager.sendPacket('', self.__listenningPort, p)
def __processElement(self, data): """ Processes a compression/decompression requiest Args: data: a dictionary containing the request's data Returns: Nothing """ try: imageDirectory = None definitionFileDirectory = None zipFilePath = None if (data["Transfer_Type"] != TRANSFER_T.STORE_IMAGE): self.__dbConnector.deleteImage(data["SourceImageID"]) # Extract the .zip file imageDirectory = path.join(self.__diskImagesDirectory, str(data["TargetImageID"])) # Change the extracted files' permissions, and look for the definition file. definitionFileDirectory = path.join( self.__definitionFileDirectory, str(data["TargetImageID"])) try: ChildProcessManager.runCommandInForeground( "rm -rf " + imageDirectory, Exception) ChildProcessManager.runCommandInForeground( "rm -rf " + definitionFileDirectory, Exception) except Exception: pass zipFilePath = path.join(self.__transferDirectory, str(data["SourceImageID"]) + ".zip") self.__compressor.extractFile(zipFilePath, imageDirectory) # Move the three extracted files if not path.exists(definitionFileDirectory): makedirs(definitionFileDirectory) definitionFileFound = False containsDataFile = False containsOSFile = False for fileName in listdir(imageDirectory): ChildProcessManager.runCommandInForegroundAsRoot( "chmod 666 " + path.join(imageDirectory, fileName), VMServerException) if fileName.endswith(".xml"): definitionFile = fileName shutil.move(path.join(imageDirectory, fileName), definitionFileDirectory) definitionFileFound = True containsDataFile = fileName == "Data.qcow2" or containsDataFile containsOSFile = fileName == "OS.qcow2" or containsOSFile if (not definitionFileFound): raise Exception("The definition file was not found") if (not containsDataFile): raise Exception("The data disk image was not found") if (not containsOSFile): raise Exception("The OS disk image was not found") # Register the new image self.__dbConnector.createImage( data["TargetImageID"], path.join(str(data["TargetImageID"]), "OS.qcow2"), path.join(str(data["TargetImageID"]), "Data.qcow2"), path.join(str(data["TargetImageID"]), definitionFile), data["Transfer_Type"] == TRANSFER_T.DEPLOY_IMAGE) if (data["Transfer_Type"] != TRANSFER_T.DEPLOY_IMAGE): # Edition request => boot the virtual machine, store the image repository connection data self.__dbConnector.addValueToConnectionDataDictionary( data["CommandID"], { "RepositoryIP": data["RepositoryIP"], "RepositoryPort": data["RepositoryPort"] }) self.__domainHandler.createDomain(data["TargetImageID"], data["UserID"], data["CommandID"]) else: p = self.__packetHandler.createConfirmationPacket( VM_SERVER_PACKET_T.IMAGE_DEPLOYED, data["TargetImageID"], data["CommandID"]) self.__networkManager.sendPacket( '', self.__serverListenningPort, p) # Delete the .zip file ChildProcessManager.runCommandInForeground( "rm " + zipFilePath, VMServerException) else: # Build the .zip file zipFilePath = path.join(self.__transferDirectory, str(data["TargetImageID"]) + ".zip") self.__compressor.createCompressedFile(zipFilePath, [ data["OSImagePath"], data["DataImagePath"], path.join(self.__definitionFileDirectory, data["DefinitionFilePath"]) ]) # Delete the source files ChildProcessManager.runCommandInForeground( "rm -rf " + path.dirname( path.join(self.__definitionFileDirectory, data["DefinitionFilePath"])), Exception) ChildProcessManager.runCommandInForeground( "rm -rf " + path.dirname(data["OSImagePath"]), Exception) # Queue a transfer request data.pop("DataImagePath") data.pop("OSImagePath") data.pop("DefinitionFilePath") data["SourceFilePath"] = path.basename(zipFilePath) self.__dbConnector.addToTransferQueue(data) except Exception: if (data["Transfer_Type"] == TRANSFER_T.DEPLOY_IMAGE): packet_type = VM_SERVER_PACKET_T.IMAGE_DEPLOYMENT_ERROR else: packet_type = VM_SERVER_PACKET_T.IMAGE_EDITION_ERROR p = self.__packetHandler.createErrorPacket( packet_type, ERROR_DESC_T.VMSRVR_COMPRESSION_ERROR, data["CommandID"]) self.__networkManager.sendPacket('', self.__serverListenningPort, p) if (data["Transfer_Type"] != TRANSFER_T.DEPLOY_IMAGE): # Build a special transfer to unlock the disk image transfer = dict() transfer["Transfer_Type"] = TRANSFER_T.CANCEL_EDITION transfer["RepositoryIP"] = data["RepositoryIP"] transfer["RepositoryPort"] = data["RepositoryPort"] transfer["CommandID"] = data["CommandID"] transfer["ImageID"] = data["TargetImageID"] self.__dbConnector.addToTransferQueue(transfer) # Delete the disk images, the definition file and the .zip file. if (imageDirectory != None): ChildProcessManager.runCommandInForeground( "rm -rf " + imageDirectory, None) if (definitionFileDirectory != None): ChildProcessManager.runCommandInForeground( "rm -rf " + definitionFileDirectory, None) if (zipFilePath != None): ChildProcessManager.runCommandInForeground( "rm -rf " + zipFilePath, None)
def initTransfers(self): """ Initializes the upload and download transfers Args: None Returns: Nothing """ store = False while not (self.__finish or self.__commandsCallback.haltReceived()): if (self.__slotCounter.read() == self.__maxConnections) : # No free slots => sleep sleep(0.1) else : # There are slots => enable uploads and downloads in parallel self.__slotCounter.decrement() if (self.__retrieveQueue.isEmpty() and self.__storeQueue.isEmpty()) : sleep(0.1) continue if (not self.__retrieveQueue.isEmpty() and self.__storeQueue.isEmpty()) : queue = self.__retrieveQueue store = False elif (self.__retrieveQueue.isEmpty() and not self.__storeQueue.isEmpty()) : queue = self.__storeQueue store = True else : if (store) : queue = self.__retrieveQueue store = False else : queue = self.__storeQueue store = True (imageID, clientIP, clientPort) = queue.pop(0) imageData = self.__dbConnector.getImageData(imageID) if (imageData == None) : if (store) : packet_type = PACKET_T.STOR_ERROR else : packet_type = PACKET_T.RETR_ERROR p = self.__repositoryPacketHandler.createErrorPacket(packet_type, ERROR_DESC_T.IR_IMAGE_DELETED) self.__networkManager.sendPacket('', self.__commandsListenningPort, p, clientIP, clientPort) else : compressedFilePath = imageData["compressedFilePath"] if (not "undefined" in compressedFilePath) : serverDirectory = path.relpath(path.dirname(compressedFilePath), self.__diskImagesDirectory) compressedFileName = path.basename(compressedFilePath) else : serverDirectory = str(imageID) compressedFileName = "" serverDirectoryPath = path.join(self.__diskImagesDirectory, serverDirectory) if (path.exists(serverDirectoryPath)) : # The directory exists, and can store shit => clean it up! ChildProcessManager.runCommandInForeground("rm -rf " + serverDirectoryPath, Exception) mkdir(serverDirectoryPath) if (store) : packet_type = PACKET_T.STOR_START else : packet_type = PACKET_T.RETR_START p = self.__repositoryPacketHandler.createTransferEnabledPacket(packet_type, imageID, self.__FTPListenningPort, self.__ftpUsername, self.__ftpPassword, serverDirectory, compressedFileName) self.__networkManager.sendPacket('', self.__commandsListenningPort, p, clientIP, clientPort)
def __processElement(self, data): """ Performs a transfer request Args: data: a dictionary containing the request's data Returns: Nothing """ attempts = 0 while attempts < self.__maxTransferAttempts: try: # Prepare for the new transfer if (data["Transfer_Type"] == TRANSFER_T.CREATE_IMAGE or data["Transfer_Type"] == TRANSFER_T.EDIT_IMAGE): p = self.__repositoryPacketHandler.createRetrieveRequestPacket( data["SourceImageID"], data["Transfer_Type"] == TRANSFER_T.EDIT_IMAGE) sourceFilePath = None elif (data["Transfer_Type"] == TRANSFER_T.DEPLOY_IMAGE): p = self.__repositoryPacketHandler.createRetrieveRequestPacket( data["SourceImageID"], False) sourceFilePath = None elif (data["Transfer_Type"] == TRANSFER_T.STORE_IMAGE): p = self.__repositoryPacketHandler.createStoreRequestPacket( int(data["TargetImageID"])) sourceFilePath = data["SourceFilePath"] else: p = self.__repositoryPacketHandler.createCancelEditionPacket( data["ImageID"]) # Establish the connection with the image repository callback = FileTransferCallback(self.__repositoryPacketHandler, self.__transferDirectory, data["RepositoryIP"], self.__ftpTimeout, sourceFilePath) callback.prepareForNewTransfer() self.__networkManager.connectTo(data["RepositoryIP"], data["RepositoryPort"], self.__ftpTimeout, callback, self.__useSSL) while not self.__networkManager.isConnectionReady( data["RepositoryIP"], data["RepositoryPort"]): sleep(0.1) # Send the transfer request packet self.__networkManager.sendPacket(data["RepositoryIP"], data["RepositoryPort"], p) if (data["Transfer_Type"] != TRANSFER_T.CANCEL_EDITION): # Wait until the transfer finishes while not callback.isTransferCompleted(): sleep(0.1) timeout = False else: elapsed_time = 0 while not callback.isTransferCompleted( ) and elapsed_time < self.__max_cancel_timeout: sleep(0.1) elapsed_time += 0.1 timeout = elapsed_time >= self.__max_cancel_timeout if (callback.getErrorDescription() != None or timeout): if callback.getImageNotFound(): attempts = self.__maxTransferAttempts else: attempts += 1 if (attempts == self.__maxTransferAttempts): if (data["Transfer_Type"] != TRANSFER_T.CANCEL_EDITION): # Error => abort the transfer and warn the user p = self.__vmServerPacketHandler.createErrorPacket( VM_SERVER_PACKET_T.IMAGE_EDITION_ERROR, callback.getErrorDescription(), data["CommandID"]) else: p = self.__vmServerPacketHandler.createInternalErrorPacket( data["CommandID"]) self.__networkManager.sendPacket( '', self.__serverListeningPort, p) else: sleep(4**attempts) else: # The transfer has finished => do something with the .zip file if (data["Transfer_Type"] == TRANSFER_T.CREATE_IMAGE): # Image creation => ask for a new image ID and add a request to the compression queue callback.prepareForNewTransfer() self.__networkManager.sendPacket( data["RepositoryIP"], data["RepositoryPort"], self.__repositoryPacketHandler. createAddImagePacket()) while not callback.isTransferCompleted(): sleep(0.1) data["TargetImageID"] = callback.getDomainImageID() self.__dbConnector.addToCompressionQueue(data) elif (data["Transfer_Type"] == TRANSFER_T.EDIT_IMAGE or data["Transfer_Type"] == TRANSFER_T.DEPLOY_IMAGE): # Add a request to the compression queue data["TargetImageID"] = data["SourceImageID"] self.__dbConnector.addToCompressionQueue(data) elif (data["Transfer_Type"] == TRANSFER_T.STORE_IMAGE): # The image was successfully uploaded => delete the .zip file and send the confirmation packet ChildProcessManager.runCommandInForeground( "rm " + path.join(self.__transferDirectory, data["SourceFilePath"]), Exception) p = self.__vmServerPacketHandler.createImageEditedPacket( data["TargetImageID"], data["CommandID"]) self.__networkManager.sendPacket( '', self.__serverListeningPort, p) # Disconnect from the image repository self.__networkManager.closeConnection(data["RepositoryIP"], data["RepositoryPort"]) attempts = self.__maxTransferAttempts except Exception: # Something went wrong => increment the attempts counter and, if necessary, abort the transfer and warn the user attempts += 1 if (attempts == self.__maxTransferAttempts): errorCode = ERROR_DESC_T.VMSRVR_IR_CONNECTION_ERROR try: self.__networkManager.closeConnection( data["RepositoryIP"], data["RepositoryPort"]) except Exception: pass p = self.__vmServerPacketHandler.createErrorPacket( VM_SERVER_PACKET_T.IMAGE_EDITION_ERROR, errorCode, data["CommandID"]) self.__networkManager.sendPacket( '', self.__serverListeningPort, p) else: sleep(4**attempts)
def initTransfers(self): """ Initializes the upload and download transfers Args: None Returns: Nothing """ store = False while not (self.__finish or self.__commandsCallback.haltReceived()): if (self.__slotCounter.read() == self.__maxConnections): # No free slots => sleep sleep(0.1) else: # There are slots => enable uploads and downloads in parallel self.__slotCounter.decrement() if (self.__retrieveQueue.isEmpty() and self.__storeQueue.isEmpty()): sleep(0.1) continue if (not self.__retrieveQueue.isEmpty() and self.__storeQueue.isEmpty()): queue = self.__retrieveQueue store = False elif (self.__retrieveQueue.isEmpty() and not self.__storeQueue.isEmpty()): queue = self.__storeQueue store = True else: if (store): queue = self.__retrieveQueue store = False else: queue = self.__storeQueue store = True (imageID, clientIP, clientPort) = queue.pop(0) imageData = self.__dbConnector.getImageData(imageID) if (imageData == None): if (store): packet_type = PACKET_T.STOR_ERROR else: packet_type = PACKET_T.RETR_ERROR p = self.__repositoryPacketHandler.createErrorPacket( packet_type, ERROR_DESC_T.IR_IMAGE_DELETED) self.__networkManager.sendPacket( '', self.__commandsListenningPort, p, clientIP, clientPort) else: compressedFilePath = imageData["compressedFilePath"] if (not "undefined" in compressedFilePath): serverDirectory = path.relpath( path.dirname(compressedFilePath), self.__diskImagesDirectory) compressedFileName = path.basename(compressedFilePath) else: serverDirectory = str(imageID) compressedFileName = "" serverDirectoryPath = path.join( self.__diskImagesDirectory, serverDirectory) if (path.exists(serverDirectoryPath)): # The directory exists, and can store shit => clean it up! ChildProcessManager.runCommandInForeground( "rm -rf " + serverDirectoryPath, Exception) mkdir(serverDirectoryPath) if (store): packet_type = PACKET_T.STOR_START else: packet_type = PACKET_T.RETR_START p = self.__repositoryPacketHandler.createTransferEnabledPacket( packet_type, imageID, self.__FTPListenningPort, self.__ftpUsername, self.__ftpPassword, serverDirectory, compressedFileName) self.__networkManager.sendPacket( '', self.__commandsListenningPort, p, clientIP, clientPort)
def __processElement(self, data): """ Processes a compression/decompression requiest Args: data: a dictionary containing the request's data Returns: Nothing """ try : imageDirectory = None definitionFileDirectory = None zipFilePath = None if(data["Transfer_Type"] != TRANSFER_T.STORE_IMAGE): self.__dbConnector.deleteImage(data["SourceImageID"]) # Extract the .zip file imageDirectory = path.join(self.__diskImagesDirectory, str(data["TargetImageID"])) # Change the extracted files' permissions, and look for the definition file. definitionFileDirectory = path.join(self.__definitionFileDirectory, str(data["TargetImageID"])) try : ChildProcessManager.runCommandInForeground("rm -rf " + imageDirectory, Exception) ChildProcessManager.runCommandInForeground("rm -rf " + definitionFileDirectory, Exception) except Exception: pass zipFilePath = path.join(self.__transferDirectory, str(data["SourceImageID"]) + ".zip") self.__compressor.extractFile(zipFilePath, imageDirectory) # Move the three extracted files if not path.exists(definitionFileDirectory): makedirs(definitionFileDirectory) definitionFileFound = False containsDataFile = False containsOSFile = False for fileName in listdir(imageDirectory): ChildProcessManager.runCommandInForegroundAsRoot("chmod 666 " + path.join(imageDirectory, fileName), VMServerException) if fileName.endswith(".xml"): definitionFile = fileName shutil.move(path.join(imageDirectory, fileName), definitionFileDirectory) definitionFileFound = True containsDataFile = fileName == "Data.qcow2" or containsDataFile containsOSFile = fileName == "OS.qcow2" or containsOSFile if(not definitionFileFound): raise Exception("The definition file was not found") if (not containsDataFile) : raise Exception("The data disk image was not found") if (not containsOSFile) : raise Exception("The OS disk image was not found") # Register the new image self.__dbConnector.createImage(data["TargetImageID"], path.join(str(data["TargetImageID"]), "OS.qcow2"), path.join(str(data["TargetImageID"]), "Data.qcow2"), path.join(str(data["TargetImageID"]), definitionFile), data["Transfer_Type"] == TRANSFER_T.DEPLOY_IMAGE) if (data["Transfer_Type"] != TRANSFER_T.DEPLOY_IMAGE): # Edition request => boot the virtual machine, store the image repository connection data self.__dbConnector.addValueToConnectionDataDictionary(data["CommandID"], {"RepositoryIP": data["RepositoryIP"], "RepositoryPort" : data["RepositoryPort"]}) self.__domainHandler.createDomain(data["TargetImageID"], data["UserID"], data["CommandID"]) else : p = self.__packetHandler.createConfirmationPacket(VM_SERVER_PACKET_T.IMAGE_DEPLOYED, data["TargetImageID"], data["CommandID"]) self.__networkManager.sendPacket('', self.__serverListenningPort, p) # Delete the .zip file ChildProcessManager.runCommandInForeground("rm " + zipFilePath, VMServerException) else: # Build the .zip file zipFilePath = path.join(self.__transferDirectory, str(data["TargetImageID"]) + ".zip") self.__compressor.createCompressedFile(zipFilePath, [data["OSImagePath"], data["DataImagePath"], path.join(self.__definitionFileDirectory, data["DefinitionFilePath"])]) # Delete the source files ChildProcessManager.runCommandInForeground("rm -rf " + path.dirname(path.join(self.__definitionFileDirectory, data["DefinitionFilePath"])), Exception) ChildProcessManager.runCommandInForeground("rm -rf " + path.dirname(data["OSImagePath"]), Exception) # Queue a transfer request data.pop("DataImagePath") data.pop("OSImagePath") data.pop("DefinitionFilePath") data["SourceFilePath"] = path.basename(zipFilePath) self.__dbConnector.addToTransferQueue(data) except Exception: if (data["Transfer_Type"] == TRANSFER_T.DEPLOY_IMAGE): packet_type = VM_SERVER_PACKET_T.IMAGE_DEPLOYMENT_ERROR else : packet_type = VM_SERVER_PACKET_T.IMAGE_EDITION_ERROR p = self.__packetHandler.createErrorPacket(packet_type, ERROR_DESC_T.VMSRVR_COMPRESSION_ERROR, data["CommandID"]) self.__networkManager.sendPacket('', self.__serverListenningPort, p) if (data["Transfer_Type"] != TRANSFER_T.DEPLOY_IMAGE): # Build a special transfer to unlock the disk image transfer = dict() transfer["Transfer_Type"] = TRANSFER_T.CANCEL_EDITION transfer["RepositoryIP"] = data["RepositoryIP"] transfer["RepositoryPort"] = data["RepositoryPort"] transfer["CommandID"] = data["CommandID"] transfer["ImageID"] = data["TargetImageID"] self.__dbConnector.addToTransferQueue(transfer) # Delete the disk images, the definition file and the .zip file. if (imageDirectory != None): ChildProcessManager.runCommandInForeground("rm -rf " + imageDirectory, None) if (definitionFileDirectory != None): ChildProcessManager.runCommandInForeground("rm -rf " + definitionFileDirectory, None) if (zipFilePath != None): ChildProcessManager.runCommandInForeground("rm -rf " + zipFilePath, None)
def __processElement(self, data): """ Performs a transfer request Args: data: a dictionary containing the request's data Returns: Nothing """ attempts = 0 while attempts < self.__maxTransferAttempts: try: # Prepare for the new transfer if data["Transfer_Type"] == TRANSFER_T.CREATE_IMAGE or data["Transfer_Type"] == TRANSFER_T.EDIT_IMAGE: p = self.__repositoryPacketHandler.createRetrieveRequestPacket( data["SourceImageID"], data["Transfer_Type"] == TRANSFER_T.EDIT_IMAGE ) sourceFilePath = None elif data["Transfer_Type"] == TRANSFER_T.DEPLOY_IMAGE: p = self.__repositoryPacketHandler.createRetrieveRequestPacket(data["SourceImageID"], False) sourceFilePath = None elif data["Transfer_Type"] == TRANSFER_T.STORE_IMAGE: p = self.__repositoryPacketHandler.createStoreRequestPacket(int(data["TargetImageID"])) sourceFilePath = data["SourceFilePath"] else: p = self.__repositoryPacketHandler.createCancelEditionPacket(data["ImageID"]) # Establish the connection with the image repository callback = FileTransferCallback( self.__repositoryPacketHandler, self.__transferDirectory, data["RepositoryIP"], self.__ftpTimeout, sourceFilePath, ) callback.prepareForNewTransfer() self.__networkManager.connectTo( data["RepositoryIP"], data["RepositoryPort"], self.__ftpTimeout, callback, self.__useSSL ) while not self.__networkManager.isConnectionReady(data["RepositoryIP"], data["RepositoryPort"]): sleep(0.1) # Send the transfer request packet self.__networkManager.sendPacket(data["RepositoryIP"], data["RepositoryPort"], p) if data["Transfer_Type"] != TRANSFER_T.CANCEL_EDITION: # Wait until the transfer finishes while not callback.isTransferCompleted(): sleep(0.1) timeout = False else: elapsed_time = 0 while not callback.isTransferCompleted() and elapsed_time < self.__max_cancel_timeout: sleep(0.1) elapsed_time += 0.1 timeout = elapsed_time >= self.__max_cancel_timeout if callback.getErrorDescription() != None or timeout: if callback.getImageNotFound(): attempts = self.__maxTransferAttempts else: attempts += 1 if attempts == self.__maxTransferAttempts: if data["Transfer_Type"] != TRANSFER_T.CANCEL_EDITION: # Error => abort the transfer and warn the user p = self.__vmServerPacketHandler.createErrorPacket( VM_SERVER_PACKET_T.IMAGE_EDITION_ERROR, callback.getErrorDescription(), data["CommandID"], ) else: p = self.__vmServerPacketHandler.createInternalErrorPacket(data["CommandID"]) self.__networkManager.sendPacket("", self.__serverListeningPort, p) else: sleep(4 ** attempts) else: # The transfer has finished => do something with the .zip file if data["Transfer_Type"] == TRANSFER_T.CREATE_IMAGE: # Image creation => ask for a new image ID and add a request to the compression queue callback.prepareForNewTransfer() self.__networkManager.sendPacket( data["RepositoryIP"], data["RepositoryPort"], self.__repositoryPacketHandler.createAddImagePacket(), ) while not callback.isTransferCompleted(): sleep(0.1) data["TargetImageID"] = callback.getDomainImageID() self.__dbConnector.addToCompressionQueue(data) elif ( data["Transfer_Type"] == TRANSFER_T.EDIT_IMAGE or data["Transfer_Type"] == TRANSFER_T.DEPLOY_IMAGE ): # Add a request to the compression queue data["TargetImageID"] = data["SourceImageID"] self.__dbConnector.addToCompressionQueue(data) elif data["Transfer_Type"] == TRANSFER_T.STORE_IMAGE: # The image was successfully uploaded => delete the .zip file and send the confirmation packet ChildProcessManager.runCommandInForeground( "rm " + path.join(self.__transferDirectory, data["SourceFilePath"]), Exception ) p = self.__vmServerPacketHandler.createImageEditedPacket( data["TargetImageID"], data["CommandID"] ) self.__networkManager.sendPacket("", self.__serverListeningPort, p) # Disconnect from the image repository self.__networkManager.closeConnection(data["RepositoryIP"], data["RepositoryPort"]) attempts = self.__maxTransferAttempts except Exception: # Something went wrong => increment the attempts counter and, if necessary, abort the transfer and warn the user attempts += 1 if attempts == self.__maxTransferAttempts: errorCode = ERROR_DESC_T.VMSRVR_IR_CONNECTION_ERROR try: self.__networkManager.closeConnection(data["RepositoryIP"], data["RepositoryPort"]) except Exception: pass p = self.__vmServerPacketHandler.createErrorPacket( VM_SERVER_PACKET_T.IMAGE_EDITION_ERROR, errorCode, data["CommandID"] ) self.__networkManager.sendPacket("", self.__serverListeningPort, p) else: sleep(4 ** attempts)
def startListenning(self, networkInterface, useSSL, certificatesDirectory, commandsListenningPort, ftpListenningPort, maxConnections, maxConnectionsPerIP, uploadBandwidthRatio, downloadBandwidthRatio, ftpUsername, ftpPasswordLength): """ Boots up the FTP server and creates the control connection. Args: networkInterface: the network interface that will be used by the FTP server useSSL: indicates if SSL encryption must be used in the control connection or not certificatesDirectory: the directory where the files server.crt and server.key are commandsListenningPort: the control connection's port ftpListenningPort: the FTP server listenning port maxConnections: maximum FTP connections maxConnectionsPerIP: maximum FTP connections per IP address uploadBandwidthRatio: maximum download bandwidth fraction downloadBandwidthRatio: maximum upload bandwidth fraction ftpUsername: the FTP user that the virtual machine servers will use ftpPasswordLength: the random FTP password length Returns: Nothing @attention: The FTP password will be randomly generated at every boot. """ try: self.__maxConnections = maxConnections self.__commandsListenningPort = commandsListenningPort self.__FTPListenningPort = ftpListenningPort self.__networkManager = NetworkManager(certificatesDirectory) self.__repositoryPacketHandler = ImageRepositoryPacketHandler( self.__networkManager) self.__commandsCallback = CommandsCallback( self.__networkManager, self.__repositoryPacketHandler, commandsListenningPort, self.__dbConnector, self.__retrieveQueue, self.__storeQueue, self.__diskImagesDirectory) self.__networkManager.startNetworkService() self.__networkManager.listenIn(commandsListenningPort, self.__commandsCallback, useSSL) dataCallback = FTPServerCallback(self.__slotCounter, self.__dbConnector) self.__ftpUsername = ftpUsername self.__ftpPassword = ChildProcessManager.runCommandInForeground( "openssl rand -base64 {0}".format(ftpPasswordLength), Exception) self.__ftpServer = ConfigurableFTPServer( "Image repository FTP Server") self.__ftpServer.startListenning(networkInterface, ftpListenningPort, maxConnections, maxConnectionsPerIP, dataCallback, downloadBandwidthRatio, uploadBandwidthRatio) self.__ftpServer.addUser(self.__ftpUsername, self.__ftpPassword, self.__diskImagesDirectory, "eramw") except Exception as e: print "Error: " + e.message self.__finish = True