Files
securityonion/salt/soc/dyanno/hypervisor/soc_hypervisor.yaml.jinja
2025-11-20 17:13:36 -05:00

227 lines
10 KiB
Django/Jinja

{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
https://securityonion.net/license; you may not use this file except in compliance with the
Elastic License 2.0.
Note: Per the Elastic License 2.0, the second limitation states:
"You may not move, change, disable, or circumvent the license key functionality
in the software, and you may not remove or obscure any functionality in the
software that is protected by the license key." #}
{%- if 'vrt' in salt['pillar.get']('features', []) -%}
{%- import_yaml 'soc/dyanno/hypervisor/hypervisor.yaml' as ANNOTATION -%}
{%- from 'hypervisor/map.jinja' import HYPERVISORS -%}
{%- set TEMPLATE = ANNOTATION.hypervisor.hosts.pop('defaultHost') -%}
{%- macro update_description(description, cpu_free, mem_free, disk_free, copper_free, sfp_free, vm_list, cpu_total, mem_total, disk_total, copper_total, sfp_total) -%}
#### Resource Summary
| | CPU Cores | Memory (GB) | Disk | Copper | SFP |
|-----------|-----------|-------------|-------------|-------------|-------------|
| Available | {{ cpu_free }} | {{ mem_free }} | {{ disk_free | replace('\n', ',') if disk_free else 'None' }} | {{ copper_free | replace('\n', ',') if copper_free else 'None' }} | {{ sfp_free | replace('\n', ',') if sfp_free else 'None' }} |
| Total | {{ cpu_total }} | {{ mem_total }} | {{ disk_total | replace('\n', ',') if disk_total else 'None' }} | {{ copper_total | replace('\n', ',') if copper_total else 'None' }} | {{ sfp_total | replace('\n', ',') if sfp_total else 'None' }} |
{%- if baseDomainStatus == 'Initialized' %}
{%- if vm_list %}
#### Virtual Machines
| Name | Status | CPU Cores | Memory (GB)| Disk | Copper | SFP | Last Updated |
|--------------------|--------------------|-----------|------------|------|--------|------|---------------------|
{%- for hostname, vm_data in vm_list.items() %}
{%- set vm_status = vm_data.get('status', {}).get('status', 'Unknown') %}
{%- set is_destroyed = vm_status == 'Destroyed Instance' %}
{%- if is_destroyed %}
| {{ hostname }} | {{ vm_status }} | - | - | - | - | - | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} |
{%- else %}
| {{ hostname }} | {{ vm_status }} | {{ vm_data.get('config', {}).get('cpu', 'N/A') }} | {{ vm_data.get('config', {}).get('memory', 'N/A') }} | {{ vm_data.get('config', {}).get('disk', []) | join(',') if vm_data.get('config', {}).get('disk') else '-' }} | {{ vm_data.get('config', {}).get('copper', []) | join(',') if vm_data.get('config', {}).get('copper') else '-' }} | {{ vm_data.get('config', {}).get('sfp', []) | join(',') if vm_data.get('config', {}).get('sfp') else '-' }} | {{ vm_data.get('status', {}).get('timestamp', 'Never') | replace('T', ' ') | regex_replace('\\.[0-9]+', '') }} |
{%- endif %}
{%- endfor %}
{%- else %}
#### Virtual Machines
No Virtual Machines Found
{%- endif %}
{%- elif baseDomainStatus == 'ImageDownloadStart' %}
#### INFO
Base domain image download started.
{%- elif baseDomainStatus == 'ImageDownloadFailed' %}
#### ERROR
Base domain image download failed. Please check the salt-master log for details and verify network connectivity.
{%- elif baseDomainStatus == 'SSHKeySetupFailed' %}
#### ERROR
SSH key setup failed. Please check the salt-master log for details.
{%- elif baseDomainStatus == 'SetupFailed' %}
#### WARNING
Setup failed. Please check the salt-master log for details.
{%- elif baseDomainStatus == 'PreInit' %}
#### WARNING
Base domain has not been initialized. Waiting for hypervisor to highstate.
{%- endif %}
{%- endmacro -%}
{%- macro update_label(label, total, free) -%}
{{- label | replace('TOTAL', total | string)
| replace('FREE', free | string) -}}
{%- endmacro -%}
{%- macro get_available_pci(hw_config, device_type, used_indices) -%}
{%- set available = [] -%}
{%- set device_config = hw_config.get(device_type, {}) or {} -%}
{%- for idx in device_config.keys() -%}
{%- if idx | string not in used_indices -%}
{%- do available.append(idx) -%}
{%- endif -%}
{%- endfor -%}
{{- available | join(',') -}}
{%- endmacro -%}
{%- macro update_resource_field(field, free_value, total_value, unit_label) -%}
{%- set resource_regex = '^[0-9]{1,3}$' -%}
{%- do field.update({
'label': field.label | replace('FREE', free_value | string) | replace('TOTAL', total_value | string),
'regex': resource_regex,
'regexFailureMessage': 'Enter a value not exceeding ' ~ free_value | string ~ ' ' ~ unit_label
}) -%}
{%- endmacro -%}
{%- for role in HYPERVISORS -%}
{%- for hypervisor in HYPERVISORS[role].keys() -%}
{%- set hw_config = HYPERVISORS[role][hypervisor].hardware -%}
{%- set vms = HYPERVISORS[role][hypervisor].vms -%}
{# Calculate used CPU and memory #}
{%- set used_cpu = 0 -%}
{%- set used_memory = 0 -%}
{%- set ns = namespace(used_cpu=0, used_memory=0) -%}
{%- for hostname, vm_data in vms.items() -%}
{%- set vm_status = vm_data.get('status', {}).get('status', '') -%}
{%- if vm_status != 'Destroyed Instance' -%}
{%- set vm_config = vm_data.config -%}
{%- set ns.used_cpu = ns.used_cpu + vm_config.get('cpu', 0) | int -%}
{%- set ns.used_memory = ns.used_memory + vm_config.get('memory', 0) | int -%}
{%- endif -%}
{%- endfor -%}
{# Determine host OS overhead based on role #}
{%- if role == 'hypervisor' -%}
{%- set host_os_cpu = 8 -%}
{%- set host_os_memory = 16 -%}
{%- elif role == 'managerhype' -%}
{%- set host_os_cpu = 16 -%}
{%- set host_os_memory = 32 -%}
{%- else -%}
{%- set host_os_cpu = 0 -%}
{%- set host_os_memory = 0 -%}
{%- endif -%}
{# Calculate available resources (subtract both VM usage and host OS overhead) #}
{%- set cpu_free = hw_config.cpu - ns.used_cpu - host_os_cpu -%}
{%- set mem_free = hw_config.memory - ns.used_memory - host_os_memory -%}
{# Get used PCI indices #}
{%- set used_disk = [] -%}
{%- set used_copper = [] -%}
{%- set used_sfp = [] -%}
{%- for hostname, vm in vms.items() -%}
{%- set vm_status = vm.get('status', {}).get('status', '') -%}
{%- if vm_status != 'Destroyed Instance' -%}
{%- set config = vm.get('config', {}) -%}
{%- do used_disk.extend(config.get('disk', [])) -%}
{%- do used_copper.extend(config.get('copper', [])) -%}
{%- do used_sfp.extend(config.get('sfp', [])) -%}
{%- endif -%}
{%- endfor -%}
{# Get available PCI indices #}
{%- set disk_free = get_available_pci(hw_config, 'disk', used_disk) -%}
{%- set copper_free = get_available_pci(hw_config, 'copper', used_copper) -%}
{%- set sfp_free = get_available_pci(hw_config, 'sfp', used_sfp) -%}
{# Get total resources #}
{%- set cpu_total = hw_config.cpu -%}
{%- set mem_total = hw_config.memory -%}
{%- set disk_total = (hw_config.get('disk', {}) or {}).keys() | join('\n') if hw_config.get('disk', {}) else '' -%}
{%- set copper_total = (hw_config.get('copper', {}) or {}).keys() | join('\n') if hw_config.get('copper', {}) else '' -%}
{%- set sfp_total = (hw_config.get('sfp', {}) or {}).keys() | join('\n') if hw_config.get('sfp', {}) else '' -%}
{# Update field labels with total and free values #}
{%- set updated_template = TEMPLATE.copy() -%}
{%- set updated_elements = [] -%}
{%- for field in updated_template.uiElements -%}
{%- set updated_field = field.copy() -%}
{%- if field.field == 'cpu' -%}
{%- do update_resource_field(updated_field, cpu_free, cpu_total, 'cores') -%}
{%- elif field.field == 'memory' -%}
{%- do update_resource_field(updated_field, mem_free, mem_total, 'GB') -%}
{%- elif field.field == 'disk' -%}
{%- set disk_free_list = disk_free.split(',') if disk_free else [] -%}
{%- set disk_free_safe = disk_free if disk_free is defined else '' -%}
{%- set disk_total_safe = disk_total if disk_total is defined else '' -%}
{%- do updated_field.update({
'label': field.label | replace('FREE', disk_free_safe) | replace('TOTAL', disk_total_safe | replace('\n', ',')),
'options': disk_free_list
}) -%}
{%- elif field.field == 'copper' -%}
{%- set copper_free_list = copper_free.split(',') if copper_free else [] -%}
{%- set copper_free_safe = copper_free if copper_free is defined else '' -%}
{%- set copper_total_safe = copper_total if copper_total is defined else '' -%}
{%- do updated_field.update({
'label': field.label | replace('FREE', copper_free_safe) | replace('TOTAL', copper_total_safe | replace('\n', ',')),
'options': copper_free_list
}) -%}
{%- elif field.field == 'sfp' -%}
{%- set sfp_free_list = sfp_free.split(',') if sfp_free else [] -%}
{%- set sfp_free_safe = sfp_free if sfp_free is defined else '' -%}
{%- set sfp_total_safe = sfp_total if sfp_total is defined else '' -%}
{%- do updated_field.update({
'label': field.label | replace('FREE', sfp_free_safe) | replace('TOTAL', sfp_total_safe | replace('\n', ',')),
'options': sfp_free_list
}) -%}
{%- endif -%}
{%- do updated_elements.append(updated_field) -%}
{%- endfor -%}
{%- if baseDomainStatus == 'Initialized' %}
{%- do updated_template.update({'uiElements': updated_elements}) -%}
{%- else -%}
{%- do updated_template.pop('uiElements') -%}
{%- endif -%}
{%- do updated_template.update({
'title': hypervisor,
'description': update_description(
hypervisor,
cpu_free,
mem_free,
disk_free,
copper_free,
sfp_free,
vms,
cpu_total,
mem_total,
disk_total,
copper_total,
sfp_total
)
}) -%}
{%- do ANNOTATION.hypervisor.hosts.update({hypervisor ~ 'VMs': updated_template}) -%}
{%- endfor -%}
{%- endfor -%}
{{- ANNOTATION | yaml(False) -}}
{%- else -%}
{%- do salt.log.error(
'Hypervisor nodes are a feature supported only for customers with a valid license.'
'Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com'
'for more information about purchasing a license to enable this feature.'
) -%}
{%- endif -%}