Beispiel #1
0
 def setUp(self):
     # Create the database
     self.__dbConfigurator = DBConfigurator("")
     self.__dbConfigurator.runSQLScript("CommandsDBTest",
                                        "./CommandsDBTest.sql")
     # Add a user to it
     self.__dbConfigurator.addUser("cygnuscloud", "cygnuscloud",
                                   "CommandsDBTest")
     self.__connector = CommandsDatabaseConnector("cygnuscloud",
                                                  "cygnuscloud",
                                                  "CommandsDBTest", 1)
     self.__connector.connect()
 def connectToDatabases(self, mysqlRootsPassword, statusDBName, commandsDBName, statusdbSQLFilePath, commandsDBSQLFilePath,
                        websiteUser, websiteUserPassword, endpointUser, endpointUserPassword):
     """
     Establishes a connection with the system status database.
     Args:
         mysqlRootsPassword: MySQL root's password
         statusDBName: the status database name
         statusdbSQLFilePath: the database schema definition SQL file path
         websiteUser: the website user's name. 
         websiteUserPassword: the website user's password
         endpointUser: the update user's name. This user will have ALL privileges on the status database.
         endpointUserPassword: the update user's password.
     """        
     # Create the status database
     self.__rootsPassword = mysqlRootsPassword
     self.__statusDatabaseName = statusDBName
     self.__commandsDatabaseName = commandsDBName
     configurator = DBConfigurator(mysqlRootsPassword)
     configurator.runSQLScript(statusDBName, statusdbSQLFilePath)
     configurator.runSQLScript(commandsDBName, commandsDBSQLFilePath)
     # Register the website and the endpoint users
     configurator.addUser(websiteUser, websiteUserPassword, statusDBName, False)
     configurator.addUser(endpointUser, endpointUserPassword, statusDBName, True)
     configurator.addUser(websiteUser, websiteUserPassword, commandsDBName, True)
     configurator.addUser(endpointUser, endpointUserPassword, commandsDBName, True)
     # Create the database connectors
     self.__commandsDBConnector = CommandsDatabaseConnector(endpointUser, endpointUserPassword, 
                                                            commandsDBName, 1) 
     self.__writer = SystemStatusDatabaseWriter(endpointUser, endpointUserPassword, statusDBName)
     # Connect to the database
     self.__writer.connect()
     self.__commandsDBConnector.connect()
 def connectToDatabases(self, mysqlRootsPassword, statusDBName, commandsDBName, statusdbSQLFilePath, commandsDBSQLFilePath,
                        websiteUser, websiteUserPassword, endpointUser, endpointUserPassword, minCommandInterval):
     """
     Establece la conexión con la base de datos de estado y con la base de datos de comandos.
     Argumentos:
         mysqlRootsPassword: la contraseña de root de MySQL
         statusDBName: el nombre de la base de datos de estado
         statusdbSQLFilePath: la ruta del script que crea la base de datos de estado
         websiteUser: nombre de usuario que usará la web para manipular las bases de datos
         websiteUserPassword: contraseña del usuario de la web
         endpointUser: usuario que utilizará en eldpoint para manipular las bases de datos de estado. Será el único
         que puede escribir en la base de datos de estado.
         endpointUserPassword: contraseña del usuario del endpoint
     """        
     # Crear las bases de datos
     self.__rootsPassword = mysqlRootsPassword
     self.__statusDatabaseName = statusDBName
     self.__commandsDatabaseName = commandsDBName
     configurator = DBConfigurator(mysqlRootsPassword)
     configurator.runSQLScript(statusDBName, statusdbSQLFilePath)
     configurator.runSQLScript(commandsDBName, commandsDBSQLFilePath)
     # Registrar en ellas los usuarios
     configurator.addUser(websiteUser, websiteUserPassword, statusDBName, False)
     configurator.addUser(endpointUser, endpointUserPassword, statusDBName, True)
     configurator.addUser(websiteUser, websiteUserPassword, commandsDBName, True)
     configurator.addUser(endpointUser, endpointUserPassword, commandsDBName, True)
     # Crear los conectores
     self.__commandsDBConnector = CommandsDatabaseConnector(endpointUser, endpointUserPassword, 
                                                            commandsDBName, minCommandInterval) 
     self.__endpointDBConnector = ClusterEndpointDBConnector(endpointUser, endpointUserPassword, statusDBName)
 def connectToDatabases(self, statusDBName, commandsDBName, databaseUser,
                        databasePassword):
     """
     Establece una conexión con las bases de datos de estado y comandos.
     Argumentos:
         statusDBName: el nombre de la base de datos de estado
         commandsDBName: el nombre de la base de datos de comandos
         databaseUser: el nombre de usuario con el que se accederá a las dos bases de datos
         databasePassword: la contraseña para acceder a las bases de datos
     Devuelve:
         Nada
     """
     self.__endpointDBConnector = ClusterEndpointDBConnector(
         databaseUser, databasePassword, statusDBName)
     self.__commandsDBConnector = CommandsDatabaseConnector(
         databaseUser, databasePassword, commandsDBName, 1)
 def setUp(self):
     # Create the database
     self.__dbConfigurator = DBConfigurator("")
     self.__dbConfigurator.runSQLScript("CommandsDBTest", "./CommandsDBTest.sql")
     # Add a user to it
     self.__dbConfigurator.addUser("cygnuscloud", "cygnuscloud", "CommandsDBTest")
     self.__connector = CommandsDatabaseConnector("cygnuscloud", "cygnuscloud", "CommandsDBTest", 1)     
     self.__connector.connect()   
Beispiel #6
0
 def connectToDatabases(self, mysqlRootsPassword, statusDBName,
                        commandsDBName, statusdbSQLFilePath,
                        commandsDBSQLFilePath, websiteUser,
                        websiteUserPassword, endpointUser,
                        endpointUserPassword):
     """
     Establishes a connection with the system status database.
     Args:
         mysqlRootsPassword: MySQL root's password
         statusDBName: the status database name
         statusdbSQLFilePath: the database schema definition SQL file path
         websiteUser: the website user's name. 
         websiteUserPassword: the website user's password
         endpointUser: the update user's name. This user will have ALL privileges on the status database.
         endpointUserPassword: the update user's password.
     """
     # Create the status database
     self.__rootsPassword = mysqlRootsPassword
     self.__statusDatabaseName = statusDBName
     self.__commandsDatabaseName = commandsDBName
     configurator = DBConfigurator(mysqlRootsPassword)
     configurator.runSQLScript(statusDBName, statusdbSQLFilePath)
     configurator.runSQLScript(commandsDBName, commandsDBSQLFilePath)
     # Register the website and the endpoint users
     configurator.addUser(websiteUser, websiteUserPassword, statusDBName,
                          False)
     configurator.addUser(endpointUser, endpointUserPassword, statusDBName,
                          True)
     configurator.addUser(websiteUser, websiteUserPassword, commandsDBName,
                          True)
     configurator.addUser(endpointUser, endpointUserPassword,
                          commandsDBName, True)
     # Create the database connectors
     self.__commandsDBConnector = CommandsDatabaseConnector(
         endpointUser, endpointUserPassword, commandsDBName, 1)
     self.__writer = SystemStatusDatabaseWriter(endpointUser,
                                                endpointUserPassword,
                                                statusDBName)
     # Connect to the database
     self.__writer.connect()
     self.__commandsDBConnector.connect()
 def connectToDatabases(self, statusDBName, commandsDBName, databaseUser, databasePassword):
     """
     Establece una conexión con las bases de datos de estado y comandos.
     Argumentos:
         statusDBName: el nombre de la base de datos de estado
         commandsDBName: el nombre de la base de datos de comandos
         databaseUser: el nombre de usuario con el que se accederá a las dos bases de datos
         databasePassword: la contraseña para acceder a las bases de datos
     Devuelve:
         Nada
     """
     self.__endpointDBConnector = ClusterEndpointDBConnector(databaseUser, databasePassword, statusDBName)
     self.__commandsDBConnector = CommandsDatabaseConnector(databaseUser, databasePassword, commandsDBName, 1)
 def connectToDatabases(self, mysqlRootsPassword, statusDBName,
                        commandsDBName, statusdbSQLFilePath,
                        commandsDBSQLFilePath, websiteUser,
                        websiteUserPassword, endpointUser,
                        endpointUserPassword, minCommandInterval):
     """
     Establece la conexión con la base de datos de estado y con la base de datos de comandos.
     Argumentos:
         mysqlRootsPassword: la contraseña de root de MySQL
         statusDBName: el nombre de la base de datos de estado
         statusdbSQLFilePath: la ruta del script que crea la base de datos de estado
         websiteUser: nombre de usuario que usará la web para manipular las bases de datos
         websiteUserPassword: contraseña del usuario de la web
         endpointUser: usuario que utilizará en eldpoint para manipular las bases de datos de estado. Será el único
         que puede escribir en la base de datos de estado.
         endpointUserPassword: contraseña del usuario del endpoint
     """
     # Crear las bases de datos
     self.__rootsPassword = mysqlRootsPassword
     self.__statusDatabaseName = statusDBName
     self.__commandsDatabaseName = commandsDBName
     configurator = DBConfigurator(mysqlRootsPassword)
     configurator.runSQLScript(statusDBName, statusdbSQLFilePath)
     configurator.runSQLScript(commandsDBName, commandsDBSQLFilePath)
     # Registrar en ellas los usuarios
     configurator.addUser(websiteUser, websiteUserPassword, statusDBName,
                          False)
     configurator.addUser(endpointUser, endpointUserPassword, statusDBName,
                          True)
     configurator.addUser(websiteUser, websiteUserPassword, commandsDBName,
                          True)
     configurator.addUser(endpointUser, endpointUserPassword,
                          commandsDBName, True)
     # Crear los conectores
     self.__commandsDBConnector = CommandsDatabaseConnector(
         endpointUser, endpointUserPassword, commandsDBName,
         minCommandInterval)
     self.__endpointDBConnector = ClusterEndpointDBConnector(
         endpointUser, endpointUserPassword, statusDBName)
