Merge "OvS DPDK and SRIOV derive parameters"

This commit is contained in:
Zuul 2020-09-17 19:04:20 +00:00 committed by Gerrit Code Review
commit d5aaeb3f43
17 changed files with 1791 additions and 57 deletions

View File

@ -0,0 +1,58 @@
#!/usr/bin/python
try:
from ansible.module_utils import tripleo_common_utils as tc
except ImportError:
from tripleo_ansible.ansible_plugins.module_utils import tripleo_common_utils as tc
from ansible.parsing.yaml.objects import AnsibleUnicode
class FilterModule(object):
def filters(self):
return {
'number_list': self.number_list
}
# converts range list into number list
# here input parameter and return value as list
# example: ["12-14", "^13", "17"] into [12, 14, 17]
def convert_range_to_number_list(self, range_list):
num_list = []
exclude_num_list = []
try:
for val in range_list:
val = val.strip(' ')
if '^' in val:
exclude_num_list.append(int(val[1:]))
elif '-' in val:
split_list = val.split("-")
range_min = int(split_list[0])
range_max = int(split_list[1])
num_list.extend(range(range_min, (range_max + 1)))
else:
num_list.append(int(val))
except ValueError as exc:
msg = ("Invalid number in input param "
"'range_list': %s" % exc)
raise tc.DeriveParamsError(msg)
# here, num_list is a list of integers
return [num for num in num_list if num not in exclude_num_list]
def number_list(self, range_list):
try:
if not range_list:
msg = "Input param 'range_list' is blank."
raise Exception(msg)
range_list = range_list
# converts into python list if range_list is not list type
if not isinstance(range_list, list):
range_list = range_list.split(",")
num_list = self.convert_range_to_number_list(range_list)
except Exception as err:
msg = ('Derive Params Error: %s', err)
raise tc.DeriveParamsError(msg)
# converts into comma delimited number list as string
return ','.join([str(num) for num in num_list])

View File

@ -0,0 +1,55 @@
#!/usr/bin/python
try:
from ansible.module_utils import tripleo_common_utils as tc
except ImportError:
from tripleo_ansible.ansible_plugins.module_utils import tripleo_common_utils as tc
from ansible.parsing.yaml.objects import AnsibleUnicode
class FilterModule(object):
def filters(self):
return {
'range_list': self.range_list
}
# converts number list into range list.
# here input parameter and return value as list
# example: [12, 13, 14, 17] into ["12-14", "17"]
def _convert_number_to_range_list(self, num_list):
num_list.sort()
range_list = []
range_min = num_list[0]
for num in num_list:
next_val = num + 1
if next_val not in num_list:
if range_min != num:
range_list.append(str(range_min) + '-' + str(num))
else:
range_list.append(str(range_min))
next_index = num_list.index(num) + 1
if next_index < len(num_list):
range_min = num_list[next_index]
# here, range_list is a list of strings
return range_list
def range_list(self, num_list):
if not num_list:
msg = "Input param 'num_list' is blank."
raise tc.DeriveParamsError(msg)
try:
# splitting a string (comma delimited list) into
# list of numbers
# example: "12,13,14,17" string into [12,13,14,17]
num_list = [int(num.strip(' '))
for num in num_list.split(",")]
except ValueError as exc:
msg = ("Invalid number in input param "
"'num_list': %s" % exc)
raise tc.DeriveParamsError(msg)
range_list = self._convert_number_to_range_list(num_list)
# converts into comma delimited range list as string
return ','.join(range_list)

View File

@ -32,6 +32,10 @@ from tripleo_common.utils import parameters
import ironic_inspector_client
class DeriveParamsError(Exception):
"""Error while performing a derive parameters operation"""
class TripleOCommon(object):
def __init__(self, session):
self.sess = session

View File

