예제 #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
예제 #3
0
    def build_from_snapshot(self,
                            snapshot: Snapshot,
                            resume=False,
                            # Enable incremental snapshot capability.
                            diff_snapshots=False,
                            use_ramdisk=False,
                            fc_binary=None, jailer_binary=None,
                            daemonize=True):
        """Build a microvm from a snapshot artifact."""
        vm = init_microvm(self.root_path, self.bin_cloner_path,
                          fc_binary, jailer_binary,)
        vm.jailer.daemonize = daemonize
        vm.spawn(log_level='Error', use_ramdisk=use_ramdisk)
        vm.api_session.untime()

        metrics_file_path = os.path.join(vm.path, 'metrics.log')
        metrics_fifo = log_tools.Fifo(metrics_file_path)
        response = vm.metrics.put(
            metrics_path=vm.create_jailed_resource(metrics_fifo.path)
        )
        assert vm.api_session.is_status_no_content(response.status_code)

        # Hardlink all the snapshot files into the microvm jail.
        jailed_mem = vm.copy_to_jail_ramfs(snapshot.mem) if use_ramdisk else \
            vm.create_jailed_resource(snapshot.mem)
        jailed_vmstate = vm.copy_to_jail_ramfs(snapshot.vmstate) \
            if use_ramdisk else vm.create_jailed_resource(snapshot.vmstate)

        assert len(snapshot.disks) > 0, "Snapshot requires at least one disk."
        _jailed_disks = []
        for disk in snapshot.disks:
            _jailed_disks.append(vm.copy_to_jail_ramfs(disk) if use_ramdisk
                                 else vm.create_jailed_resource(disk))

        vm.ssh_config['ssh_key_path'] = snapshot.ssh_key.local_path()

        # Create network interfaces.
        for iface in snapshot.net_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)
        response = vm.snapshot.load(mem_file_path=jailed_mem,
                                    snapshot_path=jailed_vmstate,
                                    diff=diff_snapshots,
                                    resume=resume)
        status_ok = vm.api_session.is_status_no_content(response.status_code)

        # Verify response status and cleanup if needed before assert.
        if not status_ok:
            # Destroy VM here before we assert.
            vm.kill()
            del vm

        assert status_ok, response.text

        # Return a resumed microvm.
        return vm, metrics_fifo
예제 #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 build_from_snapshot(
            self,
            snapshot: Snapshot,
            host_ip=None,
            guest_ip=None,
            netmask_len=None,
            resume=False,
            # Enable incremental snapshot capability.
            enable_diff_snapshots=False):
        """Build a microvm from a snapshot artifact."""
        self.init_root_path()
        vm = init_microvm(self.root_path, self.bin_cloner_path)

        vm.spawn(log_level='Info')

        metrics_file_path = os.path.join(vm.path, 'metrics.log')
        metrics_fifo = log_tools.Fifo(metrics_file_path)
        response = vm.metrics.put(
            metrics_path=vm.create_jailed_resource(metrics_fifo.path))
        assert vm.api_session.is_status_no_content(response.status_code)

        # Hardlink all the snapshot files into the microvm jail.
        jailed_mem = vm.create_jailed_resource(snapshot.mem)
        jailed_vmstate = vm.create_jailed_resource(snapshot.vmstate)
        assert len(snapshot.disks) > 0, "Snapshot requiures at least one disk."
        _jailed_disks = []
        for disk in snapshot.disks:
            _jailed_disks.append(vm.create_jailed_resource(disk))
        vm.ssh_config['ssh_key_path'] = snapshot.ssh_key

        if host_ip is not None:
            vm.create_tap_and_ssh_config(host_ip=host_ip,
                                         guest_ip=guest_ip,
                                         netmask_len=netmask_len,
                                         tapname="tap0")

        response = vm.snapshot_load.put(mem_file_path=jailed_mem,
                                        snapshot_path=jailed_vmstate,
                                        diff=enable_diff_snapshots)

        assert vm.api_session.is_status_no_content(response.status_code)

        if resume:
            # Resume microvm
            response = vm.vm.patch(state='Resumed')
            assert vm.api_session.is_status_no_content(response.status_code)

        # Return a resumed microvm.
        return vm, metrics_fifo