Beispiel #9
0
class CommandsDBTests(unittest.TestCase):
    def setUp(self):
        # Create the database
        self.__dbConfigurator = DBConfigurator("")
        self.__dbConfigurator.runSQLScript("CommandsDBTest",
                                           "./CommandsDBTest.sql")
        # Add a user to it
        self.__dbConfigurator.addUser("cygnuscloud", "cygnuscloud",
                                      "CommandsDBTest")
        self.__connector = CommandsDatabaseConnector("cygnuscloud",
                                                     "cygnuscloud",
                                                     "CommandsDBTest", 1)
        self.__connector.connect()

    def tearDown(self):
        self.__connector.disconnect()
        self.__dbConfigurator.dropDatabase("CommandsDBTest")

    def test_addAndRemoveCommands(self):
        self.__connector.addCommand(1, 0, "command arguments")
        result = self.__connector.popCommand()
        expectedResult = (1, 0, 'command arguments')
        self.assertEquals(result[0][0], expectedResult[0],
                          "either addCommand or popCommand does not work")
        self.assertEquals(result[1], expectedResult[1],
                          "either addCommand or popCommand does not work")
        self.assertEquals(result[2], expectedResult[2],
                          "either addCommand or popCommand does not work")
        result = self.__connector.addCommand(1, 1, "command2 arguments")
        self.assertEquals(result, None, "addCommand does not work")
        self.__connector.addCommand(2, 2, "command4 arguments")
        self.__connector.addCommand(3, 3, "command5 arguments")
        expectedResults = [(2, 2, "command4 arguments"),
                           (3, 3, "command5 arguments")]
        for expectedResult in expectedResults:
            result = self.__connector.popCommand()
            self.assertEquals(result[0][0], expectedResult[0],
                              "either addCommand or popCommand does not work")
            self.assertEquals(result[1], expectedResult[1],
                              "either addCommand or popCommand does not work")
            self.assertEquals(result[2], expectedResult[2],
                              "either addCommand or popCommand does not work")

    def test_addAndRemoveCommandOutputs(self):
        commandID = self.__connector.addCommand(1, 0, "command arguments")
        self.__connector.popCommand()
        self.__connector.addCommandOutput(commandID, 0, "commandOutput")
        result = self.__connector.getCommandOutput(commandID)
        expectedResult = (0, "commandOutput")
        self.assertEquals(
            result, expectedResult,
            "either addCommandOutput or getCommandOutput does not work")
class ClusterServerConnector(object):
    """
    Estos objetos comunican la web y el endpoint a través de memoria compartida.
    """
    
    def __init__(self, userID):
        """
        Inicializa el estado del conector
        Argumentos:
            userID: el identificador del usuario que accede al sistema. Se trata de un entero.
        """
        self.__userID = userID
    
    def connectToDatabases(self, statusDBName, commandsDBName, databaseUser, databasePassword):
        """
        Establece una conexión con las bases de datos de estado y comandos.
        Argumentos:
            statusDBName: el nombre de la base de datos de estado
            commandsDBName: el nombre de la base de datos de comandos
            databaseUser: el nombre de usuario con el que se accederá a las dos bases de datos
            databasePassword: la contraseña para acceder a las bases de datos
        Devuelve:
            Nada
        """
        self.__endpointDBConnector = ClusterEndpointDBConnector(databaseUser, databasePassword, statusDBName)
        self.__commandsDBConnector = CommandsDatabaseConnector(databaseUser, databasePassword, commandsDBName, 1)
        
    def dispose(self):
        """
        Cierra las conexiones con las bases de datos
        Argumentos:
            Ninguno
        Devuelve:
            Nada
        """
        pass
        
    def getActiveVMsData(self, showAllVMs=False):
        """
        Devuelve los datos de las máquinas virtuales activas
        Argumentos:
            showAllVMs: si es True, se muestran los datos de todas las máquinas activas; si es False, sólo
            las del usuario registrado en el conector
        Devuelve: una lista de diccionarios con los datos de las máquinas virtuales activas
        """
        if not showAllVMs :
            userID = self.__userID
        else :
            userID = None
        return self.__endpointDBConnector.getActiveVMsData(userID)
    
    def getVMDistributionData(self):
        """
        Devuelve los datos de distribución de las imágenes
        Argumentos:
            Ninguno
        Devuelve: una lista de diccionarios con los datos de distribución de las imágenes
        """
        return self.__endpointDBConnector.getVMDistributionData()
        
    def getVMServersData(self):
        """
        Devuelve los datos básicos de los servidores de máquinas virtuales
        Argumentos:
            Ninguno
        Devuelve: una lista de diccionarios con los datos básicos de los servidores de máquinas virtuales
        """
        return self.__endpointDBConnector.getVMServersData()
        
    def registerVMServer(self, vmServerIP, vmServerPort, vmServerName, isVanillaServer):
        """
        Registra un servidor de máquinas virtuales
        Argumentos:
            vmServerIP: la IP del servidor de máquinas virtuales
            vmServerPort: el puerto en el que escucha
            vmServerName: el nombre del servidor de máquinas virtuales
            isVanillaServer: indica si el servidor de máquinas virtuales se usará preferentemente
                para editar imágenes vanilla o no.
        Devuelve:
            El identificador único del comando.
            @attention: La representación del identificador único del comando puede cambiar sin previo aviso.
        """
        (commandType, commandArgs) = CommandsHandler.createVMServerRegistrationCommand(vmServerIP, vmServerPort, vmServerName, isVanillaServer)
        return self.__commandsDBConnector.addCommand(self.__userID, commandType, commandArgs)
        
    def unregisterVMServer(self, vmServerNameOrIP, isShutDown):
        """
        Borra un servidor de máquinas virtuales
        Argumentos:
            vmServerNameOrIP: el nombre o la IP del servidor a borrar
            isShutDown: si es True, el servidor se apagará inmediatamente. Si es False, esperará a que los usuarios apaguen sus
            máquinas virtuales.
        Devuelve:
            El identificador único del comando.
            @attention: La representación del identificador único del comando puede cambiar sin previo aviso.
        """
        (commandType, commandArgs) = CommandsHandler.createVMServerUnregistrationOrShutdownCommand(True, vmServerNameOrIP, isShutDown)
        return self.__commandsDBConnector.addCommand(self.__userID, commandType, commandArgs)
    
    def shutdownVMServer(self, vmServerNameOrIP, isShutDown):
        """
        Apaga un servidor de máquinas virtuales
        Argumentos:
            vmServerNameOrIP: el nombre o la IP del servidor a borrar
            isShutDown: si es True, el servidor se apagará inmediatamente. Si es False, esperará a que los usuarios apaguen sus
            máquinas virtuales.
        Devuelve:
            El identificador único del comando.
            @attention: La representación del identificador único del comando puede cambiar sin previo aviso.
        """
        (commandType, commandArgs) = CommandsHandler.createVMServerUnregistrationOrShutdownCommand(False, vmServerNameOrIP, isShutDown)
        return self.__commandsDBConnector.addCommand(self.__userID, commandType, commandArgs)
    
    def bootUpVMServer(self, vmServerNameOrIP):
        """
        Arranca un servidor de máquinas virtuales y lo añade a la infraestructura
        Argumentos:
            vmServerNameOrIP: el nombre o la IP del servidor a arrancar
        Devuelve:
            El identificador único del comando.
            @attention: La representación del identificador único del comando puede cambiar sin previo aviso.
        """
        (commandType, commandArgs) = CommandsHandler.createVMServerBootCommand(vmServerNameOrIP)
        return self.__commandsDBConnector.addCommand(self.__userID, commandType, commandArgs)
    
    def bootUpVM(self, imageID):
        """
        Solicita a la infraestructura el arranque de una máquina virtual
        Argumentos:
            imageID: el identificador único de la imagen a arrancar
        Devuelve:
            El identificador único del comando.
            @attention: La representación del identificador único del comando puede cambiar sin previo aviso.
        """
        (commandType, commandArgs) = CommandsHandler.createVMBootCommand(imageID, self.__userID)
        return self.__commandsDBConnector.addCommand(self.__userID, commandType, commandArgs)
    
    def isShutDown(self, haltVMServers):
        """
        Apaga toda la infraestructura
        Argumentos:
            haltVMServers: si es True, el servidor se apagará inmediatamente. Si es False, esperará a que los usuarios apaguen sus
            máquinas virtuales.
        Devuelve: 
            Nada
        """
        (commandType, commandArgs) = CommandsHandler.createHaltCommand(haltVMServers)
        self.__commandsDBConnector.addCommand(self.__userID, commandType, commandArgs)
        
    def destroyDomain(self, domainID):
        """
        Destruye una máquina virtual
        Argumentos:
            domainID: el identificador único de la máquina virtual a destruir
        Devuelve:
            Nada
        """
        (commandType, commandArgs) = CommandsHandler.createDomainDestructionCommand(domainID)
        return self.__commandsDBConnector.addCommand(self.__userID, commandType, commandArgs)
    
    def changeVMServerConfiguration(self, serverNameOrIPAddress, newName, newIPAddress, newPort, 
                                    newVanillaImageEditionBehavior):
        (commandType, commandArgs) = CommandsHandler.createVMServerConfigurationChangeCommand(serverNameOrIPAddress, 
            newName, newIPAddress, newPort, newVanillaImageEditionBehavior)
        return self.__commandsDBConnector.addCommand(self.__userID, commandType, commandArgs)
    
    def getCommandOutput(self, commandID):
        """
        Devuelve la salida de un comando
        Argumentos:
            commandID: el identificador único del comando
        Devuelve:
            - Si el comando todavía se está ejecutando, se devuelve una tupla vacía.
            - Si el comando se ha terminado de ejecutar, se devuelve un diccionario
              con los datos de su salida.
        """
        if (self.__commandsDBConnector.isRunning(commandID)) :
            return ()
        else :
            result = self.__commandsDBConnector.getCommandOutput(commandID)
            if (result != None) :
                (outputType, outputContent) = result
                result = CommandsHandler.deserializeCommandOutput(outputType, outputContent)
            return result
    
    def waitForCommandOutput(self, commandID):
        """
        Espera a que un comando termine, devolviendo su salida en caso de que la haya.
        Argumentos:
            commandID: el identificador único del comando
        Devuelve: 
            - None si el comando no tiene salida
            - Un diccionario con los datos de su salida en caso contrario
        @attention: Este método es bloqueante. Si se desea un comportamiento no bloqueante,
        es necesario utilizar el método getCommandOutput.
        """
        while (self.__commandsDBConnector.isRunning(commandID)) :
                sleep(0.1)
        result = self.__commandsDBConnector.getCommandOutput(commandID)
        if result == None :
            return None
        else :
            return CommandsHandler.deserializeCommandOutput(result[0], result[1])
        
    def getImageBasicData(self, imageID):
        return self.__endpointDBConnector.getImageBasicData(imageID)
        
    def getBootableImagesData(self, imageIDs):
        return self.__endpointDBConnector.getBootableImagesData(imageIDs)
    
    def getBaseImagesData(self):
        return self.__endpointDBConnector.getBaseImagesData()
        
    def getEditedImages(self, userID):
        return self.__endpointDBConnector.getEditedImages(userID)
    
    def getVanillaImageFamilyID(self, imageID):
        return self.__endpointDBConnector.getVanillaImageFamilyID(imageID)
    
    def getVanillaImageFamiliyData(self, vanillaImageFamilyID):
        return self.__endpointDBConnector.getVanillaImageFamiliyData(vanillaImageFamilyID)