@ -0,0 +1,164 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
__metaclass__ = type
from ansible.module_utils.basic import AnsibleModule
try:
from ansible.module_utils import tripleo_common_utils as tc
except ImportError:
from tripleo_ansible.ansible_plugins.module_utils import tripleo_common_utils as tc
from ansible.module_utils.openstack import openstack_full_argument_spec
from ansible.module_utils.openstack import openstack_module_kwargs
from ansible.module_utils.openstack import openstack_cloud_from_module
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = """
---
module: tripleo_get_dpdk_core_list.py
author:
- Jaganathan Palanisamy <jpalanis@redhat.com>
version_added: '2.8'
short_description: Gets the DPDK NICs with MTU for NUMA nodes.
notes: []
description:
- This module gets the DPDK NICs with MTU for NUMA nodes.
options:
inspect_data:
description:
- hardware data
required: True
type: dict
numa_nodes_cores_count:
description:
- cores count required for each numa node.
required: True
type: list
debug:
description:
- Whether or not debug is enabled.
default: False
required: False
type: bool
"""
EXAMPLES = """
- name: Generate containers configs data
tripleo_get_dpdk_core_list:
inspect_data: {}
numa_nodes_cores_count: 2
"""
RETURN = """
dpdk_core_list:
description:
- DPDK core list in string format.
returned: always
type: dict
"""
import glob
import json
import os
import re
import yaml
from tripleo_common import exception
def _get_dpdk_core_list(inspect_data, numa_nodes_cores_count):
dpdk_core_list = []
numa_cpus_info = inspect_data.get('numa_topology',
{}).get('cpus', [])
# Checks whether numa topology cpus information is not available
# in introspection data.
if not numa_cpus_info:
msg = 'Introspection data does not have numa_topology.cpus'
raise tc.DeriveParamsError(msg)
# Checks whether CPU physical cores count for each NUMA nodes is
# not available
if not numa_nodes_cores_count:
msg = ('CPU physical cores count for each NUMA nodes '
'is not available')
raise tc.DeriveParamsError(msg)
numa_nodes_threads = {}
# Creates list for all available threads in each NUMA node
for cpu in numa_cpus_info:
if not cpu['numa_node'] in numa_nodes_threads:
numa_nodes_threads[cpu['numa_node']] = []
numa_nodes_threads[cpu['numa_node']].extend(cpu['thread_siblings'])
for node, node_cores_count in enumerate(numa_nodes_cores_count):
# Gets least thread in NUMA node
numa_node_min = min(numa_nodes_threads[node])
cores_count = node_cores_count
for cpu in numa_cpus_info:
if cpu['numa_node'] == node:
# Adds threads from core which is not having least thread
if numa_node_min not in cpu['thread_siblings']:
dpdk_core_list.extend(cpu['thread_siblings'])
cores_count -= 1
if cores_count == 0:
break
return ','.join([str(thread) for thread in dpdk_core_list])
def main():
result = dict(
dpdk_core_list="",
success=False,
error=None,
)
module = AnsibleModule(
openstack_full_argument_spec(
**yaml.safe_load(DOCUMENTATION)['options']
),
**openstack_module_kwargs()
)
try:
result['dpdk_core_list'] = _get_dpdk_core_list(
module.params["inspect_data"],
module.params["numa_nodes_cores_count"]
)
except tc.DeriveParamsError as dexp:
result['error'] = str(dexp)
result['msg'] = 'Error unable to determine PMD CPUS : {}'.format(
dexp
)
module.fail_json(**result)
except Exception as exp:
result['error'] = str(exp)
result['msg'] = 'Error unable to determine PMD CPUS : {}'.format(
exp
)
module.fail_json(**result)
else:
result['success'] = True
module.exit_json(**result)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,280 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
__metaclass__ = type
from ansible.module_utils.basic import AnsibleModule
try:
from ansible.module_utils import tripleo_common_utils as tc
except ImportError:
from tripleo_ansible.ansible_plugins.module_utils import tripleo_common_utils as tc
from ansible.module_utils.openstack import openstack_full_argument_spec
from ansible.module_utils.openstack import openstack_module_kwargs
from ansible.module_utils.openstack import openstack_cloud_from_module
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = """
---
module: tripleo_get_dpdk_nics_numa_info
author:
- Jaganathan Palanisamy <jpalanis@redhat.com>
version_added: '2.8'
short_description: Gets the DPDK nics numa details
notes: []
description:
- This module gets the DPDK nics numa details.
options:
container:
description:
- Name of plan / container
This parameter is required.
type: str
required: true
role_name:
description:
- Name of the role
This parameter is required.
type: str
required: true
inspect_data:
description:
- Hardware data
This parameter is required
required: True
type: dict
mtu_default:
description:
- MTU default value
default: 1500
required: False
type: int
"""
EXAMPLES = """
- name: Gets DPDK nics numa details
tripleo_get_dpdk_nics_numa_info:
container: overcloud
role_name: ComputeOvsDpdk
inspect_data: {}
mtu_default: 1500
"""
RETURN = """
dpdk_nics_numa_info:
description:
- DPDK NICS NUMA details list
returned: always
type: list
"""
import glob
import json
import os
import re
import yaml
from tripleo_common.utils import stack_parameters as stack_param_utils
# Sorting active nics
def _natural_sort_key(s):
nsre = re.compile('([0-9]+)')
return [int(text) if text.isdigit() else text
for text in re.split(nsre, s)]
# Finds embedded nic or not
def _is_embedded_nic(nic):
if (nic.startswith('em') or nic.startswith('eth')
or nic.startswith('eno')):
return True
return False
# Ordering the nics
def _ordered_nics(interfaces):
embedded_nics = []
nics = []
for iface in interfaces:
nic = iface.get('name', '')
if _is_embedded_nic(nic):
embedded_nics.append(nic)
else:
nics.append(nic)
active_nics = (sorted(embedded_nics,
key=_natural_sort_key) + sorted(
nics, key=_natural_sort_key))
return active_nics
# Gets numa node id for physical NIC name
def _find_numa_node_id(numa_nics, nic_name):
for nic_info in numa_nics:
if nic_info.get('name', '') == nic_name:
return nic_info.get('numa_node', None)
return None
# Get physical interface name for NIC name
def _get_physical_iface_name(ordered_nics, nic_name):
if nic_name.startswith('nic'):
# Nic numbering, find the actual interface name
nic_number = int(nic_name.replace('nic', ''))
if nic_number > 0:
iface_name = ordered_nics[nic_number - 1]
return iface_name
return nic_name
# Gets dpdk interfaces and mtu info for dpdk config
# Default mtu(recommended 1500) is used if no MTU is set for DPDK NIC
def _get_dpdk_interfaces(dpdk_objs, mtu_default):
mtu = mtu_default
dpdk_ifaces = []
for dpdk_obj in dpdk_objs:
obj_type = dpdk_obj.get('type')
mtu = dpdk_obj.get('mtu', mtu_default)
if obj_type == 'ovs_dpdk_port':
# Member interfaces of ovs_dpdk_port
dpdk_ifaces.extend(dpdk_obj.get('members', []))
elif obj_type == 'ovs_dpdk_bond':
# ovs_dpdk_bond will have multiple ovs_dpdk_ports
for bond_member in dpdk_obj.get('members', []):
if bond_member.get('type') == 'ovs_dpdk_port':
dpdk_ifaces.extend(bond_member.get('members', []))
return (dpdk_ifaces, mtu)
def _get_dpdk_nics_numa_info(network_configs, inspect_data, mtu_default=1500):
interfaces = inspect_data.get('inventory',
{}).get('interfaces', [])
# Checks whether inventory interfaces information is not available
# in introspection data.
if not interfaces:
msg = 'Introspection data does not have inventory.interfaces'
raise tc.DeriveParamsError(msg)
numa_nics = inspect_data.get('numa_topology',
{}).get('nics', [])
# Checks whether numa topology nics information is not available
# in introspection data.
if not numa_nics:
msg = 'Introspection data does not have numa_topology.nics'
raise tc.DeriveParamsError(msg)
active_interfaces = [iface for iface in interfaces
if iface.get('has_carrier', False)]
# Checks whether active interfaces are not available
if not active_interfaces:
msg = 'Unable to determine active interfaces (has_carrier)'
raise tc.DeriveParamsError(msg)
dpdk_nics_numa_info = []
ordered_nics = _ordered_nics(active_interfaces)
# Gets DPDK network config and parses to get DPDK NICs
# with mtu and numa node id
for config in network_configs:
if config.get('type', '') == 'ovs_user_bridge':
bridge_name = config.get('name', '')
addresses = config.get('addresses', [])
members = config.get('members', [])
dpdk_ifaces, mtu = _get_dpdk_interfaces(members, mtu_default)
for dpdk_iface in dpdk_ifaces:
type = dpdk_iface.get('type', '')
if type == 'sriov_vf':
name = dpdk_iface.get('device', '')
else:
name = dpdk_iface.get('name', '')
phy_name = _get_physical_iface_name(
ordered_nics, name)
node = _find_numa_node_id(numa_nics, phy_name)
if node is None:
msg = ('Unable to determine NUMA node for '
'DPDK NIC: %s' % phy_name)
raise tc.DeriveParamsError(msg)
dpdk_nic_info = {'name': phy_name,
'numa_node': node,
'mtu': mtu,
'bridge_name': bridge_name,
'addresses': addresses}
dpdk_nics_numa_info.append(dpdk_nic_info)
return dpdk_nics_numa_info
def main():
result = dict(
dpdk_nics_numa_info=[],
success=False,
error=None,
)
module = AnsibleModule(
openstack_full_argument_spec(
**yaml.safe_load(DOCUMENTATION)['options']
),
**openstack_module_kwargs()
)
_, conn = openstack_cloud_from_module(module)
tripleo = tc.TripleOCommon(session=conn.session)
network_configs = {}
try:
# Get the network configs data for the required role name
network_configs = stack_param_utils.get_network_configs(
tripleo.get_object_client(),
tripleo.get_orchestration_client(),
container=module.params["container"],
role_name=module.params["role_name"]
)
except Exception as exp:
result['error'] = str(exp)
result['msg'] = 'Error getting network configs for role name {}: {}'.format(
module.params["role_name"],
exp
)
module.fail_json(**result)
try:
result['dpdk_nics_numa_info'] = _get_dpdk_nics_numa_info(
module.params["network_configs"],
module.params["inspect_data"],
module.params["mtu_default"]
)
except tc.DeriveParamsError as dexp:
result['error'] = str(dexp)
result['msg'] = 'Error pulling DPDK NICs NUMA information : {}'.format(
dexp
)
module.fail_json(**result)
except Exception as exp:
result['error'] = str(exp)
result['msg'] = 'Error pulling DPDK NICs NUMA information : {}'.format(
exp
)
module.fail_json(**result)
else:
result['success'] = True
module.exit_json(**result)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,180 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
__metaclass__ = type
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.openstack import openstack_full_argument_spec
from ansible.module_utils.openstack import openstack_module_kwargs
from ansible.module_utils.openstack import openstack_cloud_from_module
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = """
---
module: tripleo_get_dpdk_socket_memory
author:
- Jaganathan Palanisamy <jpalanis@redhat.com>
version_added: '2.8'
short_description: Gets the dpdk socket memory
notes: []
description:
- This module gets the dpdk socket memory
options:
dpdk_nics_numa_info:
description:
- DPDK nics numa details
required: True
type: list
numa_nodes:
description:
- NUMA nodes
required: True
type: list
overhead:
description:
- Overhead value
required: True
type: int
packet_size_in_buffer:
description:
- Packet size in buffer value
required: True
type: int
minimum_socket_memory:
description:
- Minimum socket memory per node
required: False
type: int
default: 1024
"""
EXAMPLES = """
- name: Gets the DPDK socket memory
tripleo_get_dpdk_socket_memory:
dpdk_nics_numa_info: {}
numa_nodes: []
overhead: 800
packet_size_in_buffer: 64
minimum_socket_memory: 1500
"""
RETURN = """
configs:
description:
- DPDK socket memory for each numa node.
returned: always
type: string
"""
import json
import math
import yaml
# Computes round off MTU value in bytes
# example: MTU value 9000 into 9216 bytes
def _roundup_mtu_bytes(mtu):
max_div_val = int(math.ceil(float(mtu) / float(1024)))
return (max_div_val * 1024)
# Calculates socket memory for a NUMA node
def _calculate_node_socket_memory(numa_node, dpdk_nics_numa_info,
overhead, packet_size_in_buffer,
minimum_socket_memory):
distinct_mtu_per_node = []
socket_memory = 0
# For DPDK numa node
for nics_info in dpdk_nics_numa_info:
if (numa_node == nics_info['numa_node']
and not nics_info['mtu'] in distinct_mtu_per_node):
distinct_mtu_per_node.append(nics_info['mtu'])
roundup_mtu = _roundup_mtu_bytes(nics_info['mtu'])
socket_memory += (((roundup_mtu + overhead) * packet_size_in_buffer)
/ (1024 * 1024))
# For Non DPDK numa node
if socket_memory == 0:
socket_memory = minimum_socket_memory
# For DPDK numa node
else:
socket_memory += 512
socket_memory_in_gb = int(socket_memory / 1024)
if socket_memory % 1024 > 0:
socket_memory_in_gb += 1
return (socket_memory_in_gb * 1024)
# Gets the DPDK Socket Memory List.
# For NUMA node with DPDK nic, socket memory is calculated
# based on MTU, Overhead and Packet size in buffer.
# For NUMA node without DPDK nic, minimum socket memory is
# assigned (recommended 1GB)
def _get_dpdk_socket_memory(dpdk_nics_numa_info, numa_nodes, overhead,
packet_size_in_buffer,
minimum_socket_memory=1024):
dpdk_socket_memory_list = []
for node in numa_nodes:
socket_mem = _calculate_node_socket_memory(
node, dpdk_nics_numa_info, overhead,
packet_size_in_buffer, minimum_socket_memory)
dpdk_socket_memory_list.append(socket_mem)
return ','.join([str(sm) for sm in dpdk_socket_memory_list])
def main():
result = dict(
socket_memory="",
success=False,
error=None
)
module = AnsibleModule(
openstack_full_argument_spec(
**yaml.safe_load(DOCUMENTATION)['options']
),
**openstack_module_kwargs()
)
try:
result['socket_memory'] = _get_dpdk_socket_memory(
module.params["dpdk_nics_numa_info"],
module.params["numa_nodes"],
module.params["overhead"],
module.params["packet_size_in_buffer"],
module.params["minimum_socket_memory"]
)
except Exception as exp:
result['error'] = str(exp)
result['msg'] = 'Error unable to determine DPDK socket memory : {}'.format(
exp
)
module.fail_json(**result)
else:
result['success'] = True
module.exit_json(**result)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,150 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
__metaclass__ = type
from ansible.module_utils.basic import AnsibleModule
try:
from ansible.module_utils import tripleo_common_utils as tc
except ImportError:
from tripleo_ansible.ansible_plugins.module_utils import tripleo_common_utils as tc
from ansible.module_utils.openstack import openstack_full_argument_spec
from ansible.module_utils.openstack import openstack_module_kwargs
from ansible.module_utils.openstack import openstack_cloud_from_module
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = """
---
module: tripleo_get_host_cpus
author:
- Jaganathan Palanisamy <jpalanis@redhat.com>
version_added: '2.8'
short_description: Generates a dictionary which contains all container configs
notes: []
description:
- This module reads container configs in JSON files and generate a dictionary
which later will be used to manage the containers.
options:
inspect_data:
description:
- Hardware data
required: True
type: dict
debug:
description:
- Whether or not debug is enabled.
default: False
required: False
type: bool
"""
EXAMPLES = """
- name: Gets the host cpus
tripleo_get_host_cpus:
inspect_data: {}
"""
RETURN = """
host_cpus_list:
description:
- Host cpus list
returned: always
type: list
"""
import json
import yaml
# Gets the Host CPUs List.
# CPU threads from first physical core is allocated for host processes
# on each NUMA nodes.
def _get_host_cpus_list(inspect_data):
host_cpus_list = []
numa_cpus_info = inspect_data.get('numa_topology',
{}).get('cpus', [])
# Checks whether numa topology cpus information is not available
# in introspection data.
if not numa_cpus_info:
msg = 'Introspection data does not have numa_topology.cpus'
raise tc.DeriveParamsError(msg)
numa_nodes_threads = {}
# Creates a list for all available threads in each NUMA nodes
for cpu in numa_cpus_info:
if not cpu['numa_node'] in numa_nodes_threads:
numa_nodes_threads[cpu['numa_node']] = []
numa_nodes_threads[cpu['numa_node']].extend(
cpu['thread_siblings'])
for numa_node in sorted(numa_nodes_threads.keys()):
node = int(numa_node)
# Gets least thread in NUMA node
numa_node_min = min(numa_nodes_threads[numa_node])
for cpu in numa_cpus_info:
if cpu['numa_node'] == node:
# Adds threads from core which is having least thread
if numa_node_min in cpu['thread_siblings']:
host_cpus_list.extend(cpu['thread_siblings'])
break
return ','.join([str(thread) for thread in host_cpus_list])
def main():
result = dict(
host_cpus_list="",
success=False,
error=None,
)
module = AnsibleModule(
openstack_full_argument_spec(
**yaml.safe_load(DOCUMENTATION)['options']
),
**openstack_module_kwargs()
)
try:
result['host_cpus_list'] = _get_host_cpus_list(
module.params["inspect_data"]
)
except tc.DeriveParamsError as dexp:
result['error'] = str(dexp)
result['msg'] = 'Error unable to determine Host CPUS : {}'.format(
dexp
)
module.fail_json(**result)
except Exception as exp:
result['error'] = str(exp)
result['msg'] = 'Error unable to determine Host CPUS : {}'.format(
exp
)
module.fail_json(**result)
else:
result['success'] = True
module.exit_json(**result)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,110 @@
---
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
- name: Get cpus list
set_fact:
cpus: "{{ hw_data.numa_topology.cpus }}"
- name: Get host dpdk combined cpus
set_fact:
host_dpdk_combined_cpus: "{% if pmd_cpus is defined %}{{ pmd_cpus }},{{ host_cpus }}{% else %}{{ host_cpus }}{% endif %}"
- name: Convert host dpdk combined cpus number list
set_fact:
host_dpdk_combined_cpus_list: "{{ host_dpdk_combined_cpus| number_list }}"
- name: Get cpu threads
set_fact:
cpu_threads: |-
{{ cpu_threads | default([]) }} + {{ item.thread_siblings | list}}
loop: "{{ cpus }}"
- name: Get nova cpus list
set_fact:
nova_cpus_list: |-
{{ nova_cpus_list | default([]) }} + [{{ item }}]
when: "{{ item | string not in host_dpdk_combined_cpus_list.split(',') }}"
loop: "{{ cpu_threads }}"
- name: Get nova cpus
set_fact:
nova_cpus: "{{ nova_cpus_list | join(',') }}"
# concatinates OvsPmdCoreList range format and NovaVcpuPinSet in range format. it may not be in perfect range format.
# example: concatinates '12-15,19' and 16-18' ranges '12-15,19,16-18'
- name: Get isol cpus
set_fact:
isol_cpus: "{% if pmd_cpus is defined %}{{ pmd_cpus }},{{ nova_cpus }}{% else %}{{ nova_cpus }}{% endif %}"
- name: Convert isol cpus number list
set_fact:
isol_cpus_list: "{{ isol_cpus | number_list }}"
- name: Convert nova cpus in range format
set_fact:
nova_cpus_range_list: "{{ nova_cpus | range_list}}"
- name: Convert isol cpus in range format
set_fact:
isol_cpus_range_list: "{{ isol_cpus | range_list }}"
- name: extract reserved host memory and huge page allocation percentage default value
set_fact:
host_mem_default: "{{ host_mem_default | default(4096) }}"
huge_page_allocation_percentage: "{{ huge_page_allocation_percentage | default(50) }}"
- name: Check huge page supported or not
set_fact:
default_hugepage_supported: "{{ 'pdpe1gb' in hw_data.get('inventory', {}).get('cpu', {}).get('flags', []) }}"
- name: Get total memory
set_fact:
total_memory: "{{ hw_data.get('inventory', {}).get('memory', {}).get('physical_mb', 0) }}"
- name: Get huge pages
set_fact:
hugepages: "{{ (((total_memory | int)/1024)-4)*((huge_page_allocation_percentage|float)/100) }}"
- name: Get cpu modal
set_fact:
intel_cpu_modal: "{{ 'Intel' in hw_data.get('inventory', {}).get('cpu', {}).get('model_name', '') }}"
- name: Get iommu info
set_fact:
iommu_info: "{% if intel_cpu_modal %}intel_iommu=on iommu=pt{% else %}{% endif %}"
- name: Get kernel args
set_fact:
kernel_args: "default_hugepagesz=1GB hugepagesz=1G hugepages={{ hugepages }} {{ iommu_info }} isolcpus={{ isol_cpus_range_list }}"
- name: Get host parameters in dictionary format
set_fact:
host_parameters: "{{ (host_parameters | default({})) | combine({item.key: item.value}) }}"
with_dict: {
'NovaComputeCpuDedicatedSet': '{{ nova_cpus_range_list }}',
'NovaComputeCpuSharedSet': '{{ host_cpus }}',
'NovaReservedHostMemory': '{{ host_mem_default }}',
'KernelArgs': '{{ kernel_args }}',
'IsolCpusList': '{{ isol_cpus_range_list }}'
}
- name: Update host parameters in derived parameters dictionary
set_fact:
derived_parameters: "{{
(derived_parameters |
default({})) |
combine({(tripleo_role_name + 'Parameters'): ((dpdk_parameters | default({})) | combine(host_parameters))})
}}"

