diff --git a/playbooks/infra.yml b/playbooks/infra.yml index 80f60163..70d34dbb 100644 --- a/playbooks/infra.yml +++ b/playbooks/infra.yml @@ -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 diff --git a/plugins/filter/explode_ranges.yml b/plugins/filter/explode_ranges.yml new file mode 100644 index 00000000..cc305572 --- /dev/null +++ b/plugins/filter/explode_ranges.yml @@ -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 diff --git a/plugins/filter/implode_ranges.yml b/plugins/filter/implode_ranges.yml new file mode 100644 index 00000000..0fac4f0d --- /dev/null +++ b/plugins/filter/implode_ranges.yml @@ -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 diff --git a/plugins/filter/ipv4_mac.yml b/plugins/filter/ipv4_mac.yml new file mode 100644 index 00000000..58bc7cf1 --- /dev/null +++ b/plugins/filter/ipv4_mac.yml @@ -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 diff --git a/plugins/filter/main.py b/plugins/filter/main.py index 0f0a1bda..ca0ab197 100644 --- a/plugins/filter/main.py +++ b/plugins/filter/main.py @@ -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, + ) diff --git a/plugins/module_utils/main.py b/plugins/module_utils/main.py index f697eaf9..f795be36 100644 --- a/plugins/module_utils/main.py +++ b/plugins/module_utils/main.py @@ -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='[:.]') diff --git a/pyproject.toml b/pyproject.toml index 7386da1f..369e0d18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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. diff --git a/roles/helper/numa/README.md b/roles/helper/numa/README.md new file mode 100644 index 00000000..e3400b4d --- /dev/null +++ b/roles/helper/numa/README.md @@ -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/) diff --git a/roles/helper/numa/meta/main.yml b/roles/helper/numa/meta/main.yml new file mode 100644 index 00000000..78ac06b1 --- /dev/null +++ b/roles/helper/numa/meta/main.yml @@ -0,0 +1,5 @@ +--- +collections: + - opennebula.deploy + +allow_duplicates: true diff --git a/roles/helper/numa/tasks/main.yml b/roles/helper/numa/tasks/main.yml new file mode 100644 index 00000000..98d0a385 --- /dev/null +++ b/roles/helper/numa/tasks/main.yml @@ -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 }}" diff --git a/roles/infra/README.md b/roles/infra/README.md index ea186458..75cc41bc 100644 --- a/roles/infra/README.md +++ b/roles/infra/README.md @@ -15,20 +15,25 @@ Role Variables |--------------------------------------|--------|--------------------|---------------------|-------------------------------------------------------------------| | `frontend_group` | `str` | `frontend` | | Custom name of the Frontend group in the inventory. | | `infra_group` | `str` | `infra` | | Custom name of the Infra group in the inventory. | -| | | | | | +|   |   |   |   |   | | `runtime_dir` | `str` | `/var/one-deploy/` | | Directory used to store QCOW2 and ISO images. | | `os_image_url` | `str` | | | HTTP(S) link to Debian/RedHat-like image running `one-contextd`. | | `os_image_size` | `str` | `20G` | | The size to which one-deploy will **try** to adjust the OS image. | | `memory_KiB` | `str` | `2097152` | | Memory amount to be set in XML in Libvirt. | -| `vcpu_static` | `str` | `1` | | VCPU amount to be set in XML in Libvirt. | | `vnc_max_port` | `str` | `65535` | | Upper limit for VNC ports to start counting-down from. | | `passthrough_fs` | `list` | `[]` | (check below) | Shared HV filesystems to attach to the Front-end VMs. | -| | | | | | +|   |   |   |   |   | +| `vcpu_pinned` | `str` | | `1-2,4` | List of isolcpus= ranges (comma-separated). | +| `vcpu_static` | `str` | `1` | | VCPU amount to be set in XML in Libvirt. | +| `vcpu_shares` | `str` | `200` | | The proportional weighted share (PWS) for the domain. | +|   |   |   |   |   | | `infra_bridge` | `str` | `br0` | | Pre-defined bridge interface to insert VM NICs to. | -| `infra_bridge_type` | `str` | `bridge` | | Supported values: bridge, openvswitch, openvswitch_dpdk | -| `infra_dpdk_socket_path` | `str` | | | Path for existing socket when using OVS with DPDK. | | `infra_vlan_id` | `str` | | | Optionally set the VLAN ID for the bridge. | +| `dpdk_socket_path` | `str` | | | Path for existing socket when using OVS with DPDK. | +|   |   |   |   |   | | `infra_hostname` | `str` | | `n1a1` | Defines on which HV machine the Front-end VM should be deployed. | +| `infra_xml_variant` | `str` | undefined | `pinned` | Defined which domain XML variant will be used in Libvirt. | +|   |   |   |   |   | | `context.ETH0_DNS` | `str` | | `1.1.1.1` | DNS server. | | `context.ETH0_SEARCH_DOMAIN` | `str` | | `1.1.1.1` | DNS search domain. | | `context.ETH0_GATEWAY` | `str` | | `10.2.50.1` | Gateway. | @@ -40,6 +45,7 @@ Role Variables | `context.PASSWORD` | `str` | `opennebula` | | Root's password. | | `context.SET_HOSTNAME` | `str` | name of the FE VM | | Hostname. | | `context.SSH_PUBLIC_KEY` | `str` | | (check below) | Root's extra authorized keys. | +| `context.START_SCRIPT_BASE64` | `str` | | | Start script (base64-encoded). | **NOTE**: The `infra_hostname` and `context` dictionary should be set for members of the `frontend` group (please check the `inventory/infra.yml` example). @@ -49,19 +55,51 @@ Dependencies - `community.libvirt` - `ansible.posix` -Example Playbook ----------------- +Example Inventory +----------------- + + infra: + vars: + os_image_url: https://d24fmfybwxpuhu.cloudfront.net/ubuntu2404-7.2.0-0-20260330.qcow2 + os_image_size: 20G + memory_KiB: 2097152 # 2 GiB + infra_xml_variant: pinned + vcpu_pinned: '1,3' + hosts: + u1q20: { ansible_host: 10.3.10.20 } + u1q30: { ansible_host: 10.3.10.30 } + + frontend: + vars: + context: + ETH0_DNS: 10.3.10.1 + ETH0_GATEWAY: 10.3.10.1 + ETH0_MASK: 255.255.255.0 + ETH0_NETWORK: 10.3.10.0 + ETH0_IP: "{{ ansible_host }}" + PASSWORD: asd + SSH_PUBLIC_KEY: |- + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF5ndznuZTNZ8u7FCYKgv6Q3/HUVxnaha3tPDUXPfIIw + hosts: + u1q40: { ansible_host: 10.3.10.40, infra_hostname: u1q20 } + u1q50: { ansible_host: 10.3.10.50, infra_hostname: u1q30 } - - hosts: infra + node: vars: - os_image_url: https://d24fmfybwxpuhu.cloudfront.net/ubuntu2204-6.10.0-1-20240514.qcow2 - passthrough_fs: - - driver_type: virtiofs - source_dir: /var/lib/one/datastores - target_dir: /var/lib/one/datastores - roles: - - role: opennebula.deploy.helper.facts - - role: opennebula.deploy.infra + kernel_ok_to_reboot: true + kernel_params: + - isolcpus: "1-3,5-7" + - nohz_full: "1-3,5-7" + - rcu_nocbs: "1-3,5-7" + - irqaffinity: "0,4" + - kthread_cpus: "0-4" + - systemd.cpu_affinity: "0,4" + - default_hugepagesz: "1G" + - hugepages: "0:2,1:2" + - intel_iommu: "on" + hosts: + u1q20: { ansible_host: 10.3.10.20 } + u1q30: { ansible_host: 10.3.10.30 } License ------- diff --git a/roles/infra/defaults/main.yml b/roles/infra/defaults/main.yml index d6df3480..8782dd17 100644 --- a/roles/infra/defaults/main.yml +++ b/roles/infra/defaults/main.yml @@ -2,9 +2,249 @@ runtime_dir: /var/one-deploy/ os_image_url: https://d24fmfybwxpuhu.cloudfront.net/ubuntu2204-6.8.1-1-20240131.qcow2 os_image_size: 20G -memory_KiB: 2097152 # 2 GiB -vcpu_static: 1 vnc_max_port: 65535 -infra_bridge: br0 -infra_bridge_type: bridge passthrough_fs: [] + +infra_bridge: br0 + +dpdk_socket_path: "/var/run/one/vhost-socks/frontend-{{ frontend | md5 | truncate(4, true, '') }}.sock" + +memory_KiB: 2097152 # 2 GiB + +# NOTE: In case multiple Front-ends are to be deployed on the same infra Node +# pinned CPUs will be shared. +vcpu_pinned: '' + +vcpu_static: "{{ vcpu_pinned | split(',') | select | count | d(1, true) }}" + +# NOTE: In case of non-isolated variants this is reused as CPUWeight inside +# the infra slice. +vcpu_shares: 200 + +infra_xml_variant: "{{ undef() }}" + +infra_xml: + default: + - "{{ infra_xml_base.default }}" + - "{{ infra_xml_cputune.default }}" + - "{{ infra_xml_memoryBacking.default }}" + - "{{ infra_xml_interfaces.default }}" + - "{{ infra_xml_filesystems.default }}" + pinned: + - "{{ infra_xml_base.default }}" + - "{{ infra_xml_cputune.pinned }}" + - "{{ infra_xml_memoryBacking.hugepages }}" + - "{{ infra_xml_interfaces.default }}" + - "{{ infra_xml_filesystems.default }}" + openvswitch: + - "{{ infra_xml_base.default }}" + - "{{ infra_xml_cputune.default }}" + - "{{ infra_xml_memoryBacking.default }}" + - "{{ infra_xml_interfaces.openvswitch }}" + - "{{ infra_xml_filesystems.default }}" + openvswitch_dpdk: + - "{{ infra_xml_base.default }}" + - "{{ infra_xml_cputune.pinned }}" + - "{{ infra_xml_memoryBacking.hugepages }}" + - "{{ infra_xml_interfaces.openvswitch_dpdk }}" + - "{{ infra_xml_filesystems.default }}" + +infra_xml_cputune: + default: | + + + {% if vcpu_shares | int < 10000 %} + {{ vcpu_shares | int }} + {% else %} + 10000 + {% endif %} + + + pinned: | + + + {% for v in vcpu_pinned | split(',') %} + + {% endfor %} + + + +infra_xml_memoryBacking: + default: | + + + + + + hugepages: | + + + + + + + +infra_xml_interfaces: + default: | + + + + + + {% if infra_vlan_id is defined %} + + + + {% endif %} + + + + + + openvswitch: | + + + + + + + {% if infra_vlan_id is defined %} + + + + {% endif %} + + + + + + openvswitch_dpdk: | + + + + + + + {% if infra_vlan_id is defined %} + + + + {% endif %} + + + + + + +infra_xml_filesystems: + default: | + + + {% for fs in passthrough_fs %} + + {% if fs.driver_type is defined %} + + {% endif %} + + + + {% endfor %} + + + +infra_xml_base: + default: | + + {{ frontend }} + {{ frontend }} + + {{ memory_KiB }} + {{ vcpu_static }} + + + + /infra + + + hvm + + + + + + + + + + + + destroy + restart + destroy + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/roles/infra/tasks/deploy.yml b/roles/infra/tasks/deploy.yml index 90dbdb77..aba8c53d 100644 --- a/roles/infra/tasks/deploy.yml +++ b/roles/infra/tasks/deploy.yml @@ -87,7 +87,7 @@ - name: Compute VNC ports ansible.builtin.set_fact: - frontends_to_vnc_ports: >- + frontend_vnc_ports: >- {{ dict(_frontends | zip(_ports)) }} vars: _ports: >- @@ -97,12 +97,32 @@ _frontend_group: >- {{ frontend_group | d('frontend') }} +- ansible.builtin.include_tasks: + file: "{{ role_path }}/tasks/limits.yml" + - name: Define Front-end VMs community.libvirt.virt: command: define - xml: "{{ lookup('template', 'frontend.xml.jinja') }}" + xml: >- + {%- set output = {} -%} + {%- for v in infra_xml[infra_xml_variant] -%} + {{- + output.update(output | combine( + v | ansible.utils.from_xml | combine(_fixup, recursive=true), + recursive=true, + list_merge='append_rp', + )) + -}} + {%- endfor -%} + {{- output | ansible.utils.to_xml(full_document=false) -}} autostart: true vars: + # NOTE: This is required because (for example) '' produces '{"devices": null}' + # which cannot be merged recursively. + _fixup: + domain: + cputune: {} + devices: {} context: "{{ hostvars[frontend].context }}" loop_control: { loop_var: frontend } loop: "{{ infra_to_frontends[inventory_hostname] }}" diff --git a/roles/infra/tasks/limits.yml b/roles/infra/tasks/limits.yml new file mode 100644 index 00000000..06e99069 --- /dev/null +++ b/roles/infra/tasks/limits.yml @@ -0,0 +1,86 @@ +--- +- when: infra_xml_variant in ['default', 'openvswitch'] + vars: + _frontends: >- + {{ infra_to_frontends[inventory_hostname] }} + + _memory_min: >- + {{ (_frontends | count) * (memory_KiB * 1.10 + 150 * 1024) }} + + _memory_low: >- + {{ (_frontends | count) * (memory_KiB * 1.15 + 250 * 1024) }} + + _cpu_weight: >- + {{ vcpu_shares if (vcpu_shares | int) < 10000 else 10000 }} + block: + - name: Update MemoryMin / MemoryMin / CPUWeight on infra slice + ansible.builtin.shell: + cmd: | + set -o errexit -o pipefail + BEFORE="$(systemctl show infra.slice -p MemoryMin -p MemoryLow -p CPUWeight | sort)" + systemctl set-property infra.slice 'MemoryMin={{ _memory_min | int }}K' \ + 'MemoryLow={{ _memory_low | int }}K' \ + 'CPUWeight={{ _cpu_weight | int }}' + AFTER="$(systemctl show infra.slice -p MemoryMin -p MemoryLow -p CPUWeight | sort)" + if [[ "$AFTER" == "$BEFORE" ]]; then + exit 0 + else + exit 78 # EREMCHG + fi + executable: /bin/bash + register: shell + changed_when: + - shell.rc in [78] + failed_when: + - shell.rc not in [0, 78] + +- when: infra_xml_variant in ['pinned', 'openvswitch_dpdk'] + vars: + _parsed: + machine: >- + {{ shell_allowed_cpus.stdout_lines.0 | d() | opennebula.deploy.explode_ranges(split=true) }} + infra: >- + {{ shell_allowed_cpus.stdout_lines.1 | d() | opennebula.deploy.explode_ranges(split=true) }} + + _required: + machine: >- + {{ numa_query.cpus.system }} + infra: >- + {{ vcpu_pinned | opennebula.deploy.explode_ranges(split=true) }} + block: + - name: Assert that vcpu_pinned is defined + ansible.builtin.assert: + that: + - vcpu_pinned is string + - vcpu_pinned | length > 0 + fail_msg: Please ensure vcpu_pinned is a string following the isolcpus= syntax (i.e. '1-2,4'). + + - ansible.builtin.include_role: + name: helper/numa + + - name: Assert that vcpu_pinned refers to isolated cores + ansible.builtin.assert: + that: _required.infra | intersect(numa_query.cpus.isolated) | count > 0 + fail_msg: Please ensure vcpu_pinned cores exist and are properly isolated. + + - name: Query AllowedCPUs on machine and infra slices + ansible.builtin.shell: + cmd: | + set -o errexit + systemctl show machine.slice -p AllowedCPUs --value + systemctl show infra.slice -p AllowedCPUs --value + executable: /bin/bash + register: shell_allowed_cpus + changed_when: false + + # NOTE: OpenNebula places VMs inside machine.slice, we exclude isolated cores + # from that slice so libvirt is not allowed to use them. + - name: Update AllowedCPUs on machine and infra slices + ansible.builtin.shell: + cmd: | + set -o errexit + systemctl set-property machine.slice 'AllowedCPUs={{ _required.machine | join(',') }}' + systemctl set-property infra.slice 'AllowedCPUs={{ _required.infra | join(',') }}' + executable: /bin/bash + changed_when: true + when: _parsed != _required diff --git a/roles/infra/tasks/main.yml b/roles/infra/tasks/main.yml index 0b724e0c..b5a3a95f 100644 --- a/roles/infra/tasks/main.yml +++ b/roles/infra/tasks/main.yml @@ -3,7 +3,7 @@ ansible.builtin.package: name: "{{ _common + _specific[ansible_os_family] }}" vars: - _common: [acl, genisoimage, python3-libvirt, python3-lxml] + _common: [acl, gawk, genisoimage, python3-libvirt, python3-lxml] _specific: Debian: [qemu-utils] RedHat: [qemu-img] diff --git a/roles/infra/templates/context.sh.jinja b/roles/infra/templates/context.sh.jinja index 284fe014..57b131ee 100644 --- a/roles/infra/templates/context.sh.jinja +++ b/roles/infra/templates/context.sh.jinja @@ -1,18 +1,22 @@ # Context variables generated by one-deploy DISK_ID='1' -ETH0_DNS='{{ context.ETH0_DNS }}' -ETH0_SEARCH_DOMAIN='{{ context.ETH0_SEARCH_DOMAIN }}' -ETH0_GATEWAY='{{ context.ETH0_GATEWAY }}' ETH0_IP='{{ context.ETH0_IP }}' -ETH0_MAC='{{ context.ETH0_MAC | d("02:01:%02x:%02x:%02x:%02x" | format(*(context.ETH0_IP.split(".") | map("int")))) }}' +ETH0_MAC='{{ context.ETH0_MAC | d(context.ETH0_IP | opennebula.deploy.ipv4_mac) }}' ETH0_MASK='{{ context.ETH0_MASK }}' ETH0_NETWORK='{{ context.ETH0_NETWORK }}' +ETH0_GATEWAY='{{ context.ETH0_GATEWAY }}' GROW_FS='{{ context.GROW_FS | d("/") }}' NETWORK='YES' PASSWORD='{{ context.PASSWORD | d("opennebula") }}' SET_HOSTNAME='{{ context.SET_HOSTNAME | d(frontend) }}' SSH_PUBLIC_KEY='{{ context.SSH_PUBLIC_KEY | d("") }}' TARGET='hda' +{% if context.ETH0_DNS is defined %} +ETH0_DNS='{{ context.ETH0_DNS }}' +{% endif %} +{% if context.ETH0_SEARCH_DOMAIN %} +ETH0_SEARCH_DOMAIN='{{ context.ETH0_SEARCH_DOMAIN }}' +{% endif %} {% if context.START_SCRIPT_BASE64 is defined %} START_SCRIPT_BASE64='{{ context.START_SCRIPT_BASE64 | b64encode }}' {% endif %} diff --git a/roles/infra/templates/frontend.xml.jinja b/roles/infra/templates/frontend.xml.jinja deleted file mode 100644 index 31ac150f..00000000 --- a/roles/infra/templates/frontend.xml.jinja +++ /dev/null @@ -1,143 +0,0 @@ - - {{ frontend }} - {{ frontend }} - - {{ memory_KiB }} - {{ vcpu_static }} - - - - /machine - - - hvm - - - - - - - - - - - - destroy - restart - destroy - -{% set use_dpdk = (infra_bridge_type is defined and infra_bridge_type == 'openvswitch_dpdk') %} -{% set use_virtiofs = ('virtiofs' in (passthrough_fs | map(attribute='driver_type') | map('default', None) | select | map('lower'))) %} - -{% if use_dpdk or use_virtiofs %} - -{% if use_dpdk %} - -{% endif %} -{% if use_virtiofs and not use_dpdk %} - -{% endif %} - - -{% endif %} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{% for fs in passthrough_fs %} - -{% if fs.driver_type is defined and fs.driver_type is truthy %} - -{% endif %} - - - -{% endfor %} - - - - - -{% if infra_bridge_type is defined and infra_bridge_type in ['bridge', 'openvswitch', 'openvswitch_dpdk'] %} -{% if infra_bridge_type in ['bridge', 'openvswitch'] %} - - - -{% elif infra_bridge_type == 'openvswitch_dpdk' %} - - - -{% endif %} - -{% if infra_bridge_type == 'openvswitch' %} - -{% endif %} -{% if infra_vlan_id is defined and infra_vlan_id %} - - - -{% endif %} - - - -{% endif %} - - - - - - - - - - - - - - - - - - - - -