Skip to content
Draft
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
2 changes: 1 addition & 1 deletion playbooks/infra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
- opennebula.deploy
roles:
# This installs the interpreter only.
# Extra OS/PyPI packages should not required by this playbook.
# Extra OS/PyPI packages should not be required by this playbook.
- role: helper/python3

- role: helper/facts
Expand Down
35 changes: 35 additions & 0 deletions plugins/filter/explode_ranges.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
# Copyright: OpenNebula Project, OpenNebula Systems
# Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)

DOCUMENTATION:
name: explode_ranges
short_description: Simplify isolcpus= syntax handling.
description:
- Convert 'A-C,D' into 'A,B,C,D'.
options:
_input:
description:
- String to convert.
type: str
required: true
split:
description:
- When true returns a list.
type: bool
required: false
default: false
author:
- Michal Opala (@sk4zuzu)

EXAMPLES: |
# '0-2,4' -> ['0', '1', '2', '4']
- name: Conversion example
ansible.builtin.debug:
msg: >-
{{ '0-2,4' | opennebula.deploy.explode_ranges(split=true) }}

RETURN:
_value:
description: String (joined) or a list of indices (depending on split=).
type: raw
35 changes: 35 additions & 0 deletions plugins/filter/implode_ranges.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
# Copyright: OpenNebula Project, OpenNebula Systems
# Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)

DOCUMENTATION:
name: implode_ranges
short_description: Simplify isolcpus= syntax handling.
description:
- Convert 'A,B,C,D' into 'A-C,D'.
options:
_input:
description:
- String to convert.
type: str
required: true
split:
description:
- When true returns a list.
type: bool
required: false
default: false
author:
- Michal Opala (@sk4zuzu)

EXAMPLES: |
# '0,1,2,4' -> ['0-2', '4']
- name: Conversion example
ansible.builtin.debug:
msg: >-
{{ '0,1,2,4' | opennebula.deploy.implode_ranges(split=true) }}

RETURN:
_value:
description: String (joined) or a list of ranges (depending on split=).
type: raw
35 changes: 35 additions & 0 deletions plugins/filter/ipv4_mac.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
# Copyright: OpenNebula Project, OpenNebula Systems
# Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)

DOCUMENTATION:
name: ipv4_mac
short_description: Convert IPv4 into MAC
description:
- Convert IPv4 (A.B.C.D) into MAC (02:01:A:B:C:D).
options:
_input:
description:
- String to convert.
type: str
required: true
fmt:
description:
- Format string (e.g. 02:01:%02x:%02x:%02x:%02x).
type: str
required: false
default: '02:01:%02x:%02x:%02x:%02x'
author:
- Michal Opala (@sk4zuzu)

EXAMPLES: |
# '10.11.12.13' -> '02:01:0a:0b:0c:0d'
- name: Conversion example
ansible.builtin.debug:
msg: >-
{{ '10.11.12.13' | opennebula.deploy.ipv4_mac }}

RETURN:
_value:
description: String containing MAC.
type: str
14 changes: 12 additions & 2 deletions plugins/filter/main.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
from ansible_collections.opennebula.deploy.plugins.module_utils.main import to_one
from ansible_collections.opennebula.deploy.plugins.module_utils.main import (
ipv4_mac,
explode_ranges,
implode_ranges,
to_one,
)


class FilterModule(object):

def filters(self):
return dict(to_one=to_one)
return dict(
ipv4_mac=ipv4_mac,
explode_ranges=explode_ranges,
implode_ranges=implode_ranges,
to_one=to_one,
)
63 changes: 63 additions & 0 deletions plugins/module_utils/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,69 @@
# Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)


# EXAMPLES:
# '10.11.12.13' -> '02:01:0a:0b:0c:0d'
def ipv4_mac(ipv4, fmt='02:01:%02x:%02x:%02x:%02x'):
"""Converts IPv4 (string) into MAC."""

import ipaddress

return fmt % tuple(ipaddress.IPv4Address(ipv4).packed)


# EXAMPLES:
# '0-2,3,5-7' -> '0,1,2,3,5,6,7'
def explode_ranges(ranges, split=False):
"""Converts ranges to indices."""

import re

if not ranges:
return [] if split else ''

def g():
for z in re.split('[, ]', ranges):
y = z.split('-')

if len(y) > 0:
if len(y) == 1:
yield str(y[0])
else:
for x in range(int(y[0]), int(y[1]) + 1):
yield str(x)

return list(g()) if split else ','.join(g())