View File

@ -0,0 +1,158 @@
---
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
- name: extract number of physical cores per numa node
set_fact:
num_phy_cores_per_numa_node_for_pmd: "{{ num_phy_cores_per_numa_node_for_pmd | default(2) }}"
- name: Get dpdk nics numa info
tripleo_get_dpdk_nics_numa_info:
container: "{{ tripleo_plan_name }}"
role_name: "{{ tripleo_role_name }}"
inspect_data: "{{ hw_data }}"
mtu_default: 1500
register: dpdk_nics_numa_info
- name: Fail if unable to determine DPDK NICs NUMA information
when: "{{ not dpdk_nics_numa_info.dpdk_nics_numa_info }}"
fail:
msg: "Unable to determine DPDK NIC's NUMA information for role: {{ tripleo_role_name }}"
- name: Get dpdk nics numa nodes
set_fact:
dpdk_nics_numa_nodes: >-
{{ dpdk_nics_numa_nodes | default([]) }} + {{ [item[0]] }}
loop: "{{ dpdk_nics_numa_info.dpdk_nics_numa_info | groupby('numa_node') | sort }}"
- name: Get numa nodes
set_fact:
numa_nodes: >-
{{ numa_nodes | default([]) }} + {{ [item.numa_node] }}
loop: "{{ hw_data.numa_topology.ram }}"
- name: Get sorted numa nodes
set_fact:
sorted_numa_nodes: "{{ numa_nodes | sort }}"
- name: Get number of cores per numa nodes
set_fact:
num_cores_per_numa_nodes: "{{
num_cores_per_numa_nodes |
default([]) }} + [{% if item in dpdk_nics_numa_nodes %} {{ num_phy_cores_per_numa_node_for_pmd }} {% else %} {{ 1 }} {% endif %}]"
loop: "{{ sorted_numa_nodes }}"
- name: Get pmd cpus in string format
tripleo_get_dpdk_core_list.py:
inspect_data: "{{ hw_data }}"
numa_nodes_cores_count: "{{ num_cores_per_numa_nodes }}"
register: dpdk_core_list
- name: Fail if unable to determine PMD CPU's
when: "{{ not dpdk_core_list.dpdk_core_list }}"
fail:
msg: "Unable to determine OvsPmdCoreList parameter for role: {{ tripleo_role_name }}"
- name: Convert pmd cpus in range list
set_fact:
pmd_cpus: "{{ dpdk_core_list.dpdk_core_list | range_list }}"
- name: Get host cpus list
tripleo_get_host_cpus:
inspect_data: "{{ hw_data }}"
register: host_cpus_list
- name: Fail if unable to determine Host CPU's
when: "{{ not host_cpus_list.host_cpus_list }}"
fail:
msg: "Unable to determine OvsDpdkCoreList parameter for role: {{ tripleo_role_name }}"
- name: Convert host cpus in range list
set_fact:
host_cpus: "{{ host_cpus_list.host_cpus_list | range_list}}"
- name: Get dpdk socket memory
tripleo_get_dpdk_socket_memory:
dpdk_nics_numa_info: "{{ dpdk_nics_numa_info.dpdk_nics_numa_info }}"
numa_nodes: "{{ sorted_numa_nodes }}"
overhead: "{{ overhead | default(800) }}"
packet_size_in_buffer: "{{ 4096 * 64 }}"
minimum_socket_memory: 1024
register: socket_memory
- name: Fail if unable to determine DPDK socket memory
when: "{{ not socket_memory.socket_memory }}"
fail:
msg: "Unable to determine OvsDpdkSocketMemory parameter for role: {{ tripleo_role_name }}"
- name: Get neutron bridge mappings
set_fact:
neutron_bridge_mappings: |-
{% set params = tripleo_heat_resource_tree.parameters.get('NeutronBridgeMappings', {}) %}
{{ params.get('default', {}) }}
- name: Get the physical network and ovs bridge mappings
set_fact:
phy_nw_bridge_mappings: "{{ (phy_nw_bridge_mappings | default({})) | combine({item.split(':')[0]: item.split(':')[1]}) }}"
loop: "{{ neutron_bridge_mappings.split(',') }}"
- name: Get the ovs bridge and NUMA nodes mappings
set_fact:
bridge_numa_nodes_mappings: "{{ (bridge_numa_nodes_mappings | default({})) | combine({item[0]: item[1] | map(attribute='numa_node') | list }) }}"
loop: "{{ dpdk_nics_numa_info.dpdk_nics_numa_info | groupby('bridge_name') }}"
- name: Get the physical network and NUMA nodes mappings
set_fact:
phy_nw_numa_nodes_mappings: "{{
(phy_nw_numa_nodes_mappings |
default([])) + [{(phy_nw_bridge_mappings | dict2items | selectattr('value', 'equalto', item.key) | list)[0].key: item.value}]
}}"
with_dict: "{{ bridge_numa_nodes_mappings }}"
- name: Get neutron network type
set_fact:
neutron_network_type: |-
{% set params = tripleo_heat_resource_tree.parameters.get('NeutronNetworkType', {}) %}
{{ params.get('default', '') }}
- name: Get tunnel numa nodes mappings
set_fact:
tunnel_numa_nodes_mappings: |-
{{ tunnel_numa_nodes_mappings | default([]) }} + [{{ item.numa_node }}]
loop: "{{ dpdk_nics_numa_info.dpdk_nics_numa_info }}"
when: "{{' vxlan' in neutron_network_type and item.addresses.ip_netmask is defined and item.addresses.ip_netmask }}"
- name: Get dpdk parameters in dictionary format
set_fact:
dpdk_parameters: "{{ (dpdk_parameters | default({})) | combine({item.key: item.value}) }}"
with_dict: {
'OvsPmdCoreList': '{{ pmd_cpus }}',
'OvsDpdkCoreList': '{{ host_cpus }}',
'OvsDpdkSocketMemory': '{{ socket_memory.socket_memory }}'
}
- name: Add physical network and NUMA nodes mappings in dpdk parameters
set_fact:
dpdk_parameters: "{{ dpdk_parameters | combine({'NeutronPhysnetNUMANodesMapping': phy_nw_numa_nodes_mappings}) }}"
when: "{{ phy_nw_numa_nodes_mappings is defined }}"
- name: Add tunnel numa nodes mappings in dpdk parameters
set_fact:
dpdk_parameters: "{{ dpdk_parameters | combine({'NeutronTunnelNUMANodes': tunnel_numa_nodes_mappings}) }}"
when: "{{ tunnel_numa_nodes_mappings is defined }}"
- name: Update dpdk parameters in derived parameters dictionary
set_fact:
derived_parameters: "{{ (derived_parameters | default({})) | combine({(tripleo_role_name + 'Parameters'): dpdk_parameters}) }}"

