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
2 changes: 1 addition & 1 deletion playbooks/infra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
- role: helper/online

# 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/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
10 changes: 8 additions & 2 deletions plugins/filter/main.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from ansible_collections.opennebula.deploy.plugins.module_utils.main import to_one
from ansible_collections.opennebula.deploy.plugins.module_utils.main import (
ipv4_mac,
to_one,
)


class FilterModule(object):

def filters(self):
return dict(to_one=to_one)
return dict(
ipv4_mac=ipv4_mac,
to_one=to_one,
)
10 changes: 10 additions & 0 deletions plugins/module_utils/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
# 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)


# NOTE: It does not validate character classes or character count!
# EXAMPLES:
# pci -> match_address('0000:0*:00.*', sep='[:.]')
Expand Down
202 changes: 169 additions & 33 deletions roles/infra/README.md

Large diffs are not rendered by default.

232 changes: 224 additions & 8 deletions roles/infra/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,229 @@
---
runtime_dir: /var/one-deploy/
os_image_url: https://d24fmfybwxpuhu.cloudfront.net/ubuntu2204-6.8.1-1-20240131.qcow2
os_image_url: https://d24fmfybwxpuhu.cloudfront.net/ubuntu2404-7.4.0-0-20260714.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: []
cputune_shares_base: 200 # twice the OpenNebula's default (for CGv2)
cputune_shares_max: 10000
cputune_shares: "{{ ((vcpu_static | int) * (cputune_shares_base | int)) | round(0, 'ceil') }}"

infra_bridge: br0

# NOTE: We assume that no more than a single FE VM is deployed on a HV
# (which should be considered a regular / default setup).
# More FE VMs can be deployed on a HV of course, but in such a case,
# please handle it directly in your inventory.
dpdk_socket_path: /var/run/one/vhost-socks/frontend.sock

memory_KiB: 2097152 # 2 GiB

vcpu_static: 1
vcpu_shares: "{{ ((vcpu_static | int) * 200) | int }}"

infra_xml_variant: default

infra_xml:
default:
- "{{ infra_xml_base.default }}"
- "{{ infra_xml_cputune.default }}"
- "{{ infra_xml_memoryBacking.default }}"
- "{{ 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.default }}"
- "{{ infra_xml_memoryBacking.hugepages }}"
- "{{ infra_xml_interfaces.openvswitch_dpdk }}"
- "{{ infra_xml_filesystems.default }}"

infra_xml_cputune:
default: |
<domain type='kvm'>
<cputune>
<shares>{{ [vcpu_shares | int, 10000] | min }}</shares>
</cputune>
</domain>

infra_xml_memoryBacking:
default: |
<domain type='kvm'>
<memoryBacking>
<access mode='shared'/>
</memoryBacking>
</domain>
hugepages: |
<domain type='kvm'>
<memoryBacking>
<hugepages/>
<access mode='shared'/>
</memoryBacking>
</domain>

infra_xml_interfaces:
default: |
<domain type='kvm'>
<devices>
<interface type='bridge'>
<source bridge='{{ infra_bridge }}'/>
<mac address='{{ context.ETH0_MAC | d(context.ETH0_IP | opennebula.deploy.ipv4_mac) }}'/>
{% if infra_vlan_id is defined %}
<vlan>
<tag id='{{ infra_vlan_id }}'/>
</vlan>
{% endif %}
<model type='virtio'/>
<alias name='net0'/>
</interface>
</devices>
</domain>
openvswitch: |
<domain type='kvm'>
<devices>
<interface type='bridge'>
<source bridge='{{ infra_bridge }}'/>
<mac address='{{ context.ETH0_MAC | d(context.ETH0_IP | opennebula.deploy.ipv4_mac) }}'/>
<virtualport type='openvswitch' />
{% if infra_vlan_id is defined %}
<vlan>
<tag id='{{ infra_vlan_id }}'/>
</vlan>
{% endif %}
<model type='virtio'/>
<alias name='net0'/>
</interface>
</devices>
</domain>
openvswitch_dpdk: |
<domain type='kvm'>
<devices>
<interface type='vhostuser'>
<source type='unix' path='{{ dpdk_socket_path }}' mode='server'/>
<driver name='vhost' queues='{{ vcpu_static }}'/>
<mac address='{{ context.ETH0_MAC | d(context.ETH0_IP | opennebula.deploy.ipv4_mac) }}'/>
{% if infra_vlan_id is defined %}
<vlan>
<tag id='{{ infra_vlan_id }}'/>
</vlan>
{% endif %}
<model type='virtio'/>
<alias name='net0'/>
</interface>
</devices>
</domain>