class CommandsDBTests(unittest.TestCase):
    
    def setUp(self):
        # Create the database
        self.__dbConfigurator = DBConfigurator("")
        self.__dbConfigurator.runSQLScript("CommandsDBTest", "./CommandsDBTest.sql")
        # Add a user to it
        self.__dbConfigurator.addUser("cygnuscloud", "cygnuscloud", "CommandsDBTest")
        self.__connector = CommandsDatabaseConnector("cygnuscloud", "cygnuscloud", "CommandsDBTest", 1)     
        self.__connector.connect()   
        
    def tearDown(self):
        self.__connector.disconnect()
        self.__dbConfigurator.dropDatabase("CommandsDBTest")
        
    def test_addAndRemoveCommands(self):
        self.__connector.addCommand(1, 0, "command arguments")
        result = self.__connector.popCommand()
        expectedResult = (1, 0, 'command arguments')
        self.assertEquals(result[0][0], expectedResult[0], "either addCommand or popCommand does not work")
        self.assertEquals(result[1], expectedResult[1], "either addCommand or popCommand does not work")
        self.assertEquals(result[2], expectedResult[2], "either addCommand or popCommand does not work")
        result = self.__connector.addCommand(1, 1, "command2 arguments")
        self.assertEquals(result, None, "addCommand does not work")
        self.__connector.addCommand(2, 2, "command4 arguments")
        self.__connector.addCommand(3, 3, "command5 arguments")
        expectedResults = [(2, 2, "command4 arguments"), (3, 3, "command5 arguments")]
        for expectedResult in expectedResults :
            result = self.__connector.popCommand()
            self.assertEquals(result[0][0], expectedResult[0], "either addCommand or popCommand does not work")
            self.assertEquals(result[1], expectedResult[1], "either addCommand or popCommand does not work")
            self.assertEquals(result[2], expectedResult[2], "either addCommand or popCommand does not work")
            
    def test_addAndRemoveCommandOutputs(self):
        commandID = self.__connector.addCommand(1, 0, "command arguments")
        self.__connector.popCommand()
        self.__connector.addCommandOutput(commandID, 0, "commandOutput")
        result = self.__connector.getCommandOutput(commandID)
        expectedResult = (0, "commandOutput")
        self.assertEquals(result, expectedResult, "either addCommandOutput or getCommandOutput does not work")
class WebServerEndpoint(object):  
    """
    These objects communicate a cluster server and the web connectors.
    """    
    def __init__(self):
        """
        Initializes the endpoint's state
        Args:
            None
        """
        self.__stopped = False
    
    def connectToDatabases(self, mysqlRootsPassword, statusDBName, commandsDBName, statusdbSQLFilePath, commandsDBSQLFilePath,
                           websiteUser, websiteUserPassword, endpointUser, endpointUserPassword):
        """
        Establishes a connection with the system status database.
        Args:
            mysqlRootsPassword: MySQL root's password
            statusDBName: the status database name
            statusdbSQLFilePath: the database schema definition SQL file path
            websiteUser: the website user's name. 
            websiteUserPassword: the website user's password
            endpointUser: the update user's name. This user will have ALL privileges on the status database.
            endpointUserPassword: the update user's password.
        """        
        # Create the status database
        self.__rootsPassword = mysqlRootsPassword
        self.__statusDatabaseName = statusDBName
        self.__commandsDatabaseName = commandsDBName
        configurator = DBConfigurator(mysqlRootsPassword)
        configurator.runSQLScript(statusDBName, statusdbSQLFilePath)
        configurator.runSQLScript(commandsDBName, commandsDBSQLFilePath)
        # Register the website and the endpoint users
        configurator.addUser(websiteUser, websiteUserPassword, statusDBName, False)
        configurator.addUser(endpointUser, endpointUserPassword, statusDBName, True)
        configurator.addUser(websiteUser, websiteUserPassword, commandsDBName, True)
        configurator.addUser(endpointUser, endpointUserPassword, commandsDBName, True)
        # Create the database connectors
        self.__commandsDBConnector = CommandsDatabaseConnector(endpointUser, endpointUserPassword, 
                                                               commandsDBName, 1) 
        self.__writer = SystemStatusDatabaseWriter(endpointUser, endpointUserPassword, statusDBName)
        # Connect to the database
        self.__writer.connect()
        self.__commandsDBConnector.connect()
        
    def connectToClusterServer(self, certificatePath, clusterServerIP, clusterServerListenningPort, statusDBUpdateInterval):
        """
        Establishes a connection with the cluster server.
        Args:
            certificatePath: the server.crt and server.key directory path.
            clusterServerIP: the cluster server's IPv4 address
            clusterServerListenningPort: the cluster server's listenning port.
            statusDBUpdateInterval: the status database update interval (in seconds)
        Returns:
            Nothing
        """
        self.__manager = NetworkManager(certificatePath)
        self.__manager.startNetworkService()
        callback = _ClusterServerEndpointCallback(self)
        # Connect to the main server
        self.__clusterServerIP = clusterServerIP
        self.__clusterServerPort = clusterServerListenningPort
        self.__manager.connectTo(clusterServerIP, clusterServerListenningPort, 5, callback, True)
        while (not self.__manager.isConnectionReady(clusterServerIP, clusterServerListenningPort)) :
            sleep(0.1)
        # Create the packet handler
        self.__pHandler = ClusterServerPacketHandler(self.__manager)
        # Create the update thread
        self.__updateRequestThread = StatusDatabaseUpdateThread(_ClusterServerEndpointUpdateHandler(self), statusDBUpdateInterval)
        # Start it
        self.__updateRequestThread.start()
        
    def disconnectFromClusterServer(self):
        """
        Closes the connection with the cluster server and drops the databases.
        Args:
            haltVMServers: if True, the virtual machine servers will be halted immediately. If false, they will be
            halted until all their virtual machines have been shut down.
        Returns:
            Nothing
        @attention: DO NOT call this method inside a network thread (i.e. inside the web callback). If you do so,
        your application will hang.
        """
        # Send a halt packet to the cluster server
        p = self.__pHandler.createHaltPacket(self.__haltVMServers)
        self.__manager.sendPacket(self.__clusterServerIP, self.__clusterServerPort, p)
        # Stop the update request thread
        self.__updateRequestThread.stop()
        # Close the database connections
        self.__commandsDBConnector.disconnect()
        self.__writer.disconnect()
        # Stop the network service
        self.__manager.stopNetworkService()
        # Delete the status database
        dbConfigurator = DBConfigurator(self.__rootsPassword)
        dbConfigurator.dropDatabase(self.__statusDatabaseName)
        dbConfigurator.dropDatabase(self.__commandsDatabaseName)    
        
    def _processIncomingPacket(self, packet):
        """
        Processes an incoming package (sent from the cluster server).
        Args:
            packet: the packet to process
        Returns:
            Nothing
        """
        if (self.__stopped) :
            return
        data = self.__pHandler.readPacket(packet)
        if (data["packet_type"] == PACKET_T.VM_SERVERS_STATUS_DATA) :
            self.__writer.processVMServerSegment(data["Segment"], data["SequenceSize"], data["Data"])
        elif (data["packet_type"] == PACKET_T.VM_DISTRIBUTION_DATA) :
            self.__writer.processVMDistributionSegment(data["Segment"], data["SequenceSize"], data["Data"])
        elif (data["packet_type"] == PACKET_T.ACTIVE_VM_DATA) :
            self.__writer.processActiveVMSegment(data["Segment"], data["SequenceSize"], data["VMServerIP"], data["Data"])
        else :
            l = data["CommandID"].split("|")
            commandID = (int(l[0]), float(l[1]))
            if (data["packet_type"] == PACKET_T.COMMAND_EXECUTED) :
                self.__commandsDBConnector.removeExecutedCommand(commandID)
            else :           
                # Command outputs => serialize and add them to the commands database 
                if (data["packet_type"] == PACKET_T.VM_SERVER_BOOTUP_ERROR or 
                    data["packet_type"] == PACKET_T.VM_SERVER_UNREGISTRATION_ERROR or 
                    data["packet_type"] == PACKET_T.VM_SERVER_SHUTDOWN_ERROR) :
                    (outputType, outputContent) = CommandsHandler.createVMServerGenericErrorOutput(
                        data["packet_type"], data["ServerNameOrIPAddress"], data["ErrorMessage"])
                elif (data["packet_type"] == PACKET_T.VM_SERVER_REGISTRATION_ERROR) :
                    (outputType, outputContent) = CommandsHandler.createVMServerRegistrationErrorOutput(
                        data["VMServerIP"], data["VMServerPort"], data["VMServerName"], data["ErrorMessage"])
                elif (data["packet_type"] == PACKET_T.VM_BOOT_FAILURE) :
                    (outputType, outputContent) = CommandsHandler.createVMBootFailureErrorOutput(
                        data["VMID"], data["ErrorMessage"])  
                elif (data["packet_type"] == PACKET_T.VM_CONNECTION_DATA) :
                    (outputType, outputContent) = CommandsHandler.createVMConnectionDataOutput(
                        data["VNCServerIPAddress"], data["VNCServerPort"], data["VNCServerPassword"])
                self.__commandsDBConnector.addCommandOutput(commandID, outputType, outputContent)
                
    def processCommands(self):
        """
        Processes the commands sent from the web connectors.
        Args:
            None
        Returns:
            Nothing
        @attention: This method will only finish after processing a halt command.
        """
        while not self.__stopped :
            commandData = self.__commandsDBConnector.popCommand()
            if (commandData == None) :
                sleep(0.1)
            else :
                (commandID, commandType, commandArgs) = commandData
                parsedArgs = CommandsHandler.deserializeCommandArgs(commandType, commandArgs)
                if (commandType != COMMAND_TYPE.HALT) :
                    serializedCommandID = "{0}|{1}".format(commandID[0], commandID[1])                    
                    if (commandType == COMMAND_TYPE.BOOTUP_VM_SERVER) :                    
                        packet = self.__pHandler.createVMServerBootUpPacket(parsedArgs["VMServerNameOrIP"], serializedCommandID)
                    elif (commandType == COMMAND_TYPE.REGISTER_VM_SERVER) :
                        packet = self.__pHandler.createVMServerRegistrationPacket(parsedArgs["VMServerIP"], 
                            parsedArgs["VMServerPort"], parsedArgs["VMServerName"], serializedCommandID)
                    elif (commandType == COMMAND_TYPE.UNREGISTER_OR_SHUTDOWN_VM_SERVER) :
                        packet = self.__pHandler.createVMServerUnregistrationOrShutdownPacket(parsedArgs["VMServerNameOrIP"], 
                            parsedArgs["Halt"], parsedArgs["Unregister"], serializedCommandID)
                    elif (commandType == COMMAND_TYPE.VM_BOOT_REQUEST) :
                        packet = self.__pHandler.createVMBootRequestPacket(parsedArgs["VMID"], parsedArgs["UserID"], serializedCommandID)
                    self.__manager.sendPacket(self.__clusterServerIP, self.__clusterServerPort, packet)
                else :
                    self.__stopped = True
                    self.__haltVMServers = parsedArgs["HaltVMServers"]
    
    def _sendUpdateRequestPackets(self):
        """
        Sends the update request packets to the cluster server.
        Args:
            None
        Returns:
            Nothing
        """
        if (self.__stopped) :
            return
        # Send some update request packets to the cluster server
        p = self.__pHandler.createDataRequestPacket(PACKET_T.QUERY_VM_SERVERS_STATUS)
        self.__manager.sendPacket(self.__clusterServerIP, self.__clusterServerPort, p)        
        p = self.__pHandler.createDataRequestPacket(PACKET_T.QUERY_VM_DISTRIBUTION)
        self.__manager.sendPacket(self.__clusterServerIP, self.__clusterServerPort, p)
        p = self.__pHandler.createDataRequestPacket(PACKET_T.QUERY_ACTIVE_VM_DATA)
        self.__manager.sendPacket(self.__clusterServerIP, self.__clusterServerPort, p)
