diff --git a/roles/network/defaults/main.yml b/roles/network/defaults/main.yml index 4c4ba4f..ff39093 100644 --- a/roles/network/defaults/main.yml +++ b/roles/network/defaults/main.yml @@ -9,6 +9,7 @@ network__manage_iptables: false network__manage_udev_rules: false network__manage_gai: false +network__use_only: ['host', 'group', 'default'] network__default: [] network__group: [] network__host: [] diff --git a/roles/network/vars/main.yml b/roles/network/vars/main.yml index 2a4ecc2..8e6acbf 100644 --- a/roles/network/vars/main.yml +++ b/roles/network/vars/main.yml @@ -1,91 +1,8 @@ -network__all: "{{ (network__host + network__group + network__default) | - map('aybarsm.helper.combine_reverse', {'keep__entry': true, 'skip__entry': false}) | - rejectattr('keep__entry', 'eq', false) | rejectattr('skip__entry', 'eq', true) | rejectattr('type', 'undefined') | - aybarsm.helper.all_except(['keep__entry', 'skip__entry']) }}" - -##### BEGIN: network systemd vars -__network_systemd_available_change_modules: ['systemd_service', 'command'] -__network__systemd_link_name: '{"type":"systemd","name":"__SYSTEMD_LINK_NAME__","children":[{"name":"Match","children":[{"name":"MACAddress","value":"__MAC_ADDRESS__"},{"name":"Type","value":"ether"}]},{"name":"Link","children":[{"name":"NamePolicy","value":""},{"name":"Name","value":"__LINK_NAME__"}]}]}' -__network__systemd_rename: >- - {%- set __rtr = [] -%} - {%- set __cfgs = (network__all | selectattr('type', 'eq', 'systemd_link_rename') | - selectattr('name', 'defined') | selectattr('name', 'match', '^(?:[0-9]|[1-9][0-9])-[a-zA-Z]+\\d+\\.link$') | - selectattr('macaddress', 'defined') | selectattr('macaddress', 'match', '^([0-9A-Fa-f]{2}([:])?){5}([0-9A-Fa-f]{2})$') | default([])) -%} - {%- for cfg in __cfgs if cfg -%} - {%- set __rtr = __rtr.append(__network__systemd_link_name | - replace('__SYSTEMD_LINK_NAME__', cfg.name) | replace('__MAC_ADDRESS__', cfg.macaddress) | - replace('__LINK_NAME__', (cfg.name | regex_replace('^(?:[0-9]|[1-9][0-9])-(.*).link$', '\\1'))) | from_json) -%} - {%- endfor -%} - {{ __rtr }} - -network__systemd_all: "{{ ((network__all | selectattr('type', 'eq', 'systemd') | - selectattr('name', 'defined') | selectattr('name', 'search', '\\.(network|link|netdev)$') | - selectattr('children', 'defined') | default([])) + __network__systemd_rename) | reverse | - community.general.lists_mergeby('name', recursive=true, list_merge='prepend') | - aybarsm.helper.unique_recursive(attributes='name', recurse='children') }}" - -__network__systemd_names: "{{ network__systemd_all | map(attribute='name') }}" -# REVIEW: There is room for optimisation -# Escape file names defined in network__systemd_all -__network__systemd_cleanup_regex: - - "^({{ __network__systemd_names | select('match', '.*\\.link$') | map('replace', '.link', '') | join('|') }})\\.link$" - - "^({{ __network__systemd_names | select('match', '.*\\.netdev$') | map('replace', '.netdev', '') | join('|') }})\\.netdev$" - - "^({{ __network__systemd_names | select('match', '.*\\.network$') | map('replace', '.network', '') | join('|') }})\\.network$" -# Escape backup files: - - "^.*\\.\\d+\\.\\d{4}-\\d{2}-\\d{2}@\\d{2}:\\d{2}:\\d{2}~$" - -# Join regex expressions -network__systemd_cleanup_patterns: ["(?!{{ __network__systemd_cleanup_regex | join('|') }})"] -##### END: network systemd vars - -##### BEGIN: network interfaces vars -__network_interfaces_available_change_modules: ['service', 'systemd_service', 'command'] - -# Sort interfaces by name to avoid unneccessary changes -network__interfaces_all: "{{ network__all | reverse | - selectattr('type', 'eq', 'interface') | selectattr('name', 'defined') | - community.general.lists_mergeby('name', recursive=true, list_merge='prepend') | - aybarsm.helper.unique_recursive(attributes='name', recurse='inet') | - aybarsm.helper.unique_recursive(attributes='name', recurse='inet6') | - sort(attribute='name') }}" +network__all: "{{ {'host': network__host, 'group': network__group, 'default': network__default} | aybarsm.helper.role_vars(only=network__use_only) }}" ##### BEGIN: network sysctl vars -network__sysctl_all: "{{ network__all | - selectattr('type', 'defined') | selectattr('type', 'equalto', 'sysctl') | - aybarsm.helper.replace_aliases(__ansible.modules.ansible_posix_sysctl.aliases) | - selectattr('name', 'defined') | selectattr('value', 'defined') | unique(attribute='name') }}" -##### END: network sysctl vars - -##### BEGIN: network hosts vars -__network__hosts_auto_discovered: >- - {%- if (network__hosts_auto_discovery | default(false) | bool) and network__hosts_auto_discovery_inventories is defined and network__hosts_auto_discovery_inventories | length > 0 -%} - {%- set inventory_lookup = lookup('ansible.builtin.inventory_hostnames', network__hosts_auto_discovery_inventories) -%} - {%- if inventory_lookup | length > 0 -%} - {%- set inventory_hosts = inventory_lookup | split(',') -%} - {%- set discovered_hosts = dict(hostvars) | aybarsm.helper.only_with(inventory_hosts) | dict2items | selectattr('value.ansible_host', 'defined') -%} - {%- set ips = discovered_hosts | map(attribute='value.ansible_host') -%} - {%- set hostnames = discovered_hosts | map(attribute='value.inventory_hostname_short') -%} - {%- set fqdns = discovered_hosts | map(attribute='value.inventory_hostname') -%} - {%- set auto_discovered = {'ip': ips, 'hostname': hostnames, 'fqdn': fqdns} | aybarsm.helper.to_list_of_dicts({'type': 'host'}) -%} - {%- endif -%} - {%- else -%} - {%- set auto_discovered = [] -%} - {%- endif -%} - {{ auto_discovered }} - -network__hosts_all: "{{ (network__all + __network__hosts_auto_discovered) | - selectattr('type', 'eq', 'host') | selectattr('ip', 'defined') | selectattr('hostname', 'defined') | - aybarsm.helper.replace_aliases({'fqdn': ['hostname']}) | unique(attribute='ip') }}" - -# Sort hosts by hostname to avoid unneccessary changes -network__hosts_all_ipv4: "{{ network__hosts_all | selectattr('ip', 'ansible.utils.ipv4') | sort(attribute='hostname') }}" -network__hosts_all_ipv6: "{{ network__hosts_all | selectattr('ip', 'ansible.utils.ipv6') | sort(attribute='hostname') }}" -##### END: network hosts vars - -##### BEGIN: network iptables vars -network__iptables_all: "{{ network__all | selectattr('type', 'eq', 'iptables') }}" -##### END: network iptables vars - -##### BEGIN: network udev rules vars -network__udev_rules_all: "{{ network__all | selectattr('type', 'eq', 'udev_rule') | selectattr('entries', 'defined') }}" -##### END: network udev rules vars \ No newline at end of file +network__sysctl_all: "{{ network__all | selectattr('entry__type', 'eq', 'sysctl') | + aybarsm.helper.replace_aliases(__ansible.modules.ansible_posix_sysctl.aliases, removeAliases=true) | + community.general.json_query('[?not_null(name) && not_null(value)]') | + unique(attribute='name') }}" +##### END: network sysctl vars \ No newline at end of file diff --git a/roles/proxmox/defaults/main.yml b/roles/proxmox/defaults/main.yml index e58e8db..3e24e2a 100644 --- a/roles/proxmox/defaults/main.yml +++ b/roles/proxmox/defaults/main.yml @@ -1,108 +1,9 @@ -##### BEGIN: proxmox per host/node configuration proxmox__role_enabled: false -proxmox__manage_repo_keys: false -proxmox__manage_repos: false -proxmox__manage_packages: false -proxmox__manage_grub: false -proxmox__manage_hostname: false -proxmox__manage_hosts: false -proxmox__manage_iptables: false -# This option force root user to generate ssh key and distribute to all hosts within the cluster -proxmox__manage_root_access: false -proxmox__manage_sshd_config: false -proxmox__manage_ssh_config: false -proxmox__manage_files: false -proxmox__manage_cluster: false +proxmox__clusters: {} -proxmox__hostname: "{{ inventory_hostname_short }}" -proxmox__domain: local +proxmox__use_only: ['host', 'group', 'default'] -# Ip addresses for the cluster links for the host -# i.e. proxmox__cluster_links: ['10.0.0.2', 'fd00::2'] -# If more than one ip provided, the first link ip will be used as the cluster ip for the hosts file -proxmox__cluster_links: [] -proxmox__ssh_port: 22 -proxmox__ssh_ciphers: "aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com" -proxmox__remove_subscription_warning: false -#TODO: pveproxy configuration -> /etc/default/pveproxy -##### END: proxmox per host/node configuration - -##### BEGIN: proxmox shared configuration -# Cluster configuration -# For target inventory specs, consult https://docs.ansible.com/ansible/latest/inventory_guide/intro_patterns.html for more information -# If init node not provided, the init node will be designated as the first node regarding ascending sorted of inventory_hostname -# proxmox__clusters variables has been designed to be managed from a single source of truth, i.e. group_vars/all.yml However, it can be overwritten from the host vars. -# proxmox__clusters: -# - name: 'pve-london01' -# target: 'proxmox:&london' -# manage_pools: true -# manage_roles: true -# manage_groups: false -# manage_users: false -# manage_acls: false -# - name: 'pve-atlanta01'# (required) -# target: 'proxmox:&atlanta'# (required) -# init: 'pve01-atlanta01'# (optional | default: first of asc sorted inventory_hostname) -# manage_pools: true# (optional | default: false) -# manage_roles: true# (optional | default: false) -# manage_groups: false# (optional | default: false) -# manage_users: false# (optional | default: false) -# manage_acls: false# (optional | default: false) -proxmox__clusters: [] - -proxmox__repo_url_enterprise: https://enterprise.proxmox.com/debian -proxmox__repo_url_no_subscription: http://download.proxmox.com/debian -proxmox__repo_keys: - bookworm: - url: https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg - keyring: /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg - bullseye: - url: https://enterprise.proxmox.com/debian/proxmox-release-bullseye.gpg - keyring: /etc/apt/trusted.gpg.d/proxmox-release-bullseye.gpg - -proxmox__purpose_names: ['pve', 'pbs', 'pmg', 'ceph_pacific', 'ceph_quincy', 'ceph_reef', 'zfs'] -proxmox__purpose_types: ['enterprise', 'no-subscription'] -proxmox__purpose_packages: - pve: ['pve-manager'] - pbs: ['proxmox-backup-server'] - pmg: ['proxmox-mailgateway'] - ceph_pacific: ['ceph', 'ceph-common', 'ceph-mds', 'ceph-fuse'] - ceph_quincy: ['ceph', 'ceph-common', 'ceph-mds', 'ceph-fuse'] - ceph_reef: ['ceph', 'ceph-common', 'ceph-mds', 'ceph-fuse'] - zfs: ['zfsutils-linux', 'zfs-initramfs', 'zfs-zed'] - -proxmox__default: {} -proxmox__group: {} -proxmox__host: {} - -# Example configuration: -# Purposes will be overwritten by the host configuration. -# The type can be set other than the provided list to rule out. -## ZFS Consult with: https://pve.proxmox.com/wiki/ZFS_on_Linux#sysadmin_zfs_limit_memory_usage -## ZFS Consult with: https://pve.proxmox.com/wiki/ZFS_on_Linux#_configure_e_mail_notification -# proxmox__default: -# purposes: -# pve: -# type: no-subscription -# version: latest -# # ------------------------------------------------ -# proxmox__host: -# purposes: -# pve: -# type: no-subscription -# version: 8.2.4 -# ceph_reef: -# type: no-subscription -# pbs: -# type: no-subscription -# version: 3.2.4-1 -# pmg: -# type: no-subscription -# version: 8.1.0 -# zfs: -# version: 2.2.4-pve1 -# params: 'zfs_arc_max=2147483648' -# zed_email: 'noc@example.com' -# post_install: "{{ playbook_dir }}/tasks/zfs_post_install.yml" -##### END: proxmox shared configuration \ No newline at end of file +proxmox__default: [] +proxmox__group: [] +proxmox__host: [] \ No newline at end of file diff --git a/roles/proxmox/meta/main.yml b/roles/proxmox/meta/main.yml index 0c14010..483683b 100644 --- a/roles/proxmox/meta/main.yml +++ b/roles/proxmox/meta/main.yml @@ -1,3 +1,4 @@ +#TODO: re-enable geerlingguy.ntp role dependencies: - role: aybarsm.helper.ansible - - role: geerlingguy.ntp \ No newline at end of file + # - role: geerlingguy.ntp \ No newline at end of file diff --git a/roles/proxmox/tasks/lxc/crud.yml b/roles/proxmox/tasks/lxc/crud.yml new file mode 100644 index 0000000..ed97d53 --- /dev/null +++ b/roles/proxmox/tasks/lxc/crud.yml @@ -0,0 +1 @@ +--- diff --git a/roles/proxmox/tasks/main.yml b/roles/proxmox/tasks/main.yml index b42a054..dae3251 100644 --- a/roles/proxmox/tasks/main.yml +++ b/roles/proxmox/tasks/main.yml @@ -1,149 +1,11 @@ --- -- name: Include set fact tasks +- name: Include Proxmox QEMU tasks ansible.builtin.include_tasks: - file: set_facts.yml - -- name: Inform when host not cluster eligible - ansible.builtin.debug: - msg: 'Host is not cluster eligible.' - when: not __proxmox__cluster_eligible - delegate_to: localhost - -# - name: Inform cluster configuration -# ansible.builtin.debug: -# msg: "{{ __proxmox__cluster }}" -# when: __proxmox__cluster_eligible -# delegate_to: localhost - -- name: Import aybarsm.linux.package_manager role - ansible.builtin.import_role: - name: aybarsm.linux.package_manager + file: qemu.yml + loop: "{{ proxmox__all | selectattr('entry__type', 'match', '^qemu_(vm|disk|nic)$') }}" + loop_control: + loop_var: proxmox__qemu_item + index_var: proxmox__qemu_item_index when: - - proxmox__role_enabled - - proxmox__manage_repo_keys or proxmox__manage_repos or proxmox__manage_packages - -- name: Import aybarsm.linux.grub role - ansible.builtin.import_role: - name: aybarsm.linux.grub - when: - - proxmox__role_enabled - - proxmox__manage_grub - -- name: Import aybarsm.linux.network role - ansible.builtin.import_role: - name: aybarsm.linux.network - when: - - proxmox__role_enabled - - proxmox__manage_hostname or proxmox__manage_hosts or proxmox__manage_iptables - -- name: Import aybarsm.helper.file_mgr role - ansible.builtin.import_role: - name: aybarsm.helper.file_mgr - when: - - proxmox__role_enabled - - proxmox__manage_files - -- name: Update grub and initramfs when systemd network and/or grub changed - become: true - ansible.builtin.command: - cmd: "{{ item }}" - with_items: - - update-grub - - proxmox-boot-tool refresh - - update-initramfs -u -k all - when: (grub__deploy is defined and grub__deploy is changed) or - (network__systemd_deploy is defined and network__systemd_deploy is changed) - -- name: Reboot node and wait if upgraded, grub, network-hostname, systemd, or interfaces changed - become: true - ansible.builtin.reboot: - test_command: "uptime" - vars: - chk_upgrade: "{{ package_manager__upgrade_deb is defined and package_manager__upgrade_deb is changed }}" - chk_grub: "{{ grub__deploy is defined and grub__deploy is changed }}" - chk_hostname: "{{ network__hostname_deploy is defined and network__hostname_deploy is changed }}" - chk_systemd: "{{ network__systemd_deploy is defined and network__systemd_deploy is changed }}" - chk_interfaces: "{{ network__interfaces_deploy is defined and network__interfaces_deploy is changed }}" - register: proxmox__primary_reboot - when: chk_upgrade or chk_grub or chk_hostname or chk_systemd or chk_interfaces - throttle: 1 - -- name: Include auth tasks - ansible.builtin.include_tasks: - file: auth.yml - when: - - proxmox__role_enabled - - __proxmox__cluster_eligible - -- name: Remove subscription check wrapper function in web UI - become: true - ansible.builtin.lineinfile: - path: /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js - line: ' orig_cmd(); return;' - insertafter: '^\s+checked_command: function\(orig_cmd\) {$' - firstmatch: true - backup: true - when: - - proxmox__role_enabled - - proxmox__remove_subscription_warning - -- name: Include Proxmox cluster pool tasks - ansible.builtin.include_tasks: - file: cluster_pools.yml - when: - - proxmox__role_enabled - - __proxmox__cluster_eligible - - __proxmox__cluster.manage_pools | default(false) | bool - - inventory_hostname == __proxmox__cluster.init - -- name: Include Proxmox cluster roles tasks - ansible.builtin.include_tasks: - file: cluster_roles.yml - when: - - proxmox__role_enabled - - __proxmox__cluster_eligible - - __proxmox__cluster.manage_roles | default(false) | bool - - inventory_hostname == __proxmox__cluster.init - -- name: Include Proxmox cluster groups tasks - ansible.builtin.include_tasks: - file: cluster_groups.yml - when: - - proxmox__role_enabled - - __proxmox__cluster_eligible - - __proxmox__cluster.manage_groups | default(false) | bool - - inventory_hostname == __proxmox__cluster.init - -- name: Include Proxmox cluster users tasks - ansible.builtin.include_tasks: - file: cluster_users.yml - when: - - proxmox__role_enabled - - __proxmox__cluster_eligible - - __proxmox__cluster.manage_users | default(false) | bool - - inventory_hostname == __proxmox__cluster.init - -- name: Include Proxmox cluster ACLs tasks - ansible.builtin.include_tasks: - file: cluster_acls.yml - when: - - proxmox__role_enabled - - __proxmox__cluster_eligible - - __proxmox__cluster.manage_acls | default(false) | bool - - inventory_hostname == __proxmox__cluster.init - - -#TODO: Remove old kernel packages -#TODO: IPMI Watchdog - -# - name: Gather package facts -# ansible.builtin.package_facts: -# manager: auto -# register: proxmox__package_facts - -# - name: Include ZFS tasks -# ansible.builtin.include_tasks: -# file: zfs.yml -# when: proxmox__role_enabled - -# #TODO: Kernel module cleanup + - proxmox__role_enabled | default(false) | bool + - proxmox__all | selectattr('entry__type', 'match', '^qemu_(vm|disk|nic)$') | default([]) | length > 0 \ No newline at end of file diff --git a/roles/proxmox/tasks/qemu.yml b/roles/proxmox/tasks/qemu.yml new file mode 100644 index 0000000..fc84056 --- /dev/null +++ b/roles/proxmox/tasks/qemu.yml @@ -0,0 +1,23 @@ +--- +- name: Proxmox QEMU Item + block: + - name: "Include QEMU VM Tasks - Index: {{ proxmox_qemu_item_index }}" + ansible.builtin.include_tasks: + file: qemu/vm.yml + vars: + qemu_vm: "{{ __proxmox__module_vars | combine(proxmox__qemu_item) }}" + when: proxmox__qemu_item.entry__type == 'qemu_vm' + + - name: "Include QEMU NIC Tasks - Index: {{ proxmox_qemu_item_index }}" + ansible.builtin.include_tasks: + file: qemu/nic.yml + vars: + qemu_nic: "{{ __proxmox__module_vars | combine(proxmox__qemu_item) }}" + when: proxmox__qemu_item.entry__type == 'qemu_nic' + + - name: "Include QEMU DISK Tasks - Index: {{ proxmox_qemu_item_index }}" + ansible.builtin.include_tasks: + file: qemu/disk.yml + vars: + qemu_disk: "{{ __proxmox__module_vars | combine(proxmox__qemu_item) }}" + when: proxmox__qemu_item.entry__type == 'qemu_disk' diff --git a/roles/proxmox/tasks/qemu/disk.yml b/roles/proxmox/tasks/qemu/disk.yml new file mode 100644 index 0000000..7d38323 --- /dev/null +++ b/roles/proxmox/tasks/qemu/disk.yml @@ -0,0 +1,68 @@ +--- +- name: Proxmox QEMU Disk + community.general.proxmox_disk: + aio: "{{ qemu_disk.aio | default(omit, true) }}" + api_host: "{{ qemu_disk.api_host | default(omit, true) }}" + api_host: "{{ qemu_disk.api_host }}" + api_password: "{{ qemu_disk.api_password | default(omit, true) }}" + api_port: "{{ qemu_disk.api_port | default(omit, true) }}" + api_token_id: "{{ qemu_disk.api_token_id | default(omit, true) }}" + api_token_secret: "{{ qemu_disk.api_token_secret | default(omit, true) }}" + api_user: "{{ qemu_disk.api_user }}" + backup: "{{ qemu_disk.backup | default(omit, true) }}" + bps_max_length: "{{ qemu_disk.bps_max_length | default(omit, true) }}" + bps_rd_max_length: "{{ qemu_disk.bps_rd_max_length | default(omit, true) }}" + bps_wr_max_length: "{{ qemu_disk.bps_wr_max_length | default(omit, true) }}" + bwlimit: "{{ qemu_disk.bwlimit | default(omit, true) }}" + cache: "{{ qemu_disk.cache | default(omit, true) }}" + create: "{{ qemu_disk.create | default(omit, true) }}" + cyls: "{{ qemu_disk.cyls | default(omit, true) }}" + delete_moved: "{{ qemu_disk.delete_moved | default(omit, true) }}" + detect_zeroes: "{{ qemu_disk.detect_zeroes | default(omit, true) }}" + dsicard: "{{ qemu_disk.dsicard | default(omit, true) }}" + disk: "{{ qemu_disk.disk }}" + format: "{{ qemu_disk.format | default(omit, true) }}" + heads: "{{ qemu_disk.heads | default(omit, true) }}" + import_from: "{{ qemu_disk.import_from | default(omit, true) }}" + iops: "{{ qemu_disk.iops | default(omit, true) }}" + iops_max: "{{ qemu_disk.iops_max | default(omit, true) }}" + iops_max_length: "{{ qemu_disk.iops_max_length | default(omit, true) }}" + iops_rd: "{{ qemu_disk.iops_rd | default(omit, true) }}" + iops_rd_max: "{{ qemu_disk.iops_rd_max | default(omit, true) }}" + iops_rd_max_length: "{{ qemu_disk.iops_rd_max_length | default(omit, true) }}" + iops_wr: "{{ qemu_disk.iops_wr | default(omit, true) }}" + iops_wr_max: "{{ qemu_disk.iops_wr_max | default(omit, true) }}" + iops_wr_max_length: "{{ qemu_disk.iops_wr_max_length | default(omit, true) }}" + iothread: "{{ qemu_disk.iothread | default(omit, true) }}" + iso_image: "{{ qemu_disk.iso_image | default(omit, true) }}" + mbps: "{{ qemu_disk.mbps | default(omit, true) }}" + mbps_max: "{{ qemu_disk.mbps_max | default(omit, true) }}" + mbps_rd: "{{ qemu_disk.mbps_rd | default(omit, true) }}" + mbps_rd_max: "{{ qemu_disk.mbps_rd_max | default(omit, true) }}" + mbps_wr: "{{ qemu_disk.mbps_wr | default(omit, true) }}" + mbps_wr_max: "{{ qemu_disk.mbps_wr_max | default(omit, true) }}" + media: "{{ qemu_disk.media | default(omit, true) }}" + name: "{{ qemu_disk.name | default(omit, true) }}" + queues: "{{ qemu_disk.queues | default(omit, true) }}" + replicate: "{{ qemu_disk.replicate | default(omit, true) }}" + rerror: "{{ qemu_disk.rerror | default(omit, true) }}" + ro: "{{ qemu_disk.ro | default(omit, true) }}" + scsiblock: "{{ qemu_disk.scsiblock | default(omit, true) }}" + secs: "{{ qemu_disk.secs | default(omit, true) }}" + serial: "{{ qemu_disk.serial | default(omit, true) }}" + shared: "{{ qemu_disk.shared | default(omit, true) }}" + size: "{{ qemu_disk.size | default(omit, true) }}" + snapshot: "{{ qemu_disk.snapshot | default(omit, true) }}" + ssd: "{{ qemu_disk.ssd | default(omit, true) }}" + state: "{{ qemu_disk.state | default(omit, true) }}" + storage: "{{ qemu_disk.storage | default(omit, true) }}" + target_disk: "{{ qemu_disk.target_disk | default(omit, true) }}" + target_storage: "{{ qemu_disk.target_storage | default(omit, true) }}" + target_vmid: "{{ qemu_disk.target_vmid | default(omit, true) }}" + timeout: "{{ qemu_disk.timeout | default(omit, true) }}" + trans: "{{ qemu_disk.trans | default(omit, true) }}" + validate_certs: "{{ qemu_disk.validate_certs | default(omit, true) }}" + vmid: "{{ qemu_disk.vmid | default(omit, true) }}" + werror: "{{ qemu_disk.werror | default(omit, true) }}" + wwn: "{{ qemu_disk.wwn | default(omit, true) }}" + register: proxmox__apply_qemu_disk \ No newline at end of file diff --git a/roles/proxmox/tasks/qemu/nic.yml b/roles/proxmox/tasks/qemu/nic.yml new file mode 100644 index 0000000..af1c523 --- /dev/null +++ b/roles/proxmox/tasks/qemu/nic.yml @@ -0,0 +1,25 @@ +--- +- name: Proxmox QEMU Nic + community.general.proxmox_nic: + api_host: "{{ qemu_nic.api_host }}" + api_password: "{{ qemu_nic.api_password | default(omit, true) }}" + api_port: "{{ qemu_nic.api_port | default(omit, true) }}" + api_token_id: "{{ qemu_nic.api_token_id | default(omit, true) }}" + api_token_secret: "{{ qemu_nic.api_token_secret | default(omit, true) }}" + api_user: "{{ qemu_nic.api_user | default(omit, true) }}" + bridge: "{{ qemu_nic.bridge | default(omit, true) }}" + firewall: "{{ qemu_nic.firewall | default(omit, true) }}" + interface: "{{ qemu_nic.interface | default(omit, true) }}" + link_down: "{{ qemu_nic.link_down | default(omit, true) }}" + mac: "{{ qemu_nic.mac | default(omit, true) }}" + model: "{{ qemu_nic.model | default(omit, true) }}" + mtu: "{{ qemu_nic.mtu | default(omit, true) }}" + name: "{{ qemu_nic.name | default(omit, true) }}" + queues: "{{ qemu_nic.queues | default(omit, true) }}" + rate: "{{ qemu_nic.rate | default(omit, true) }}" + state: "{{ qemu_nic.state | default(omit, true) }}" + tag: "{{ qemu_nic.tag | default(omit, true) }}" + trunks: "{{ qemu_nic.trunks | default(omit, true) }}" + validate_certs: "{{ qemu_nic.validate_certs | default(omit, true) }}" + vmid: "{{ qemu_nic.vmid | default(omit, true) }}" + register: proxmox__apply_qemu_nic \ No newline at end of file diff --git a/roles/proxmox/tasks/qemu/vm.yml b/roles/proxmox/tasks/qemu/vm.yml new file mode 100644 index 0000000..3e3184d --- /dev/null +++ b/roles/proxmox/tasks/qemu/vm.yml @@ -0,0 +1,199 @@ +--- +- name: Proxmox QEMU VM + ansible.builtin.debug: + msg: + raw: "{{ qemu_vm }}" + gathered_module_vars: "{{ gathered }}" + vars: + gathered: + acpi: "{{ qemu_vm.acpi | default(omit, true) }}" + agent: "{{ qemu_vm.agent | default(omit, true) }}" + api_host: "{{ qemu_vm.api_host }}" + api_password: "{{ qemu_vm.api_password | default(omit, true) }}" + api_port: "{{ qemu_vm.api_port | default(omit, true) }}" + api_token_id: "{{ qemu_vm.api_token_id | default(omit, true) }}" + api_token_secret: "{{ qemu_vm.api_token_secret | default(omit, true) }}" + api_user: "{{ qemu_vm.api_user }}" + archive: "{{ qemu_vm.archive | default(omit, true) }}" + args: "{{ qemu_vm.args | default(omit, true) }}" + autostart: "{{ qemu_vm.autostart | default(omit, true) }}" + balloon: "{{ qemu_vm.balloon | default(omit, true) }}" + bios: "{{ qemu_vm.bios | default(omit, true) }}" + boot: "{{ qemu_vm.boot | default(omit, true) }}" + bootdisk: "{{ qemu_vm.bootdisk | default(omit, true) }}" + cicustom: "{{ qemu_vm.cicustom | default(omit, true) }}" + cipassword: "{{ qemu_vm.cipassword | default(omit, true) }}" + citype: "{{ qemu_vm.citype | default(omit, true) }}" + ciuser: "{{ qemu_vm.ciuser | default(omit, true) }}" + clone: "{{ qemu_vm.clone | default(omit, true) }}" + cores: "{{ qemu_vm.cores | default(omit, true) }}" + cpu: "{{ qemu_vm.cpu | default(omit, true) }}" + cpulimit: "{{ qemu_vm.cpulimit | default(omit, true) }}" + cpuunits: "{{ qemu_vm.cpuunits | default(omit, true) }}" + delete: "{{ qemu_vm.delete | default(omit, true) }}" + description: "{{ qemu_vm.description | default(omit, true) }}" + digest: "{{ qemu_vm.digest | default(omit, true) }}" + efidisk0: "{{ qemu_vm.efidisk0 | default(omit, true) }}" + force: "{{ qemu_vm.force | default(omit, true) }}" + format: "{{ qemu_vm.format | default(omit, true) }}" + freeze: "{{ qemu_vm.freeze | default(omit, true) }}" + full: "{{ qemu_vm.full | default(omit, true) }}" + hookscript: "{{ qemu_vm.hookscript | default(omit, true) }}" + hostpci: "{{ qemu_vm.hostpci | default(omit, true) }}" + hotplug: "{{ qemu_vm.hotplug | default(omit, true) }}" + hugepages: "{{ qemu_vm.hugepages | default(omit, true) }}" + ide: "{{ qemu_vm.ide | default(omit, true) }}" + ipconfig: "{{ qemu_vm.ipconfig | default(omit, true) }}" + keyboard: "{{ qemu_vm.keyboard | default(omit, true) }}" + kvm: "{{ qemu_vm.kvm | default(omit, true) }}" + localtime: "{{ qemu_vm.localtime | default(omit, true) }}" + lock: "{{ qemu_vm.lock | default(omit, true) }}" + machine: "{{ qemu_vm.machine | default(omit, true) }}" + memory: "{{ qemu_vm.memory | default(omit, true) }}" + migrate: "{{ qemu_vm.migrate | default(omit, true) }}" + migrate_downtime: "{{ qemu_vm.migrate_downtime | default(omit, true) }}" + migrate_speed: "{{ qemu_vm.migrate_speed | default(omit, true) }}" + name: "{{ qemu_vm.name | default(omit, true) }}" + nameservers: "{{ qemu_vm.nameservers | default(omit, true) }}" + net: "{{ qemu_vm.net | default(omit, true) }}" + newid: "{{ qemu_vm.newid | default(omit, true) }}" + node: "{{ qemu_vm.node | default(omit, true) }}" + numa: "{{ qemu_vm.numa | default(omit, true) }}" + numa_enabled: "{{ qemu_vm.numa_enabled | default(omit, true) }}" + onboot: "{{ qemu_vm.onboot | default(omit, true) }}" + ostype: "{{ qemu_vm.ostype | default(omit, true) }}" + parallel: "{{ qemu_vm.parallel | default(omit, true) }}" + pool: "{{ qemu_vm.pool | default(omit, true) }}" + protection: "{{ qemu_vm.protection | default(omit, true) }}" + proxmox_default_behavior: "{{ qemu_vm.proxmox_default_behavior | default(omit, true) }}" + reboot: "{{ qemu_vm.reboot | default(omit, true) }}" + revert: "{{ qemu_vm.revert | default(omit, true) }}" + sata: "{{ qemu_vm.sata | default(omit, true) }}" + scsi: "{{ qemu_vm.scsi | default(omit, true) }}" + scsihw: "{{ qemu_vm.scsihw | default(omit, true) }}" + searchdomains: "{{ qemu_vm.searchdomains | default(omit, true) }}" + serial: "{{ qemu_vm.serial | default(omit, true) }}" + shares: "{{ qemu_vm.shares | default(omit, true) }}" + skiplock: "{{ qemu_vm.skiplock | default(omit, true) }}" + smbios: "{{ qemu_vm.smbios | default(omit, true) }}" + snapname: "{{ qemu_vm.snapname | default(omit, true) }}" + sockets: "{{ qemu_vm.sockets | default(omit, true) }}" + sshkeys: "{{ qemu_vm.sshkeys | default(omit, true) }}" + startdate: "{{ qemu_vm.startdate | default(omit, true) }}" + startup: "{{ qemu_vm.startup | default(omit, true) }}" + state: "{{ qemu_vm.state | default(omit, true) }}" + storage: "{{ qemu_vm.storage | default(omit, true) }}" + tablet: "{{ qemu_vm.tablet | default(omit, true) }}" + tags: "{{ qemu_vm.tags | default(omit, true) }}" + target: "{{ qemu_vm.target | default(omit, true) }}" + tdf: "{{ qemu_vm.tdf | default(omit, true) }}" + template: "{{ qemu_vm.template | default(omit, true) }}" + timeout: "{{ qemu_vm.timeout | default(omit, true) }}" + tpmstate0: "{{ qemu_vm.tpmstate0 | default(omit, true) }}" + update: "{{ omit if qemu_vm['update'] is undefined else 'YEYEYE' }}" + update__ret: "{{ lookup('ansible.builtin.vars', 'qemu_vm.update', default=omit) }}" + update_unsafe: "{{ qemu_vm.update_unsafe | default(omit, true) }}" + usb: "{{ qemu_vm.usb | default(omit, true) }}" + validate_certs: "{{ qemu_vm.validate_certs | default(omit, true) }}" + vcpus: "{{ qemu_vm.vcpus | default(omit, true) }}" + vga: "{{ qemu_vm.vga | default(omit, true) }}" + virtio: "{{ qemu_vm.virtio | default(omit, true) }}" + vmid: "{{ qemu_vm.vmid | default(omit, true) }}" + watchdog: "{{ qemu_vm.watchdog | default(omit, true) }}" + +# - name: Proxmox QEMU VM +# community.general.proxmox_kvm: +# acpi: "{{ qemu_vm.acpi | default(omit, true) }}" +# agent: "{{ qemu_vm.agent | default(omit, true) }}" +# api_host: "{{ qemu_vm.api_host }}" +# api_password: "{{ qemu_vm.api_password | default(omit, true) }}" +# api_port: "{{ qemu_vm.api_port | default(omit, true) }}" +# api_token_id: "{{ qemu_vm.api_token_id | default(omit, true) }}" +# api_token_secret: "{{ qemu_vm.api_token_secret | default(omit, true) }}" +# api_user: "{{ qemu_vm.api_user }}" +# archive: "{{ qemu_vm.archive | default(omit, true) }}" +# args: "{{ qemu_vm.args | default(omit, true) }}" +# autostart: "{{ qemu_vm.autostart | default(omit, true) }}" +# balloon: "{{ qemu_vm.balloon | default(omit, true) }}" +# bios: "{{ qemu_vm.bios | default(omit, true) }}" +# boot: "{{ qemu_vm.boot | default(omit, true) }}" +# bootdisk: "{{ qemu_vm.bootdisk | default(omit, true) }}" +# cicustom: "{{ qemu_vm.cicustom | default(omit, true) }}" +# cipassword: "{{ qemu_vm.cipassword | default(omit, true) }}" +# citype: "{{ qemu_vm.citype | default(omit, true) }}" +# ciuser: "{{ qemu_vm.ciuser | default(omit, true) }}" +# clone: "{{ qemu_vm.clone | default(omit, true) }}" +# cores: "{{ qemu_vm.cores | default(omit, true) }}" +# cpu: "{{ qemu_vm.cpu | default(omit, true) }}" +# cpulimit: "{{ qemu_vm.cpulimit | default(omit, true) }}" +# cpuunits: "{{ qemu_vm.cpuunits | default(omit, true) }}" +# delete: "{{ qemu_vm.delete | default(omit, true) }}" +# description: "{{ qemu_vm.description | default(omit, true) }}" +# digest: "{{ qemu_vm.digest | default(omit, true) }}" +# efidisk0: "{{ qemu_vm.efidisk0 | default(omit, true) }}" +# force: "{{ qemu_vm.force | default(omit, true) }}" +# format: "{{ qemu_vm.format | default(omit, true) }}" +# freeze: "{{ qemu_vm.freeze | default(omit, true) }}" +# full: "{{ qemu_vm.full | default(omit, true) }}" +# hookscript: "{{ qemu_vm.hookscript | default(omit, true) }}" +# hostpci: "{{ qemu_vm.hostpci | default(omit, true) }}" +# hotplug: "{{ qemu_vm.hotplug | default(omit, true) }}" +# hugepages: "{{ qemu_vm.hugepages | default(omit, true) }}" +# ide: "{{ qemu_vm.ide | default(omit, true) }}" +# ipconfig: "{{ qemu_vm.ipconfig | default(omit, true) }}" +# keyboard: "{{ qemu_vm.keyboard | default(omit, true) }}" +# kvm: "{{ qemu_vm.kvm | default(omit, true) }}" +# localtime: "{{ qemu_vm.localtime | default(omit, true) }}" +# lock: "{{ qemu_vm.lock | default(omit, true) }}" +# machine: "{{ qemu_vm.machine | default(omit, true) }}" +# memory: "{{ qemu_vm.memory | default(omit, true) }}" +# migrate: "{{ qemu_vm.migrate | default(omit, true) }}" +# migrate_downtime: "{{ qemu_vm.migrate_downtime | default(omit, true) }}" +# migrate_speed: "{{ qemu_vm.migrate_speed | default(omit, true) }}" +# name: "{{ qemu_vm.name | default(omit, true) }}" +# nameservers: "{{ qemu_vm.nameservers | default(omit, true) }}" +# net: "{{ qemu_vm.net | default(omit, true) }}" +# newid: "{{ qemu_vm.newid | default(omit, true) }}" +# node: "{{ qemu_vm.node | default(omit, true) }}" +# numa: "{{ qemu_vm.numa | default(omit, true) }}" +# numa_enabled: "{{ qemu_vm.numa_enabled | default(omit, true) }}" +# onboot: "{{ qemu_vm.onboot | default(omit, true) }}" +# ostype: "{{ qemu_vm.ostype | default(omit, true) }}" +# parallel: "{{ qemu_vm.parallel | default(omit, true) }}" +# pool: "{{ qemu_vm.pool | default(omit, true) }}" +# protection: "{{ qemu_vm.protection | default(omit, true) }}" +# proxmox_default_behavior: "{{ qemu_vm.proxmox_default_behavior | default(omit, true) }}" +# reboot: "{{ qemu_vm.reboot | default(omit, true) }}" +# revert: "{{ qemu_vm.revert | default(omit, true) }}" +# sata: "{{ qemu_vm.sata | default(omit, true) }}" +# scsi: "{{ qemu_vm.scsi | default(omit, true) }}" +# scsihw: "{{ qemu_vm.scsihw | default(omit, true) }}" +# searchdomains: "{{ qemu_vm.searchdomains | default(omit, true) }}" +# serial: "{{ qemu_vm.serial | default(omit, true) }}" +# shares: "{{ qemu_vm.shares | default(omit, true) }}" +# skiplock: "{{ qemu_vm.skiplock | default(omit, true) }}" +# smbios: "{{ qemu_vm.smbios | default(omit, true) }}" +# snapname: "{{ qemu_vm.snapname | default(omit, true) }}" +# sockets: "{{ qemu_vm.sockets | default(omit, true) }}" +# sshkeys: "{{ qemu_vm.sshkeys | default(omit, true) }}" +# startdate: "{{ qemu_vm.startdate | default(omit, true) }}" +# startup: "{{ qemu_vm.startup | default(omit, true) }}" +# state: "{{ qemu_vm.state | default(omit, true) }}" +# storage: "{{ qemu_vm.storage | default(omit, true) }}" +# tablet: "{{ qemu_vm.tablet | default(omit, true) }}" +# tags: "{{ qemu_vm.tags | default(omit, true) }}" +# target: "{{ qemu_vm.target | default(omit, true) }}" +# tdf: "{{ qemu_vm.tdf | default(omit, true) }}" +# template: "{{ qemu_vm.template | default(omit, true) }}" +# timeout: "{{ qemu_vm.timeout | default(omit, true) }}" +# tpmstate0: "{{ qemu_vm.tpmstate0 | default(omit, true) }}" +# update: "{{ qemu_vm.update | default(omit, true) }}" +# update_unsafe: "{{ qemu_vm.update_unsafe | default(omit, true) }}" +# usb: "{{ qemu_vm.usb | default(omit, true) }}" +# validate_certs: "{{ qemu_vm.validate_certs | default(omit, true) }}" +# vcpus: "{{ qemu_vm.vcpus | default(omit, true) }}" +# vga: "{{ qemu_vm.vga | default(omit, true) }}" +# virtio: "{{ qemu_vm.virtio | default(omit, true) }}" +# vmid: "{{ qemu_vm.vmid | default(omit, true) }}" +# watchdog: "{{ qemu_vm.watchdog | default(omit, true) }}" +# register: proxmox__apply_qemu_vm \ No newline at end of file diff --git a/roles/proxmox/vars/main.yml b/roles/proxmox/vars/main.yml index bb53ed7..847d295 100644 --- a/roles/proxmox/vars/main.yml +++ b/roles/proxmox/vars/main.yml @@ -1,102 +1,11 @@ -# The combination strategy below is highly nested hierarchy compliant and recommended (Example provided below) -# proxmox__host > proxmox__group > proxmox__default -proxmox__all: "{{ {'purposes': {}} | combine(proxmox__default, proxmox__group, proxmox__host, recursive=true, list_merge='replace') }}" +proxmox__all: "{{ {'host': proxmox__host, 'group': proxmox__group, 'default': proxmox__default} | aybarsm.helper.role_vars(only=proxmox__use_only) }}" -__proxmox__purpose_packages: >- - {%- set proxmox_repo_keys = [proxmox__repo_keys[ansible_distribution_release] | combine({'type': 'repo_key', 'state': 'present'})] -%} - {%- set proxmox_repos = [] -%} - {%- set proxmox_packages = [] -%} - {%- set purpose_packages_done = [] -%} - {%- if proxmox__all.purposes is defined -%} - {%- for purpose in proxmox__purpose_names -%} - {% set proxmox_purpose_loop = loop %} - {%- for purpose_type in proxmox__purpose_types -%} - {%- set host_config = proxmox__all.purposes[purpose] if purpose in proxmox__all.purposes else none -%} - {%- set is_host_purpose = true if host_config else false -%} - {%- set is_host_purpose_type = true if host_config and host_config.type is defined and host_config.type == purpose_type else false -%} - {%- set purpose_package_version = host_config.version if host_config and host_config.version is defined else none -%} - {%- set purpose_repo_state = 'present' if is_host_purpose and is_host_purpose_type else 'absent' -%} - {%- set purpose_repo = proxmox__repo_url_enterprise if purpose_type == 'enterprise' else proxmox__repo_url_no_subscription -%} - {%- if purpose in ['pve', 'pbs', 'pmg'] -%} - {%- set proxmox_repos = proxmox_repos.append({ - 'type': 'repo', - 'repo': 'deb ' + purpose_repo + '/' + purpose + ' ' + ansible_distribution_release + ' ' + purpose + '-' + purpose_type, - 'filename': purpose + '-' + (purpose_type | replace('_', '-')), - 'state': purpose_repo_state, - 'update_cache': proxmox_purpose_loop.last - }) -%} - {%- elif purpose.startswith('ceph-') or purpose.startswith('ceph_') -%} - {%- set proxmox_repos = proxmox_repos.append({ - 'type': 'repo', - 'repo': 'deb ' + purpose_repo + '/' + (purpose | replace('_', '-')) + ' ' + ansible_distribution_release + ' ' + purpose_type, - 'filename': 'ceph', - 'state': purpose_repo_state, - 'update_cache': proxmox_purpose_loop.last - }) -%} - {%- endif -%} - {%- if is_host_purpose and proxmox__purpose_packages[purpose] is defined and not purpose in purpose_packages_done -%} - {%- set purpose_packages_done = purpose_packages_done.append(purpose) -%} - {%- for purpose_package in proxmox__purpose_packages[purpose] -%} - {%- set package_name = purpose_package + '=' + purpose_package_version if purpose_package_version else purpose_package -%} - {%- set proxmox_packages = proxmox_packages.append({ - 'type': 'package', - 'name': package_name, - 'state': 'present', - 'update_cache': true - }) -%} - {%- endfor -%} - {%- endif -%} - {%- endfor -%} - {%- endfor -%} - {%- endif -%} - {{ proxmox_repo_keys + proxmox_repos + proxmox_packages }} +__proxmox__cluster: "{{ proxmox__clusters | selectattr('target', 'contains', inventory_hostname) | first | default({}, true) }}" -__proxmox__grub_change_strategy: - module: command - cmd: 'proxmox-boot-tool refresh' - immediate: true - -__proxmox__cluster_query: '*.{ - host: inventory_hostname, - hostname: proxmox__hostname, - domain: proxmox__domain, - fqdn: join(`.`, [not_null(proxmox__hostname, ``), not_null(proxmox__domain, ``)]), - links: proxmox__cluster_links} | - [?not_null(hostname) && not_null(domain) && not_null(links) && contains(__MEMBERS__, host)]' - -__proxmox__root_user_selector: - - when: - - ['type', 'defined'] - - ['type', 'equalto', 'user'] - - ['name', 'defined'] - - ['name', 'equalto', 'root'] - -__proxmox__root_user: - type: user - name: root - generate_ssh_key: true - -__proxmox__ssh_config: - type: ssh_config - name: Host - value: '' - children: - - name: IdentityFile - value: /root/.ssh/id_rsa - - name: Port - value: "{{ proxmox__ssh_port | default(22) }}" - -__proxmox__sshd_config: - type: sshd_config - name: 'Match Address' - value: '' - children: - - name: PermitRootLogin - value: prohibit-password - -__proxmox__default_cluster_config: - manage_pools: false - manage_roles: false - manage_groups: false - manage_users: false - manage_acls: false \ No newline at end of file +__proxmox__module_vars: + api_host: "{{ hostvars[__proxmox__cluster.init]['proxmox__cluster_links'] | first | default(omit, true) if __proxmox__cluster.init is defined else omit }}" + api_user: "{{ __proxmox__cluster.api.user | default(omit, true) }}" + api_password: "{{ __proxmox__cluster.api.password | default(omit, true) }}" + api_port: "{{ __proxmox__cluster.api.port | default(omit, true) }}" + api_token_id: "{{ __proxmox__cluster.api.token.id | default(omit, true) }}" + api_token_secret: "{{ __proxmox__cluster.api.token.secret | default(omit, true) }}" \ No newline at end of file