def test_requirement_str(self): id, sample = self.add_task( tags=["doge"], platform="DogeOS", machine="Doge1" ) id = submit_task.add_path( self.get_file(), tags=["doge"], platform="DogeOS", machine="Doge1" ) task = Task() task.load_from_db(id) req_str = task.requirements_str(task.db_task) assert req_str == "machine=Doge1 platform=DogeOS tags=doge, "
def handle_pending(self): """Handles pending tasks. Checks if a new task can be started. Eg: not too many machines already running, disk space left etc. Selects a machine matching the task requirements and creates a matching analysis manager for the type of the selected pending task""" # Acquire machine lock non-blocking. This is because the scheduler # also handles requests made by analysis manager. A blocking lock # could cause a deadlock if not self.machine_lock.acquire(False): return # Select task that is specifically for one of the available machines # possibly a service machine or reserved machine machine, task, analysis = None, None, False for available_machine in self.db.get_available_machines(): # If the machine has been reserved for a specific task, this # task should be processed first, as the machine will only be # released it has finished (Example: longterm task). if available_machine.reserved_by: task = self.db.fetch(task_id=available_machine.reserved_by) if task: machine = self.machinery.acquire( machine_id=available_machine.name ) break continue task = self.db.fetch(machine=available_machine.name) if task: machine = self.machinery.acquire( machine_id=available_machine.name ) break if available_machine.is_analysis(): analysis = True # No task for a specific machine and at least one of the available # machines is not a service machine. Fetch task that is not # for a service machine if not task and not machine and analysis: # Search for a task, but don't lock it until we are sure a machine # for this task is available, since it might have tags or require # a specific platform. Ignore a task if we know a machine is not # available for it. exclude = [] while not machine: task = self.db.fetch(service=False, exclude=exclude) if task is None: break try: machine = self.machinery.acquire( machine_id=task.machine, platform=task.platform, tags=task.tags ) except CuckooOperationalError: log.error( "Task #%s cannot be started, no machine with matching " "requirements for this task exists. Requirements: %s", task.id, Task.requirements_str(task) ) # No machine with required tags, name etc exists # Set analysis to failed. # TODO Use another status so it might be recovered # on next Cuckoo startup if the machine exists by then self.db.set_status(task.id, TASK_FAILED_ANALYSIS) break if not machine: exclude.append(task.id) if not task or not machine: self.machine_lock.release() if machine: self.machinery.release(label=machine.label) return log.info( "Task #%d: acquired machine %s (label=%s)", task.id, machine.name, machine.label, extra={ "action": "vm.acquire", "status": "success", "vmname": machine.name, } ) # Task and matching machine found. Find analysis manager # which supports the type of this task. Lock it when found analysis_manager = self.get_analysis_manager(task, machine) if not analysis_manager: # If no analysis manager is found for this task type, it # cannot be started, therefore we release the machine again self.machinery.release(label=machine.label) # Release machine lock as the machine will not be starting self.machine_lock.release() # Set task status to failed as it cannot be analysed if no matching # analysis manager for its type exists self.db.set_status(task.id, TASK_FAILED_ANALYSIS) return # Only lock task for running if we are sure we will try to start it self.db.set_status(task.id, TASK_RUNNING) # Increment the total amount of analyses self.total_analysis_count += 1 analysis_manager.daemon = True if not analysis_manager.init(self.db): self.db.set_status(task.id, TASK_FAILED_ANALYSIS) log.error( "Failed to initialize analysis manager for task #%s", task.id ) self.machine_lock.release() self.machinery.release(label=machine.label) return # If initialization succeeded, start the analysis manager # and store it so we can track it analysis_manager.start() self.managers.append(analysis_manager)