View File

@ -0,0 +1,24 @@
---
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
- name: Get host cpus list
tripleo_get_host_cpus:
inspect_data: "{{ hw_data }}"
register: host_cpus_list
- name: Convert host cpus in range list
set_fact:
host_cpus: "{{ host_cpus_list.host_cpus_list | range_list }}"

View File

@ -38,14 +38,9 @@
- name: Set features facts
set_fact:
dpdk: |-
{% set service_types = role_services.values() | sum(attribute='parameters', start=[]) %}
{% set neutron_datapath = ((service_types | map('regex_search', '.*NeutronDatapathType.*') | list | length) > 0) | bool %}
{% set heat_service_types = tripleo_heat_resource_tree.resources.values() | list | sum(attribute='parameters', start=[]) %}
{% set heat_neutron_datapath = ((heat_service_types | map('regex_search', '.*NeutronDatapathType.*') | list | length) > 0) | bool %}
{{ (neutron_datapath | bool) or (heat_neutron_datapath | bool) }}
{{ (role_services_from_key|map('regex_search', '.*\:\:ComputeNeutronOvsDpdk')|list|select('string')|list|length)>0 }}
sriov: |-
{% set service_types = role_services.values() | map(attribute='type') | list %}
{{ ((service_types | map('regex_search', '.*\:\:NeutronSriovAgent') | list | length) > 0) | bool }}
{{ (role_services_from_key|map('regex_search', '.*\:\:NeutronSriovAgent')|list|select('string')|list|length)>0 }}
hci: |-
{% set novacompute = ((role_services_from_key | map('regex_search', '.*\:\:NovaCompute') | select('string') | list | length) > 0) | bool %}
{% set cephosd = ((role_services_from_key | map('regex_search', '.*\:\:CephOSD') | select('string') | list | length) > 0) | bool %}
@ -171,58 +166,20 @@
- baremetal_data is defined
- baremetal_data['data'] is defined
# TODO
- name: Derive parameters for OvS Dpdk
when:
- dpdk
include_tasks: derive-ovs-dpdk-parameters.yml
# handle_dpdk_feature:
# on-success:
# - get_dpdk_derive_params: <% $.role_features.contains('DPDK') %>
# - handle_sriov_feature: <% not $.role_features.contains('DPDK') %>
- name: Derive parameters for SRIOV
when:
- sriov
include_tasks: derive-sriov-parameters.yml
# get_dpdk_derive_params:
# workflow: tripleo.derive_params_formulas.v1.dpdk_derive_params
# input:
# plan: <% $.plan %>
# tripleo_role_name: <% $.tripleo_role_name %>
# tripleo_heat_resource_tree: <% $.tripleo_heat_resource_tree %>
# hw_data: <% $.hw_data %>
# user_inputs: <% $.user_inputs %>
# publish:
# derived_parameters: <% task().result.get('derived_parameters', {}) %>
# on-success: handle_sriov_feature
# on-error: set_status_failed_get_dpdk_derive_params
# handle_sriov_feature:
# on-success:
# - get_sriov_derive_params: <% $.role_features.contains('SRIOV') %>
# - handle_host_feature: <% not $.role_features.contains('SRIOV') %>
# get_sriov_derive_params:
# workflow: tripleo.derive_params_formulas.v1.sriov_derive_params
# input:
# tripleo_role_name: <% $.tripleo_role_name %>
# hw_data: <% $.hw_data %>
# derived_parameters: <% $.derived_parameters %>
# publish:
# derived_parameters: <% task().result.get('derived_parameters', {}) %>
# on-success: handle_host_feature
# on-error: set_status_failed_get_sriov_derive_params
# handle_host_feature:
# on-success:
# - get_host_derive_params: <% $.role_features.contains('HOST') %>
# - handle_hci_feature: <% not $.role_features.contains('HOST') %>
# get_host_derive_params:
# workflow: tripleo.derive_params_formulas.v1.host_derive_params
# input:
# tripleo_role_name: <% $.tripleo_role_name %>
# hw_data: <% $.hw_data %>
# user_inputs: <% $.user_inputs %>
# derived_parameters: <% $.derived_parameters %>
# publish:
# derived_parameters: <% task().result.get('derived_parameters', {}) %>
# on-success: handle_hci_feature
# on-error: set_status_failed_get_host_derive_params
- name: Host derive parameters
when:
- dpdk or sriov
include_tasks: derive-host-parameters.yml
- name: Derive parameters for HCI
when:

