Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions plugins/test/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env python

import fnmatch
import re

class TestModule(object):
def tests(self):
return {
'match_address': self.match_address,
}

# NOTE: It does not validate character classes or character count!
# EXAMPLES:
# pci -> match_address('0000:0*:00.*', sep='[:.]')
# mac -> match_address('52:54:*:*:*:0*', sep='[:]')
def match_address(self, address, pattern, sep=None):
"""Tests if a split string matches a set of simple glob patterns."""

# In case no separator is provided simply match the whole string.
if sep is None:
return fnmatch.fnmatch(address, pattern)

# Make sure both address and pattern contain identical separators.
if re.findall(sep, address) != re.findall(sep, pattern):
return False

# Try matching (glob) each segment separately.
for x, y in zip(re.split(sep, address), re.split(sep, pattern)):
if not fnmatch.fnmatch(x, y):
return False

return True
43 changes: 43 additions & 0 deletions plugins/test/match_address.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
# Copyright: OpenNebula Project, OpenNebula Systems
# Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)

DOCUMENTATION:
name: match_address
short_description: Apply glob patterns to a generic address.
description:
- Tests if a split string matches a set of simple glob patterns.
options:
_input:
description:
- An address to match.
type: string
required: true
sep:
description:
- A regex expression used to split the input string (optional).
type: string
required: false
author:
- Michal Opala (@sk4zuzu)

EXAMPLES: |
- name: Match MAC address
ansible.builtin.debug:
msg: >-
{{ '12:34:56:78:90:ab' is opennebula.deploy.match_address('12:34:56:78:90:*', sep='[:]') }}

- name: Select matching PCI addresses
ansible.builtin.debug:
msg: >-
{{ _addresses | select('opennebula.deploy.match_address', '0000:03:00.*', sep='[:.]') }}
vars:
_addresses:
- '12:34:56:78:90:ab' # MAC (skipped)
- '0000:03:00.4' # PCI (matched)
- '0000:04:00.0' # PCI (skipped)

RETURN:
_value:
description: Returns True if the check passes.
type: boolean
11 changes: 6 additions & 5 deletions roles/helper/pci/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ N/A
Role Variables
--------------

| Name | Type | Default | Example | Description |
|---------------------------|--------|---------|---------------|---------------------------------|
| `pci_passthrough_enabled` | `bool` | `false` | | Enable/Disable PCI passthrough. |
| `pci_devices` | `list` | `[]` | (check below) | PCI devices configuration. |
| Name | Type | Default | Example | Description |
|---------------|--------|---------|---------------|---------------------------------|
| `pci_devices` | `list` | `[]` | (check below) | PCI devices configuration. |

Dependencies
------------
Expand All @@ -26,10 +25,12 @@ Example Playbook

- hosts: node
vars:
pci_passthrough_enabled: true
pci_devices:
- address: "0000:02:00.0"
excluded: true
- address: "0000:03:00.*"
unlisted: true
set_name: "asd{0[3]}"
- vendor: "1af4"
device: "*"
class: "0200"
Expand Down
1 change: 0 additions & 1 deletion roles/helper/pci/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
---
pci_passthrough_enabled: false
pci_devices: []
65 changes: 26 additions & 39 deletions roles/helper/pci/tasks/devices.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,30 @@
v.device | d('*'),
v.class | d('*'),
) | lower,
"key_regex": "^{}:{}:{}$".format(
(v.vendor | d('*') == '*') | ternary('[^:]*', v.vendor),
(v.device | d('*') == '*') | ternary('[^:]*', v.device),
(v.class | d('*') == '*') | ternary('[^:]*', v.class),
) | lower,
"key_type": "vdc",
}))
-}}
{%- endfor -%}
{{- output -}}
pci_devices_by_address: >-
{%- set output = [] -%}
{%- for v in pci_devices | selectattr('address', 'defined') -%}
{{-
output.append(v | combine({
"key": v.address | lower,
"key_regex": "^{}$".format(v.address) | lower,
}))
-}}
{%- if v.address is opennebula.deploy.match_address('*:*:*.*', sep='[:.]') -%}
{{-
output.append(v | combine({
"key": v.address | lower,
"key_type": "pci",
}))
-}}
{%- endif -%}
{%- if v.address is opennebula.deploy.match_address('*:*:*:*:*:*', sep='[:]') -%}
{{-
output.append(v | combine({
"key": v.address | lower,
"key_type": "mac",
}))
-}}
{%- endif -%}
{%- endfor -%}
{{- output -}}

Expand All @@ -52,25 +58,6 @@

