tripleo-common/workbooks/derive_params_formulas.yaml

564 lines
22 KiB
YAML

---
version: '2.0'
name: tripleo.derive_params_formulas.v1
description: TripleO Workflows to derive deployment parameters from the introspected data
workflows:
dpdk_derive_params:
description: >
Workflow to derive parameters for DPDK service.
input:
- plan
- role_name
- hw_data # introspection data
- user_inputs
- derived_parameters: {}
output:
derived_parameters: <% $.derived_parameters.mergeWith($.get('dpdk_parameters', {})) %>
tags:
- tripleo-common-managed
tasks:
get_network_config:
action: tripleo.parameters.get_network_config
input:
container: <% $.plan %>
role_name: <% $.role_name %>
publish:
network_configs: <% task().result.get('network_config', []) %>
on-success: get_dpdk_nics_numa_info
on-error: set_status_failed_get_network_config
get_dpdk_nics_numa_info:
action: tripleo.derive_params.get_dpdk_nics_numa_info
input:
network_configs: <% $.network_configs %>
inspect_data: <% $.hw_data %>
publish:
dpdk_nics_numa_info: <% task().result %>
on-success:
# TODO: Need to remove condtions here
# adding condition and throw error in action for empty check
- get_dpdk_nics_numa_nodes: <% $.dpdk_nics_numa_info %>
- set_status_failed_get_dpdk_nics_numa_info: <% not $.dpdk_nics_numa_info %>
on-error: set_status_failed_on_error_get_dpdk_nics_numa_info
get_dpdk_nics_numa_nodes:
publish:
dpdk_nics_numa_nodes: <% $.dpdk_nics_numa_info.groupBy($.numa_node).select($[0]).orderBy($) %>
on-success:
- get_numa_nodes: <% $.dpdk_nics_numa_nodes %>
- set_status_failed_get_dpdk_nics_numa_nodes: <% not $.dpdk_nics_numa_nodes %>
get_numa_nodes:
publish:
numa_nodes: <% $.hw_data.numa_topology.ram.select($.numa_node).orderBy($) %>
on-success:
- get_num_cores_per_numa_nodes: <% $.numa_nodes %>
- set_status_failed_get_numa_nodes: <% not $.numa_nodes %>
# For NUMA node with DPDK nic, number of cores should be used from user input (defaults to 2)
# For NUMA node without DPDK nic, number of cores should be 1
get_num_cores_per_numa_nodes:
publish:
num_cores_per_numa_nodes: <% let(dpdk_nics_nodes => $.dpdk_nics_numa_nodes, cores => $.user_inputs.get('num_phy_cores_per_numa_node_for_pmd', 2)) -> $.numa_nodes.select(switch($ in $dpdk_nics_nodes => $cores, not $ in $dpdk_nics_nodes => 1)) %>
on-success: get_pmd_cpus
get_pmd_cpus:
action: tripleo.derive_params.get_dpdk_core_list
input:
inspect_data: <% $.hw_data %>
numa_nodes_cores_count: <% $.num_cores_per_numa_nodes %>
publish:
pmd_cpus: <% task().result %>
on-success:
- get_host_cpus: <% $.pmd_cpus %>
- set_status_failed_get_pmd_cpus: <% not $.pmd_cpus %>
on-error: set_status_failed_on_error_get_pmd_cpus
get_host_cpus:
action: tripleo.derive_params.get_host_cpus_list inspect_data=<% $.hw_data %>
publish:
host_cpus: <% task().result %>
on-success:
- get_sock_mem: <% $.host_cpus %>
- set_status_failed_get_host_cpus: <% not $.host_cpus %>
on-error: set_status_failed_on_error_get_host_cpus
get_sock_mem:
action: tripleo.derive_params.get_dpdk_socket_memory
input:
dpdk_nics_numa_info: <% $.dpdk_nics_numa_info %>
numa_nodes: <% $.numa_nodes %>
overhead: <% $.user_inputs.get('overhead', 800) %>
packet_size_in_buffer: <% 4096*64 %>
publish:
sock_mem: <% task().result %>
on-success:
- get_memory_slot_info: <% $.sock_mem %>
- set_status_failed_get_sock_mem: <% not $.sock_mem %>
on-error: set_status_failed_on_error_get_sock_mem
get_memory_slot_info:
publish:
memory_slot_info: <% $.hw_data.extra.memory.values().select($.get("slot")).where($) %>
on-success:
- remove_slots_prefix_string: <% $.memory_slot_info %>
- set_status_failed_get_memory_slot_info: <% not $.memory_slot_info %>
# Memory channels are identified by the number of memory slots to the NUMA node
# Memory slots will be off different formats in the introspection data, like P1-DIMMA1, DIMM_A1, etc
# This task removes the prefix string format like 'P1-DIMM' or 'DIMM_' and provides the list with only slot names like 'A1'
remove_slots_prefix_string:
publish:
updated_mem_slot_info: <% $.memory_slot_info.select($.replaceBy(regex("[A-Z0-9]*[-_]*DIMM{1}[-_]*"), '')) %>
on-success: remove_slots_suffix_number
# In the above list of slot names, this task removes the suffix number like '1' in 'A1' and provide the list with slot name as 'A'
remove_slots_suffix_number:
publish:
updated_mem_slot_info: <% $.updated_mem_slot_info.select($.replaceBy(regex("[0-9]"), '')) %>
on-success: get_memory_channels_per_node
# The total memory slot names list will have both NUMA nodes slot.
# Average out the length of slot name list with number of NUMA nodes to get the final value
get_memory_channels_per_node:
publish:
mem_channel: <% $.updated_mem_slot_info.distinct().len() / $.numa_nodes.len() %>
on-success:
- get_dpdk_parameters: <% $.mem_channel %>
- set_status_failed_get_memory_channels_per_node: <% not $.mem_channel %>
get_dpdk_parameters:
publish:
dpdk_parameters: <% dict(concat($.role_name, 'Parameters') => dict('OvsPmdCoreList' => $.get('pmd_cpus', ''), 'OvsDpdkCoreList' => $.get('host_cpus', ''), 'OvsDpdkSocketMemory' => $.get('sock_mem', ''), 'OvsDpdkMemoryChannels' => $.get('mem_channel', ''))) %>
set_status_failed_get_network_config:
publish:
status: FAILED
message: <% task(get_network_config).result %>
on-success: fail
set_status_failed_get_dpdk_nics_numa_info:
publish:
status: FAILED
message: "Unable to determine DPDK NIC's NUMA information"
on-success: fail
set_status_failed_on_error_get_dpdk_nics_numa_info:
publish:
status: FAILED
message: <% task(get_dpdk_nics_numa_info).result %>
on-success: fail
set_status_failed_get_dpdk_nics_numa_nodes:
publish:
status: FAILED
message: "Unable to determine DPDK NIC's numa nodes"
on-success: fail
set_status_failed_get_numa_nodes:
publish:
status: FAILED
message: 'Unable to determine available NUMA nodes'
on-success: fail
set_status_failed_get_pmd_cpus:
publish:
status: FAILED
message: 'Unable to determine OvsPmdCoreList parameter'
on-success: fail
set_status_failed_on_error_get_pmd_cpus:
publish:
status: FAILED
message: <% task(get_pmd_cpus).result %>
on-success: fail
set_status_failed_get_host_cpus:
publish:
status: FAILED
message: 'Unable to determine OvsDpdkCoreList parameter'
on-success: fail
set_status_failed_on_error_get_host_cpus:
publish:
status: FAILED
message: <% task(get_host_cpus).result %>
on-success: fail
set_status_failed_get_sock_mem:
publish:
status: FAILED
message: 'Unable to determine OvsDpdkSocketMemory parameter'
on-success: fail
set_status_failed_on_error_get_sock_mem:
publish:
status: FAILED
message: <% task(get_sock_mem).result %>
on-success: fail
set_status_failed_get_memory_slot_info:
publish:
status: FAILED
message: 'Unable to determine memory slot name on NUMA nodes'
on-success: fail
set_status_failed_get_memory_channels_per_node:
publish:
status: FAILED
message: 'Unable to determine OvsDpdkMemoryChannels parameter'
on-success: fail
host_derive_params:
description: >
This workflow derives parameters for the Host process, and is mainly associated with CPU pinning and huge memory pages.
This workflow can be dependent on any feature or also can be invoked individually as well.
input:
- role_name
- hw_data # introspection data
- user_inputs
- derived_parameters: {}
output:
derived_parameters: <% $.derived_parameters.mergeWith($.get('host_parameters', {})) %>
tags:
- tripleo-common-managed
tasks:
get_cpus:
publish:
cpus: <% $.hw_data.numa_topology.cpus %>
on-success:
- get_role_derive_params: <% $.cpus %>
- set_status_failed_get_cpus: <% not $.cpus %>
get_role_derive_params:
publish:
role_derive_params: <% $.derived_parameters.get(concat($.role_name, 'Parameters'), {}) %>
on-success: get_host_dpdk_combined_cpus
get_host_dpdk_combined_cpus:
publish:
host_dpdk_combined_cpus: <% let(params => $.role_derive_params) -> concat($params.get('OvsPmdCoreList', ''), ',', $params.get('OvsDpdkCoreList', '')).split(",").select(int($)) %>
on-success:
- get_nova_cpus: <% $.host_dpdk_combined_cpus %>
- set_status_failed_get_host_dpdk_combined_cpus: <% not $.host_dpdk_combined_cpus %>
get_nova_cpus:
publish:
nova_cpus: <% let(invalid_threads => $.host_dpdk_combined_cpus) -> $.cpus.select($.thread_siblings).flatten().where(not $ in $invalid_threads).join(',') %>
on-success:
- get_isol_cpus: <% $.nova_cpus %>
- set_status_failed_get_nova_cpus: <% not $.nova_cpus %>
get_isol_cpus:
publish:
isol_cpus: <% let(params => $.role_derive_params) -> concat($params.get('OvsPmdCoreList',''), ',', $.nova_cpus) %>
on-success: get_host_mem
get_host_mem:
publish:
host_mem: <% $.user_inputs.get('host_mem_default', 4096) %>
on-success: check_default_hugepage_supported
check_default_hugepage_supported:
publish:
default_hugepage_supported: <% $.hw_data.get('inventory', {}).get('cpu', {}).get('flags', []).contains('pdpe1gb') %>
on-success:
- get_total_memory: <% $.default_hugepage_supported %>
- set_status_failed_check_default_hugepage_supported: <% not $.default_hugepage_supported %>
get_total_memory:
publish:
total_memory: <% $.hw_data.get('inventory', {}).get('memory', {}).get('physical_mb', 0) %>
on-success:
- get_hugepages: <% $.total_memory %>
- set_status_failed_get_total_memory: <% not $.total_memory %>
get_hugepages:
publish:
hugepages: <% let(huge_page_perc => float($.user_inputs.get('huge_page_allocation_percentage', 90))/100)-> int((($.total_memory/1024)-4) * $huge_page_perc) %>
on-success:
- get_cpu_model: <% $.hugepages %>
- set_status_failed_get_hugepages: <% not $.hugepages %>
get_cpu_model:
publish:
intel_cpu_model: <% $.hw_data.get('inventory', {}).get('cpu', {}).get('model_name', '').startsWith('Intel') %>
on-success: get_iommu_info
get_iommu_info:
publish:
iommu_info: <% switch($.intel_cpu_model => 'intel_iommu=on iommu=pt', not $.intel_cpu_model => '') %>
on-success: get_kernel_args
get_kernel_args:
publish:
kernel_args: <% concat('default_hugepagesz=1GB hugepagesz=1G ', 'hugepages=', str($.hugepages), ' ', $.iommu_info, ' isolcpus=', $.isol_cpus) %>
on-success: get_host_parameters
get_host_parameters:
publish:
host_parameters: <% dict(concat($.role_name, 'Parameters') => dict('NovaVcpuPinSet' => $.get('nova_cpus', ''), 'NovaReservedHostMemory' => $.get('host_mem', ''), 'KernelArgs' => $.get('kernel_args', ''), 'IsolCpusList' => $.get('isol_cpus', ''))) %>
set_status_failed_get_cpus:
publish:
status: FAILED
message: "Unable to determine CPU's on NUMA nodes"
on-success: fail
set_status_failed_get_host_dpdk_combined_cpus:
publish:
status: FAILED
message: 'Unable to combine host and dpdk cpus list'
on-success: fail
set_status_failed_get_nova_cpus:
publish:
status: FAILED
message: 'Unable to determine nova vcpu pin set'
on-success: fail
set_status_failed_check_default_hugepage_supported:
publish:
status: FAILED
message: 'default huge page size 1GB is not supported'
on-success: fail
set_status_failed_get_total_memory:
publish:
status: FAILED
message: 'Unable to determine total memory'
on-success: fail
set_status_failed_get_hugepages:
publish:
status: FAILED
message: 'Unable to determine huge pages'
on-success: fail
hci_derive_params:
description: Derive the deployment parameters for HCI
input:
- role_name
- environment_parameters
- heat_resource_tree
- introspection_data
- user_inputs
- derived_parameters: {}
output:
derived_parameters: <% $.derived_parameters.mergeWith($.get('hci_parameters', {})) %>
tags:
- tripleo-common-managed
tasks:
get_hci_inputs:
publish:
hci_profile: <% $.user_inputs.get('hci_profile', '') %>
hci_profile_config: <% $.user_inputs.get('hci_profile_config', {}) %>
MB_PER_GB: 1024
on-success:
- get_average_guest_memory_size_in_mb: <% $.hci_profile and $.hci_profile_config.get($.hci_profile, {}) %>
- set_failed_invalid_hci_profile: <% $.hci_profile and not $.hci_profile_config.get($.hci_profile, {}) %>
# When no hci_profile is specified, the workflow terminates without deriving any HCI parameters.
get_average_guest_memory_size_in_mb:
publish:
average_guest_memory_size_in_mb: <% $.hci_profile_config.get($.hci_profile, {}).get('average_guest_memory_size_in_mb', 0) %>
on-success:
- get_average_guest_cpu_utilization_percentage: <% isInteger($.average_guest_memory_size_in_mb) %>
- set_failed_invalid_average_guest_memory_size_in_mb: <% not isInteger($.average_guest_memory_size_in_mb) %>
get_average_guest_cpu_utilization_percentage:
publish:
average_guest_cpu_utilization_percentage: <% $.hci_profile_config.get($.hci_profile, {}).get('average_guest_cpu_utilization_percentage', 0) %>
on-success:
- get_gb_overhead_per_guest: <% isInteger($.average_guest_cpu_utilization_percentage) %>
- set_failed_invalid_average_guest_cpu_utilization_percentage: <% not isInteger($.average_guest_cpu_utilization_percentage) %>
get_gb_overhead_per_guest:
publish:
gb_overhead_per_guest: <% $.user_inputs.get('gb_overhead_per_guest', 0.5) %>
on-success:
- get_gb_per_osd: <% isNumber($.gb_overhead_per_guest) %>
- set_failed_invalid_gb_overhead_per_guest: <% not isNumber($.gb_overhead_per_guest) %>
get_gb_per_osd:
publish:
gb_per_osd: <% $.user_inputs.get('gb_per_osd', 3) %>
on-success:
- get_cores_per_osd: <% isNumber($.gb_per_osd) %>
- set_failed_invalid_gb_per_osd: <% not isNumber($.gb_per_osd) %>
get_cores_per_osd:
publish:
cores_per_osd: <% $.user_inputs.get('cores_per_osd', 1.0) %>
on-success:
- get_extra_configs: <% isNumber($.cores_per_osd) %>
- set_failed_invalid_cores_per_osd: <% not isNumber($.cores_per_osd) %>
get_extra_configs:
publish:
extra_config: <% $.environment_parameters.get('ExtraConfig', {}) %>
role_extra_config: <% $.environment_parameters.get(concat($.role_name, 'ExtraConfig'), {}) %>
on-success: get_num_osds
get_num_osds:
publish:
num_osds: <% $.role_extra_config.get('ceph::profile::params::osds', $.extra_config.get('ceph::profile::params::osds', {})).keys().count() %>
on-success:
- get_memory_mb: <% $.num_osds %>
- set_failed_no_osds: <% not $.num_osds %>
get_memory_mb:
publish:
memory_mb: <% $.introspection_data.get('memory_mb', 0) %>
on-success:
- get_num_cores: <% $.memory_mb %>
- set_failed_get_memory_mb: <% not $.memory_mb %>
get_num_cores:
publish:
# TODO(abishop): If NovaVcpuPinSet is defined then use it to determine num_cores
num_cores: <% $.introspection_data.get('cpus', 0) %>
on-success:
- calculate_nova_parameters: <% $.num_cores %>
- set_failed_get_num_cores: <% not $.num_cores %>
# HCI calculations are broken into multiple steps. This is necessary
# because variables published by a Mistral task are not available
# for use by that same task. Variables computed and published in a task
# are only available in subsequent tasks.
#
# The HCI calculations compute two Nova parameters:
# - reserved_host_memory
# - cpu_allocation_ratio
#
# The reserved_host_memory calculation computes the amount of memory
# that needs to be reserved for Ceph and the total amount of "guest
# overhead" memory that is based on the anticipated number of guests.
# Psuedo-code for the calculation (disregarding MB and GB units) is
# as follows:
#
# ceph_memory = mem_per_osd * num_osds
# nova_memory = total_memory - ceph_memory
# num_guests = nova_memory /
# (average_guest_memory_size + overhead_per_guest)
# reserved_memory = ceph_memory + (num_guests * overhead_per_guest)
#
# The cpu_allocation_ratio calculation is similar in that it takes into
# account the number of cores that must be reserved for Ceph.
#
# ceph_cores = cores_per_osd * num_osds
# guest_cores = num_cores - ceph_cores
# guest_vcpus = guest_cores / average_guest_utilization
# cpu_allocation_ratio = guest_vcpus / num_cores
calculate_nova_parameters:
publish:
avg_guest_util: <% $.average_guest_cpu_utilization_percentage / 100.0 %>
avg_guest_size_gb: <% $.average_guest_memory_size_in_mb / float($.MB_PER_GB) %>
memory_gb: <% $.memory_mb / float($.MB_PER_GB) %>
ceph_mem_gb: <% $.gb_per_osd * $.num_osds %>
nonceph_cores: <% $.num_cores - int($.cores_per_osd * $.num_osds) %>
on-success: calc_step_2
calc_step_2:
publish:
num_guests: <% int(($.memory_gb - $.ceph_mem_gb) / ($.avg_guest_size_gb + $.gb_overhead_per_guest)) %>
guest_vcpus: <% $.nonceph_cores / $.avg_guest_util %>
on-success: calc_step_3
calc_step_3:
publish:
reserved_host_memory: <% $.MB_PER_GB * int($.ceph_mem_gb + ($.num_guests * $.gb_overhead_per_guest)) %>
cpu_allocation_ratio: <% $.guest_vcpus / $.num_cores %>
on-success: validate_results
validate_results:
publish:
# Verify whether HCI is viable:
# - At least 80% of the memory is reserved for Ceph and guest overhead
# - At least half of the CPU cores must be available to Nova
mem_ok: <% $.reserved_host_memory <= ($.memory_mb * 0.8) %>
cpu_ok: <% $.cpu_allocation_ratio >= 0.5 %>
on-success:
- set_failed_insufficient_mem: <% not $.mem_ok %>
- set_failed_insufficient_cpu: <% not $.cpu_ok %>
- publish_hci_parameters: <% $.mem_ok and $.cpu_ok %>
publish_hci_parameters:
publish:
# TODO(abishop): Update this when the cpu_allocation_ratio can be set
# via a THT parameter (no such parameter currently exists). Until a
# THT parameter exists, use hiera data to set the cpu_allocation_ratio.
hci_parameters: <% dict(concat($.role_name, 'Parameters') => dict('NovaReservedHostMemory' => $.reserved_host_memory)) + dict(concat($.role_name, 'ExtraConfig') => dict('nova::cpu_allocation_ratio' => $.cpu_allocation_ratio)) %>
set_failed_invalid_hci_profile:
publish:
message: "'<% $.hci_profile %>' is not a valid HCI profile."
on-success: fail
set_failed_invalid_average_guest_memory_size_in_mb:
publish:
message: "'<% $.average_guest_memory_size_in_mb %>' is not a valid average_guest_memory_size_in_mb value."
on-success: fail
set_failed_invalid_gb_overhead_per_guest:
publish:
message: "'<% $.gb_overhead_per_guest %>' is not a valid gb_overhead_per_guest value."
on-success: fail
set_failed_invalid_gb_per_osd:
publish:
message: "'<% $.gb_per_osd %>' is not a valid gb_per_osd value."
on-success: fail
set_failed_invalid_cores_per_osd:
publish:
message: "'<% $.cores_per_osd %>' is not a valid cores_per_osd value."
on-success: fail
set_failed_invalid_average_guest_cpu_utilization_percentage:
publish:
message: "'<% $.average_guest_cpu_utilization_percentage %>' is not a valid average_guest_cpu_utilization_percentage value."
on-success: fail
set_failed_no_osds:
publish:
message: "No Ceph OSDs found in the overcloud definition ('ceph::profile::params::osds')."
on-success: fail
set_failed_get_memory_mb:
publish:
message: "Unable to determine the amount of physical memory (no 'memory_mb' found in introspection_data)."
on-success: fail
set_failed_get_num_cores:
publish:
message: "Unable to determine the number of CPU cores (no 'cpus' found in introspection_data)."
on-success: fail
set_failed_insufficient_mem:
publish:
message: "<% $.memory_mb %> MB is not enough memory to run hyperconverged."
on-success: fail
set_failed_insufficient_cpu:
publish:
message: "<% $.num_cores %> CPU cores are not enough to run hyperconverged."
on-success: fail