class WebServerEndpoint(object):  
    """
    Estos objetos comunican un servidor de cluster con la web
    """    
    def __init__(self):
        """
        Inicializa el estado del endpoint
        Argumentos:
            Ninguno
        """
        self.__stopped = False
    
    def connectToDatabases(self, mysqlRootsPassword, statusDBName, commandsDBName, statusdbSQLFilePath, commandsDBSQLFilePath,
                           websiteUser, websiteUserPassword, endpointUser, endpointUserPassword, minCommandInterval):
        """
        Establece la conexión con la base de datos de estado y con la base de datos de comandos.
        Argumentos:
            mysqlRootsPassword: la contraseña de root de MySQL
            statusDBName: el nombre de la base de datos de estado
            statusdbSQLFilePath: la ruta del script que crea la base de datos de estado
            websiteUser: nombre de usuario que usará la web para manipular las bases de datos
            websiteUserPassword: contraseña del usuario de la web
            endpointUser: usuario que utilizará en eldpoint para manipular las bases de datos de estado. Será el único
            que puede escribir en la base de datos de estado.
            endpointUserPassword: contraseña del usuario del endpoint
        """        
        # Crear las bases de datos
        self.__rootsPassword = mysqlRootsPassword
        self.__statusDatabaseName = statusDBName
        self.__commandsDatabaseName = commandsDBName
        configurator = DBConfigurator(mysqlRootsPassword)
        configurator.runSQLScript(statusDBName, statusdbSQLFilePath)
        configurator.runSQLScript(commandsDBName, commandsDBSQLFilePath)
        # Registrar en ellas los usuarios
        configurator.addUser(websiteUser, websiteUserPassword, statusDBName, False)
        configurator.addUser(endpointUser, endpointUserPassword, statusDBName, True)
        configurator.addUser(websiteUser, websiteUserPassword, commandsDBName, True)
        configurator.addUser(endpointUser, endpointUserPassword, commandsDBName, True)
        # Crear los conectores
        self.__commandsDBConnector = CommandsDatabaseConnector(endpointUser, endpointUserPassword, 
                                                               commandsDBName, minCommandInterval) 
        self.__endpointDBConnector = ClusterEndpointDBConnector(endpointUser, endpointUserPassword, statusDBName)
        
    def connectToClusterServer(self, certificatePath, clusterServerIP, clusterServerListenningPort, statusDBUpdateInterval,
                               commandTimeout, commandTimeoutCheckInterval):
        """
        Establece la conexión con el servidor de cluster
        Argumentos:
            certificatePath: la ruta del directorio con los ficheros server.crt y server.key.
            clusterServerIP: la IP del servidor de cluster
            clusterServerListenningPort: el puerto en el que escucha el servidor de cluster
            statusDBUpdateInterval: el periodo de actualización de la base de datos (en segundos)
        Devuelve:
            Nada
        Lanza:
            EnpointException: se lanza cuando no se puede establecer una conexión con el servidor web
        """
        self.__manager = NetworkManager(certificatePath)
        self.__manager.startNetworkService()
        callback = _ClusterServerEndpointCallback(self)
        # Establecer la conexión
        self.__clusterServerIP = clusterServerIP
        self.__clusterServerPort = clusterServerListenningPort
        try :
            self.__manager.connectTo(clusterServerIP, clusterServerListenningPort, 5, callback, True)
            while (not self.__manager.isConnectionReady(clusterServerIP, clusterServerListenningPort)) :
                sleep(0.1)
                    
            # TODO: si esto falla, terminar.
            # Preparar la recepción de paquetes y la actualización automática de la base de datos de estado
            self.__repositoryPacketHandler = ClusterServerPacketHandler(self.__manager)
            
            self.__updateRequestThread = VMServerMonitoringThread(_ClusterServerEndpointUpdateHandler(self), statusDBUpdateInterval)
            self.__updateRequestThread.start()            
            self.__commandMonitoringThread = CommandMonitoringThread(self.__commandsDBConnector, commandTimeout, commandTimeoutCheckInterval)
            self.__commandMonitoringThread.start()
        except NetworkManagerException as e :
            raise EndpointException(e.message)
        
    def disconnectFromClusterServer(self):
        """
        Cierra la conexión con el servidor de cluster y borra las bases de datos de estado
        Argumentos:
            Ninguno
        Devuelve:
            Nada
        @attention: Este método debe llamarse desde el hilo principal para evitar cuelgues
        """
        # Apagar el servidor de cluster
        p = self.__repositoryPacketHandler.createHaltPacket(self.__haltVMServers)
        errorMessage = self.__manager.sendPacket(self.__clusterServerIP, self.__clusterServerPort, p)
        NetworkManager.printConnectionWarningIfNecessary(self.__clusterServerIP, self.__clusterServerPort, "Cluster server halt", 
                                                         errorMessage)
        # Dejar de actualizar las bases de datos
        self.__updateRequestThread.stop()
        
        # Dejar de monitorizar los comandos
        self.__commandMonitoringThread.stop()
        
        # Cerrar las conexiones con las bases de datos
        self.closeNetworkAndDBConnections()
        
    def closeNetworkAndDBConnections(self):
        """
        Cierra las conexiones con las bases de datos
        Argumentos:
            Ninguno
        Devuelve:
            Nada
        """
        # Detener el servicio de red
        self.__manager.stopNetworkService()
        # Borrar las bases de datos de comandos y de estado
        dbConfigurator = DBConfigurator(self.__rootsPassword)
        dbConfigurator.dropDatabase(self.__commandsDatabaseName)    
        
    def _processIncomingPacket(self, packet):
        """
        Procesa un paquete enviado desde el servidor de cluster
        Argumentos:
            packet: el paquete a procesar
        Devuelve:
            Nada
        """
        if (self.__stopped) :
            return
        data = self.__repositoryPacketHandler.readPacket(packet)
        if (data["packet_type"] == PACKET_T.VM_SERVERS_STATUS_DATA) :
            self.__endpointDBConnector.processVMServerSegment(data["Segment"], data["SequenceSize"], data["Data"])
        elif (data["packet_type"] == PACKET_T.VM_DISTRIBUTION_DATA) :
            self.__endpointDBConnector.processVMDistributionSegment(data["Segment"], data["SequenceSize"], data["Data"])
        elif (data["packet_type"] == PACKET_T.ACTIVE_VM_DATA) :
            self.__endpointDBConnector.processActiveVMSegment(data["Segment"], data["SequenceSize"], data["VMServerIP"], data["Data"])
        else :
            l = data["CommandID"].split("|")
            commandID = (int(l[0]), float(l[1]))
            if (data["packet_type"] == PACKET_T.COMMAND_EXECUTED) :
                self.__commandsDBConnector.removeExecutedCommand(commandID)
            else :           
                # El resto de paquetes contienen el resultado de ejecutar comandos => los serializamos y los añadimos
                # a la base de datos de comandos para que los conectores se enteren
                if (data["packet_type"] == PACKET_T.VM_SERVER_BOOTUP_ERROR or 
                    data["packet_type"] == PACKET_T.VM_SERVER_UNREGISTRATION_ERROR or 
                    data["packet_type"] == PACKET_T.VM_SERVER_SHUTDOWN_ERROR) :
                    (outputType, outputContent) = CommandsHandler.createVMServerGenericErrorOutput(
                        data["packet_type"], data["ServerNameOrIPAddress"], data["ErrorMessage"])
                elif (data["packet_type"] == PACKET_T.VM_SERVER_REGISTRATION_ERROR) :
                    (outputType, outputContent) = CommandsHandler.createVMServerRegistrationErrorOutput(
                        data["VMServerIP"], data["VMServerPort"], data["VMServerName"], data["ErrorMessage"])
                elif (data["packet_type"] == PACKET_T.VM_BOOT_FAILURE) :
                    (outputType, outputContent) = CommandsHandler.createVMBootFailureErrorOutput(
                        data["VMID"], data["ErrorMessage"])  
                elif (data["packet_type"] == PACKET_T.VM_CONNECTION_DATA) :
                    (outputType, outputContent) = CommandsHandler.createVMConnectionDataOutput(
                        data["VNCServerIPAddress"], data["VNCServerPort"], data["VNCServerPassword"])
                elif (data["packet_type"] == PACKET_T.DOMAIN_DESTRUCTION_ERROR):
                    (outputType, outputContent) = CommandsHandler.createDomainDestructionErrorOutput(data["ErrorMessage"])
                elif (data["packet_type"] == PACKET_T.VM_SERVER_CONFIGURATION_CHANGE_ERROR) :
                    (outputType, outputContent) = CommandsHandler.createVMServerConfigurationChangeErrorOutput(data["ErrorMessage"])
                self.__commandsDBConnector.addCommandOutput(commandID, outputType, outputContent)
                
    def processCommands(self):
        """
        Procesa los comandos enviados desde los conectores
        Argumentos:
            Ninguno
        Devuelve:
            Nada
        """
        while not self.__stopped :
            commandData = self.__commandsDBConnector.popCommand()
            if (commandData == None) :
                sleep(0.1)
            else :
                (commandID, commandType, commandArgs) = commandData
                parsedArgs = CommandsHandler.deserializeCommandArgs(commandType, commandArgs)
                if (commandType != COMMAND_TYPE.HALT) :
                    serializedCommandID = "{0}|{1}".format(commandID[0], commandID[1])                    
                    if (commandType == COMMAND_TYPE.BOOTUP_VM_SERVER) :                    
                        packet = self.__repositoryPacketHandler.createVMServerBootUpPacket(parsedArgs["VMServerNameOrIP"], serializedCommandID)
                    elif (commandType == COMMAND_TYPE.REGISTER_VM_SERVER) :
                        packet = self.__repositoryPacketHandler.createVMServerRegistrationPacket(parsedArgs["VMServerIP"], 
                            parsedArgs["VMServerPort"], parsedArgs["VMServerName"], parsedArgs["IsVanillaServer"], serializedCommandID)
                    elif (commandType == COMMAND_TYPE.UNREGISTER_OR_SHUTDOWN_VM_SERVER) :
                        packet = self.__repositoryPacketHandler.createVMServerUnregistrationOrShutdownPacket(parsedArgs["VMServerNameOrIP"], 
                            parsedArgs["Halt"], parsedArgs["Unregister"], serializedCommandID)
                    elif (commandType == COMMAND_TYPE.VM_BOOT_REQUEST) :
                        packet = self.__repositoryPacketHandler.createVMBootRequestPacket(parsedArgs["VMID"], parsedArgs["UserID"], serializedCommandID)
                    elif (commandType == COMMAND_TYPE.DESTROY_DOMAIN):
                        packet = self.__repositoryPacketHandler.createDomainDestructionPacket(parsedArgs["DomainID"], serializedCommandID)
                    elif (commandType == COMMAND_TYPE.VM_SERVER_CONFIGURATION_CHANGE) :
                        packet = self.__repositoryPacketHandler.createVMServerConfigurationChangePacket(parsedArgs["VMServerNameOrIPAddress"],  parsedArgs["NewServerName"],
                                                                                         parsedArgs["NewServerIPAddress"], parsedArgs["NewServerPort"],
                                                                                         parsedArgs["NewVanillaImageEditionBehavior"], serializedCommandID)
                    errorMessage = self.__manager.sendPacket(self.__clusterServerIP, self.__clusterServerPort, packet)
                    if (errorMessage != None) :
                        # Error al enviar el paquete => el comando no se podrá ejecutar => avisar a la web
                        (outputType, outputContent) = CommandsHandler.createConnectionErrorOutput()
                        self.__commandsDBConnector.addCommandOutput(commandID, outputType, outputContent)
                        
                else :
                    self.__stopped = True
                    self.__haltVMServers = parsedArgs["HaltVMServers"]
    
    def _sendUpdateRequestPackets(self):
        """
        Solicita información de estado al serividor de cluster
        Argumentos:
            Ninguno
        Devuelve:
            Nada
        """
        if (self.__stopped) :
            return
        # Enviamos paquetes para obtener los tres tipos de información que necesitamos para actualizar la base de datos de estado
        p = self.__repositoryPacketHandler.createDataRequestPacket(PACKET_T.QUERY_VM_SERVERS_STATUS)
        errorMessage = self.__manager.sendPacket(self.__clusterServerIP, self.__clusterServerPort, p)          
        NetworkManager.printConnectionWarningIfNecessary(self.__clusterServerIP, self.__clusterServerPort, "Virtual machine servers status", errorMessage)     
        
        p = self.__repositoryPacketHandler.createDataRequestPacket(PACKET_T.QUERY_VM_DISTRIBUTION)
        errorMessage = self.__manager.sendPacket(self.__clusterServerIP, self.__clusterServerPort, p)        
        NetworkManager.printConnectionWarningIfNecessary(self.__clusterServerIP, self.__clusterServerPort, "Virtual machine distribution", errorMessage)
        
        p = self.__repositoryPacketHandler.createDataRequestPacket(PACKET_T.QUERY_ACTIVE_VM_DATA)
        errorMessage = self.__manager.sendPacket(self.__clusterServerIP, self.__clusterServerPort, p)
        NetworkManager.printConnectionWarningIfNecessary(self.__clusterServerIP, self.__clusterServerPort, "Active virtual machines data", errorMessage)