View File

@ -0,0 +1,75 @@
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import yaml
try:
from ansible.module_utils import tripleo_common_utils as tc
except ImportError:
from tripleo_ansible.ansible_plugins.module_utils import tripleo_common_utils as tc
from tripleo_ansible.ansible_plugins.modules import tripleo_get_dpdk_core_list as derive_params
from tripleo_ansible.tests import base as tests_base
class TestTripleoGetDpdkCoreList(tests_base.TestCase):
"""Test the _get_dpdk_core_list method of the OvS DPDK module"""
def test_run(self):
inspect_data = {
"numa_topology": {
"cpus": [{"cpu": 21, "numa_node": 1,
"thread_siblings": [38, 82]},
{"cpu": 27, "numa_node": 0,
"thread_siblings": [20, 64]},
{"cpu": 3, "numa_node": 1,
"thread_siblings": [25, 69]},
{"cpu": 20, "numa_node": 0,
"thread_siblings": [15, 59]},
{"cpu": 17, "numa_node": 1,
"thread_siblings": [34, 78]},
{"cpu": 16, "numa_node": 0,
"thread_siblings": [11, 55]}]
}
}
numa_nodes_cores_count = [2, 1]
expected_result = "20,64,15,59,38,82"
result = derive_params._get_dpdk_core_list(inspect_data,
numa_nodes_cores_count)
self.assertEqual(result, expected_result)
def test_run_invalid_inspect_data(self):
inspect_data = {"numa_topology": {"cpus": []}}
numa_nodes_cores_count = [2, 1]
#msg = 'Introspection data does not have numa_topology.cpus'
self.assertRaises(tc.DeriveParamsError,
derive_params._get_dpdk_core_list,
inspect_data, numa_nodes_cores_count)
def test_run_invalid_numa_nodes_cores_count(self):
inspect_data = {"numa_topology": {
"cpus": [{"cpu": 21, "numa_node": 1, "thread_siblings": [38, 82]},
{"cpu": 27, "numa_node": 0, "thread_siblings": [20, 64]}]
}}
numa_nodes_cores_count = []
self.assertRaises(tc.DeriveParamsError,
derive_params._get_dpdk_core_list,
inspect_data, numa_nodes_cores_count)