예제 #6
0
    def build_from_snapshot(
            self,
            snapshot: Snapshot,
            resume=False,
            # Enable incremental snapshot capability.
            enable_diff_snapshots=False):
        """Build a microvm from a snapshot artifact."""
        vm = init_microvm(self.root_path, self.bin_cloner_path,
                          self._fc_binary, self._jailer_binary)
        vm.spawn(log_level='Info')

        metrics_file_path = os.path.join(vm.path, 'metrics.log')
        metrics_fifo = log_tools.Fifo(metrics_file_path)
        response = vm.metrics.put(
            metrics_path=vm.create_jailed_resource(metrics_fifo.path))
        assert vm.api_session.is_status_no_content(response.status_code)

        # Hardlink all the snapshot files into the microvm jail.
        jailed_mem = vm.create_jailed_resource(snapshot.mem)
        jailed_vmstate = vm.create_jailed_resource(snapshot.vmstate)
        assert len(snapshot.disks) > 0, "Snapshot requires at least one disk."
        _jailed_disks = []
        for disk in snapshot.disks:
            _jailed_disks.append(vm.create_jailed_resource(disk))
        vm.ssh_config['ssh_key_path'] = snapshot.ssh_key

        vm.create_tap_and_ssh_config(host_ip=DEFAULT_HOST_IP,
                                     guest_ip=DEFAULT_GUEST_IP,
                                     netmask_len=DEFAULT_NETMASK,
                                     tapname=DEFAULT_TAP_NAME)

        response = vm.snapshot_load.put(mem_file_path=jailed_mem,
                                        snapshot_path=jailed_vmstate,
                                        diff=enable_diff_snapshots)

        assert vm.api_session.is_status_no_content(response.status_code)

        if resume:
            # Resume microvm
            response = vm.vm.patch(state='Resumed')
            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 a resumed microvm.
        return vm, metrics_fifo
예제 #7
0
def setup_vm(context):
    """Init microVM using context provided."""
    root_path = context.custom['session_root_path']
    bin_cloner_path = context.custom['bin_cloner_path']

    print(f"Creating snapshot of microVM with kernel {context.kernel.name()}"
          f" and disk {context.disk.name()}.")

    vm = init_microvm(root_path, bin_cloner_path)

    # Change kernel name to match the one in the config file.
    kernel_full_path = os.path.join(vm.path, DEST_KERNEL_NAME)
    shutil.copyfile(context.kernel.local_path(), kernel_full_path)
    vm.kernel_file = kernel_full_path

    rootfs_full_path = os.path.join(vm.path, context.disk.name())
    shutil.copyfile(context.disk.local_path(), rootfs_full_path)
    vm.rootfs_file = rootfs_full_path

    return vm
예제 #8
0
    def build_from_snapshot(
            self,
            snapshot: Snapshot,
            host_ip,
            guest_ip,
            netmask_len,
            resume=False,
            # Enable incremental snapshot capability.
            enable_diff_snapshots=False):
        """Build a microvm from a snapshot artifact."""
        self.init_root_path()
        vm = init_microvm(self.root_path, self.bin_cloner_path)

        vm.spawn(log_level='Debug')

        # Hardlink all the snapshot files into the microvm jail.
        jailed_mem = vm.create_jailed_resource(snapshot.mem)
        jailed_vmstate = vm.create_jailed_resource(snapshot.vmstate)
        assert len(snapshot.disks) > 0, "Snapshot requiures at least one disk."
        _jailed_disk = vm.create_jailed_resource(snapshot.disks[0])
        vm.ssh_config['ssh_key_path'] = snapshot.ssh_key

        vm.create_tap_and_ssh_config(host_ip=host_ip,
                                     guest_ip=guest_ip,
                                     netmask_len=netmask_len,
                                     tapname="tap0")

        response = vm.snapshot_load.put(mem_file_path=jailed_mem,
                                        snapshot_path=jailed_vmstate,
                                        diff=enable_diff_snapshots)

        assert vm.api_session.is_status_no_content(response.status_code)

        if resume:
            # Resume microvm
            response = vm.vm.patch(state='Resumed')
            assert vm.api_session.is_status_no_content(response.status_code)

        # Return a resumed microvm.
        return vm
예제 #9
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
예제 #10
0
 def create_basevm(self):
     """Create a clean VM in an initial state."""
     return init_microvm(self.root_path, self.bin_cloner_path,
                         self._fc_binary, self._jailer_binary)