Update SR-IOV support for >= Mitaka
SR-IOV network for OpenStack release later than Mitaka requires the use of the neutron-sriov-agent to support management of SR-IOV PF and VF interface state by Neutron - said interfaces are still consumed directly by nova-compute/libvirt via PCI device allocation scheduling for instances. Add new configuration options to the neutron-openvswitch charm to support enablement of the SR-IOV agent; this could have been done automatically from data presented from neutron-api, but its possible that cloud deployments may only have subsets of compute nodes that are SR-IOV enabled in terms of hardware. Enabling this option ('enable-sriov') will install and configure the neutron-sriov-agent; configuration of SR-IOV PF's are made using the 'sriov-numvfs', which by default automatically configures all SR-IOV devices on every machine to the maximum number of VF's supported by the device. This option can be used to configure devices at an individual level as well. Finally, neutron needs to understand what underlying provider network each SR-IOV device maps to - this is configured using the sriov-device-mappings configuration option. Change-Id: Ie185fd347ddc1b11e9ed13cefaf44fb7c8546ab0
This commit is contained in:
parent
cd5fb8b51b
commit
790819c237
31
config.yaml
31
config.yaml
@ -172,3 +172,34 @@ options:
|
||||
uio_pci_generic
|
||||
.
|
||||
Only used when DPDK is enabled.
|
||||
enable-sriov:
|
||||
type: boolean
|
||||
default: false
|
||||
description: |
|
||||
Enable SR-IOV NIC agent on deployed units; use with sriov-device-mappings to
|
||||
map SR-IOV devices to underlying provider networks. Enabling this option
|
||||
allows instances to be plugged into directly into SR-IOV VF devices connected
|
||||
to underlying provider networks alongside the default Open vSwitch networking
|
||||
options.
|
||||
sriov-device-mappings:
|
||||
type: string
|
||||
default:
|
||||
description: |
|
||||
Space-delimited list of SR-IOV device mappings with format
|
||||
.
|
||||
<provider>:<interface>
|
||||
.
|
||||
Multiple mappings can be provided, delimited by spaces.
|
||||
sriov-numvfs:
|
||||
type: string
|
||||
default: auto
|
||||
description: |
|
||||
Number of VF's to configure each PF with; by default, each SR-IOV PF will be
|
||||
configured with the maximum number of VF's it can support. Either use a
|
||||
single integer to apply the same VF configuration to all detected SR-IOV
|
||||
devices or use a per-device configuration in the following format
|
||||
.
|
||||
<device>:<numvfs>
|
||||
.
|
||||
Multiple devices can be configured by providing multi values delimited by
|
||||
spaces.
|
||||
|
@ -103,6 +103,12 @@ class OVSPluginContext(context.NeutronContext):
|
||||
if mappings:
|
||||
ovs_ctxt['bridge_mappings'] = ','.join(mappings.split())
|
||||
|
||||
sriov_mappings = config('sriov-device-mappings')
|
||||
if sriov_mappings:
|
||||
ovs_ctxt['sriov_device_mappings'] = (
|
||||
','.join(sriov_mappings.split())
|
||||
)
|
||||
|
||||
flat_providers = config('flat-network-providers')
|
||||
if flat_providers:
|
||||
ovs_ctxt['network_providers'] = ','.join(flat_providers.split())
|
||||
|
@ -39,6 +39,7 @@ from neutron_ovs_utils import (
|
||||
DVR_PACKAGES,
|
||||
METADATA_PACKAGES,
|
||||
configure_ovs,
|
||||
configure_sriov,
|
||||
git_install,
|
||||
get_topics,
|
||||
get_shared_secret,
|
||||
@ -72,6 +73,7 @@ def config_changed():
|
||||
git_install(config('openstack-origin-git'))
|
||||
|
||||
configure_ovs()
|
||||
configure_sriov()
|
||||
CONFIGS.write_all()
|
||||
for rid in relation_ids('zeromq-configuration'):
|
||||
zeromq_configuration_relation_joined(rid)
|
||||
|
@ -33,6 +33,7 @@ from charmhelpers.contrib.openstack.utils import (
|
||||
make_assess_status_func,
|
||||
is_unit_paused_set,
|
||||
os_application_version_set,
|
||||
remote_restart,
|
||||
)
|
||||
from collections import OrderedDict
|
||||
from charmhelpers.contrib.openstack.utils import (
|
||||
@ -48,6 +49,7 @@ from charmhelpers.core.hookenv import (
|
||||
charm_dir,
|
||||
config,
|
||||
status_set,
|
||||
log,
|
||||
)
|
||||
from charmhelpers.contrib.openstack.neutron import (
|
||||
parse_bridge_mappings,
|
||||
@ -79,6 +81,9 @@ from charmhelpers.fetch import (
|
||||
filter_installed_packages,
|
||||
)
|
||||
|
||||
from pci import PCINetDevices
|
||||
|
||||
|
||||
# The interface is said to be satisfied if anyone of the interfaces in the
|
||||
# list has a complete context.
|
||||
# LY: Note the neutron-plugin is always present since that is the relation
|
||||
@ -134,6 +139,8 @@ PHY_NIC_MTU_CONF = '/etc/init/os-charm-phy-nic-mtu.conf'
|
||||
TEMPLATES = 'templates/'
|
||||
OVS_DEFAULT = '/etc/default/openvswitch-switch'
|
||||
DPDK_INTERFACES = '/etc/dpdk/interfaces'
|
||||
NEUTRON_SRIOV_AGENT_CONF = os.path.join(NEUTRON_CONF_DIR,
|
||||
'plugins/ml2/sriov_agent.ini')
|
||||
|
||||
BASE_RESOURCE_MAP = OrderedDict([
|
||||
(NEUTRON_CONF, {
|
||||
@ -195,6 +202,12 @@ DVR_RESOURCE_MAP = OrderedDict([
|
||||
'contexts': [context.ExternalPortContext()],
|
||||
}),
|
||||
])
|
||||
SRIOV_RESOURCE_MAP = OrderedDict([
|
||||
(NEUTRON_SRIOV_AGENT_CONF, {
|
||||
'services': ['neutron-sriov-agent'],
|
||||
'contexts': [neutron_ovs_context.OVSPluginContext()],
|
||||
}),
|
||||
])
|
||||
|
||||
TEMPLATES = 'templates/'
|
||||
INT_BRIDGE = "br-int"
|
||||
@ -254,6 +267,9 @@ def determine_packages():
|
||||
if use_dpdk():
|
||||
pkgs.append('openvswitch-switch-dpdk')
|
||||
|
||||
if enable_sriov_agent():
|
||||
pkgs.append('neutron-sriov-agent')
|
||||
|
||||
return pkgs
|
||||
|
||||
|
||||
@ -296,6 +312,10 @@ def resource_map():
|
||||
)
|
||||
if not use_dpdk():
|
||||
drop_config.append(DPDK_INTERFACES)
|
||||
if enable_sriov_agent():
|
||||
resource_map.update(SRIOV_RESOURCE_MAP)
|
||||
resource_map[NEUTRON_CONF]['services'].append(
|
||||
'neutron-sriov-agent')
|
||||
else:
|
||||
drop_config.extend([OVS_CONF, DPDK_INTERFACES])
|
||||
|
||||
@ -409,6 +429,53 @@ def configure_ovs():
|
||||
service_restart('os-charm-phy-nic-mtu')
|
||||
|
||||
|
||||
def configure_sriov():
|
||||
'''Configure SR-IOV devices based on provided configuration options'''
|
||||
charm_config = config()
|
||||
enable_sriov = charm_config.get('enable-sriov')
|
||||
if enable_sriov and charm_config.changed('sriov-numvfs'):
|
||||
devices = PCINetDevices()
|
||||
sriov_numvfs = charm_config.get('sriov-numvfs')
|
||||
|
||||
# automatic configuration of all SR-IOV devices
|
||||
if sriov_numvfs == 'auto':
|
||||
log('Configuring SR-IOV device VF functions in auto mode')
|
||||
for device in devices.pci_devices:
|
||||
if device and device.sriov:
|
||||
log("Configuring SR-IOV device"
|
||||
" {} with {} VF's".format(device.interface_name,
|
||||
device.sriov_totalvfs))
|
||||
device.set_sriov_numvfs(device.sriov_totalvfs)
|
||||
else:
|
||||
# Single int blanket configuration
|
||||
try:
|
||||
sriov_numvfs = int(sriov_numvfs)
|
||||
log('Configuring SR-IOV device VF functions'
|
||||
' with blanket setting')
|
||||
for device in devices.pci_devices:
|
||||
if device and device.sriov:
|
||||
log("Configuring SR-IOV device"
|
||||
" {} with {} VF's".format(device.interface_name,
|
||||
sriov_numvfs))
|
||||
device.set_sriov_numvfs(sriov_numvfs)
|
||||
except ValueError:
|
||||
# <device>:<numvfs>[ <device>:numvfs] configuration
|
||||
sriov_numvfs = sriov_numvfs.split()
|
||||
for device_config in sriov_numvfs:
|
||||
log('Configuring SR-IOV device VF functions per interface')
|
||||
interface_name, numvfs = device_config.split(':')
|
||||
device = devices.get_device_from_interface_name(
|
||||
interface_name)
|
||||
if device and device.sriov:
|
||||
log("Configuring SR-IOV device"
|
||||
" {} with {} VF's".format(device.interface_name,
|
||||
numvfs))
|
||||
device.set_sriov_numvfs(int(numvfs))
|
||||
|
||||
# Trigger remote restart in parent application
|
||||
remote_restart('neutron-plugin', 'nova-compute')
|
||||
|
||||
|
||||
def get_shared_secret():
|
||||
ctxt = neutron_ovs_context.SharedSecretContext()()
|
||||
if 'shared_secret' in ctxt:
|
||||
@ -438,6 +505,14 @@ def use_dpdk():
|
||||
return False
|
||||
|
||||
|
||||
def enable_sriov_agent():
|
||||
'''Determine with SR-IOV agent should be used'''
|
||||
release = os_release('neutron-common', base='icehouse')
|
||||
if (release >= 'mitaka' and config('enable-sriov')):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# TODO: update into charm-helpers to add port_type parameter
|
||||
def dpdk_add_bridge_port(name, port, promisc=False, port_type=None):
|
||||
''' Add a port to the named openvswitch bridge '''
|
||||
|
170
hooks/pci.py
170
hooks/pci.py
@ -18,9 +18,6 @@ import os
|
||||
import glob
|
||||
import subprocess
|
||||
import shlex
|
||||
from charmhelpers.core.hookenv import(
|
||||
log,
|
||||
)
|
||||
|
||||
|
||||
def format_pci_addr(pci_addr):
|
||||
@ -30,30 +27,22 @@ def format_pci_addr(pci_addr):
|
||||
func)
|
||||
|
||||
|
||||
class PCINetDevice(object):
|
||||
def get_sysnet_interfaces_and_macs():
|
||||
'''Catalog interface information from local system
|
||||
|
||||
def __init__(self, pci_address):
|
||||
self.pci_address = pci_address
|
||||
self.interface_name = None
|
||||
self.mac_address = None
|
||||
self.state = None
|
||||
self.update_attributes()
|
||||
each device dict contains:
|
||||
|
||||
def update_attributes(self):
|
||||
self.update_interface_info()
|
||||
interface: logical name
|
||||
mac_address: MAC address
|
||||
pci_address: PCI address
|
||||
state: Current interface state (up/down)
|
||||
sriov: Boolean indicating whether inteface is an SR-IOV
|
||||
capable device.
|
||||
sriov_totalvfs: Total VF capacity of device
|
||||
sriov_numvfs: Configured VF capacity of device
|
||||
|
||||
def update_interface_info(self):
|
||||
self.update_interface_info_eth()
|
||||
|
||||
def update_interface_info_eth(self):
|
||||
net_devices = self.get_sysnet_interfaces_and_macs()
|
||||
for interface in net_devices:
|
||||
if self.pci_address == interface['pci_address']:
|
||||
self.interface_name = interface['interface']
|
||||
self.mac_address = interface['mac_address']
|
||||
self.state = interface['state']
|
||||
|
||||
def get_sysnet_interfaces_and_macs(self):
|
||||
:returns: array: of dict objects containing details of each interface
|
||||
'''
|
||||
net_devs = []
|
||||
for sdir in glob.glob('/sys/class/net/*'):
|
||||
sym_link = sdir + "/device"
|
||||
@ -64,34 +53,141 @@ class PCINetDevice(object):
|
||||
pci_address = path[-2]
|
||||
else:
|
||||
pci_address = path[-1]
|
||||
net_devs.append({
|
||||
'interface': self.get_sysnet_interface(sdir),
|
||||
'mac_address': self.get_sysnet_mac(sdir),
|
||||
device = {
|
||||
'interface': get_sysnet_interface(sdir),
|
||||
'mac_address': get_sysnet_mac(sdir),
|
||||
'pci_address': pci_address,
|
||||
'state': self.get_sysnet_device_state(sdir),
|
||||
})
|
||||
'state': get_sysnet_device_state(sdir),
|
||||
'sriov': is_sriov(sdir)
|
||||
}
|
||||
if device['sriov']:
|
||||
device['sriov_totalvfs'] = \
|
||||
get_sriov_totalvfs(sdir)
|
||||
device['sriov_numvfs'] = \
|
||||
get_sriov_numvfs(sdir)
|
||||
net_devs.append(device)
|
||||
|
||||
return net_devs
|
||||
|
||||
def get_sysnet_mac(self, sysdir):
|
||||
|
||||
def get_sysnet_mac(sysdir):
|
||||
'''Read MAC address for a device
|
||||
|
||||
:sysdir: string: path to device /sys directory
|
||||
|
||||
:returns: string: MAC address of device
|
||||
'''
|
||||
mac_addr_file = sysdir + '/address'
|
||||
with open(mac_addr_file, 'r') as f:
|
||||
read_data = f.read()
|
||||
mac = read_data.strip()
|
||||
log('mac from {} is {}'.format(mac_addr_file, mac))
|
||||
return mac
|
||||
|
||||
def get_sysnet_device_state(self, sysdir):
|
||||
|
||||
def get_sysnet_device_state(sysdir):
|
||||
'''Read operational state of a device
|
||||
|
||||
:sysdir: string: path to device /sys directory
|
||||
|
||||
:returns: string: current device state
|
||||
'''
|
||||
state_file = sysdir + '/operstate'
|
||||
with open(state_file, 'r') as f:
|
||||
read_data = f.read()
|
||||
state = read_data.strip()
|
||||
log('state from {} is {}'.format(state_file, state))
|
||||
return state
|
||||
|
||||
def get_sysnet_interface(self, sysdir):
|
||||
|
||||
def is_sriov(sysdir):
|
||||
'''Determine whether a device is SR-IOV capable
|
||||
|
||||
:sysdir: string: path to device /sys directory
|
||||
|
||||
:returns: boolean: indicating whether device is SR-IOV
|
||||
capable or not.
|
||||
'''
|
||||
return os.path.exists(os.path.join(sysdir,
|
||||
'device',
|
||||
'sriov_totalvfs'))
|
||||
|
||||
|
||||
def get_sriov_totalvfs(sysdir):
|
||||
'''Read total VF capacity for a device
|
||||
|
||||
:sysdir: string: path to device /sys directory
|
||||
|
||||
:returns: int: number of VF's the device supports
|
||||
'''
|
||||
sriov_totalvfs_file = os.path.join(sysdir,
|
||||
'device',
|
||||
'sriov_totalvfs')
|
||||
with open(sriov_totalvfs_file, 'r') as f:
|
||||
read_data = f.read()
|
||||
sriov_totalvfs = int(read_data.strip())
|
||||
return sriov_totalvfs
|
||||
|
||||
|
||||
def get_sriov_numvfs(sysdir):
|
||||
'''Read configured VF capacity for a device
|
||||
|
||||
:sysdir: string: path to device /sys directory
|
||||
|
||||
:returns: int: number of VF's the device is configured for
|
||||
'''
|
||||
sriov_numvfs_file = os.path.join(sysdir,
|
||||
'device',
|
||||
'sriov_numvfs')
|
||||
with open(sriov_numvfs_file, 'r') as f:
|
||||
read_data = f.read()
|
||||
sriov_numvfs = int(read_data.strip())
|
||||
return sriov_numvfs
|
||||
|
||||
|
||||
def get_sysnet_interface(sysdir):
|
||||
return sysdir.split('/')[-1]
|
||||
|
||||
|
||||
class PCINetDevice(object):
|
||||
|
||||
def __init__(self, pci_address):
|
||||
self.pci_address = pci_address
|
||||
self.interface_name = None
|
||||
self.mac_address = None
|
||||
self.state = None
|
||||
self.sriov = False
|
||||
self.update_attributes()
|
||||
|
||||
def update_attributes(self):
|
||||
self.update_interface_info()
|
||||
|
||||
def update_interface_info(self):
|
||||
net_devices = get_sysnet_interfaces_and_macs()
|
||||
for interface in net_devices:
|
||||
if self.pci_address == interface['pci_address']:
|
||||
self.interface_name = interface['interface']
|
||||
self.mac_address = interface['mac_address']
|
||||
self.state = interface['state']
|
||||
self.sriov = interface['sriov']
|
||||
if self.sriov:
|
||||
self.sriov_totalvfs = interface['sriov_totalvfs']
|
||||
self.sriov_numvfs = interface['sriov_numvfs']
|
||||
|
||||
def set_sriov_numvfs(self, numvfs):
|
||||
'''Set the number of VF devices for a SR-IOV PF
|
||||
|
||||
Assuming the device is an SR-IOV device, this function will attempt
|
||||
to change the number of VF's created by the PF.
|
||||
|
||||
@param numvfs: integer to set the current number of VF's to
|
||||
'''
|
||||
if self.sriov:
|
||||
sdevice = os.path.join('/sys/class/net',
|
||||
self.interface_name,
|
||||
'device', 'sriov_numvfs')
|
||||
with open(sdevice, 'w') as sh:
|
||||
sh.write(str(numvfs))
|
||||
|
||||
|
||||
class PCINetDevices(object):
|
||||
|
||||
def __init__(self):
|
||||
@ -131,3 +227,9 @@ class PCINetDevices(object):
|
||||
if pcidev.pci_address == pci_addr:
|
||||
return pcidev
|
||||
return None
|
||||
|
||||
def get_device_from_interface_name(self, interface_name):
|
||||
for pcidev in self.pci_devices:
|
||||
if pcidev.interface_name == interface_name:
|
||||
return pcidev
|
||||
return None
|
||||
|
12
templates/mitaka/sriov_agent.ini
Normal file
12
templates/mitaka/sriov_agent.ini
Normal file
@ -0,0 +1,12 @@
|
||||
# mitaka
|
||||
###############################################################################
|
||||
# [ WARNING ]
|
||||
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||
# Config managed by neutron-openvswitch charm
|
||||
###############################################################################
|
||||
[securitygroup]
|
||||
firewall_driver = neutron.agent.firewall.NoopFirewallDriver
|
||||
|
||||
[sriov_nic]
|
||||
physical_device_mappings = {{ sriov_device_mappings }}
|
||||
exclude_devices =
|
@ -41,6 +41,7 @@ TO_PATCH = [
|
||||
'relation_ids',
|
||||
'relation_set',
|
||||
'configure_ovs',
|
||||
'configure_sriov',
|
||||
'use_dvr',
|
||||
'install_packages',
|
||||
'purge_packages',
|
||||
@ -99,6 +100,7 @@ class NeutronOVSHooksTests(CharmTestCase):
|
||||
self.assertTrue(self.CONFIGS.write_all.called)
|
||||
self.assertTrue(_zmq_joined.called_with('relid'))
|
||||
self.configure_ovs.assert_called_with()
|
||||
self.configure_sriov.assert_called_with()
|
||||
|
||||
@patch.object(hooks, 'git_install_requested')
|
||||
@patch.object(hooks, 'config_value_changed')
|
||||
|
@ -51,6 +51,8 @@ TO_PATCH = [
|
||||
'status_set',
|
||||
'use_dpdk',
|
||||
'os_application_version_set',
|
||||
'remote_restart',
|
||||
'PCINetDevices',
|
||||
]
|
||||
|
||||
head_pkg = 'linux-headers-3.15.0-5-generic'
|
||||
@ -596,3 +598,99 @@ class TestNeutronOVSUtils(CharmTestCase):
|
||||
asf.assert_called_once_with('some-config')
|
||||
# ports=None whilst port checks are disabled.
|
||||
f.assert_called_once_with('assessor', services='s1', ports=None)
|
||||
|
||||
def _configure_sriov_base(self, config,
|
||||
changed=False):
|
||||
self.mock_config = MagicMock()
|
||||
self.config.side_effect = None
|
||||
self.config.return_value = self.mock_config
|
||||
self.mock_config.get.side_effect = lambda x: config.get(x)
|
||||
self.mock_config.changed.return_value = changed
|
||||
|
||||
self.mock_eth_device = MagicMock()
|
||||
self.mock_eth_device.sriov = False
|
||||
self.mock_eth_device.interface_name = 'eth0'
|
||||
self.mock_eth_device.sriov_totalvfs = 0
|
||||
|
||||
self.mock_sriov_device = MagicMock()
|
||||
self.mock_sriov_device.sriov = True
|
||||
self.mock_sriov_device.interface_name = 'ens0'
|
||||
self.mock_sriov_device.sriov_totalvfs = 64
|
||||
|
||||
self.mock_sriov_device2 = MagicMock()
|
||||
self.mock_sriov_device2.sriov = True
|
||||
self.mock_sriov_device2.interface_name = 'ens49'
|
||||
self.mock_sriov_device2.sriov_totalvfs = 64
|
||||
|
||||
self.pci_devices = {
|
||||
'eth0': self.mock_eth_device,
|
||||
'ens0': self.mock_sriov_device,
|
||||
'ens49': self.mock_sriov_device2,
|
||||
}
|
||||
|
||||
mock_pci_devices = MagicMock()
|
||||
mock_pci_devices.pci_devices = [
|
||||
self.mock_eth_device,
|
||||
self.mock_sriov_device,
|
||||
self.mock_sriov_device2
|
||||
]
|
||||
self.PCINetDevices.return_value = mock_pci_devices
|
||||
|
||||
mock_pci_devices.get_device_from_interface_name.side_effect = \
|
||||
lambda x: self.pci_devices.get(x)
|
||||
|
||||
def test_configure_sriov_no_changes(self):
|
||||
_config = {
|
||||
'enable-sriov': True,
|
||||
'sriov-numvfs': 'auto'
|
||||
}
|
||||
self._configure_sriov_base(_config, False)
|
||||
|
||||
nutils.configure_sriov()
|
||||
|
||||
self.assertFalse(self.remote_restart.called)
|
||||
|
||||
def test_configure_sriov_auto(self):
|
||||
_config = {
|
||||
'enable-sriov': True,
|
||||
'sriov-numvfs': 'auto'
|
||||
}
|
||||
self._configure_sriov_base(_config, True)
|
||||
|
||||
nutils.configure_sriov()
|
||||
|
||||
self.mock_sriov_device.set_sriov_numvfs.assert_called_with(
|
||||
self.mock_sriov_device.sriov_totalvfs
|
||||
)
|
||||
self.mock_sriov_device2.set_sriov_numvfs.assert_called_with(
|
||||
self.mock_sriov_device2.sriov_totalvfs
|
||||
)
|
||||
self.assertTrue(self.remote_restart.called)
|
||||
|
||||
def test_configure_sriov_numvfs(self):
|
||||
_config = {
|
||||
'enable-sriov': True,
|
||||
'sriov-numvfs': '32',
|
||||
}
|
||||
self._configure_sriov_base(_config, True)
|
||||
|
||||
nutils.configure_sriov()
|
||||
|
||||
self.mock_sriov_device.set_sriov_numvfs.assert_called_with(32)
|
||||
self.mock_sriov_device2.set_sriov_numvfs.assert_called_with(32)
|
||||
|
||||
self.assertTrue(self.remote_restart.called)
|
||||
|
||||
def test_configure_sriov_numvfs_per_device(self):
|
||||
_config = {
|
||||
'enable-sriov': True,
|
||||
'sriov-numvfs': 'ens0:32 sriov23:64'
|
||||
}
|
||||
self._configure_sriov_base(_config, True)
|
||||
|
||||
nutils.configure_sriov()
|
||||
|
||||
self.mock_sriov_device.set_sriov_numvfs.assert_called_with(32)
|
||||
self.mock_sriov_device2.set_sriov_numvfs.assert_not_called()
|
||||
|
||||
self.assertTrue(self.remote_restart.called)
|
||||
|
@ -26,7 +26,6 @@ import pci
|
||||
|
||||
TO_PATCH = [
|
||||
'glob',
|
||||
'log',
|
||||
'subprocess',
|
||||
]
|
||||
NOT_JSON = "Im not json"
|
||||
@ -73,43 +72,48 @@ class PCINetDeviceTest(CharmTestCase):
|
||||
'mac_address': 'a8:9d:21:cf:93:fc',
|
||||
'pci_address': '0000:10:00.0',
|
||||
'state': 'up',
|
||||
'sriov': False,
|
||||
}
|
||||
self.assertTrue(check_device(net, expect))
|
||||
|
||||
@patch('pci.PCINetDevice.get_sysnet_interfaces_and_macs')
|
||||
@patch('pci.get_sysnet_interfaces_and_macs')
|
||||
@patch('pci.PCINetDevice.update_attributes')
|
||||
def test_update_interface_info_eth(self, _update, _sysnet_ints):
|
||||
def test_update_interface_info(self, _update, _sysnet_ints):
|
||||
dev = pci.PCINetDevice('0000:10:00.0')
|
||||
_sysnet_ints.return_value = [
|
||||
{
|
||||
'interface': 'eth2',
|
||||
'mac_address': 'a8:9d:21:cf:93:fc',
|
||||
'pci_address': '0000:10:00.0',
|
||||
'state': 'up'
|
||||
'state': 'up',
|
||||
'sriov': False,
|
||||
},
|
||||
{
|
||||
'interface': 'eth3',
|
||||
'mac_address': 'a8:9d:21:cf:93:fd',
|
||||
'pci_address': '0000:10:00.1',
|
||||
'state': 'down'
|
||||
'state': 'down',
|
||||
'sriov': False,
|
||||
}
|
||||
]
|
||||
dev.update_interface_info_eth()
|
||||
dev.update_interface_info()
|
||||
self.assertEqual(dev.interface_name, 'eth2')
|
||||
|
||||
@patch('os.path.islink')
|
||||
@patch('os.path.realpath')
|
||||
@patch('pci.PCINetDevice.get_sysnet_device_state')
|
||||
@patch('pci.PCINetDevice.get_sysnet_mac')
|
||||
@patch('pci.PCINetDevice.get_sysnet_interface')
|
||||
@patch('pci.is_sriov')
|
||||
@patch('pci.get_sysnet_device_state')
|
||||
@patch('pci.get_sysnet_mac')
|
||||
@patch('pci.get_sysnet_interface')
|
||||
@patch('pci.PCINetDevice.update_attributes')
|
||||
def test_get_sysnet_interfaces_and_macs(self, _update, _interface, _mac,
|
||||
_state, _osrealpath, _osislink):
|
||||
dev = pci.PCINetDevice('0000:06:00.0')
|
||||
_state, _sriov, _osrealpath,
|
||||
_osislink):
|
||||
self.glob.glob.return_value = ['/sys/class/net/eth2']
|
||||
_interface.return_value = 'eth2'
|
||||
_mac.return_value = 'a8:9d:21:cf:93:fc'
|
||||
_state.return_value = 'up'
|
||||
_sriov.return_value = False
|
||||
_osrealpath.return_value = ('/sys/devices/pci0000:00/0000:00:02.0/'
|
||||
'0000:02:00.0/0000:03:00.0/0000:04:00.0/'
|
||||
'0000:05:01.0/0000:07:00.0')
|
||||
@ -118,23 +122,26 @@ class PCINetDeviceTest(CharmTestCase):
|
||||
'mac_address': 'a8:9d:21:cf:93:fc',
|
||||
'pci_address': '0000:07:00.0',
|
||||
'state': 'up',
|
||||
'sriov': False,
|
||||
}
|
||||
self.assertEqual(dev.get_sysnet_interfaces_and_macs(), [expect])
|
||||
self.assertEqual(pci.get_sysnet_interfaces_and_macs(), [expect])
|
||||
|
||||
@patch('os.path.islink')
|
||||
@patch('os.path.realpath')
|
||||
@patch('pci.PCINetDevice.get_sysnet_device_state')
|
||||
@patch('pci.PCINetDevice.get_sysnet_mac')
|
||||
@patch('pci.PCINetDevice.get_sysnet_interface')
|
||||
@patch('pci.is_sriov')
|
||||
@patch('pci.get_sysnet_device_state')
|
||||
@patch('pci.get_sysnet_mac')
|
||||
@patch('pci.get_sysnet_interface')
|
||||
@patch('pci.PCINetDevice.update_attributes')
|
||||
def test_get_sysnet_interfaces_and_macs_virtio(self, _update, _interface,
|
||||
_mac, _state, _osrealpath,
|
||||
_mac, _state, _sriov,
|
||||
_osrealpath,
|
||||
_osislink):
|
||||
dev = pci.PCINetDevice('0000:06:00.0')
|
||||
self.glob.glob.return_value = ['/sys/class/net/eth2']
|
||||
_interface.return_value = 'eth2'
|
||||
_mac.return_value = 'a8:9d:21:cf:93:fc'
|
||||
_state.return_value = 'up'
|
||||
_sriov.return_value = False
|
||||
_osrealpath.return_value = ('/sys/devices/pci0000:00/0000:00:07.0/'
|
||||
'virtio5')
|
||||
expect = {
|
||||
@ -142,36 +149,34 @@ class PCINetDeviceTest(CharmTestCase):
|
||||
'mac_address': 'a8:9d:21:cf:93:fc',
|
||||
'pci_address': '0000:00:07.0',
|
||||
'state': 'up',
|
||||
'sriov': False,
|
||||
}
|
||||
self.assertEqual(dev.get_sysnet_interfaces_and_macs(), [expect])
|
||||
self.assertEqual(pci.get_sysnet_interfaces_and_macs(), [expect])
|
||||
|
||||
@patch('pci.PCINetDevice.update_attributes')
|
||||
def test_get_sysnet_mac(self, _update):
|
||||
device = pci.PCINetDevice('0000:10:00.1')
|
||||
with patch_open() as (_open, _file):
|
||||
super_fh = mocked_filehandle()
|
||||
_file.readlines = MagicMock()
|
||||
_open.side_effect = super_fh._setfilename
|
||||
_file.read.side_effect = super_fh._getfilecontents_read
|
||||
macaddr = device.get_sysnet_mac('/sys/class/net/eth3')
|
||||
macaddr = pci.get_sysnet_mac('/sys/class/net/eth3')
|
||||
self.assertEqual(macaddr, 'a8:9d:21:cf:93:fd')
|
||||
|
||||
@patch('pci.PCINetDevice.update_attributes')
|
||||
def test_get_sysnet_device_state(self, _update):
|
||||
device = pci.PCINetDevice('0000:10:00.1')
|
||||
with patch_open() as (_open, _file):
|
||||
super_fh = mocked_filehandle()
|
||||
_file.readlines = MagicMock()
|
||||
_open.side_effect = super_fh._setfilename
|
||||
_file.read.side_effect = super_fh._getfilecontents_read
|
||||
state = device.get_sysnet_device_state('/sys/class/net/eth3')
|
||||
state = pci.get_sysnet_device_state('/sys/class/net/eth3')
|
||||
self.assertEqual(state, 'down')
|
||||
|
||||
@patch('pci.PCINetDevice.update_attributes')
|
||||
def test_get_sysnet_interface(self, _update):
|
||||
device = pci.PCINetDevice('0000:10:00.1')
|
||||
self.assertEqual(
|
||||
device.get_sysnet_interface('/sys/class/net/eth3'), 'eth3')
|
||||
pci.get_sysnet_interface('/sys/class/net/eth3'), 'eth3')
|
||||
|
||||
|
||||
class PCINetDevicesTest(CharmTestCase):
|
||||
@ -208,12 +213,14 @@ class PCINetDevicesTest(CharmTestCase):
|
||||
'mac_address': 'a8:9d:21:cf:93:fc',
|
||||
'pci_address': '0000:10:00.0',
|
||||
'state': 'up',
|
||||
'sriov': False,
|
||||
},
|
||||
'0000:10:00.1': {
|
||||
'interface_name': 'eth3',
|
||||
'mac_address': 'a8:9d:21:cf:93:fd',
|
||||
'pci_address': '0000:10:00.1',
|
||||
'state': 'down',
|
||||
'sriov': False,
|
||||
},
|
||||
}
|
||||
for device in devices.pci_devices:
|
||||
@ -244,6 +251,7 @@ class PCINetDevicesTest(CharmTestCase):
|
||||
'mac_address': 'a8:9d:21:cf:93:fd',
|
||||
'pci_address': '0000:10:00.1',
|
||||
'state': 'down',
|
||||
'sriov': False,
|
||||
},
|
||||
}
|
||||
self.assertTrue(check_device(
|
||||
|
@ -86,12 +86,14 @@ def mocked_realpath(link):
|
||||
return pci_responses.SYS_TREE[resolved_link]
|
||||
|
||||
|
||||
@patch('pci.cached')
|
||||
@patch('pci.log')
|
||||
@patch('pci.subprocess.Popen')
|
||||
@patch('pci.subprocess.check_output')
|
||||
@patch('pci.glob.glob')
|
||||
@patch('pci.os.path.islink')
|
||||
def pci_devs(_osislink, _glob, _check_output, _Popen, _log, subproc_map=None):
|
||||
def pci_devs(_osislink, _glob, _check_output, _Popen, _log,
|
||||
_cached, subproc_map=None):
|
||||
_glob.side_effect = mocked_globs
|
||||
_osislink.side_effect = mocked_islink
|
||||
_check_output.side_effect = mocked_subprocess(
|
||||
|
Loading…
Reference in New Issue
Block a user