View File

@ -0,0 +1,270 @@
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import yaml
try:
from ansible.module_utils import tripleo_common_utils as tc
except ImportError:
from tripleo_ansible.ansible_plugins.module_utils import tripleo_common_utils as tc
from tripleo_ansible.ansible_plugins.modules import tripleo_get_dpdk_nics_numa_info as derive_params
from tripleo_ansible.tests import base as tests_base
class TestTripleoGetDpdkNicsNumaInfo(tests_base.TestCase):
"""Test the _get_dpdk_nics_numa_info method of the OvS DPDK module"""
def test_run_dpdk_port(self):
network_configs = [{
"members": [{
"members": [{"name": "nic5", "type": "interface"}],
"name": "dpdk0",
"type": "ovs_dpdk_port",
"mtu": 8192,
"rx_queue": 4}],
"name": "br-link",
"type": "ovs_user_bridge",
"addresses": [{"ip_netmask": ""}]}]
inspect_data = {
"numa_topology": {
"nics": [{"name": "ens802f1", "numa_node": 1},
{"name": "ens802f0", "numa_node": 1},
{"name": "eno1", "numa_node": 0},
{"name": "eno2", "numa_node": 0},
{"name": "enp12s0f1", "numa_node": 0},
{"name": "enp12s0f0", "numa_node": 0},
{"name": "enp13s0f0", "numa_node": 0},
{"name": "enp13s0f1", "numa_node": 0}]
},
"inventory": {
"interfaces": [{"has_carrier": True,
"name": "ens802f1"},
{"has_carrier": True,
"name": "ens802f0"},
{"has_carrier": True,
"name": "eno1"},
{"has_carrier": True,
"name": "eno2"},
{"has_carrier": True,
"name": "enp12s0f0"},
{"has_carrier": False,
"name": "enp13s0f0"},
{"has_carrier": False,
"name": "enp13s0f1"}]
}
}
expected_result = [{'bridge_name': 'br-link', 'name': 'ens802f1',
'mtu': 8192, 'numa_node': 1,
'addresses': [{'ip_netmask': ''}]}]
result = derive_params._get_dpdk_nics_numa_info(network_configs,
inspect_data)
self.assertEqual(result, expected_result)
def test_run_dpdk_bond(self):
network_configs = [{
"members": [{"type": "ovs_dpdk_bond", "name": "dpdkbond0",
"mtu": 9000, "rx_queue": 4,
"members": [{"type": "ovs_dpdk_port",
"name": "dpdk0",
"members": [{"type": "interface",
"name": "nic4"}]},
{"type": "ovs_dpdk_port",
"name": "dpdk1",
"members": [{"type": "interface",
"name": "nic5"}]}]}],
"name": "br-link",
"type": "ovs_user_bridge",
"addresses": [{"ip_netmask": "172.16.10.0/24"}]}]
inspect_data = {
"numa_topology": {
"nics": [{"name": "ens802f1", "numa_node": 1},
{"name": "ens802f0", "numa_node": 1},
{"name": "eno1", "numa_node": 0},
{"name": "eno2", "numa_node": 0},
{"name": "enp12s0f1", "numa_node": 0},
{"name": "enp12s0f0", "numa_node": 0},
{"name": "enp13s0f0", "numa_node": 0},
{"name": "enp13s0f1", "numa_node": 0}]
},
"inventory": {
"interfaces": [{"has_carrier": True,
"name": "ens802f1"},
{"has_carrier": True,
"name": "ens802f0"},
{"has_carrier": True,
"name": "eno1"},
{"has_carrier": True,
"name": "eno2"},
{"has_carrier": True,
"name": "enp12s0f0"},
{"has_carrier": False,
"name": "enp13s0f0"},
{"has_carrier": False,
"name": "enp13s0f1"}]
}
}
expected_result = [{'bridge_name': 'br-link', 'mtu': 9000,
'numa_node': 1, 'name': 'ens802f0',
'addresses': [{'ip_netmask': '172.16.10.0/24'}]},
{'bridge_name': 'br-link', 'mtu': 9000,
'numa_node': 1, 'name': 'ens802f1',
'addresses': [{'ip_netmask': '172.16.10.0/24'}]}]
result = derive_params._get_dpdk_nics_numa_info(network_configs,
inspect_data)
self.assertEqual(result, expected_result)
def test_run_no_inspect_nics(self):
network_configs = [{
"members": [{
"members": [{"name": "nic5", "type": "interface"}],
"name": "dpdk0",
"type": "ovs_dpdk_port",
"mtu": 8192,
"rx_queue": 4}],
"name": "br-link",
"type": "ovs_user_bridge"}]
inspect_data = {
"numa_topology": {
"nics": []
},
"inventory": {
"interfaces": [{"has_carrier": True,
"name": "ens802f1"},
{"has_carrier": True,
"name": "ens802f0"},
{"has_carrier": True,
"name": "eno1"},
{"has_carrier": True,
"name": "eno2"},
{"has_carrier": True,
"name": "enp12s0f0"},
{"has_carrier": False,
"name": "enp13s0f0"},
{"has_carrier": False,
"name": "enp13s0f1"}]
}
}
self.assertRaises(tc.DeriveParamsError,
derive_params._get_dpdk_nics_numa_info,
network_configs, inspect_data)
def test_run_no_inspect_interfaces(self):
network_configs = [{
"members": [{
"members": [{"name": "nic5", "type": "interface"}],
"name": "dpdk0",
"type": "ovs_dpdk_port",
"mtu": 8192,
"rx_queue": 4}],
"name": "br-link",
"type": "ovs_user_bridge"}]
inspect_data = {
"numa_topology": {
"nics": []
},
"inventory": {
"interfaces": []
}
}
self.assertRaises(tc.DeriveParamsError,
derive_params._get_dpdk_nics_numa_info,
network_configs, inspect_data)
def test_run_no_inspect_active_interfaces(self):
network_configs = [{
"members": [{
"members": [{"name": "nic5", "type": "interface"}],
"name": "dpdk0",
"type": "ovs_dpdk_port",
"mtu": 8192,
"rx_queue": 4}],
"name": "br-link",
"type": "ovs_user_bridge"}]
inspect_data = {
"numa_topology": {
"nics": [{"name": "ens802f1", "numa_node": 1},
{"name": "ens802f0", "numa_node": 1},
{"name": "eno1", "numa_node": 0},
{"name": "eno2", "numa_node": 0},
{"name": "enp12s0f1", "numa_node": 0},
{"name": "enp12s0f0", "numa_node": 0},
{"name": "enp13s0f0", "numa_node": 0},
{"name": "enp13s0f1", "numa_node": 0}]
},
"inventory": {
"interfaces": [{"has_carrier": False,
"name": "enp13s0f0"},
{"has_carrier": False,
"name": "enp13s0f1"}]
}
}
self.assertRaises(tc.DeriveParamsError,
derive_params._get_dpdk_nics_numa_info,
network_configs, inspect_data)
def test_run_no_numa_node(self):
network_configs = [{
"members": [{
"members": [{"name": "nic5", "type": "interface"}],
"name": "dpdk0",
"type": "ovs_dpdk_port",
"mtu": 8192,
"rx_queue": 4}],
"name": "br-link",
"type": "ovs_user_bridge"}]
inspect_data = {
"numa_topology": {
"nics": [{"name": "ens802f1"},
{"name": "ens802f0", "numa_node": 1},
{"name": "eno1", "numa_node": 0},
{"name": "eno2", "numa_node": 0},
{"name": "enp12s0f1", "numa_node": 0},
{"name": "enp12s0f0", "numa_node": 0},
{"name": "enp13s0f0", "numa_node": 0},
{"name": "enp13s0f1", "numa_node": 0}]
},
"inventory": {
"interfaces": [{"has_carrier": True,
"name": "ens802f1"},
{"has_carrier": True,
"name": "ens802f0"},
{"has_carrier": True,
"name": "eno1"},
{"has_carrier": True,
"name": "eno2"},
{"has_carrier": True,
"name": "enp12s0f0"},
{"has_carrier": False,
"name": "enp13s0f0"},
{"has_carrier": False,
"name": "enp13s0f1"}]
}
}
self.assertRaises(tc.DeriveParamsError,
derive_params._get_dpdk_nics_numa_info,
network_configs, inspect_data)