Beispiel #14
0
class WebServerEndpoint(object):
    """
    These objects communicate a cluster server and the web connectors.
    """
    def __init__(self):
        """
        Initializes the endpoint's state
        Args:
            None
        """
        self.__stopped = False

    def connectToDatabases(self, mysqlRootsPassword, statusDBName,
                           commandsDBName, statusdbSQLFilePath,
                           commandsDBSQLFilePath, websiteUser,
                           websiteUserPassword, endpointUser,
                           endpointUserPassword):
        """
        Establishes a connection with the system status database.
        Args:
            mysqlRootsPassword: MySQL root's password
            statusDBName: the status database name
            statusdbSQLFilePath: the database schema definition SQL file path
            websiteUser: the website user's name. 
            websiteUserPassword: the website user's password
            endpointUser: the update user's name. This user will have ALL privileges on the status database.
            endpointUserPassword: the update user's password.
        """
        # Create the status database
        self.__rootsPassword = mysqlRootsPassword
        self.__statusDatabaseName = statusDBName
        self.__commandsDatabaseName = commandsDBName
        configurator = DBConfigurator(mysqlRootsPassword)
        configurator.runSQLScript(statusDBName, statusdbSQLFilePath)
        configurator.runSQLScript(commandsDBName, commandsDBSQLFilePath)
        # Register the website and the endpoint users
        configurator.addUser(websiteUser, websiteUserPassword, statusDBName,
                             False)
        configurator.addUser(endpointUser, endpointUserPassword, statusDBName,
                             True)
        configurator.addUser(websiteUser, websiteUserPassword, commandsDBName,
                             True)
        configurator.addUser(endpointUser, endpointUserPassword,
                             commandsDBName, True)
        # Create the database connectors
        self.__commandsDBConnector = CommandsDatabaseConnector(
            endpointUser, endpointUserPassword, commandsDBName, 1)
        self.__writer = SystemStatusDatabaseWriter(endpointUser,
                                                   endpointUserPassword,
                                                   statusDBName)
        # Connect to the database
        self.__writer.connect()
        self.__commandsDBConnector.connect()

    def connectToClusterServer(self, certificatePath, clusterServerIP,
                               clusterServerListenningPort,
                               statusDBUpdateInterval):
        """
        Establishes a connection with the cluster server.
        Args:
            certificatePath: the server.crt and server.key directory path.
            clusterServerIP: the cluster server's IPv4 address
            clusterServerListenningPort: the cluster server's listenning port.
            statusDBUpdateInterval: the status database update interval (in seconds)
        Returns:
            Nothing
        """
        self.__manager = NetworkManager(certificatePath)
        self.__manager.startNetworkService()
        callback = _ClusterServerEndpointCallback(self)
        # Connect to the main server
        self.__clusterServerIP = clusterServerIP
        self.__clusterServerPort = clusterServerListenningPort
        self.__manager.connectTo(clusterServerIP, clusterServerListenningPort,
                                 5, callback, True)
        while (not self.__manager.isConnectionReady(
                clusterServerIP, clusterServerListenningPort)):
            sleep(0.1)
        # Create the packet handler
        self.__pHandler = ClusterServerPacketHandler(self.__manager)
        # Create the update thread
        self.__updateRequestThread = StatusDatabaseUpdateThread(
            _ClusterServerEndpointUpdateHandler(self), statusDBUpdateInterval)
        # Start it
        self.__updateRequestThread.start()

    def disconnectFromClusterServer(self):
        """
        Closes the connection with the cluster server and drops the databases.
        Args:
            haltVMServers: if True, the virtual machine servers will be halted immediately. If false, they will be
            halted until all their virtual machines have been shut down.
        Returns:
            Nothing
        @attention: DO NOT call this method inside a network thread (i.e. inside the web callback). If you do so,
        your application will hang.
        """
        # Send a halt packet to the cluster server
        p = self.__pHandler.createHaltPacket(self.__haltVMServers)
        self.__manager.sendPacket(self.__clusterServerIP,
                                  self.__clusterServerPort, p)
        # Stop the update request thread
        self.__updateRequestThread.stop()
        # Close the database connections
        self.__commandsDBConnector.disconnect()
        self.__writer.disconnect()
        # Stop the network service
        self.__manager.stopNetworkService()
        # Delete the status database
        dbConfigurator = DBConfigurator(self.__rootsPassword)
        dbConfigurator.dropDatabase(self.__statusDatabaseName)
        dbConfigurator.dropDatabase(self.__commandsDatabaseName)

    def _processIncomingPacket(self, packet):
        """
        Processes an incoming package (sent from the cluster server).
        Args:
            packet: the packet to process
        Returns:
            Nothing
        """
        if (self.__stopped):
            return
        data = self.__pHandler.readPacket(packet)
        if (data["packet_type"] == PACKET_T.VM_SERVERS_STATUS_DATA):
            self.__writer.processVMServerSegment(data["Segment"],
                                                 data["SequenceSize"],
                                                 data["Data"])
        elif (data["packet_type"] == PACKET_T.VM_DISTRIBUTION_DATA):
            self.__writer.processVMDistributionSegment(data["Segment"],
                                                       data["SequenceSize"],
                                                       data["Data"])
        elif (data["packet_type"] == PACKET_T.ACTIVE_VM_DATA):
            self.__writer.processActiveVMSegment(data["Segment"],
                                                 data["SequenceSize"],
                                                 data["VMServerIP"],
                                                 data["Data"])
        else:
            l = data["CommandID"].split("|")
            commandID = (int(l[0]), float(l[1]))
            if (data["packet_type"] == PACKET_T.COMMAND_EXECUTED):
                self.__commandsDBConnector.removeExecutedCommand(commandID)
            else:
                # Command outputs => serialize and add them to the commands database
                if (data["packet_type"] == PACKET_T.VM_SERVER_BOOTUP_ERROR
                        or data["packet_type"]
                        == PACKET_T.VM_SERVER_UNREGISTRATION_ERROR
                        or data["packet_type"]
                        == PACKET_T.VM_SERVER_SHUTDOWN_ERROR):
                    (outputType, outputContent
                     ) = CommandsHandler.createVMServerGenericErrorOutput(
                         data["packet_type"], data["ServerNameOrIPAddress"],
                         data["ErrorMessage"])
                elif (data["packet_type"] ==
                      PACKET_T.VM_SERVER_REGISTRATION_ERROR):
                    (outputType, outputContent
                     ) = CommandsHandler.createVMServerRegistrationErrorOutput(
                         data["VMServerIP"], data["VMServerPort"],
                         data["VMServerName"], data["ErrorMessage"])
                elif (data["packet_type"] == PACKET_T.VM_BOOT_FAILURE):
                    (outputType, outputContent
                     ) = CommandsHandler.createVMBootFailureErrorOutput(
                         data["VMID"], data["ErrorMessage"])
                elif (data["packet_type"] == PACKET_T.VM_CONNECTION_DATA):
                    (outputType, outputContent
                     ) = CommandsHandler.createVMConnectionDataOutput(
                         data["VNCServerIPAddress"], data["VNCServerPort"],
                         data["VNCServerPassword"])
                self.__commandsDBConnector.addCommandOutput(
                    commandID, outputType, outputContent)

    def processCommands(self):
        """
        Processes the commands sent from the web connectors.
        Args:
            None
        Returns:
            Nothing
        @attention: This method will only finish after processing a halt command.
        """
        while not self.__stopped:
            commandData = self.__commandsDBConnector.popCommand()
            if (commandData == None):
                sleep(0.1)
            else:
                (commandID, commandType, commandArgs) = commandData
                parsedArgs = CommandsHandler.deserializeCommandArgs(
                    commandType, commandArgs)
                if (commandType != COMMAND_TYPE.HALT):
                    serializedCommandID = "{0}|{1}".format(
                        commandID[0], commandID[1])
                    if (commandType == COMMAND_TYPE.BOOTUP_VM_SERVER):
                        packet = self.__pHandler.createVMServerBootUpPacket(
                            parsedArgs["VMServerNameOrIP"],
                            serializedCommandID)
                    elif (commandType == COMMAND_TYPE.REGISTER_VM_SERVER):
                        packet = self.__pHandler.createVMServerRegistrationPacket(
                            parsedArgs["VMServerIP"],
                            parsedArgs["VMServerPort"],
                            parsedArgs["VMServerName"], serializedCommandID)
                    elif (commandType ==
                          COMMAND_TYPE.UNREGISTER_OR_SHUTDOWN_VM_SERVER):
                        packet = self.__pHandler.createVMServerUnregistrationOrShutdownPacket(
                            parsedArgs["VMServerNameOrIP"], parsedArgs["Halt"],
                            parsedArgs["Unregister"], serializedCommandID)
                    elif (commandType == COMMAND_TYPE.VM_BOOT_REQUEST):
                        packet = self.__pHandler.createVMBootRequestPacket(
                            parsedArgs["VMID"], parsedArgs["UserID"],
                            serializedCommandID)
                    self.__manager.sendPacket(self.__clusterServerIP,
                                              self.__clusterServerPort, packet)
                else:
                    self.__stopped = True
                    self.__haltVMServers = parsedArgs["HaltVMServers"]

    def _sendUpdateRequestPackets(self):
        """
        Sends the update request packets to the cluster server.
        Args:
            None
        Returns:
            Nothing
        """
        if (self.__stopped):
            return
        # Send some update request packets to the cluster server
        p = self.__pHandler.createDataRequestPacket(
            PACKET_T.QUERY_VM_SERVERS_STATUS)
        self.__manager.sendPacket(self.__clusterServerIP,
                                  self.__clusterServerPort, p)
        p = self.__pHandler.createDataRequestPacket(
            PACKET_T.QUERY_VM_DISTRIBUTION)
        self.__manager.sendPacket(self.__clusterServerIP,
                                  self.__clusterServerPort, p)
        p = self.__pHandler.createDataRequestPacket(
            PACKET_T.QUERY_ACTIVE_VM_DATA)
        self.__manager.sendPacket(self.__clusterServerIP,
                                  self.__clusterServerPort, p)
