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 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): """ 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)