View File

@ -0,0 +1,77 @@
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import yaml
from tripleo_ansible.ansible_plugins.modules import tripleo_get_dpdk_socket_memory as derive_params
from tripleo_ansible.tests import base as tests_base
class TestTripleoGetDpdkSocketMemory(tests_base.TestCase):
"""Test the _get_dpdk_socket_memory method of the OvS DPDK module"""
def test_run_valid_dpdk_nics_numa_info(self):
dpdk_nics_numa_info = [{"name": "ens802f1", "numa_node": 1,
"mtu": 8192}]
numa_nodes = [0, 1]
overhead = 800
packet_size_in_buffer = (4096 * 64)
expected_result = "1024,3072"
result = derive_params._get_dpdk_socket_memory(
dpdk_nics_numa_info, numa_nodes, overhead,
packet_size_in_buffer)
self.assertEqual(result, expected_result)
def test_run_multiple_mtu_in_same_numa_node(self):
dpdk_nics_numa_info = [{"name": "ens802f1", "numa_node": 1,
"mtu": 1500},
{"name": "ens802f2", "numa_node": 1,
"mtu": 2048}]
numa_nodes = [0, 1]
overhead = 800
packet_size_in_buffer = (4096 * 64)
expected_result = "1024,2048"
result = derive_params._get_dpdk_socket_memory(
dpdk_nics_numa_info, numa_nodes, overhead, packet_size_in_buffer)
self.assertEqual(result, expected_result)
def test_run_duplicate_mtu_in_same_numa_node(self):
dpdk_nics_numa_info = [{"name": "ens802f1", "numa_node": 1,
"mtu": 4096},
{"name": "ens802f2", "numa_node": 1,
"mtu": 4096}]
numa_nodes = [0, 1]
overhead = 800
packet_size_in_buffer = (4096 * 64)
expected_result = "1024,2048"
result = derive_params._get_dpdk_socket_memory(
dpdk_nics_numa_info, numa_nodes, overhead, packet_size_in_buffer)
self.assertEqual(result, expected_result)
def test_run_valid_roundup_mtu(self):
dpdk_nics_numa_info = [{"name": "ens802f1", "numa_node": 1,
"mtu": 1200}]
numa_nodes = [0, 1]
overhead = 800
packet_size_in_buffer = (4096 * 64)
expected_result = "1024,2048"
result = derive_params._get_dpdk_socket_memory(
dpdk_nics_numa_info, numa_nodes, overhead,
packet_size_in_buffer)
self.assertEqual(result, expected_result)