class ClusterServerConnector(object):
    """
    Estos objetos comunican la web y el endpoint a través de memoria compartida.
    """
    def __init__(self, userID):
        """
        Inicializa el estado del conector
        Argumentos:
            userID: el identificador del usuario que accede al sistema. Se trata de un entero.
        """
        self.__userID = userID

    def connectToDatabases(self, statusDBName, commandsDBName, databaseUser,
                           databasePassword):
        """
        Establece una conexión con las bases de datos de estado y comandos.
        Argumentos:
            statusDBName: el nombre de la base de datos de estado
            commandsDBName: el nombre de la base de datos de comandos
            databaseUser: el nombre de usuario con el que se accederá a las dos bases de datos
            databasePassword: la contraseña para acceder a las bases de datos
        Devuelve:
            Nada
        """
        self.__endpointDBConnector = ClusterEndpointDBConnector(
            databaseUser, databasePassword, statusDBName)
        self.__commandsDBConnector = CommandsDatabaseConnector(
            databaseUser, databasePassword, commandsDBName, 1)

    def dispose(self):
        """
        Cierra las conexiones con las bases de datos
        Argumentos:
            Ninguno
        Devuelve:
            Nada
        """
        pass

    def getActiveVMsData(self, showAllVMs=False):
        """
        Devuelve los datos de las máquinas virtuales activas
        Argumentos:
            showAllVMs: si es True, se muestran los datos de todas las máquinas activas; si es False, sólo
            las del usuario registrado en el conector
        Devuelve: una lista de diccionarios con los datos de las máquinas virtuales activas
        """
        if not showAllVMs:
            userID = self.__userID
        else:
            userID = None
        return self.__endpointDBConnector.getActiveVMsData(userID)

    def getVMDistributionData(self):
        """
        Devuelve los datos de distribución de las imágenes
        Argumentos:
            Ninguno
        Devuelve: una lista de diccionarios con los datos de distribución de las imágenes
        """
        return self.__endpointDBConnector.getVMDistributionData()

    def getVMServersData(self):
        """
        Devuelve los datos básicos de los servidores de máquinas virtuales
        Argumentos:
            Ninguno
        Devuelve: una lista de diccionarios con los datos básicos de los servidores de máquinas virtuales
        """
        return self.__endpointDBConnector.getVMServersData()

    def registerVMServer(self, vmServerIP, vmServerPort, vmServerName,
                         isVanillaServer):
        """
        Registra un servidor de máquinas virtuales
        Argumentos:
            vmServerIP: la IP del servidor de máquinas virtuales
            vmServerPort: el puerto en el que escucha
            vmServerName: el nombre del servidor de máquinas virtuales
            isVanillaServer: indica si el servidor de máquinas virtuales se usará preferentemente
                para editar imágenes vanilla o no.
        Devuelve:
            El identificador único del comando.
            @attention: La representación del identificador único del comando puede cambiar sin previo aviso.
        """
        (commandType,
         commandArgs) = CommandsHandler.createVMServerRegistrationCommand(
             vmServerIP, vmServerPort, vmServerName, isVanillaServer)
        return self.__commandsDBConnector.addCommand(self.__userID,
                                                     commandType, commandArgs)

    def unregisterVMServer(self, vmServerNameOrIP, isShutDown):
        """
        Borra un servidor de máquinas virtuales
        Argumentos:
            vmServerNameOrIP: el nombre o la IP del servidor a borrar
            isShutDown: si es True, el servidor se apagará inmediatamente. Si es False, esperará a que los usuarios apaguen sus
            máquinas virtuales.
        Devuelve:
            El identificador único del comando.
            @attention: La representación del identificador único del comando puede cambiar sin previo aviso.
        """
        (commandType, commandArgs
         ) = CommandsHandler.createVMServerUnregistrationOrShutdownCommand(
             True, vmServerNameOrIP, isShutDown)
        return self.__commandsDBConnector.addCommand(self.__userID,
                                                     commandType, commandArgs)

    def shutdownVMServer(self, vmServerNameOrIP, isShutDown):
        """
        Apaga un servidor de máquinas virtuales
        Argumentos:
            vmServerNameOrIP: el nombre o la IP del servidor a borrar
            isShutDown: si es True, el servidor se apagará inmediatamente. Si es False, esperará a que los usuarios apaguen sus
            máquinas virtuales.
        Devuelve:
            El identificador único del comando.
            @attention: La representación del identificador único del comando puede cambiar sin previo aviso.
        """
        (commandType, commandArgs
         ) = CommandsHandler.createVMServerUnregistrationOrShutdownCommand(
             False, vmServerNameOrIP, isShutDown)
        return self.__commandsDBConnector.addCommand(self.__userID,
                                                     commandType, commandArgs)

    def bootUpVMServer(self, vmServerNameOrIP):
        """
        Arranca un servidor de máquinas virtuales y lo añade a la infraestructura
        Argumentos:
            vmServerNameOrIP: el nombre o la IP del servidor a arrancar
        Devuelve:
            El identificador único del comando.
            @attention: La representación del identificador único del comando puede cambiar sin previo aviso.
        """
        (commandType, commandArgs
         ) = CommandsHandler.createVMServerBootCommand(vmServerNameOrIP)
        return self.__commandsDBConnector.addCommand(self.__userID,
                                                     commandType, commandArgs)

    def bootUpVM(self, imageID):
        """
        Solicita a la infraestructura el arranque de una máquina virtual
        Argumentos:
            imageID: el identificador único de la imagen a arrancar
        Devuelve:
            El identificador único del comando.
            @attention: La representación del identificador único del comando puede cambiar sin previo aviso.
        """
        (commandType, commandArgs) = CommandsHandler.createVMBootCommand(
            imageID, self.__userID)
        return self.__commandsDBConnector.addCommand(self.__userID,
                                                     commandType, commandArgs)

    def isShutDown(self, haltVMServers):
        """
        Apaga toda la infraestructura
        Argumentos:
            haltVMServers: si es True, el servidor se apagará inmediatamente. Si es False, esperará a que los usuarios apaguen sus
            máquinas virtuales.
        Devuelve: 
            Nada
        """
        (commandType,
         commandArgs) = CommandsHandler.createHaltCommand(haltVMServers)
        self.__commandsDBConnector.addCommand(self.__userID, commandType,
                                              commandArgs)

    def destroyDomain(self, domainID):
        """
        Destruye una máquina virtual
        Argumentos:
            domainID: el identificador único de la máquina virtual a destruir
        Devuelve:
            Nada
        """
        (commandType, commandArgs
         ) = CommandsHandler.createDomainDestructionCommand(domainID)
        return self.__commandsDBConnector.addCommand(self.__userID,
                                                     commandType, commandArgs)

    def changeVMServerConfiguration(self, serverNameOrIPAddress, newName,
                                    newIPAddress, newPort,
                                    newVanillaImageEditionBehavior):
        (commandType, commandArgs
         ) = CommandsHandler.createVMServerConfigurationChangeCommand(
             serverNameOrIPAddress, newName, newIPAddress, newPort,
             newVanillaImageEditionBehavior)
        return self.__commandsDBConnector.addCommand(self.__userID,
                                                     commandType, commandArgs)

    def getCommandOutput(self, commandID):
        """
        Devuelve la salida de un comando
        Argumentos:
            commandID: el identificador único del comando
        Devuelve:
            - Si el comando todavía se está ejecutando, se devuelve una tupla vacía.
            - Si el comando se ha terminado de ejecutar, se devuelve un diccionario
              con los datos de su salida.
        """
        if (self.__commandsDBConnector.isRunning(commandID)):
            return ()
        else:
            result = self.__commandsDBConnector.getCommandOutput(commandID)
            if (result != None):
                (outputType, outputContent) = result
                result = CommandsHandler.deserializeCommandOutput(
                    outputType, outputContent)
            return result

    def waitForCommandOutput(self, commandID):
        """
        Espera a que un comando termine, devolviendo su salida en caso de que la haya.
        Argumentos:
            commandID: el identificador único del comando
        Devuelve: 
            - None si el comando no tiene salida
            - Un diccionario con los datos de su salida en caso contrario
        @attention: Este método es bloqueante. Si se desea un comportamiento no bloqueante,
        es necesario utilizar el método getCommandOutput.
        """
        while (self.__commandsDBConnector.isRunning(commandID)):
            sleep(0.1)
        result = self.__commandsDBConnector.getCommandOutput(commandID)
        if result == None:
            return None
        else:
            return CommandsHandler.deserializeCommandOutput(
                result[0], result[1])

    def getImageBasicData(self, imageID):
        return self.__endpointDBConnector.getImageBasicData(imageID)

    def getBootableImagesData(self, imageIDs):
        return self.__endpointDBConnector.getBootableImagesData(imageIDs)

    def getBaseImagesData(self):
        return self.__endpointDBConnector.getBaseImagesData()

    def getEditedImages(self, userID):
        return self.__endpointDBConnector.getEditedImages(userID)

    def getVanillaImageFamilyID(self, imageID):
        return self.__endpointDBConnector.getVanillaImageFamilyID(imageID)

    def getVanillaImageFamiliyData(self, vanillaImageFamilyID):
        return self.__endpointDBConnector.getVanillaImageFamiliyData(
            vanillaImageFamilyID)
