Exemplo n.º 1
0
 def test_kernel_to_debian_architecture(self):
     self.assertEquals(self.kernel,
                       debian_to_kernel_architecture(self.debian))
Exemplo n.º 2
0
    def test_compose_multiple_interface_constraints(self):
        pod_id = factory.make_name("pod_id")
        context = self.make_parameters_context()
        request = make_requested_machine()
        request.interfaces = [
            RequestedMachineInterface(
                ifname=factory.make_name("ifname"),
                attach_name=factory.make_name("bridge_name"),
                attach_type="bridge",
                attach_options=None,
            )
            for _ in range(3)
        ]
        # LXD uses 'bridged' while MAAS uses 'bridge' so convert
        # the nictype as this is what we expect from LXDPodDriver.compose.
        expected_interfaces = [
            {
                "name": request.interfaces[i].ifname,
                "parent": request.interfaces[i].attach_name,
                "nictype": "bridged",
                "type": "nic",
            }
            for i in range(3)
        ]
        expected_interfaces[0]["boot.priority"] = "1"
        driver = lxd_module.LXDPodDriver()
        Client = self.patch(driver, "get_client")
        client = Client.return_value
        mock_profile = Mock()
        mock_profile.name = random.choice(["maas", "default"])
        profile_devices = {
            "eth0": {
                "name": "eth0",
                "nictype": "bridged",
                "parent": "lxdbr0",
                "type": "nic",
            },
            "eth1": {
                "boot.priority": "1",
                "name": "eth1",
                "nictype": "bridged",
                "parent": "virbr1",
                "type": "nic",
            },
            "root": {
                "boot.priority": "0",
                "path": "/",
                "pool": "default",
                "type": "disk",
                "size": "20GB",
            },
        }
        mock_profile.devices = profile_devices
        client.profiles.get.return_value = mock_profile
        mock_storage_pools = Mock()
        client.storage_pools.all.return_value = mock_storage_pools
        mock_get_usable_storage_pool = self.patch(
            driver, "get_usable_storage_pool"
        )
        usable_pool = factory.make_name("pool")
        mock_get_usable_storage_pool.return_value = usable_pool
        mock_get_best_nic_from_profile = self.patch(
            driver, "get_best_nic_from_profile"
        )
        mock_get_best_nic_from_profile.return_value = (
            "eth1",
            profile_devices["eth1"],
        )
        mock_machine = Mock()
        client.virtual_machines.create.return_value = mock_machine
        mock_get_discovered_machine = self.patch(
            driver, "get_discovered_machine"
        )
        mock_get_discovered_machine.return_value = sentinel.discovered_machine
        definition = {
            "name": request.hostname,
            "architecture": debian_to_kernel_architecture(
                request.architecture
            ),
            "config": {
                "limits.cpu": str(request.cores),
                "limits.memory": str(request.memory * 1024 ** 2),
                "security.secureboot": "false",
            },
            "profiles": [mock_profile.name],
            "source": {"type": "none"},
            "devices": {
                "root": {
                    "path": "/",
                    "type": "disk",
                    "pool": usable_pool,
                    "size": str(request.block_devices[0].size),
                    "boot.priority": "0",
                },
                expected_interfaces[0]["name"]: expected_interfaces[0],
                expected_interfaces[1]["name"]: expected_interfaces[1],
                expected_interfaces[2]["name"]: expected_interfaces[2],
                "eth1": {"type": "none"},
                "eth0": {"type": "none"},
            },
        }

        discovered_machine, empty_hints = yield driver.compose(
            pod_id, context, request
        )
        self.assertThat(
            client.virtual_machines.create,
            MockCalledOnceWith(definition, wait=True),
        )
        self.assertEquals(sentinel.discovered_machine, discovered_machine)
        self.assertThat(
            empty_hints,
            MatchesAll(
                IsInstance(DiscoveredPodHints),
                MatchesStructure(
                    cores=Equals(-1),
                    cpu_speed=Equals(-1),
                    memory=Equals(-1),
                    local_storage=Equals(-1),
                    local_disks=Equals(-1),
                    iscsi_storage=Equals(-1),
                ),
            ),
        )
