Merge "OvS DPDK and SRIOV derive parameters"
This commit is contained in:
commit
d5aaeb3f43
58
tripleo_ansible/ansible_plugins/filter/number_list.py
Normal file
58
tripleo_ansible/ansible_plugins/filter/number_list.py
Normal 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])
|
55
tripleo_ansible/ansible_plugins/filter/range_list.py
Normal file
55
tripleo_ansible/ansible_plugins/filter/range_list.py
Normal 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)
|
@ -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
|
||||
|
@ -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()
|
@ -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()
|
@ -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()
|
150
tripleo_ansible/ansible_plugins/modules/tripleo_get_host_cpus.py
Normal file
150
tripleo_ansible/ansible_plugins/modules/tripleo_get_host_cpus.py
Normal 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()
|
@ -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))})
|
||||
}}"
|
@ -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}) }}"
|
@ -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 }}"
|
@ -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:
|
||||
|
@ -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)
|
@ -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)
|
@ -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)
|
52
tripleo_ansible/tests/modules/test_tripleo_get_host_cpus.py
Normal file
52
tripleo_ansible/tests/modules/test_tripleo_get_host_cpus.py
Normal 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)
|
70
tripleo_ansible/tests/plugins/filter/test_number_list.py
Normal file
70
tripleo_ansible/tests/plugins/filter/test_number_list.py
Normal 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)
|
50
tripleo_ansible/tests/plugins/filter/test_range_list.py
Normal file
50
tripleo_ansible/tests/plugins/filter/test_range_list.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user