361 lines
13 KiB
Python
361 lines
13 KiB
Python
#
|
|
# Copyright (c) 2020 Wind River Systems, Inc.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
|
|
"""
|
|
Tests for the sysinv agent pci utilities.
|
|
"""
|
|
|
|
import mock
|
|
try:
|
|
from contextlib import nested # Python 2
|
|
except ImportError:
|
|
from contextlib import ExitStack
|
|
from contextlib import contextmanager
|
|
|
|
@contextmanager
|
|
def nested(*contexts):
|
|
"""
|
|
Reimplementation of nested in python 3.
|
|
"""
|
|
with ExitStack() as stack:
|
|
yield tuple(stack.enter_context(cm) for cm in contexts)
|
|
|
|
from sysinv.agent.pci import PCIOperator
|
|
from sysinv.agent.pci import PCI
|
|
from sysinv.agent.manager import AgentManager
|
|
from sysinv.tests import base
|
|
from sysinv.common import constants
|
|
from sysinv.common import fpga_constants
|
|
import tsconfig.tsconfig as tsc
|
|
|
|
FAKE_LSPCI_OUTPUT = {
|
|
'82:00.0':
|
|
"""Slot: 82:00.0
|
|
Class: Ethernet controller
|
|
Vendor: Intel Corporation
|
|
Device: 82599ES 10-Gigabit SFI/SFP+ Network Connection
|
|
SVendor: Intel Corporation
|
|
SDevice: Ethernet Server Adapter X520-2
|
|
PhySlot: 803
|
|
Rev: 01
|
|
Driver: ixgbe
|
|
Module: ixgbe
|
|
NUMANode:""",
|
|
'82:10.0':
|
|
"""Slot: 82:10.0
|
|
Class: Ethernet controller
|
|
Vendor: Intel Corporation
|
|
Device: 82599 Ethernet Controller Virtual Function
|
|
SVendor: Intel Corporation
|
|
SDevice: Device 000c
|
|
Rev: 01
|
|
Driver: vfio-pci
|
|
Module: ixgbevf
|
|
NUMANode: 1""",
|
|
'b4:00.0':
|
|
"""Slot: b4:00.0
|
|
Class: Processing accelerators
|
|
Vendor: Intel Corporation
|
|
Device: Device 0d8f
|
|
SVendor: Intel Corporation
|
|
SDevice: Device 0001
|
|
Rev: 01
|
|
Driver: igb_uio
|
|
NUMANode: 1""",
|
|
'b4:00.1':
|
|
"""Slot: b4:00.1
|
|
Class: Processing accelerators
|
|
Vendor: Intel Corporation
|
|
Device: Device 0d90
|
|
SVendor: Intel Corporation
|
|
SDevice: Device e001
|
|
Rev: 01
|
|
Driver: igb_uio
|
|
NUMANode: 1"""
|
|
}
|
|
|
|
FAKE_DEVICE_ATTRIBUTES = [{
|
|
"name": "fake_device",
|
|
"pci_address": "b4:00.0",
|
|
"pclass_id": "120000",
|
|
"pvendor_id": "8086",
|
|
"pdevice_id": "0d8f",
|
|
"numa_node": 0,
|
|
"sriov_totalvfs": 8,
|
|
"sriov_numvfs": 1,
|
|
"sriov_vfs_pci_address": "b4:00.1",
|
|
"sriov_vf_driver": "igb_uio",
|
|
"sriov_vf_pdevice_id": "0d90",
|
|
"driver": "igb_uio",
|
|
"enabled": True,
|
|
}]
|
|
|
|
FAKE_PORT_ATTRIBUTES = [{
|
|
"name": "fake_port",
|
|
"numa_node": 0,
|
|
"sriov_totalvfs": 8,
|
|
"sriov_numvfs": 1,
|
|
"sriov_vfs_pci_address": "82:10.0",
|
|
"sriov_vf_driver": "ixgbevf",
|
|
"sriov_vf_pdevice_id": "000c",
|
|
"driver": "ixgbe",
|
|
"pci_address": "82:00.0",
|
|
"mac": "3c:fd:fe:b5:72:fd",
|
|
"mtu": 1500,
|
|
"speed": 1000,
|
|
"link_mode": 0,
|
|
"dev_id": 1,
|
|
"dpdksupport": True
|
|
}]
|
|
|
|
FAKE_PORTS = [PCI(
|
|
'82:10.0', 'Ethernet controller [0200]', 'Intel Corporation [8086]', 'Device [1518]',
|
|
'-r04', 'Intel Corporation [8086]', 'Device [0000]')]
|
|
|
|
FAKE_DEVICES = [PCI(
|
|
'b4:00.0', 'Processing accelerators', 'Intel Corporation [8086]', 'Device [0d8f]',
|
|
'', 'Intel Corporation [8086]', 'Device [0000]')]
|
|
|
|
|
|
class TestPciOperator(base.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestPciOperator, self).setUp()
|
|
self.pci_operator = PCIOperator()
|
|
|
|
def tearDown(self):
|
|
super(TestPciOperator, self).tearDown()
|
|
|
|
def mock_get_lspci_output_by_addr(addr): # pylint: disable=no-self-argument
|
|
return FAKE_LSPCI_OUTPUT[addr]
|
|
|
|
@mock.patch.object(PCIOperator, 'get_lspci_output_by_addr',
|
|
side_effect=mock_get_lspci_output_by_addr)
|
|
def test_get_pci_sriov_vf_driver_name(self, get_lspci_output_by_addr):
|
|
pfaddr = '82:00.0'
|
|
vfaddrs = ['82:10.0']
|
|
result = self.pci_operator.get_pci_sriov_vf_driver_name(pfaddr, vfaddrs)
|
|
assert result == "vfio-pci"
|
|
|
|
@mock.patch.object(PCIOperator, 'get_lspci_output_by_addr',
|
|
side_effect=mock_get_lspci_output_by_addr)
|
|
def test_get_pci_sriov_vf_module_name(self, get_lspci_output_by_addr):
|
|
pfaddr = '82:00.0'
|
|
vfaddrs = ['82:10.0']
|
|
result = self.pci_operator.get_pci_sriov_vf_module_name(pfaddr, vfaddrs)
|
|
assert result == "ixgbevf"
|
|
|
|
@mock.patch.object(PCIOperator, 'get_lspci_output_by_addr',
|
|
side_effect=mock_get_lspci_output_by_addr)
|
|
def test_get_pci_sriov_vf_module_name_none(self, get_lspci_output_by_addr):
|
|
pfaddr = 'b4:00.0'
|
|
vfaddrs = ['b4:00.1']
|
|
result = self.pci_operator.get_pci_sriov_vf_module_name(pfaddr, vfaddrs)
|
|
assert result is None
|
|
|
|
|
|
class TestAgentOperator(base.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestAgentOperator, self).setUp()
|
|
self.agent_manager = AgentManager('test-host', 'test-topic')
|
|
|
|
def tearDown(self):
|
|
super(TestAgentOperator, self).tearDown()
|
|
|
|
def _get_ports_inventory(self):
|
|
with nested(mock.patch.object(PCIOperator, 'pci_get_net_attrs'),
|
|
mock.patch.object(PCIOperator, 'pci_get_device_attrs'),
|
|
mock.patch.object(PCIOperator, 'inics_get'),
|
|
mock.patch.object(PCIOperator, 'pci_devices_get'),
|
|
mock.patch.object(AgentManager, 'subfunctions_list_get'),
|
|
mock.patch.object(AgentManager, '_acquire_network_config_lock'),
|
|
mock.patch.object(AgentManager, '_release_network_config_lock')) as (
|
|
mock_net_attrs, mock_device_attrs, mock_nics, mock_devices,
|
|
mock_subfunctions, aquire_lock, release_lock):
|
|
|
|
def fake_get_net_attrs(a):
|
|
return FAKE_PORT_ATTRIBUTES
|
|
|
|
def fake_get_device_attrs(a):
|
|
return FAKE_DEVICE_ATTRIBUTES
|
|
|
|
def fake_get_nics():
|
|
return FAKE_PORTS
|
|
|
|
def fake_get_devices():
|
|
return FAKE_DEVICES
|
|
|
|
def fake_subfunctions_list_get():
|
|
return self.subfunctions_list
|
|
|
|
mock_net_attrs.side_effect = fake_get_net_attrs
|
|
mock_device_attrs.side_effect = fake_get_device_attrs
|
|
mock_nics.side_effect = fake_get_nics
|
|
mock_devices.side_effect = fake_get_devices
|
|
mock_subfunctions.side_effect = fake_subfunctions_list_get
|
|
|
|
ports, devices, macs = self.agent_manager._get_ports_inventory()
|
|
return ports, devices, macs
|
|
|
|
@mock.patch('os.path.exists')
|
|
def test_get_pci_inventory_during_network_boot_install(self, mock_exists):
|
|
def file_exists_side_effect(filename):
|
|
if filename == constants.FIRST_BOOT_FLAG:
|
|
# first boot flag is set.
|
|
return True
|
|
else:
|
|
# ansible bootstrap flag is not set.
|
|
# Neither the initial nor volatile worker config complete flags are set
|
|
return False
|
|
|
|
self.agent_manager._first_boot_flag = True
|
|
mock_exists.side_effect = file_exists_side_effect
|
|
self.subfunctions_list = [constants.WORKER]
|
|
|
|
ports, devices, macs = self._get_ports_inventory()
|
|
assert len(ports) == 1
|
|
assert len(devices) == 1
|
|
assert len(macs) == 1
|
|
|
|
@mock.patch('os.path.exists')
|
|
def test_get_pci_inventory_during_bootstrap_fresh_install(self, mock_exists):
|
|
def file_exists_side_effect(filename):
|
|
if filename == constants.ANSIBLE_BOOTSTRAP_FLAG:
|
|
# ansible bootstrap flag is set.
|
|
return True
|
|
else:
|
|
# Neither the initial nor volatile worker config complete flags are set
|
|
return False
|
|
|
|
mock_exists.side_effect = file_exists_side_effect
|
|
self.subfunctions_list = [constants.WORKER]
|
|
|
|
ports, devices, macs = self._get_ports_inventory()
|
|
assert len(ports) == 1
|
|
assert len(devices) == 1
|
|
assert len(macs) == 1
|
|
|
|
@mock.patch('os.path.exists')
|
|
def test_get_pci_inventory_during_restore(self, mock_exists):
|
|
def file_exists_side_effect(filename):
|
|
if filename in [constants.ANSIBLE_BOOTSTRAP_FLAG,
|
|
tsc.RESTORE_IN_PROGRESS_FLAG]:
|
|
# Both ansible bootstrap and restore flag are set.
|
|
return True
|
|
else:
|
|
# Neither the initial nor volatile worker config complete flags are set
|
|
return False
|
|
|
|
mock_exists.side_effect = file_exists_side_effect
|
|
self.subfunctions_list = [constants.WORKER]
|
|
|
|
ports, devices, macs = self._get_ports_inventory()
|
|
assert len(ports) == 1
|
|
assert len(devices) == 1
|
|
assert len(macs) == 1
|
|
|
|
@mock.patch('os.path.exists')
|
|
def test_get_pci_inventory_controller_before_config_complete(self, mock_exists):
|
|
def file_exists_side_effect(filename):
|
|
# Neither the initial nor volatile controller config complete flags are set
|
|
# Neither first boot nor ansible bootstrap flag are not set.
|
|
return False
|
|
|
|
mock_exists.side_effect = file_exists_side_effect
|
|
self.subfunctions_list = [constants.CONTROLLER]
|
|
|
|
ports, devices, macs = self._get_ports_inventory()
|
|
assert len(ports) == 1
|
|
assert len(devices) == 1
|
|
assert len(macs) == 1
|
|
|
|
@mock.patch('os.path.exists')
|
|
def test_get_pci_inventory_storage_before_config_complete(self, mock_exists):
|
|
def file_exists_side_effect(filename):
|
|
# Neither the initial nor volatile storage config complete flags are set
|
|
# Neither first boot nor ansible bootstrap flag are not set.
|
|
return False
|
|
|
|
mock_exists.side_effect = file_exists_side_effect
|
|
self.subfunctions_list = [constants.STORAGE]
|
|
|
|
ports, devices, macs = self._get_ports_inventory()
|
|
assert len(ports) == 1
|
|
assert len(devices) == 1
|
|
assert len(macs) == 1
|
|
|
|
@mock.patch('os.path.exists')
|
|
def test_get_pci_inventory_before_worker_initial_config_complete(self, mock_exists):
|
|
def file_exists_side_effect(filename):
|
|
# Neither the initial nor volatile worker config complete flags are set
|
|
# Neither first boot nor ansible bootstrap flag are not set.
|
|
return False
|
|
mock_exists.side_effect = file_exists_side_effect
|
|
self.subfunctions_list = [constants.WORKER]
|
|
|
|
ports, devices, macs = self._get_ports_inventory()
|
|
assert len(ports) == 0
|
|
assert len(devices) == 0
|
|
assert len(macs) == 0
|
|
|
|
@mock.patch('os.path.exists')
|
|
def test_get_pci_inventory_before_worker_config_complete(self, mock_exists):
|
|
def file_exists_side_effect(filename):
|
|
if filename == tsc.INITIAL_WORKER_CONFIG_COMPLETE:
|
|
# Only the initial worker config complete flag is set
|
|
return True
|
|
else:
|
|
# worker config complete is not set.
|
|
# Neither first boot nor ansible bootstrap flag are set.
|
|
return False
|
|
mock_exists.side_effect = file_exists_side_effect
|
|
self.subfunctions_list = [constants.WORKER]
|
|
|
|
ports, devices, macs = self._get_ports_inventory()
|
|
assert len(ports) == 0
|
|
assert len(devices) == 0
|
|
assert len(macs) == 0
|
|
|
|
@mock.patch('os.path.exists')
|
|
def test_get_pci_inventory_after_worker_config_complete(self, mock_exists):
|
|
def file_exists_side_effect(filename):
|
|
if filename in [tsc.INITIAL_WORKER_CONFIG_COMPLETE,
|
|
tsc.VOLATILE_WORKER_CONFIG_COMPLETE]:
|
|
# Both of the initial and volatile worker config complete flags are set
|
|
return True
|
|
else:
|
|
# Neither first boot nor ansible bootstrap flag are set.
|
|
return False
|
|
mock_exists.side_effect = file_exists_side_effect
|
|
self.subfunctions_list = [constants.WORKER]
|
|
|
|
ports, devices, macs = self._get_ports_inventory()
|
|
for dev in devices:
|
|
assert dev['fpga_n3000_reset'] is False
|
|
assert len(ports) == 1
|
|
assert len(devices) == 1
|
|
assert len(macs) == 1
|
|
|
|
@mock.patch('os.path.exists')
|
|
def test_get_pci_inventory_n3000_reset_flag(self, mock_exists):
|
|
def file_exists_side_effect(filename):
|
|
if filename in [tsc.INITIAL_WORKER_CONFIG_COMPLETE,
|
|
tsc.VOLATILE_WORKER_CONFIG_COMPLETE,
|
|
fpga_constants.N3000_RESET_FLAG]:
|
|
return True
|
|
else:
|
|
return False
|
|
mock_exists.side_effect = file_exists_side_effect
|
|
self.subfunctions_list = [constants.WORKER]
|
|
|
|
ports, devices, macs = self._get_ports_inventory()
|
|
for dev in devices:
|
|
assert dev['fpga_n3000_reset'] is True
|
|
assert len(ports) == 1
|
|
assert len(devices) == 1
|
|
assert len(macs) == 1
|