Exemplo n.º 3
0
    def compose(self, pod_id: str, context: dict, request: RequestedMachine):
        """Compose a virtual machine."""
        client = yield self.get_client(pod_id, context)
        # Check to see if there is a maas profile.  If not, use the default.
        try:
            profile = yield deferToThread(client.profiles.get, "maas")
        except NotFound:
            # Fall back to default
            try:
                profile = yield deferToThread(client.profiles.get, "default")
            except NotFound:
                raise LXDPodError(
                    f"Pod {pod_id}: MAAS needs LXD to have either a 'maas' "
                    "profile or a 'default' profile, defined.")
        resources = yield deferToThread(lambda: client.resources)

        definition = {
            "name": request.hostname,
            "architecture":
            debian_to_kernel_architecture(request.architecture),
            "config": {
                "limits.cpu": str(request.cores),
                "limits.memory": str(request.memory * 1024**2),
                # LP: 1867387 - Disable secure boot until its fixed in MAAS
                "security.secureboot": "false",
            },
            "profiles": [profile.name],
            # Image source is empty as we get images
            # from MAAS when netbooting.
            "source": {
                "type": "none"
            },
        }

        # Add disk to the definition.
        # XXX: LXD VMs currently only support one virtual block device.
        # Loop will need to be modified once LXD has multiple virtual
        # block device support.
        devices = {}
        storage_pools = yield deferToThread(client.storage_pools.all)
        default_storage_pool = context.get("default_storage_pool_id",
                                           context.get("default_storage_pool"))
        for idx, disk in enumerate(request.block_devices):
            usable_pool = self.get_usable_storage_pool(disk, storage_pools,
                                                       default_storage_pool)
            devices["root"] = {
                "path": "/",
                "type": "disk",
                "pool": usable_pool,
                "size": str(disk.size),
                "boot.priority": "0",
            }

        # Create and attach interfaces to the machine.
        # The reason we are doing this after the machine is created
        # is because pylxd doesn't have a way to override the devices
        # that are defined in the profile.  Since the profile is provided
        # by the user, we have no idea how many interfaces are defined.
        #
        # Currently, only the bridged type is supported with virtual machines.
        # https://lxd.readthedocs.io/en/latest/instances/#device-types
        nic_devices = {}
        profile_devices = profile.devices
        device_names = []
        boot = True
        for interface in request.interfaces:
            if interface.ifname is None:
                # No interface constraints sent so use the best
                # nic device from the profile's devices.
                device_name, device = self.get_best_nic_device_from_profile(
                    profile_devices)
                nic_devices[device_name] = device
                if "boot.priority" not in device and boot:
                    nic_devices[device_name]["boot.priority"] = "1"
                    boot = False
                device_names.append(device_name)
            else:
                nic_devices[interface.ifname] = get_lxd_nic_device(interface)

                # Set to boot from the first nic
                if boot:
                    nic_devices[interface.ifname]["boot.priority"] = "1"
                    boot = False
                device_names.append(interface.ifname)

        # Iterate over all of the profile's devices with type=nic
        # and set to type=none if not nic_device.  This overrides
        # the device settings on the profile used by the machine.
        for dk, dv in profile_devices.items():
            if dk not in device_names and dv["type"] == "nic":
                nic_devices[dk] = {"type": "none"}

        # Merge the devices and attach the devices to the defintion.
        for k, v in nic_devices.items():
            devices[k] = v
        definition["devices"] = devices

        # Create the machine.
        machine = yield deferToThread(client.virtual_machines.create,
                                      definition,
                                      wait=True)
        # Pod hints are updated on the region after the machine
        # is composed.
        discovered_machine = yield ensureDeferred(
            self.get_discovered_machine(client,
                                        machine,
                                        storage_pools,
                                        request=request))
        # Update the machine cpu speed.
        discovered_machine.cpu_speed = lxd_cpu_speed(resources)
        return discovered_machine, DiscoveredPodHints()
Exemplo n.º 4
0
    def test_compose_no_interface_constraints(self):
        pod_id = factory.make_name("pod_id")
        context = self.make_parameters_context()
        request = make_requested_machine()
        driver = lxd_module.LXDPodDriver()
        Client = self.patch(driver, "get_client")
        client = Client.return_value
        mock_profile = Mock()
        mock_profile.name = random.choice(["maas", "default"])
        profile_devices = {
            "eth0": {
                "name": "eth0",
                "nictype": "bridged",
                "parent": "lxdbr0",
                "type": "nic",
            },
            "eth1": {
                "boot.priority": "1",
                "name": "eth1",
                "nictype": "bridged",
                "parent": "virbr1",
                "type": "nic",
            },
            "root": {
                "boot.priority": "0",
                "path": "/",
                "pool": "default",
                "type": "disk",
                "size": "20GB",
            },
        }
        mock_profile.devices = profile_devices
        client.profiles.get.return_value = mock_profile
        mock_storage_pools = Mock()
        client.storage_pools.all.return_value = mock_storage_pools
        mock_get_usable_storage_pool = self.patch(
            driver, "get_usable_storage_pool"
        )
        usable_pool = factory.make_name("pool")
        mock_get_usable_storage_pool.return_value = usable_pool
        mock_get_best_nic_from_profile = self.patch(
            driver, "get_best_nic_from_profile"
        )
        mock_get_best_nic_from_profile.return_value = (
            "eth1",
            profile_devices["eth1"],
        )
        mock_machine = Mock()
        client.virtual_machines.create.return_value = mock_machine
        mock_get_discovered_machine = self.patch(
            driver, "get_discovered_machine"
        )
        mock_get_discovered_machine.side_effect = async_succeed(
            sentinel.discovered_machine
        )
        definition = {
            "name": request.hostname,
            "architecture": debian_to_kernel_architecture(
                request.architecture
            ),
            "config": {
                "limits.cpu": str(request.cores),
                "limits.memory": str(request.memory * 1024 ** 2),
                "limits.memory.hugepages": "false",
                "security.secureboot": "false",
            },
            "profiles": [mock_profile.name],
            "source": {"type": "none"},
            "devices": {
                "root": {
                    "path": "/",
                    "type": "disk",
                    "pool": usable_pool,
                    "size": str(request.block_devices[0].size),
                    "boot.priority": "0",
                },
                "eth1": profile_devices["eth1"],
                "eth0": {"type": "none"},
            },
        }

        discovered_machine, empty_hints = yield driver.compose(
            pod_id, context, request
        )
        self.assertThat(
            client.virtual_machines.create,
            MockCalledOnceWith(definition, wait=True),
        )
        self.assertEquals(sentinel.discovered_machine, discovered_machine)
        self.assertThat(
            empty_hints,
            MatchesAll(
                IsInstance(DiscoveredPodHints),
                MatchesStructure(
                    cores=Equals(-1),
                    cpu_speed=Equals(-1),
                    memory=Equals(-1),
                    local_storage=Equals(-1),
                    local_disks=Equals(-1),
                    iscsi_storage=Equals(-1),
                ),
            ),
        )