# EXAMPLES:
# '0,1,2,3,5,6,7' -> '0-3,5-7'
def implode_ranges(indices, split=False):
"""Converts indices to ranges."""

import re

if not indices:
return [] if split else ''

def index_or_range(y):
return str(y[0]) if len(y) == 1 else str(y[0]) + '-' + str(y[-1])

def g():
y = []

for x in re.split('[, ]', indices):
if len(y) > 0:
if y[-1] + 1 != int(x):
yield index_or_range(y)
y.clear()

y.append(int(x))

yield index_or_range(y)

return list(g()) if split else ','.join(g())


# NOTE: It does not validate character classes or character count!
# EXAMPLES:
# pci -> match_address('0000:0*:00.*', sep='[:.]')
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies = [
"netaddr",
"pyone",
"six",
"xmltodict",
]
# NOTE: If you experience more dynamic linker issues in your OS,
# you may want to extend LD_LIBRARY_PATH further.
Expand Down
39 changes: 39 additions & 0 deletions roles/helper/numa/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Role: opennebula.deploy.helper.numa
===================================

A role that queries NUMA resources.

Requirements
------------

N/A

Role Variables
--------------

| Name | Type | Default | Description |
|------|------|---------|-------------|
| | | | |

Dependencies
------------

N/A

Example Playbook
----------------

- hosts: node
roles:
- role: opennebula.deploy.helper.facts
- role: opennebula.deploy.helper.numa

License
-------

Apache-2.0

Author Information
------------------

[OpenNebula Systems](https://opennebula.io/)
5 changes: 5 additions & 0 deletions roles/helper/numa/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
collections:
- opennebula.deploy

allow_duplicates: true
82 changes: 82 additions & 0 deletions roles/helper/numa/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
- vars:
_query: >-
{{ shell_cpus_numa.stdout | split(_sep1)
| select('truthy')
| map('split', _sep2)
| map('map', 'split', _sep3) }}
_sep1: "\n\n"
_sep2: "\n"
_sep3: ":\t" # noqa no-tabs

_cpus: >-
{%- set output = {} -%}
{%- for k, v in _query.0 -%}
{{-
output.update({
k: (output.get(k, []) + [v | opennebula.deploy.explode_ranges(split=true)]) | flatten | unique,
})
-}}
{%- endfor -%}
{{-
output | combine({
"system": output.present | difference(output.isolated),

"free": output.isolated | difference(output.allowed)
| intersect(output.present),
})
-}}

_numa: >-
{%- set output = {} -%}
{%- for k, v in _query.1 -%}
{{-
output.update({
k: {
"cpus": {
"free": v.split(';').0 | opennebula.deploy.explode_ranges(split=true)
| intersect(_cpus.free),
},
"pages1g": { "free": v.split(';').1 },
"pages2m": { "free": v.split(';').2 },
},
})
-}}
{%- endfor -%}
{{- output -}}
block:
- name: Query CPU and NUMA resources
ansible.builtin.shell:
cmd: |
set -o errexit; shopt -s nullglob
# Query CPU availability and affinity.
PRESENT="$(head -1 '/sys/devices/system/cpu/present')"
echo -e "present:\t$PRESENT"
ISOLATED="$(head -1 '/sys/devices/system/cpu/isolated')"
echo -e "isolated:\t$ISOLATED"
find '/proc' -maxdepth 4 -path '/proc/[0-9]*/task/[0-9]*/status' -exec gawk "$AWK_CPUS_ALLOWED" {} +
echo
# Query NUMA topology.
for DIR in '/sys/devices/system/node/node'*; do
NODE="$(basename "$DIR")"
CPUS="$(head -1 "$DIR/cpulist")"
HP1G="$(head -1 "$DIR/hugepages/hugepages-1048576kB/free_hugepages")"
HP2M="$(head -1 "$DIR/hugepages/hugepages-2048kB/free_hugepages")"
echo -e "${NODE#node}:\t$CPUS;$HP1G;$HP2M"
done
echo
executable: /bin/bash
environment:
AWK_CPUS_ALLOWED: |
BEGINFILE { if (ERRNO) nextfile }
$1 == "Kthread:" { Kthread=$2; if (Kthread) nextfile }
$1 == "Cpus_allowed_list:" { Cpus_allowed_list=$2 }
ENDFILE { if (!Kthread) print "allowed:\t" Cpus_allowed_list }
register: shell_cpus_numa
changed_when: false

- name: Store query results in the numa_query fact
ansible.builtin.set_fact:
numa_query:
cpus: "{{ _cpus }}"
numa: "{{ _numa }}"
Loading