View File

@ -0,0 +1,52 @@
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import yaml
try:
from ansible.module_utils import tripleo_common_utils as tc
except ImportError:
from tripleo_ansible.ansible_plugins.module_utils import tripleo_common_utils as tc
from tripleo_ansible.ansible_plugins.modules import tripleo_get_host_cpus as derive_params
from tripleo_ansible.tests import base as tests_base
class TestTripleoGetHostCpus(tests_base.TestCase):
"""Test the _get_host_cpus_list of the OvS DPDK module"""
def test_run_valid_inspect_data(self):
inspect_data = {
"numa_topology": {
"cpus": [{"cpu": 21, "numa_node": 1,
"thread_siblings": [38, 82]},
{"cpu": 27, "numa_node": 0,
"thread_siblings": [20, 64]},
{"cpu": 3, "numa_node": 1,
"thread_siblings": [25, 69]},
{"cpu": 20, "numa_node": 0,
"thread_siblings": [15, 59]}]
}
}
expected_result = "15,59,25,69"
result = derive_params._get_host_cpus_list(inspect_data)
self.assertEqual(result, expected_result)
def test_run_invalid_inspect_data(self):
inspect_data = {"numa_topology": {"cpus": []}}
self.assertRaises(tc.DeriveParamsError,
derive_params._get_host_cpus_list,
inspect_data)

View File

@ -0,0 +1,70 @@
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
try:
from ansible.module_utils import tripleo_common_utils as tc
except ImportError:
from tripleo_ansible.ansible_plugins.module_utils import tripleo_common_utils as tc
from tripleo_ansible.ansible_plugins.filter import number_list
from tripleo_ansible.tests import base as tests_base
class TestNumberListFilters(tests_base.TestCase):
def setUp(self):
super(TestNumberListFilters, self).setUp()
self.filters = number_list.FilterModule()
def test_run_with_ranges_in_comma_delimited_str(self):
range_list = "24-27,60,65-67"
expected_result = "24,25,26,27,60,65,66,67"
result = self.filters.number_list(range_list)
self.assertEqual(result, expected_result)
def test_run_with_ranges_in_comma_delimited_list(self):
range_list = ['24-27', '60', '65-67']
expected_result = "24,25,26,27,60,65,66,67"
result = self.filters.number_list(range_list)
self.assertEqual(result, expected_result)
def test_run_with_ranges_exclude_num(self):
range_list = "24-27,^25,60,65-67"
expected_result = "24,26,27,60,65,66,67"
result = self.filters.number_list(range_list)
self.assertEqual(result, expected_result)
def test_run_with_no_ranges(self):
range_list = "24,25,26,27,60,65,66,67"
expected_result = "24,25,26,27,60,65,66,67"
result = self.filters.number_list(range_list)
self.assertEqual(result, expected_result)
def test_run_with_empty_input(self):
range_list = ""
self.assertRaises(tc.DeriveParamsError,
self.filters.number_list,
range_list)
def test_run_with_invalid_input(self):
range_list = ",d"
self.assertRaises(tc.DeriveParamsError,
self.filters.number_list,
range_list)
def test_run_with_invalid_exclude_number(self):
range_list = "12-15,^17"
expected_result = "12,13,14,15"
result = self.filters.number_list(range_list)
self.assertEqual(result, expected_result)

View File

@ -0,0 +1,50 @@
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
try:
from ansible.module_utils import tripleo_common_utils as tc
except ImportError:
from tripleo_ansible.ansible_plugins.module_utils import tripleo_common_utils as tc
from tripleo_ansible.ansible_plugins.filter import range_list
from tripleo_ansible.tests import base as tests_base
class TestRangeListFilters(tests_base.TestCase):
def setUp(self):
super(TestRangeListFilters, self).setUp()
self.filters = range_list.FilterModule()
def test_run_with_ranges(self):
num_list = "0,22,23,24,25,60,65,66,67"
expected_result = "0,22-25,60,65-67"
result = self.filters.range_list(num_list)
self.assertEqual(result, expected_result)
def test_run_with_no_range(self):
num_list = "0,22,24,60,65,67"
expected_result = "0,22,24,60,65,67"
result = self.filters.range_list(num_list)
self.assertEqual(result, expected_result)
def test_run_with_empty_input(self):
num_list = ""
self.assertRaises(tc.DeriveParamsError,
self.filters.range_list, num_list)
def test_run_with_invalid_input(self):
num_list = ",d"
self.assertRaises(tc.DeriveParamsError,
self.filters.range_list, num_list)