class WebServerEndpoint(object):
    """
    Estos objetos comunican un servidor de cluster con la web
    """
    def __init__(self):
        """
        Inicializa el estado del endpoint
        Argumentos:
            Ninguno
        """
        self.__stopped = False

    def connectToDatabases(self, mysqlRootsPassword, statusDBName,
                           commandsDBName, statusdbSQLFilePath,
                           commandsDBSQLFilePath, websiteUser,
                           websiteUserPassword, endpointUser,
                           endpointUserPassword, minCommandInterval):
        """
        Establece la conexión con la base de datos de estado y con la base de datos de comandos.
        Argumentos:
            mysqlRootsPassword: la contraseña de root de MySQL
            statusDBName: el nombre de la base de datos de estado
            statusdbSQLFilePath: la ruta del script que crea la base de datos de estado
            websiteUser: nombre de usuario que usará la web para manipular las bases de datos
            websiteUserPassword: contraseña del usuario de la web
            endpointUser: usuario que utilizará en eldpoint para manipular las bases de datos de estado. Será el único
            que puede escribir en la base de datos de estado.
            endpointUserPassword: contraseña del usuario del endpoint
        """
        # Crear las bases de datos
        self.__rootsPassword = mysqlRootsPassword
        self.__statusDatabaseName = statusDBName
        self.__commandsDatabaseName = commandsDBName
        configurator = DBConfigurator(mysqlRootsPassword)
        configurator.runSQLScript(statusDBName, statusdbSQLFilePath)
        configurator.runSQLScript(commandsDBName, commandsDBSQLFilePath)
        # Registrar en ellas los usuarios
        configurator.addUser(websiteUser, websiteUserPassword, statusDBName,
                             False)
        configurator.addUser(endpointUser, endpointUserPassword, statusDBName,
                             True)
        configurator.addUser(websiteUser, websiteUserPassword, commandsDBName,
                             True)
        configurator.addUser(endpointUser, endpointUserPassword,
                             commandsDBName, True)
        # Crear los conectores
        self.__commandsDBConnector = CommandsDatabaseConnector(
            endpointUser, endpointUserPassword, commandsDBName,
            minCommandInterval)
        self.__endpointDBConnector = ClusterEndpointDBConnector(
            endpointUser, endpointUserPassword, statusDBName)

    def connectToClusterServer(self, certificatePath, clusterServerIP,
                               clusterServerListenningPort,
                               statusDBUpdateInterval, commandTimeout,
                               commandTimeoutCheckInterval):
        """
        Establece la conexión con el servidor de cluster
        Argumentos:
            certificatePath: la ruta del directorio con los ficheros server.crt y server.key.
            clusterServerIP: la IP del servidor de cluster
            clusterServerListenningPort: el puerto en el que escucha el servidor de cluster
            statusDBUpdateInterval: el periodo de actualización de la base de datos (en segundos)
        Devuelve:
            Nada
        Lanza:
            EnpointException: se lanza cuando no se puede establecer una conexión con el servidor web
        """
        self.__manager = NetworkManager(certificatePath)
        self.__manager.startNetworkService()
        callback = _ClusterServerEndpointCallback(self)
        # Establecer la conexión
        self.__clusterServerIP = clusterServerIP
        self.__clusterServerPort = clusterServerListenningPort
        try:
            self.__manager.connectTo(clusterServerIP,
                                     clusterServerListenningPort, 5, callback,
                                     True)
            while (not self.__manager.isConnectionReady(
                    clusterServerIP, clusterServerListenningPort)):
                sleep(0.1)

            # TODO: si esto falla, terminar.
            # Preparar la recepción de paquetes y la actualización automática de la base de datos de estado
            self.__repositoryPacketHandler = ClusterServerPacketHandler(
                self.__manager)

            self.__updateRequestThread = VMServerMonitoringThread(
                _ClusterServerEndpointUpdateHandler(self),
                statusDBUpdateInterval)
            self.__updateRequestThread.start()
            self.__commandMonitoringThread = CommandMonitoringThread(
                self.__commandsDBConnector, commandTimeout,
                commandTimeoutCheckInterval)
            self.__commandMonitoringThread.start()
        except NetworkManagerException as e:
            raise EndpointException(e.message)

    def disconnectFromClusterServer(self):
        """
        Cierra la conexión con el servidor de cluster y borra las bases de datos de estado
        Argumentos:
            Ninguno
        Devuelve:
            Nada
        @attention: Este método debe llamarse desde el hilo principal para evitar cuelgues
        """
        # Apagar el servidor de cluster
        p = self.__repositoryPacketHandler.createHaltPacket(
            self.__haltVMServers)
        errorMessage = self.__manager.sendPacket(self.__clusterServerIP,
                                                 self.__clusterServerPort, p)
        NetworkManager.printConnectionWarningIfNecessary(
            self.__clusterServerIP, self.__clusterServerPort,
            "Cluster server halt", errorMessage)
        # Dejar de actualizar las bases de datos
        self.__updateRequestThread.stop()

        # Dejar de monitorizar los comandos
        self.__commandMonitoringThread.stop()

        # Cerrar las conexiones con las bases de datos
        self.closeNetworkAndDBConnections()

    def closeNetworkAndDBConnections(self):
        """
        Cierra las conexiones con las bases de datos
        Argumentos:
            Ninguno
        Devuelve:
            Nada
        """
        # Detener el servicio de red
        self.__manager.stopNetworkService()
        # Borrar las bases de datos de comandos y de estado
        dbConfigurator = DBConfigurator(self.__rootsPassword)
        dbConfigurator.dropDatabase(self.__commandsDatabaseName)

    def _processIncomingPacket(self, packet):
        """
        Procesa un paquete enviado desde el servidor de cluster
        Argumentos:
            packet: el paquete a procesar
        Devuelve:
            Nada
        """
        if (self.__stopped):
            return
        data = self.__repositoryPacketHandler.readPacket(packet)
        if (data["packet_type"] == PACKET_T.VM_SERVERS_STATUS_DATA):
            self.__endpointDBConnector.processVMServerSegment(
                data["Segment"], data["SequenceSize"], data["Data"])
        elif (data["packet_type"] == PACKET_T.VM_DISTRIBUTION_DATA):
            self.__endpointDBConnector.processVMDistributionSegment(
                data["Segment"], data["SequenceSize"], data["Data"])
        elif (data["packet_type"] == PACKET_T.ACTIVE_VM_DATA):
            self.__endpointDBConnector.processActiveVMSegment(
                data["Segment"], data["SequenceSize"], data["VMServerIP"],
                data["Data"])
        else:
            l = data["CommandID"].split("|")
            commandID = (int(l[0]), float(l[1]))
            if (data["packet_type"] == PACKET_T.COMMAND_EXECUTED):
                self.__commandsDBConnector.removeExecutedCommand(commandID)
            else:
                # El resto de paquetes contienen el resultado de ejecutar comandos => los serializamos y los añadimos
                # a la base de datos de comandos para que los conectores se enteren
                if (data["packet_type"] == PACKET_T.VM_SERVER_BOOTUP_ERROR
                        or data["packet_type"]
                        == PACKET_T.VM_SERVER_UNREGISTRATION_ERROR
                        or data["packet_type"]
                        == PACKET_T.VM_SERVER_SHUTDOWN_ERROR):
                    (outputType, outputContent
                     ) = CommandsHandler.createVMServerGenericErrorOutput(
                         data["packet_type"], data["ServerNameOrIPAddress"],
                         data["ErrorMessage"])
                elif (data["packet_type"] ==
                      PACKET_T.VM_SERVER_REGISTRATION_ERROR):
                    (outputType, outputContent
                     ) = CommandsHandler.createVMServerRegistrationErrorOutput(
                         data["VMServerIP"], data["VMServerPort"],
                         data["VMServerName"], data["ErrorMessage"])
                elif (data["packet_type"] == PACKET_T.VM_BOOT_FAILURE):
                    (outputType, outputContent
                     ) = CommandsHandler.createVMBootFailureErrorOutput(
                         data["VMID"], data["ErrorMessage"])
                elif (data["packet_type"] == PACKET_T.VM_CONNECTION_DATA):
                    (outputType, outputContent
                     ) = CommandsHandler.createVMConnectionDataOutput(
                         data["VNCServerIPAddress"], data["VNCServerPort"],
                         data["VNCServerPassword"])
                elif (data["packet_type"] == PACKET_T.DOMAIN_DESTRUCTION_ERROR
                      ):
                    (outputType, outputContent
                     ) = CommandsHandler.createDomainDestructionErrorOutput(
                         data["ErrorMessage"])
                elif (data["packet_type"] ==
                      PACKET_T.VM_SERVER_CONFIGURATION_CHANGE_ERROR):
                    (
                        outputType, outputContent
                    ) = CommandsHandler.createVMServerConfigurationChangeErrorOutput(
                        data["ErrorMessage"])
                self.__commandsDBConnector.addCommandOutput(
                    commandID, outputType, outputContent)

    def processCommands(self):
        """
        Procesa los comandos enviados desde los conectores
        Argumentos:
            Ninguno
        Devuelve:
            Nada
        """
        while not self.__stopped:
            commandData = self.__commandsDBConnector.popCommand()
            if (commandData == None):
                sleep(0.1)
            else:
                (commandID, commandType, commandArgs) = commandData
                parsedArgs = CommandsHandler.deserializeCommandArgs(
                    commandType, commandArgs)
                if (commandType != COMMAND_TYPE.HALT):
                    serializedCommandID = "{0}|{1}".format(
                        commandID[0], commandID[1])
                    if (commandType == COMMAND_TYPE.BOOTUP_VM_SERVER):
                        packet = self.__repositoryPacketHandler.createVMServerBootUpPacket(
                            parsedArgs["VMServerNameOrIP"],
                            serializedCommandID)
                    elif (commandType == COMMAND_TYPE.REGISTER_VM_SERVER):
                        packet = self.__repositoryPacketHandler.createVMServerRegistrationPacket(
                            parsedArgs["VMServerIP"],
                            parsedArgs["VMServerPort"],
                            parsedArgs["VMServerName"],
                            parsedArgs["IsVanillaServer"], serializedCommandID)
                    elif (commandType ==
                          COMMAND_TYPE.UNREGISTER_OR_SHUTDOWN_VM_SERVER):
                        packet = self.__repositoryPacketHandler.createVMServerUnregistrationOrShutdownPacket(
                            parsedArgs["VMServerNameOrIP"], parsedArgs["Halt"],
                            parsedArgs["Unregister"], serializedCommandID)
                    elif (commandType == COMMAND_TYPE.VM_BOOT_REQUEST):
                        packet = self.__repositoryPacketHandler.createVMBootRequestPacket(
                            parsedArgs["VMID"], parsedArgs["UserID"],
                            serializedCommandID)
                    elif (commandType == COMMAND_TYPE.DESTROY_DOMAIN):
                        packet = self.__repositoryPacketHandler.createDomainDestructionPacket(
                            parsedArgs["DomainID"], serializedCommandID)
                    elif (commandType ==
                          COMMAND_TYPE.VM_SERVER_CONFIGURATION_CHANGE):
                        packet = self.__repositoryPacketHandler.createVMServerConfigurationChangePacket(
                            parsedArgs["VMServerNameOrIPAddress"],
                            parsedArgs["NewServerName"],
                            parsedArgs["NewServerIPAddress"],
                            parsedArgs["NewServerPort"],
                            parsedArgs["NewVanillaImageEditionBehavior"],
                            serializedCommandID)
                    errorMessage = self.__manager.sendPacket(
                        self.__clusterServerIP, self.__clusterServerPort,
                        packet)
                    if (errorMessage != None):
                        # Error al enviar el paquete => el comando no se podrá ejecutar => avisar a la web
                        (outputType, outputContent
                         ) = CommandsHandler.createConnectionErrorOutput()
                        self.__commandsDBConnector.addCommandOutput(
                            commandID, outputType, outputContent)

                else:
                    self.__stopped = True
                    self.__haltVMServers = parsedArgs["HaltVMServers"]

    def _sendUpdateRequestPackets(self):
        """
        Solicita información de estado al serividor de cluster
        Argumentos:
            Ninguno
        Devuelve:
            Nada
        """
        if (self.__stopped):
            return
        # Enviamos paquetes para obtener los tres tipos de información que necesitamos para actualizar la base de datos de estado
        p = self.__repositoryPacketHandler.createDataRequestPacket(
            PACKET_T.QUERY_VM_SERVERS_STATUS)
        errorMessage = self.__manager.sendPacket(self.__clusterServerIP,
                                                 self.__clusterServerPort, p)
        NetworkManager.printConnectionWarningIfNecessary(
            self.__clusterServerIP, self.__clusterServerPort,
            "Virtual machine servers status", errorMessage)

        p = self.__repositoryPacketHandler.createDataRequestPacket(
            PACKET_T.QUERY_VM_DISTRIBUTION)
        errorMessage = self.__manager.sendPacket(self.__clusterServerIP,
                                                 self.__clusterServerPort, p)
        NetworkManager.printConnectionWarningIfNecessary(
            self.__clusterServerIP, self.__clusterServerPort,
            "Virtual machine distribution", errorMessage)

        p = self.__repositoryPacketHandler.createDataRequestPacket(
            PACKET_T.QUERY_ACTIVE_VM_DATA)
        errorMessage = self.__manager.sendPacket(self.__clusterServerIP,
                                                 self.__clusterServerPort, p)
        NetworkManager.printConnectionWarningIfNecessary(
            self.__clusterServerIP, self.__clusterServerPort,
            "Active virtual machines data", errorMessage)