def test_load_snapshot_failure_handling(test_microvm_with_api): """ Test error case of loading empty snapshot files. @type: functional """ logger = logging.getLogger("snapshot_load_failure") vm = test_microvm_with_api vm.spawn(log_level="Info") # Create two empty files for snapshot state and snapshot memory chroot_path = vm.jailer.chroot_path() snapshot_dir = os.path.join(chroot_path, "snapshot") Path(snapshot_dir).mkdir(parents=True, exist_ok=True) snapshot_mem = os.path.join(snapshot_dir, "snapshot_mem") open(snapshot_mem, "w+", encoding="utf-8").close() snapshot_vmstate = os.path.join(snapshot_dir, "snapshot_vmstate") open(snapshot_vmstate, "w+", encoding="utf-8").close() # Hardlink the snapshot files into the microvm jail. jailed_mem = vm.create_jailed_resource(snapshot_mem) jailed_vmstate = vm.create_jailed_resource(snapshot_vmstate) # Load the snapshot response = vm.snapshot.load(mem_file_path=jailed_mem, snapshot_path=jailed_vmstate) logger.info("Response status code %d, content: %s.", response.status_code, response.text) assert vm.api_session.is_status_bad_request(response.status_code) assert "Cannot deserialize the microVM state" in response.text # Check if FC process is closed wait_process_termination(vm.jailer_clone_pid)
def test_enosys_error_code(test_microvm_with_initrd): """ Test that ENOSYS error is caught and firecracker exits gracefully. @type: functional """ # On aarch64 we trigger this error by adding to initrd a C program that # maps a file into memory and then tries to load the content from an # offset in the file bigger than its length into a register asm volatile # ("ldr %0, [%1], 4" : "=r" (ret), "+r" (buf)); vm = test_microvm_with_initrd vm.jailer.daemonize = False vm.spawn() vm.memory_monitor = None vm.initrd_file = os.path.join(vm.path, "fsfiles/", "initrd_enosys.img") vm.basic_config(add_root_device=False, vcpu_count=1, boot_args='console=ttyS0 reboot=k panic=1 pci=off', use_initrd=True) vm.start() # Check if FC process is closed wait_process_termination(vm.jailer_clone_pid) vm.check_log_message("Received ENOSYS error because KVM failed to" " emulate an instruction.") vm.check_log_message("Vmm is stopping.")
def test_generic_signal_handler(test_microvm_with_api, signum): """ Test signal handling for all handled signals. @type: functional """ microvm = test_microvm_with_api microvm.spawn() # We don't need to monitor the memory for this test. microvm.memory_monitor = None microvm.basic_config() # Configure metrics based on a file. metrics_path = os.path.join(microvm.path, 'metrics_fifo') utils.run_cmd("touch {}".format(metrics_path)) response = microvm.metrics.put( metrics_path=microvm.create_jailed_resource(metrics_path) ) assert microvm.api_session.is_status_no_content(response.status_code) microvm.start() firecracker_pid = int(microvm.jailer_clone_pid) sleep(0.5) metrics_jail_path = os.path.join(microvm.chroot(), metrics_path) metrics_fd = open(metrics_jail_path, encoding='utf-8') line_metrics = metrics_fd.readlines() assert len(line_metrics) == 1 os.kill(firecracker_pid, signum) # Firecracker gracefully handles SIGPIPE (doesn't terminate). if signum == int(SIGPIPE): msg = 'Received signal 13' # Flush metrics to file, so we can see the SIGPIPE at bottom assert. # This is going to fail if process has exited. response = microvm.actions.put(action_type='FlushMetrics') assert microvm.api_session.is_status_no_content(response.status_code) else: microvm.expect_kill_by_signal = True # Ensure that the process was terminated. utils.wait_process_termination(firecracker_pid) msg = 'Shutting down VM after intercepting signal {}'.format(signum) microvm.check_log_message(msg) if signum != SIGSYS: metric_line = json.loads(metrics_fd.readlines()[0]) assert metric_line["signals"][signum_str[signum]] == 1
def test_load_snapshot_failure_handling(test_microvm_with_api): """ Test scenario. 1. Create two empty files representing snapshot memory and microvm state 2. Try to load a VM snapshot out of the empty files. 3. Verify that an error was shown and the FC process is terminated. """ logger = logging.getLogger("snapshot_load_failure") vm = test_microvm_with_api vm.spawn(log_level='Info') # Create two empty files for snapshot state and snapshot memory chroot_path = vm.jailer.chroot_path() snapshot_dir = os.path.join(chroot_path, "snapshot") Path(snapshot_dir).mkdir(parents=True, exist_ok=True) snapshot_mem = os.path.join(snapshot_dir, "snapshot_mem") open(snapshot_mem, "w+").close() snapshot_vmstate = os.path.join(snapshot_dir, "snapshot_vmstate") open(snapshot_vmstate, "w+").close() # Hardlink the snapshot files into the microvm jail. jailed_mem = vm.create_jailed_resource(snapshot_mem) jailed_vmstate = vm.create_jailed_resource(snapshot_vmstate) # Load the snapshot response = vm.snapshot.load(mem_file_path=jailed_mem, snapshot_path=jailed_vmstate) logger.info("Response status code %d, content: %s.", response.status_code, response.text) assert vm.api_session.is_status_bad_request(response.status_code) assert "Cannot deserialize MicrovmState" in response.text # Check if FC process is closed wait_process_termination(vm.jailer_clone_pid)