infra_xml_filesystems:
default: |
<domain type='kvm'>
<devices>
{% for fs in passthrough_fs %}
<filesystem type='mount' accessmode='passthrough'>
{% if fs.driver_type is defined %}
<driver type='{{ fs.driver_type }}'/>
{% endif %}
<source dir='{{ fs.source_dir }}'/>
<target dir='{{ fs.target_dir }}'/>
</filesystem>
{% endfor %}
</devices>
</domain>

infra_xml_base:
default: |
<domain type='kvm'>
<name>{{ frontend }}</name>
<title>{{ frontend }}</title>

<memory unit='KiB'>{{ memory_KiB }}</memory>
<vcpu placement='static'>{{ vcpu_static }}</vcpu>
<cpu mode='host-passthrough' check='none' migratable='on'/>

<resource>
<partition>/machine</partition>
</resource>
<os firmware='efi'>
<type arch='x86_64' machine='q35'>hvm</type>
<firmware>
<feature enabled='no' name='enrolled-keys'/>
<feature enabled='no' name='secure-boot'/>
</firmware>
<boot dev='hd'/>
</os>
<features>
<acpi/>
</features>
<clock offset='utc'/>

<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>

<devices>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='{{ runtime_dir }}/{{ frontend }}.iso' index='1'/>
<backingStore/>
<target dev='sda' bus='sata'/>
<readonly/>
<alias name='sata0-0-0'/>
</disk>

<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='none' discard='unmap'/>
<source file='{{ runtime_dir }}/{{ frontend }}.qcow2' index='2'/>
<backingStore/>
<target dev='vda' bus='virtio'/>
<alias name='virtio-disk0'/>
</disk>

<controller type='pci' index='0' model='pcie-root'>
<alias name='pcie.0'/>
</controller>

<controller type='pci' index='1' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='1' port='0x10'/>
<alias name='pcie-root-port-1'/>
</controller>

<controller type='sata' index='0'>
<alias name='sata'/>
</controller>

<controller type='usb' index='0' model='qemu-xhci'>
<alias name='usb'/>
</controller>

<controller type='virtio-serial' index='0'>
<alias name='virtio-serial0'/>
</controller>

<channel type='unix'>
<source mode='bind'/>
<target type='virtio' name='org.qemu.guest_agent.0'/>
<alias name='channel0'/>
</channel>

<input type='mouse' bus='usb'>
<alias name='input0'/>
</input>

<input type='keyboard' bus='usb'>
<alias name='input1'/>
</input>

<graphics type='vnc' port='{{ frontend_vnc_ports[frontend] }}' listen='0.0.0.0'>
<listen type='address' address='0.0.0.0'/>
</graphics>

<audio id='1' type='none'/>

<video>
<model type='virtio' vram='16384' heads='1' primary='yes'/>
<alias name='video0'/>
</video>
</devices>
</domain>
15 changes: 13 additions & 2 deletions roles/infra/tasks/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@

- name: Compute VNC ports
ansible.builtin.set_fact:
frontends_to_vnc_ports: >-
frontend_vnc_ports: >-
{{ dict(_frontends | zip(_ports)) }}
vars:
_ports: >-
Expand All @@ -103,9 +103,20 @@
- name: Define Front-end VMs
community.libvirt.virt:
command: define
xml: "{{ lookup('template', 'frontend.xml.jinja') }}"
xml: >-
{{ _variant | map('ansible.utils.from_xml')
| map('combine', _fixup, recursive=true)
| combine(recursive=true)
| ansible.utils.to_xml(full_document=false) }}
autostart: true
vars:
_variant: >-
{{ infra_xml.get(infra_xml_variant, undef(hint='Unknown variant "{}"'.format(infra_xml_variant))) }}
# NOTE: This is required because (for example) '<devices></devices>' produces '{"devices": null}'
# which cannot be merged correctly.
_fixup:
domain:
devices: {}
context: "{{ hostvars[frontend].context }}"
loop_control: { loop_var: frontend }
loop: "{{ infra_to_frontends[inventory_hostname] }}"
Expand Down
14 changes: 9 additions & 5 deletions roles/infra/templates/context.sh.jinja
Original file line number Diff line number Diff line change
@@ -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 | d("") }}'
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.START_SCRIPT_BASE64 is defined %}
{% if context.ETH0_DNS | d('') %}
ETH0_DNS='{{ context.ETH0_DNS }}'
{% endif %}
{% if context.ETH0_SEARCH_DOMAIN | d('') %}
ETH0_SEARCH_DOMAIN='{{ context.ETH0_SEARCH_DOMAIN }}'
{% endif %}
{% if context.START_SCRIPT_BASE64 | d('') %}
START_SCRIPT_BASE64='{{ context.START_SCRIPT_BASE64 | b64encode }}'
{% endif %}
Loading