def compose(self, pod_id: int, context: dict, request: RequestedMachine): """Compose a virtual machine.""" with self._get_client(pod_id, context) as client: storage_pools = client.storage_pools.all() default_storage_pool = context.get( "default_storage_pool_id", context.get("default_storage_pool")) include_profile = client.profiles.exists(LXD_MAAS_PROFILE) definition = get_lxd_machine_definition( request, include_profile=include_profile) definition["devices"] = { **self._get_machine_disks(request.block_devices, storage_pools, default_storage_pool), **self._get_machine_nics(request), } # Create the machine. machine = client.virtual_machines.create(definition, wait=True) # Pod hints are updated on the region after the machine is composed. discovered_machine = self._get_discovered_machine(client, machine, storage_pools, request=request) # Update the machine cpu speed. discovered_machine.cpu_speed = lxd_cpu_speed(client.resources) return discovered_machine, DiscoveredPodHints()
def _discover(self, client: Client, pod_id: int, context: dict): self._check_required_extensions(client) if not client.trusted: # return empty information as the client is not authenticated and # gathering other info requires auth. return DiscoveredPod() self._ensure_project(client) environment = client.host_info["environment"] # After the region creates the Pod object it will sync LXD commissioning # data for all hardware information. discovered_pod = DiscoveredPod( # client.host_info["environment"]["architectures"] reports all the # architectures the host CPU supports, not the architectures LXD # supports. On x86_64 LXD reports [x86_64, i686] however LXD does # not currently support VMs on i686. The LXD API currently does not # have a way to query which architectures are usable for VMs. The # safest bet is to just use the kernel_architecture. architectures=[ kernel_to_debian_architecture( environment["kernel_architecture"]) ], name=environment["server_name"], version=environment["server_version"], capabilities=[ Capabilities.COMPOSABLE, Capabilities.DYNAMIC_LOCAL_STORAGE, Capabilities.OVER_COMMIT, Capabilities.STORAGE_POOLS, ], ) # Discover networks. "unknown" interfaces are considered too to match # ethernets in containers. networks_state = [ net.state() for net in client.networks.all() if net.type in ("unknown", "physical") ] discovered_pod.mac_addresses = list( {state.hwaddr for state in networks_state if state.hwaddr}) # Discover storage pools. storage_pools = client.storage_pools.all() if not storage_pools: raise LXDPodError( "No storage pools exists. Please create a storage pool in LXD." ) pools = [] local_storage = 0 for storage_pool in storage_pools: discovered_storage_pool = self._get_discovered_pod_storage_pool( storage_pool) local_storage += discovered_storage_pool.storage pools.append(discovered_storage_pool) discovered_pod.storage_pools = pools discovered_pod.local_storage = local_storage # Discover VMs. host_cpu_speed = lxd_cpu_speed(client.resources) projects = [project.name for project in client.projects.all()] machines = [] for project in projects: with self._get_client(pod_id, context, project=project) as project_cli: for virtual_machine in project_cli.virtual_machines.all(): discovered_machine = self._get_discovered_machine( project_cli, virtual_machine, storage_pools=discovered_pod.storage_pools, ) discovered_machine.cpu_speed = host_cpu_speed machines.append(discovered_machine) discovered_pod.machines = machines return discovered_pod
def test_lxd_cpu_speed(self): self.assertEqual(2400, lxd_cpu_speed(SAMPLE_LXD_RESOURCES))
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 = get_lxd_machine_definition(request, profile.name) # 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()
async def discover(self, pod_id, context): """Discover all Pod host resources.""" # Connect to the Pod and make sure it is valid. client = await self.get_client(pod_id, context) if not client.has_api_extension("virtual-machines"): raise LXDPodError( "Please upgrade your LXD host to 3.19+ for virtual machine support." ) resources = await deferToThread(lambda: client.resources) mac_addresses = [] for card in resources["network"]["cards"]: for port in card["ports"]: mac_addresses.append(port["address"]) # After the region creates the Pod object it will sync LXD commissioning # data for all hardware information. discovered_pod = DiscoveredPod( # client.host_info["environment"]["architectures"] reports all the # architectures the host CPU supports, not the architectures LXD # supports. On x86_64 LXD reports [x86_64, i686] however LXD does # not currently support VMs on i686. The LXD API currently does not # have a way to query which architectures are usable for VMs. The # safest bet is to just use the kernel_architecture. architectures=[ kernel_to_debian_architecture( client.host_info["environment"]["kernel_architecture"]) ], name=client.host_info["environment"]["server_name"], mac_addresses=mac_addresses, capabilities=[ Capabilities.COMPOSABLE, Capabilities.DYNAMIC_LOCAL_STORAGE, Capabilities.OVER_COMMIT, Capabilities.STORAGE_POOLS, ], ) # Check that we have at least one storage pool. # If not, user should be warned that they need to create one. storage_pools = await deferToThread(client.storage_pools.all) if not storage_pools: raise LXDPodError( "No storage pools exists. Please create a storage pool in LXD." ) # Discover Storage Pools. pools = [] storage_pools = await deferToThread(client.storage_pools.all) local_storage = 0 for storage_pool in storage_pools: discovered_storage_pool = self.get_discovered_pod_storage_pool( storage_pool) local_storage += discovered_storage_pool.storage pools.append(discovered_storage_pool) discovered_pod.storage_pools = pools discovered_pod.local_storage = local_storage # Discover VMs. machines = [] virtual_machines = await deferToThread(client.virtual_machines.all) for virtual_machine in virtual_machines: discovered_machine = await self.get_discovered_machine( client, virtual_machine, storage_pools=discovered_pod.storage_pools, ) discovered_machine.cpu_speed = lxd_cpu_speed(resources) machines.append(discovered_machine) discovered_pod.machines = machines # Return the DiscoveredPod. return discovered_pod
def discover(self, pod_id: int, context: dict): """Discover all Pod host resources.""" # Connect to the Pod and make sure it is valid. client = self._get_client(pod_id, context) if not client.has_api_extension("virtual-machines"): raise LXDPodError( "Please upgrade your LXD host to 3.19+ for virtual machine support." ) self._ensure_project(client) # get MACs for host interfaces. "unknown" interfaces are considered too # to match ethernets in containers networks_state = [ net.state() for net in client.networks.all() if net.type in ("unknown", "physical") ] mac_addresses = list( {state.hwaddr for state in networks_state if state.hwaddr}) environment = client.host_info["environment"] # After the region creates the Pod object it will sync LXD commissioning # data for all hardware information. discovered_pod = DiscoveredPod( # client.host_info["environment"]["architectures"] reports all the # architectures the host CPU supports, not the architectures LXD # supports. On x86_64 LXD reports [x86_64, i686] however LXD does # not currently support VMs on i686. The LXD API currently does not # have a way to query which architectures are usable for VMs. The # safest bet is to just use the kernel_architecture. architectures=[ kernel_to_debian_architecture( environment["kernel_architecture"]) ], name=environment["server_name"], version=environment["server_version"], mac_addresses=mac_addresses, capabilities=[ Capabilities.COMPOSABLE, Capabilities.DYNAMIC_LOCAL_STORAGE, Capabilities.OVER_COMMIT, Capabilities.STORAGE_POOLS, ], ) # Check that we have at least one storage pool. # If not, user should be warned that they need to create one. storage_pools = client.storage_pools.all() if not storage_pools: raise LXDPodError( "No storage pools exists. Please create a storage pool in LXD." ) # Discover Storage Pools. pools = [] local_storage = 0 for storage_pool in storage_pools: discovered_storage_pool = self._get_discovered_pod_storage_pool( storage_pool) local_storage += discovered_storage_pool.storage pools.append(discovered_storage_pool) discovered_pod.storage_pools = pools discovered_pod.local_storage = local_storage host_cpu_speed = lxd_cpu_speed(client.resources) # Discover VMs. projects = [project.name for project in client.projects.all()] machines = [] for project in projects: project_cli = self._get_client(pod_id, context, project=project) for virtual_machine in project_cli.virtual_machines.all(): discovered_machine = self._get_discovered_machine( project_cli, virtual_machine, storage_pools=discovered_pod.storage_pools, ) discovered_machine.cpu_speed = host_cpu_speed machines.append(discovered_machine) discovered_pod.machines = machines # Return the DiscoveredPod. return discovered_pod