예제 #1
0
    def build(self, kernel: Artifact, disks: [DiskArtifact], config: Artifact):
        """Build a fresh microvm."""
        vm = init_microvm(self.root_path, self.bin_cloner_path)
        vm.setup()

        # Link the microvm to kernel, rootfs, ssh_key artifacts.
        vm.kernel_file = kernel.local_path()
        vm.rootfs_file = disks[0].local_path()
        ssh_key = disks[0].ssh_key()

        # Download ssh key into microvm root.
        ssh_key.download(self.root_path)
        vm.ssh_config['ssh_key_path'] = ssh_key.local_path()
        os.chmod(vm.ssh_config['ssh_key_path'], 0o400)

        # Start firecracker.
        vm.spawn()

        with open(config.local_path()) as microvm_config_file:
            microvm_config = json.load(microvm_config_file)

        # Apply the microvm artifact configuration
        vm.basic_config(vcpu_count=int(microvm_config['vcpu_count']),
                        mem_size_mib=int(microvm_config['mem_size_mib']),
                        ht_enabled=bool(microvm_config['ht_enabled']))

        return vm
예제 #2
0
    def build(self,
              kernel: Artifact,
              disks: [DiskArtifact],
              ssh_key: Artifact,
              config: Artifact,
              enable_diff_snapshots=False):
        """Build a fresh microvm."""
        self.init_root_path()

        vm = init_microvm(self.root_path, self.bin_cloner_path)

        # Link the microvm to kernel, rootfs, ssh_key artifacts.
        vm.kernel_file = kernel.local_path()
        vm.rootfs_file = disks[0].local_path()

        # Download ssh key into the microvm root.
        ssh_key.download(self.root_path)
        vm.ssh_config['ssh_key_path'] = ssh_key.local_path()
        os.chmod(vm.ssh_config['ssh_key_path'], 0o400)

        # Start firecracker.
        vm.spawn()

        with open(config.local_path()) as microvm_config_file:
            microvm_config = json.load(microvm_config_file)

        # Apply the microvm artifact configuration
        vm.basic_config(vcpu_count=int(microvm_config['vcpu_count']),
                        mem_size_mib=int(microvm_config['mem_size_mib']),
                        ht_enabled=bool(microvm_config['ht_enabled']),
                        track_dirty_pages=enable_diff_snapshots,
                        boot_args='console=ttyS0 reboot=k panic=1')
        return vm
def _get_snapshot_files_paths(snapshot_dir):
    mem = vmstate = ssh_key = disk = None

    for file in os.listdir(snapshot_dir):
        file_path = os.path.join(Artifact.LOCAL_ARTIFACT_DIR, file)

        if file.endswith(".mem"):
            mem = file_path
        elif file.endswith(".vmstate"):
            vmstate = file_path
        elif file.endswith(".id_rsa"):
            ssh_key = Artifact(
                None,
                os.path.basename(file),
                ArtifactType.SSH_KEY,
                DEFAULT_TEST_SESSION_ROOT_PATH,
            )
            file_path = ssh_key.local_path()
            pathlib.Path(os.path.dirname(file_path)).mkdir(parents=True, exist_ok=True)
        elif file.endswith(".ext4"):
            disk = file_path

        # Copy to default root session.
        shutil.copy(os.path.join(snapshot_dir, file), file_path)
        assert os.path.isfile(file_path)

    # Ensure all required snapshot files are present inside the dir.
    assert mem and vmstate and disk and ssh_key

    # Change ssh key permissions.
    os.chmod(ssh_key.local_path(), 0o400)

    return mem, vmstate, disk, ssh_key
예제 #4
0
    def build(self,
              kernel: Artifact,
              disks: [DiskArtifact],
              ssh_key: Artifact,
              config: Artifact,
              enable_diff_snapshots=False,
              cpu_template=None):
        """Build a fresh microvm."""
        vm = init_microvm(self.root_path, self.bin_cloner_path,
                          self._fc_binary, self._jailer_binary)

        # Link the microvm to kernel, rootfs, ssh_key artifacts.
        vm.kernel_file = kernel.local_path()
        vm.rootfs_file = disks[0].local_path()

        # Start firecracker.
        vm.spawn()

        # Download ssh key into the microvm root.
        ssh_key.download(self.root_path)
        vm.ssh_config['ssh_key_path'] = ssh_key.local_path()
        os.chmod(vm.ssh_config['ssh_key_path'], 0o400)
        vm.create_tap_and_ssh_config(host_ip=DEFAULT_HOST_IP,
                                     guest_ip=DEFAULT_GUEST_IP,
                                     netmask_len=DEFAULT_NETMASK,
                                     tapname=DEFAULT_TAP_NAME)

        # TODO: propper network configuraiton with artifacts.
        guest_mac = net_tools.mac_from_ip(DEFAULT_GUEST_IP)
        response = vm.network.put(
            iface_id=DEFAULT_DEV_NAME,
            host_dev_name=DEFAULT_TAP_NAME,
            guest_mac=guest_mac,
            allow_mmds_requests=True,
        )

        assert vm.api_session.is_status_no_content(response.status_code)

        with open(config.local_path()) as microvm_config_file:
            microvm_config = json.load(microvm_config_file)

        response = vm.basic_config(boot_args='console=ttyS0 reboot=k panic=1')

        # Apply the microvm artifact configuration and template.
        response = vm.machine_cfg.put(
            vcpu_count=int(microvm_config['vcpu_count']),
            mem_size_mib=int(microvm_config['mem_size_mib']),
            ht_enabled=bool(microvm_config['ht_enabled']),
            track_dirty_pages=enable_diff_snapshots,
            cpu_template=cpu_template,
        )
        assert vm.api_session.is_status_no_content(response.status_code)

        # Reset root path so next microvm is built some place else.
        self.init_root_path()
        return vm
