def cuckoo_machine(vmname, action, ip, platform, options, tags, interface, snapshot, resultserver): db = Database() cfg = Config.from_confdir(cwd("conf")) machinery = cfg["cuckoo"]["cuckoo"]["machinery"] machines = cfg[machinery][machinery]["machines"] if action == "add": if not ip: sys.exit("You have to specify a legitimate IP address for --add.") if db.view_machine(vmname): sys.exit("A Virtual Machine with this name already exists!") if vmname in machines: sys.exit("A Virtual Machine with this name already exists!") if resultserver and resultserver.count(":") == 1: resultserver_ip, resultserver_port = resultserver.split(":") resultserver_port = int(resultserver_port) else: resultserver_ip = cfg["cuckoo"]["resultserver"]["ip"] resultserver_port = cfg["cuckoo"]["resultserver"]["port"] machines.append(vmname) cfg[machinery][vmname] = { "label": vmname, "platform": platform, "ip": ip, "options": options, "snapshot": snapshot, "interface": interface, "resultserver_ip": resultserver_ip, "resultserver_port": resultserver_port, "tags": tags, } db.add_machine( vmname, vmname, ip, platform, options, tags, interface, snapshot, resultserver_ip, int(resultserver_port) ) db.unlock_machine(vmname) if action == "delete": # TODO Add a db.del_machine() function for runtime modification. if vmname not in machines: sys.exit("A Virtual Machine with this name doesn't exist!") machines.remove(vmname) cfg[machinery].pop(vmname) write_cuckoo_conf(cfg=cfg)
class Machinery(object): """Base abstract class for machinery modules.""" # Default label used in machinery configuration file to supply virtual # machine name/label/vmx path. Override it if you dubbed it in another # way. LABEL = "label" def __init__(self): self.options = None self.db = Database() # Machine table is cleaned to be filled from configuration file # at each start. self.db.clean_machines() @classmethod def init_once(cls): pass def pcap_path(self, task_id): """Returns the .pcap path for this task id.""" return cwd("storage", "analyses", "%s" % task_id, "dump.pcap") def set_options(self, options): """Set machine manager options. @param options: machine manager options dict. """ self.options = options def initialize(self, module_name): """Read, load, and verify machines configuration. @param module_name: module name. """ # Load. self._initialize(module_name) # Run initialization checks. self._initialize_check() def _initialize(self, module_name): """Read configuration. @param module_name: module name. """ machinery = self.options.get(module_name) for vmname in machinery["machines"]: options = self.options.get(vmname) # If configured, use specific network interface for this # machine, else use the default value. if options.get("interface"): interface = options["interface"] else: interface = machinery.get("interface") if options.get("resultserver_ip"): ip = options["resultserver_ip"] else: ip = config("cuckoo:resultserver:ip") if options.get("resultserver_port"): port = options["resultserver_port"] else: # The ResultServer port might have been dynamically changed, # get it from the ResultServer singleton. Also avoid import # recursion issues by importing ResultServer here. from cuckoo.core.resultserver import ResultServer port = ResultServer().port self.db.add_machine(name=vmname, label=options[self.LABEL], ip=options.ip, platform=options.platform, options=options.get("options", ""), tags=options.tags, interface=interface, snapshot=options.snapshot, resultserver_ip=ip, resultserver_port=port) def _initialize_check(self): """Runs checks against virtualization software when a machine manager is initialized. @note: in machine manager modules you may override or superclass his method. @raise CuckooMachineError: if a misconfiguration or a unkown vm state is found. """ try: configured_vms = self._list() except NotImplementedError: return for machine in self.machines(): # If this machine is already in the "correct" state, then we # go on to the next machine. if machine.label in configured_vms and \ self._status(machine.label) in [self.POWEROFF, self.ABORTED]: continue # This machine is currently not in its correct state, we're going # to try to shut it down. If that works, then the machine is fine. try: self.stop(machine.label) except CuckooMachineError as e: raise CuckooCriticalError( "Please update your configuration. Unable to shut '%s' " "down or find the machine in its proper state: %s" % (machine.label, e)) if not config("cuckoo:timeouts:vm_state"): raise CuckooCriticalError( "Virtual machine state change timeout has not been set " "properly, please update it to be non-null.") def machines(self): """List virtual machines. @return: virtual machines list """ return self.db.list_machines() def availables(self): """How many machines are free. @return: free machines count. """ return self.db.count_machines_available() def acquire(self, machine_id=None, platform=None, tags=None): """Acquire a machine to start analysis. @param machine_id: machine ID. @param platform: machine platform. @param tags: machine tags @return: machine or None. """ if machine_id: return self.db.lock_machine(label=machine_id) elif platform: return self.db.lock_machine(platform=platform, tags=tags) else: return self.db.lock_machine(tags=tags) def release(self, label=None): """Release a machine. @param label: machine name. """ self.db.unlock_machine(label) def running(self): """Returns running virtual machines. @return: running virtual machines list. """ return self.db.list_machines(locked=True) def shutdown(self): """Shutdown the machine manager. Kills all alive machines. @raise CuckooMachineError: if unable to stop machine. """ if len(self.running()) > 0: log.info("Still %s guests alive. Shutting down...", len(self.running())) for machine in self.running(): try: self.stop(machine.label) except CuckooMachineError as e: log.warning( "Unable to shutdown machine %s, please check " "manually. Error: %s", machine.label, e) def set_status(self, label, status): """Set status for a virtual machine. @param label: virtual machine label @param status: new virtual machine status """ self.db.set_machine_status(label, status) def start(self, label, task): """Start a machine. @param label: machine name. @param task: task object. @raise NotImplementedError: this method is abstract. """ raise NotImplementedError def stop(self, label=None): """Stop a machine. @param label: machine name. @raise NotImplementedError: this method is abstract. """ raise NotImplementedError def _list(self): """Lists virtual machines configured. @raise NotImplementedError: this method is abstract. """ raise NotImplementedError def dump_memory(self, label, path): """Takes a memory dump of a machine. @param path: path to where to store the memory dump. """ raise NotImplementedError def _wait_status(self, label, *states): """Waits for a vm status. @param label: virtual machine name. @param state: virtual machine status, accepts multiple states as list. @raise CuckooMachineError: if default waiting timeout expire. """ # This block was originally suggested by Loic Jaquemet. waitme = 0 try: current = self._status(label) except NameError: return while current not in states: log.debug( "Waiting %i cuckooseconds for machine %s to switch " "to status %s", waitme, label, states) if waitme > config("cuckoo:timeouts:vm_state"): raise CuckooMachineError( "Timeout hit while for machine %s to change status" % label) time.sleep(1) waitme += 1 current = self._status(label)
class Machinery(object): """Base abstract class for machinery modules.""" # Default label used in machinery configuration file to supply virtual # machine name/label/vmx path. Override it if you dubbed it in another # way. LABEL = "label" def __init__(self): self.options = None self.db = Database() # Machine table is cleaned to be filled from configuration file # at each start. self.db.clean_machines() @classmethod def init_once(cls): pass def pcap_path(self, task_id): """Returns the .pcap path for this task id.""" return cwd("storage", "analyses", "%s" % task_id, "dump.pcap") def set_options(self, options): """Set machine manager options. @param options: machine manager options dict. """ self.options = options def initialize(self, module_name): """Read, load, and verify machines configuration. @param module_name: module name. """ # Load. self._initialize(module_name) # Run initialization checks. self._initialize_check() def _initialize(self, module_name): """Read configuration. @param module_name: module name. """ machinery = self.options.get(module_name) for vmname in machinery["machines"]: options = self.options.get(vmname) # If configured, use specific network interface for this # machine, else use the default value. if options.get("interface"): interface = options["interface"] else: interface = machinery.get("interface") if options.get("resultserver_ip"): ip = options["resultserver_ip"] else: ip = config("cuckoo:resultserver:ip") if options.get("resultserver_port"): port = options["resultserver_port"] else: # The ResultServer port might have been dynamically changed, # get it from the ResultServer singleton. Also avoid import # recursion issues by importing ResultServer here. from cuckoo.core.resultserver import ResultServer port = ResultServer().port self.db.add_machine( name=vmname, label=options[self.LABEL], ip=options.ip, platform=options.platform, options=options.get("options", ""), tags=options.tags, interface=interface, snapshot=options.snapshot, resultserver_ip=ip, resultserver_port=port ) def _initialize_check(self): """Runs checks against virtualization software when a machine manager is initialized. @note: in machine manager modules you may override or superclass his method. @raise CuckooMachineError: if a misconfiguration or a unkown vm state is found. """ try: configured_vms = self._list() except NotImplementedError: return for machine in self.machines(): # If this machine is already in the "correct" state, then we # go on to the next machine. if machine.label in configured_vms and \ self._status(machine.label) in [self.POWEROFF, self.ABORTED]: continue # This machine is currently not in its correct state, we're going # to try to shut it down. If that works, then the machine is fine. try: self.stop(machine.label) except CuckooMachineError as e: raise CuckooCriticalError( "Please update your configuration. Unable to shut '%s' " "down or find the machine in its proper state: %s" % (machine.label, e) ) if not config("cuckoo:timeouts:vm_state"): raise CuckooCriticalError( "Virtual machine state change timeout has not been set " "properly, please update it to be non-null." ) def machines(self): """List virtual machines. @return: virtual machines list """ return self.db.list_machines() def availables(self): """How many machines are free. @return: free machines count. """ return self.db.count_machines_available() def acquire(self, machine_id=None, platform=None, tags=None): """Acquire a machine to start analysis. @param machine_id: machine ID. @param platform: machine platform. @param tags: machine tags @return: machine or None. """ if machine_id: return self.db.lock_machine(label=machine_id) elif platform: return self.db.lock_machine(platform=platform, tags=tags) else: return self.db.lock_machine(tags=tags) def release(self, label=None): """Release a machine. @param label: machine name. """ self.db.unlock_machine(label) def running(self): """Returns running virtual machines. @return: running virtual machines list. """ return self.db.list_machines(locked=True) def shutdown(self): """Shutdown the machine manager. Kills all alive machines. @raise CuckooMachineError: if unable to stop machine. """ if len(self.running()) > 0: log.info("Still %s guests alive. Shutting down...", len(self.running())) for machine in self.running(): try: self.stop(machine.label) except CuckooMachineError as e: log.warning("Unable to shutdown machine %s, please check " "manually. Error: %s", machine.label, e) def set_status(self, label, status): """Set status for a virtual machine. @param label: virtual machine label @param status: new virtual machine status """ self.db.set_machine_status(label, status) def start(self, label, task): """Start a machine. @param label: machine name. @param task: task object. @raise NotImplementedError: this method is abstract. """ raise NotImplementedError def stop(self, label=None): """Stop a machine. @param label: machine name. @raise NotImplementedError: this method is abstract. """ raise NotImplementedError def _list(self): """Lists virtual machines configured. @raise NotImplementedError: this method is abstract. """ raise NotImplementedError def dump_memory(self, label, path): """Takes a memory dump of a machine. @param path: path to where to store the memory dump. """ raise NotImplementedError def _wait_status(self, label, *states): """Waits for a vm status. @param label: virtual machine name. @param state: virtual machine status, accepts multiple states as list. @raise CuckooMachineError: if default waiting timeout expire. """ # This block was originally suggested by Loic Jaquemet. waitme = 0 try: current = self._status(label) except NameError: return while current not in states: log.debug("Waiting %i cuckooseconds for machine %s to switch " "to status %s", waitme, label, states) if waitme > config("cuckoo:timeouts:vm_state"): raise CuckooMachineError( "Timeout hit while for machine %s to change status" % label ) time.sleep(1) waitme += 1 current = self._status(label)
class DatabaseEngine(object): """Tests database stuff.""" URI = None def setup_class(self): set_cwd(tempfile.mkdtemp()) def setup(self): self.d = Database() self.d.connect(dsn=self.URI) def teardown(self): # Clear all tables without dropping them # This is done after each test to ensure a test doesn't fail because # of data of a previous test meta = MetaData() meta.reflect(self.d.engine) ses = self.d.Session() try: for t in reversed(meta.sorted_tables): ses.execute(t.delete()) ses.commit() finally: ses.close() def test_add_target(self): count = self.d.Session().query(Target).count() add_target("http://example.com", category="url") assert self.d.Session().query(Target).count() == count + 1 def test_add_task(self): fd, sample_path = tempfile.mkstemp() os.write(fd, "hehe") os.close(fd) # Add task. count = self.d.Session().query(Task).count() add_task(sample_path, category="file") assert self.d.Session().query(Task).count() == count + 1 def test_processing_get_task(self): # First reset all existing rows so that earlier exceptions don't affect # this unit test run. null, session = None, self.d.Session() session.query(Task).filter(Task.status == "completed", Task.processing == null).update({ "processing": "something", }) session.commit() t1 = add_task("http://google.com/1", priority=1, status="completed", category="url") t2 = add_task("http://google.com/2", priority=2, status="completed", category="url") t3 = add_task("http://google.com/3", priority=1, status="completed", category="url") t4 = add_task("http://google.com/4", priority=1, status="completed", category="url") t5 = add_task("http://google.com/5", priority=3, status="completed", category="url") t6 = add_task("http://google.com/6", priority=1, status="completed", category="url") t7 = add_task("http://google.com/7", priority=1, status="completed", category="url") assert self.d.processing_get_task("foo") == t5 assert self.d.processing_get_task("foo") == t2 assert self.d.processing_get_task("foo") == t1 assert self.d.processing_get_task("foo") == t3 assert self.d.processing_get_task("foo") == t4 assert self.d.processing_get_task("foo") == t6 assert self.d.processing_get_task("foo") == t7 assert self.d.processing_get_task("foo") is None def test_error_exists(self): task_id = add_task("http://google.com/7", category="url") self.d.add_error("A" * 1024, task_id) assert len(self.d.view_errors(task_id)) == 1 self.d.add_error("A" * 1024, task_id) assert len(self.d.view_errors(task_id)) == 2 def test_long_error(self): add_task("http://google.com/", category="url") self.d.add_error("A" * 1024, 1) err = self.d.view_errors(1) assert err and len(err[0].message) == 1024 def test_submit(self): dirpath = tempfile.mkdtemp() submit_id = self.d.add_submit(dirpath, "files", { "foo": "bar", }) submit = self.d.view_submit(submit_id) assert submit.id == submit_id assert submit.tmp_path == dirpath assert submit.submit_type == "files" assert submit.data == { "foo": "bar", } def test_connect_no_create(self): AlembicVersion.__table__.drop(self.d.engine) self.d.connect(dsn=self.URI, create=False) assert "alembic_version" not in self.d.engine.table_names() self.d.connect(dsn=self.URI) assert "alembic_version" in self.d.engine.table_names() def test_view_submit_tasks(self): submit_id = self.d.add_submit(None, None, None) target_id = add_target(__file__, category="file") t1 = add_task(custom="1", submit_id=submit_id) t2 = add_task(custom="2", submit_id=submit_id) submit = self.d.view_submit(submit_id) assert submit.id == submit_id with pytest.raises(DetachedInstanceError): print submit.tasks submit = self.d.view_submit(submit_id, tasks=True) assert len(submit.tasks) == 2 tasks = sorted((task.id, task) for task in submit.tasks) assert tasks[0][1].id == t1 assert tasks[0][1].custom == "1" assert tasks[1][1].id == t2 assert tasks[1][1].custom == "2" def test_task_set_options(self): t0 = add_task(__file__, options={"foo": "bar"}) t1 = add_task(__file__, options="foo=bar") assert self.d.view_task(t0).options == {"foo": "bar"} assert self.d.view_task(t1).options == {"foo": "bar"} def test_error_action(self): task_id = add_task(__file__) self.d.add_error("message1", task_id) self.d.add_error("message2", task_id, "actionhere") e1, e2 = self.d.view_errors(task_id) assert e1.message == "message1" assert e1.action is None assert e2.message == "message2" assert e2.action == "actionhere" def test_view_tasks(self): t1 = add_task(__file__) t2 = add_task("http://example.com", category="url") tasks = self.d.view_tasks([t1, t2]) assert tasks[0].to_dict() == self.d.view_task(t1).to_dict() assert tasks[1].to_dict() == self.d.view_task(t2).to_dict() def test_add_machine(self): self.d.add_machine("name1", "label", "1.2.3.4", "windows", None, "tag1 tag2", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") self.d.add_machine("name2", "label", "1.2.3.4", "windows", "", "tag1 tag2", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") self.d.add_machine("name3", "label", "1.2.3.4", "windows", "opt1 opt2", "tag1 tag2", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") self.d.add_machine("name4", "label", "1.2.3.4", "windows", ["opt3", "opt4"], "tag1 tag2", "int0", "snap0", "5.6.7.8", 2043, "virtualbox", reserved_by=1600) m1 = self.d.view_machine("name1") m2 = self.d.view_machine("name2") m3 = self.d.view_machine("name3") m4 = self.d.view_machine("name4") assert m1.options == [] assert m2.options == [] assert m3.options == ["opt1", "opt2"] assert m4.options == ["opt3", "opt4"] assert m1.manager == "virtualbox" assert m4.reserved_by == 1600 def test_adding_task(self): now = datetime.datetime.now() id = add_task(__file__, "file", 0, "py", "free=yes", 3, "custom", "owner", "machine1", "DogeOS", ["tag1"], False, False, now, "regular", None, now) task = self.d.view_task(id) assert id is not None assert task.timeout == 0 assert task.package == "py" assert task.options == {"free": "yes"} assert task.priority == 3 assert task.custom == "custom" assert task.owner == "owner" assert task.machine == "machine1" assert task.platform == "DogeOS" assert len(task.tags) == 1 assert task.tags[0].name == "tag1" assert task.memory == False assert task.enforce_timeout == False assert task.clock == now assert task.submit_id is None assert task.start_on == now assert len(task.targets) == 1 assert task.targets[0].category == "file" assert task.targets[0].target == __file__ def test_set_machine_rcparams(self): self.d.add_machine("name5", "label5", "1.2.3.4", "windows", None, "tag1 tag2", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") self.d.set_machine_rcparams("label5", { "protocol": "rdp", "host": "127.0.0.1", "port": 3389, }) m = self.d.view_machine("name5") assert m.rcparams == { "protocol": "rdp", "host": "127.0.0.1", "port": "3389", } def test_add_target_file(self): fd, sample_path = tempfile.mkstemp() os.write(fd, os.urandom(64)) os.close(fd) target = File(sample_path) id = add_target(sample_path, "file") db_target = self.d.find_target(id=id) assert id is not None assert db_target.file_size == 64 assert db_target.file_type == target.get_type() assert db_target.md5 == target.get_md5() assert db_target.crc32 == target.get_crc32() assert db_target.sha1 == target.get_sha1() assert db_target.sha256 == target.get_sha256() assert db_target.sha512 == target.get_sha512() assert db_target.ssdeep == target.get_ssdeep() assert db_target.category == "file" def test_add_target_url(self): target = URL("http://example.com/") id = add_target(target.url, "url") db_target = self.d.find_target(id=id) assert id is not None assert db_target.md5 == target.get_md5() assert db_target.crc32 == target.get_crc32() assert db_target.sha1 == target.get_sha1() assert db_target.sha256 == target.get_sha256() assert db_target.sha512 == target.get_sha512() assert db_target.ssdeep == target.get_ssdeep() assert db_target.category == "url" def test_find_target(self): fd, sample_path = tempfile.mkstemp() os.write(fd, os.urandom(64)) os.close(fd) target = File(sample_path) id = add_target(sample_path, category="file") assert self.d.find_target(id=id).id == id assert self.d.find_target(crc32=target.get_crc32()).id == id assert self.d.find_target(md5=target.get_md5()).id == id assert self.d.find_target(sha1=target.get_sha1()).id == id assert self.d.find_target(sha256=target.get_sha256()).id == id assert self.d.find_target(sha512=target.get_sha512()).id == id def test_find_target_multifilter(self): ids = [] paths = [] target = None for x in range(2): fd, sample_path = tempfile.mkstemp() randbytes = os.urandom(64) paths.append(sample_path) os.write(fd, randbytes) os.close(fd) target = File(sample_path) ids.append(add_target(sample_path, category="file")) db_target = self.d.find_target(sha256=target.get_sha256(), target=paths[1]) assert self.d.find_target(id=ids[0], md5=target.get_md5()) is None assert db_target.id == ids[1] def test_fetch_with_machine(self): future = datetime.datetime(2200, 5, 12, 12, 12) add_task(__file__, category="file", tags=["service"]) t2 = add_task(__file__, category="file", machine="machine1") add_task(__file__, category="file", start_on=future) add_task(__file__, category="file") t = self.d.fetch(machine="machine1", service=False) assert t.id == t2 assert t.status == "pending" def test_fetch_service_false(self): add_task(__file__, category="file", tags=["service"]) t2 = add_task(__file__, category="file") t = self.d.fetch(service=False) assert t.id == t2 assert t.status == "pending" def test_fetch_service_true(self): t1 = add_task(__file__, category="file", tags=["service"]) add_task(__file__, category="file", machine="machine1") add_task(__file__) add_task(__file__) task = self.d.fetch() assert task.id == t1 assert task.status == "pending" def test_fetch_use_start_on_true(self): future = datetime.datetime(2200, 5, 12, 12, 12) add_task(__file__, category="file", start_on=future, priority=999) t2 = add_task(__file__, category="file") t = self.d.fetch(service=False) assert t.id == t2 assert t.status == "pending" def test_fetch_use_start_on_false(self): future = datetime.datetime(2200, 5, 12, 12, 12) t1 = add_task(__file__, category="file", start_on=future, priority=999) add_task(__file__, category="file") t = self.d.fetch(use_start_on=False, service=False) assert t.id == t1 assert t.status == "pending" def test_fetch_use_exclude(self): t1 = add_task(__file__, category="file", priority=999) t2 = add_task(__file__, category="file", priority=999) t3 = add_task(__file__, category="file", priority=999) t4 = add_task(__file__, category="file", priority=999) t = self.d.fetch(service=False, exclude=[t1, t2, t3]) assert t.id == t4 assert t.status == "pending" def test_fetch_specific_task(self): t1 = add_task(__file__, category="file", priority=999) t2 = add_task(__file__, category="file", priority=999) t = self.d.fetch(task_id=t1) assert t.id == t1 assert t.status == "pending" def test_lock_machine(self): t1 = add_task(__file__, category="file", tags=["app1", "office7"]) t2 = add_task(__file__, category="file", tags=["app1", "office15"]) self.d.add_machine("name1", "name1", "1.2.3.4", "windows", "", "app1,office7", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") self.d.add_machine("name2", "name2", "1.2.3.4", "DogeOS", "opt1 opt2", "office13", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") self.d.add_machine("name3", "name3", "1.2.3.4", "CoffeeOS", ["opt3", "opt4"], "cofOS,office7", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") task1 = self.d.view_task(t1) task2 = self.d.view_task(t2) m1 = self.d.lock_machine(tags=task1.tags) assert m1.locked assert m1.name == "name1" with pytest.raises(CuckooOperationalError): self.d.lock_machine(platform="DogeOS", tags=task2.tags) m2 = self.d.lock_machine(platform="DogeOS") assert m2.name == "name2" m3 = self.d.lock_machine(label="name3") assert m3.locked assert m3.name == "name3" def test_list_tasks(self): t1 = add_task(__file__, category="file", owner="doge", options={"route": "vpn511"}) t2 = add_task(__file__, category="file") add_task(__file__, category="file") self.d.set_status(t2, "reported") self.d.set_status(t1, "reported") tasks = self.d.list_tasks(owner="doge", status="reported") tasks2 = self.d.list_tasks() tasks3 = self.d.list_tasks(status="reported") assert tasks[0].id == t1 assert len(tasks2) == 3 assert len(tasks3) == 2 def test_list_tasks_between(self): for x in range(5): add_task(__file__, category="file") tasks = self.d.list_tasks(filter_by="id", operators="between", values=(1, 3)) assert len(tasks) == 3 def test_list_tasks_multiple_filter(self): ids = [] future = None for x in range(10): id = add_task(__file__, category="file") ids.append(id) future = datetime.datetime.now() + datetime.timedelta(days=id) ses = self.d.Session() task = ses.query(Task).get(id) task.completed_on = future ses.commit() ses.close() tasks = self.d.list_tasks(filter_by=["id", "completed_on"], operators=[">", "<"], values=[4, future], order_by="id", limit=1) assert len(tasks) == 1 assert tasks[0].id == 5 def test_list_tasks_offset_limit(self): for x in range(10): add_task(__file__, category="file") tasks = self.d.list_tasks(offset=5, limit=10, order_by="id") assert len(tasks) == 5 assert tasks[4].id == 10 def test_list_tasks_notvalue(self): for x in range(10): id = add_task(__file__, category="file") if id % 2 == 0: self.d.set_status(id, "running") tasks = self.d.list_tasks(filter_by="status", operators="!=", values="running", order_by="id") assert len(tasks) == 5 assert tasks[4].id == 9 def test_list_tasks_noresults(self): for x in range(5): add_task(__file__, category="file") tasks = self.d.list_tasks(status="reported") assert tasks == [] def test_get_available_machines(self): self.d.add_machine("name1", "name1", "1.2.3.4", "windows", "", "app1,office7", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") self.d.add_machine("name2", "name2", "1.2.3.4", "DogeOS", "opt1 opt2", "office13", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") self.d.add_machine("name3", "name3", "1.2.3.4", "CoffeeOS", ["opt3", "opt4"], "cofOS,office7", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") self.d.machine_reserve(label="name2", task_id=1337) self.d.lock_machine(label="name3") available = self.d.get_available_machines() names = [m["name"] for m in [db_m.to_dict() for db_m in available]] assert len(available) == 2 assert "name2" in names assert "name1" in names def test_unlock_machine(self): self.d.add_machine("name1", "name1", "1.2.3.4", "windows", "", "app1,office7", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") self.d.lock_machine(label="name1") assert self.d.view_machine(name="name1").locked self.d.unlock_machine(label="name1") assert not self.d.view_machine(name="name1").locked def test_list_machines(self): self.d.add_machine("name1", "name1", "1.2.3.4", "windows", "", "app1,office7", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") self.d.add_machine("name2", "name2", "1.2.3.4", "DogeOS", "opt1 opt2", "office13", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") allmachines = self.d.list_machines() names = [m["name"] for m in [db_m.to_dict() for db_m in allmachines]] assert len(allmachines) == 2 assert "name2" in names assert "name1" in names def test_machine_reserve(self): self.d.add_machine("name1", "name1", "1.2.3.4", "windows", "", "app1,office7", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") assert self.d.view_machine(name="name1").reserved_by is None self.d.machine_reserve(label="name1", task_id=42) assert self.d.view_machine(name="name1").reserved_by == 42 def test_clear_reservation(self): self.d.add_machine("name1", "name1", "1.2.3.4", "windows", "", "app1,office7", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") self.d.machine_reserve(label="name1", task_id=42) assert self.d.view_machine(name="name1").reserved_by == 42 self.d.clear_reservation(label="name1") assert self.d.view_machine(name="name1").reserved_by is None def test_clean_machines(self): for x in range(6): name = "name%s" % x self.d.add_machine(name, name, "1.2.3.4", "windows", "", "app1,office7", "int0", "snap0", "5.6.7.8", 2043, "virtualbox") assert len(self.d.list_machines()) == 6 self.d.clean_machines() assert len(self.d.list_machines()) == 0 def test_target_to_dict(self): fd, sample_path = tempfile.mkstemp() os.write(fd, os.urandom(64)) os.close(fd) target = File(sample_path) id = add_target(sample_path, category="file") db_target = self.d.find_target(id=id) db_target = db_target.to_dict() assert db_target["id"] == id assert db_target["file_size"] == 64 assert db_target["file_type"] == target.get_type() assert db_target["md5"] == target.get_md5() assert db_target["crc32"] == target.get_crc32() assert db_target["sha1"] == target.get_sha1() assert db_target["sha256"] == target.get_sha256() assert db_target["sha512"] == target.get_sha512() assert db_target["ssdeep"] == target.get_ssdeep() assert db_target["category"] == "file" assert db_target["target"] == sample_path def test_task_multiple_targets(self): db_targets = [] task_id = add_task() for x in range(10): fd, sample_path = tempfile.mkstemp() os.write(fd, os.urandom(64)) os.close(fd) add_target(sample_path, category="file", task_id=task_id) task = self.d.view_task(task_id) assert task.id == task_id assert len(task.targets) == 10