- when: lspci_devices | count > 0
block:
- name: Ensure udev rules for vfio
ansible.builtin.copy:
dest: /etc/udev/rules.d/99-vfio.rules
owner: 0
group: 0
mode: u=rw,go=r
content: |
SUBSYSTEM=="vfio", GROUP="kvm", MODE="0666"
register: copy_udev_vfio

- name: Refresh udev rules
ansible.builtin.shell:
cmd: |
set -o errexit
udevadm control --reload-rules && udevadm trigger
executable: /bin/bash
changed_when: true
when: copy_udev_vfio is changed

- name: Render sriov-enable service unit
ansible.builtin.copy:
dest: "{{ item.dest }}"
Expand Down Expand Up @@ -140,7 +127,7 @@
_to_revert: >-
{%- set output = [] -%}
{%- for v in lspci_devices -%}
{%- if (v.ECAP_SRIOV | bool is true) and (v.set_numvfs == 'max' or v.set_numvfs | int > 0) -%}
{%- if (v.Ecap_sriov == 'yes') and (v.Set_numvfs == 'max' or v.Set_numvfs | int > 0) -%}
{{- output.append(v) -}}
{%- endif -%}
{%- endfor -%}
Expand All @@ -162,10 +149,10 @@
set -x -o errexit -o pipefail
CHANGED=false
{% for v in _to_enable %}
{% if v.set_numvfs == 'max' %}
{% if v.Set_numvfs == 'max' %}
SRIOV_NUMVFS="$(head -n1 '/sys/bus/pci/devices/{{ v.Slot }}/sriov_totalvfs')"
{% elif v.set_numvfs | int > 0 %}
SRIOV_NUMVFS='{{ v.set_numvfs }}'
{% elif v.Set_numvfs | int > 0 %}
SRIOV_NUMVFS='{{ v.Set_numvfs }}'
{% else %}
unset SRIOV_NUMVFS
{% endif %}
Expand Down Expand Up @@ -203,7 +190,7 @@
_to_enable: >-
{%- set output = [] -%}
{%- for v in lspci_devices -%}
{%- if (v.ECAP_SRIOV | bool is true) and (v.set_numvfs == 'max' or v.set_numvfs | int > 0) -%}
{%- if (v.Ecap_sriov == 'yes') and (v.Set_numvfs == 'max' or v.Set_numvfs | int > 0) -%}
{{- output.append(v) -}}
{%- endif -%}
{%- endfor -%}
Expand All @@ -225,14 +212,14 @@
set -x -o errexit -o pipefail
BEFORE="$(driverctl list-overrides | sort)" ||:
{% for v in _to_override %}
if ! grep -E -m1 '^{{ v.Slot }}\s+{{ v.set_driver }}$' <<< "$BEFORE"; then
{% if (v.ECAP_SRIOV | bool is true) %}
if ! grep -E -m1 '^{{ v.Slot }}\s+{{ v.Set_driver }}$' <<< "$BEFORE"; then
{% if v.Ecap_sriov == 'yes' %}
TO_DISABLE="$(systemctl show --all -P Id 'sriov-enable@{{ v.Slot }}-*.service' | grep -E -v '^\s*$')" ||:
if [[ -n "$TO_DISABLE" ]] && systemctl is-active --quiet $TO_DISABLE; then
systemctl disable --now $TO_DISABLE # cleanup spurious sriov-enable@ services
fi
{% endif %}
driverctl set-override '{{ v.Slot }}' '{{ v.set_driver }}' # force the new driver (vfio-pci by default)
driverctl set-override '{{ v.Slot }}' '{{ v.Set_driver }}' # force the new driver (vfio-pci by default)
fi
{% endfor %}
AFTER="$(driverctl list-overrides | sort)" ||:
Expand All @@ -247,7 +234,7 @@
_to_override: >-
{%- set output = [] -%}
{%- for v in lspci_devices -%}
{%- if (v.set_driver != 'omit') and ((v.ECAP_SRIOV | bool is false) or (v.set_numvfs != 'max' and v.set_numvfs | int == 0)) -%}
{%- if (v.Set_driver != 'omit') and ((v.Ecap_sriov == 'no') or (v.Set_numvfs != 'max' and v.Set_numvfs | int == 0)) -%}
{{- output.append(v) -}}
{%- endif -%}
{%- endfor -%}
Expand Down
13 changes: 7 additions & 6 deletions roles/helper/pci/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
---
- when: pci_passthrough_enabled | bool is true
- when:
- pci_devices is sequence
- pci_devices | count > 0
block:
- ansible.builtin.import_tasks:
- ansible.builtin.include_tasks:
file: "{{ role_path }}/tasks/devices.yml"
when:
- pci_devices is defined
- pci_devices is sequence
- pci_devices | count > 0

- ansible.builtin.include_tasks:
file: "{{ role_path }}/tasks/udev.yml"
Loading