예제 #5
0
    def create(self,
               disks,
               ssh_key: Artifact,
               snapshot_type: SnapshotType = SnapshotType.FULL,
               target_version: str = None,
               mem_file_name: str = "vm.mem",
               snapshot_name: str = "vm.vmstate",
               net_ifaces=None):
        """Create a Snapshot object from a microvm and artifacts."""
        # Disable API timeout as the APIs for snapshot related procedures
        # take longer.
        self._microvm.api_session.untime()
        snapshot_dir = self.create_snapshot_dir()
        self._microvm.pause_to_snapshot(
            mem_file_path="/snapshot/" + mem_file_name,
            snapshot_path="/snapshot/" + snapshot_name,
            diff=snapshot_type == SnapshotType.DIFF,
            version=target_version)

        # Create a copy of the ssh_key artifact.
        ssh_key_copy = ssh_key.copy()
        mem_path = os.path.join(snapshot_dir, mem_file_name)
        vmstate_path = os.path.join(snapshot_dir, snapshot_name)
        return Snapshot(
            mem=mem_path,
            vmstate=vmstate_path,
            # TODO: To support more disks we need to figure out a
            # simple and flexible way to store snapshot artifacts
            # in S3. This should be done in a PR where we add tests
            # that resume from S3 snapshot artifacts.
            disks=disks,
            net_ifaces=net_ifaces or [NetIfaceConfig()],
            ssh_key=ssh_key_copy.local_path())
예제 #6
0
    def create(self,
               disks,
               ssh_key: Artifact,
               snapshot_type: SnapshotType = SnapshotType.FULL,
               target_version: str = None):
        """Create a Snapshot object from a microvm and artifacts."""
        # Disable API timeout as the APIs for snapshot related procedures
        # take longer.
        self._microvm.api_session.untime()
        chroot_path = self._microvm.jailer.chroot_path()
        snapshot_dir = os.path.join(chroot_path, "snapshot")
        Path(snapshot_dir).mkdir(parents=True, exist_ok=True)
        cmd = 'chown {}:{} {}'.format(self._microvm.jailer.uid,
                                      self._microvm.jailer.gid,
                                      snapshot_dir)
        utils.run_cmd(cmd)
        self._microvm.pause_to_snapshot(
            mem_file_path="/snapshot/vm.mem",
            snapshot_path="/snapshot/vm.vmstate",
            diff=snapshot_type == SnapshotType.DIFF,
            version=target_version)

        # Create a copy of the ssh_key artifact.
        ssh_key_copy = ssh_key.copy()
        mem_path = os.path.join(snapshot_dir, "vm.mem")
        vmstate_path = os.path.join(snapshot_dir, "vm.vmstate")
        return Snapshot(mem=mem_path,
                        vmstate=vmstate_path,
                        # TODO: To support more disks we need to figure out a
                        # simple and flexible way to store snapshot artifacts
                        # in S3. This should be done in a PR where we add tests
                        # that resume from S3 snapshot artifacts.
                        disks=disks,
                        ssh_key=ssh_key_copy.local_path())
