This commit adds the ability to HostNexus to learn about PCI devices. For now, we only consider NVIDIA devices for which IOMMU is enabled.
112 lines
3.7 KiB
Ruby
112 lines
3.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "../model/spec_helper"
|
|
|
|
RSpec.describe Prog::LearnPci do
|
|
describe "#make_model_instances" do
|
|
let(:nvidia_gpu_with_audio) do
|
|
end
|
|
|
|
it "exits, saving model instances" do
|
|
vmh = Prog::Vm::HostNexus.assemble("::1").subject
|
|
lp = described_class.new(Strand.new(stack: [{"subject_id" => vmh.id}]))
|
|
expect(lp.sshable).to receive(:cmd).with("/usr/bin/lspci -vnmm -d 10de::").and_return(<<EOS)
|
|
Slot: 01:00.0
|
|
Class: 0300
|
|
Vendor: 10de
|
|
Device: 27b0
|
|
SVendor: 10de
|
|
SDevice: 16fa
|
|
Rev: a1
|
|
NUMANode: 1
|
|
IOMMUGroup: 13
|
|
|
|
Slot: 01:00.1
|
|
Class: 0403
|
|
Vendor: 10de
|
|
Device: 22bc
|
|
SVendor: 10de
|
|
SDevice: 16fa
|
|
Rev: a1
|
|
IOMMUGroup: 13
|
|
EOS
|
|
expect { lp.start }.to exit({"msg" => "created PciDevice records"}).and change {
|
|
PciDevice.map { {vm_host_id: _1.vm_host_id, slot: _1.slot, device_class: _1.device_class, vendor: _1.vendor, device: _1.device, numa_node: _1.numa_node, iommu_group: _1.iommu_group, vm_id: _1.vm_id} }.sort_by { _1[:slot] }
|
|
}.from(
|
|
[]
|
|
).to(
|
|
[
|
|
{vm_host_id: vmh.id, slot: "01:00.0", device_class: "0300", vendor: "10de", device: "27b0", numa_node: 1, iommu_group: 13, vm_id: nil},
|
|
{vm_host_id: vmh.id, slot: "01:00.1", device_class: "0403", vendor: "10de", device: "22bc", numa_node: nil, iommu_group: 13, vm_id: nil}
|
|
]
|
|
)
|
|
end
|
|
|
|
it "exits, updating existing model instances" do
|
|
vmh = Prog::Vm::HostNexus.assemble("::1").subject
|
|
lp = described_class.new(Strand.new(stack: [{"subject_id" => vmh.id}]))
|
|
PciDevice.create_with_id(vm_host_id: vmh.id, slot: "01:00.0", device_class: "dc", vendor: "vd", device: "dv", numa_node: 0, iommu_group: 3)
|
|
expect(lp.sshable).to receive(:cmd).with("/usr/bin/lspci -vnmm -d 10de::").and_return(<<EOS)
|
|
Slot: 01:00.0
|
|
Class: 0300
|
|
Vendor: 10de
|
|
Device: 27b0
|
|
SVendor: 10de
|
|
SDevice: 16fa
|
|
Rev: a1
|
|
IOMMUGroup: 13
|
|
|
|
Slot: 01:00.1
|
|
Class: 0403
|
|
Vendor: 10de
|
|
Device: 22bc
|
|
SVendor: 10de
|
|
SDevice: 16fa
|
|
Rev: a1
|
|
IOMMUGroup: 13
|
|
EOS
|
|
expect { lp.start }.to exit({"msg" => "created PciDevice records"}).and change {
|
|
PciDevice.map { {vm_host_id: _1.vm_host_id, slot: _1.slot, device_class: _1.device_class, vendor: _1.vendor, device: _1.device, numa_node: _1.numa_node, iommu_group: _1.iommu_group, vm_id: _1.vm_id} }.sort_by { _1[:slot] }
|
|
}.from(
|
|
[{vm_host_id: vmh.id, slot: "01:00.0", device_class: "dc", vendor: "vd", device: "dv", numa_node: 0, iommu_group: 3, vm_id: nil}]
|
|
).to(
|
|
[
|
|
{vm_host_id: vmh.id, slot: "01:00.0", device_class: "0300", vendor: "10de", device: "27b0", numa_node: nil, iommu_group: 13, vm_id: nil},
|
|
{vm_host_id: vmh.id, slot: "01:00.1", device_class: "0403", vendor: "10de", device: "22bc", numa_node: nil, iommu_group: 13, vm_id: nil}
|
|
]
|
|
)
|
|
end
|
|
|
|
it "ignores devices without iommu group" do
|
|
vmh = Prog::Vm::HostNexus.assemble("::1").subject
|
|
lp = described_class.new(Strand.new(stack: [{"subject_id" => vmh.id}]))
|
|
expect(lp.sshable).to receive(:cmd).with("/usr/bin/lspci -vnmm -d 10de::").and_return(<<EOS)
|
|
Slot: 01:00.0
|
|
Class: 0300
|
|
Vendor: 10de
|
|
Device: 27b0
|
|
SVendor: 10de
|
|
SDevice: 16fa
|
|
Rev: a1
|
|
EOS
|
|
expect(lp.make_model_instances).to eq([])
|
|
end
|
|
|
|
it "can raise a data parse error" do
|
|
vmh = Prog::Vm::HostNexus.assemble("::1").subject
|
|
lp = described_class.new(Strand.new(stack: [{"subject_id" => vmh.id}]))
|
|
expect(lp.sshable).to receive(:cmd).with("/usr/bin/lspci -vnmm -d 10de::").and_return(<<EOS)
|
|
Slot: 01:00.0
|
|
Class: 0300
|
|
Device: 27b0
|
|
SVendor: 10de
|
|
SDevice: 16fa
|
|
Rev: a1
|
|
IOMMUGroup: 13
|
|
EOS
|
|
|
|
expect { lp.make_model_instances }.to raise_error RuntimeError, "BUG: lspci parse failed"
|
|
end
|
|
end
|
|
end
|