예제 #7
0
    def create(self,
               disks,
               ssh_key: Artifact,
               snapshot_type: SnapshotType = SnapshotType.FULL,
               target_version: str = None,
               mem_file_name: str = "vm.mem",
               snapshot_name: str = "vm.vmstate",
               net_ifaces=None,
               use_ramdisk=False):
        """Create a Snapshot object from a microvm and artifacts."""
        if use_ramdisk:
            snaps_dir = self._microvm.jailer.chroot_ramfs_path()
            mem_full_path = os.path.join(snaps_dir, mem_file_name)
            vmstate_full_path = os.path.join(snaps_dir, snapshot_name)

            memsize = self._microvm.machine_cfg.configuration['mem_size_mib']
            # Pre-allocate ram for memfile to eliminate allocation variability.
            utils.run_cmd('dd if=/dev/zero of={} bs=1M count={}'.format(
                mem_full_path, memsize
            ))
            cmd = 'chown {}:{} {}'.format(
                self._microvm.jailer.uid,
                self._microvm.jailer.gid,
                mem_full_path
            )
            utils.run_cmd(cmd)
        else:
            snaps_dir = self.create_snapshot_dir()
            mem_full_path = os.path.join(snaps_dir, mem_file_name)
            vmstate_full_path = os.path.join(snaps_dir, snapshot_name)

        snaps_dir_name = os.path.basename(snaps_dir)
        self._microvm.pause_to_snapshot(
            mem_file_path=os.path.join('/', snaps_dir_name, mem_file_name),
            snapshot_path=os.path.join('/', snaps_dir_name, snapshot_name),
            diff=snapshot_type == SnapshotType.DIFF,
            version=target_version)

        # Create a copy of the ssh_key artifact.
        ssh_key_copy = ssh_key.copy()
        return Snapshot(mem=mem_full_path,
                        vmstate=vmstate_full_path,
                        # TODO: To support more disks we need to figure out a
                        # simple and flexible way to store snapshot artifacts
                        # in S3. This should be done in a PR where we add tests
                        # that resume from S3 snapshot artifacts.
                        disks=disks,
                        net_ifaces=net_ifaces or [NetIfaceConfig()],
                        ssh_key=ssh_key_copy.local_path())
예제 #8
0
    def build(self,
              kernel: Artifact,
              disks: [DiskArtifact],
              ssh_key: Artifact,
              config: Artifact,
              net_ifaces=None,
              enable_diff_snapshots=False,
              cpu_template=None,
              use_ramdisk=False):
        """Build a fresh microvm."""
        vm = init_microvm(self.root_path, self.bin_cloner_path,
                          self._fc_binary, self._jailer_binary)

        # Start firecracker.
        vm.spawn(use_ramdisk=use_ramdisk)

        # Link the microvm to kernel, rootfs, ssh_key artifacts.
        vm.kernel_file = kernel.local_path()
        vm.rootfs_file = disks[0].local_path()
        # copy rootfs to ramdisk if needed
        jailed_rootfs_path = vm.copy_to_jail_ramfs(vm.rootfs_file) if \
            use_ramdisk else vm.create_jailed_resource(vm.rootfs_file)

        # Download ssh key into the microvm root.
        ssh_key.download(self.root_path)
        vm.ssh_config['ssh_key_path'] = ssh_key.local_path()
        os.chmod(vm.ssh_config['ssh_key_path'], 0o400)

        # Provide a default network configuration.
        if net_ifaces is None or len(net_ifaces) == 0:
            ifaces = [NetIfaceConfig()]
        else:
            ifaces = net_ifaces

        # Configure network interfaces using artifacts.
        for iface in ifaces:
            vm.create_tap_and_ssh_config(host_ip=iface.host_ip,
                                         guest_ip=iface.guest_ip,
                                         netmask_len=iface.netmask,
                                         tapname=iface.tap_name)
            guest_mac = net_tools.mac_from_ip(iface.guest_ip)
            response = vm.network.put(
                iface_id=iface.dev_name,
                host_dev_name=iface.tap_name,
                guest_mac=guest_mac,
                allow_mmds_requests=True,
            )
            assert vm.api_session.is_status_no_content(response.status_code)

        with open(config.local_path()) as microvm_config_file:
            microvm_config = json.load(microvm_config_file)

        response = vm.basic_config(
            add_root_device=False,
            boot_args='console=ttyS0 reboot=k panic=1'
        )

        # Add the root file system with rw permissions.
        response = vm.drive.put(
            drive_id='rootfs',
            path_on_host=jailed_rootfs_path,
            is_root_device=True,
            is_read_only=False
        )
        assert vm.api_session \
            .is_status_no_content(response.status_code), \
            response.text

        # Apply the microvm artifact configuration and template.
        response = vm.machine_cfg.put(
            vcpu_count=int(microvm_config['vcpu_count']),
            mem_size_mib=int(microvm_config['mem_size_mib']),
            ht_enabled=bool(microvm_config['ht_enabled']),
            track_dirty_pages=enable_diff_snapshots,
            cpu_template=cpu_template,
        )
        assert vm.api_session.is_status_no_content(response.status_code)

        vm.vcpus_count = int(microvm_config['vcpu_count'])

        # Reset root path so next microvm is built some place else.
        self.init_root_path()
        return vm