From a217d65640542fadda3c7e9c73b40b21f594f7ed Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Tue, 18 Nov 2025 16:57:39 +0100 Subject: [PATCH] feat: Update incus installation role Now uses simple external ansible galaxy role, and should install incus from a pre-fixed seed. --- roles/incus-install/tasks/bootstrap.yaml | 220 ----------------------- roles/incus-install/tasks/install.yaml | 70 ++++++++ roles/incus-install/tasks/main.yaml | 10 +- site.yaml | 5 + 4 files changed, 81 insertions(+), 224 deletions(-) delete mode 100644 roles/incus-install/tasks/bootstrap.yaml create mode 100644 roles/incus-install/tasks/install.yaml diff --git a/roles/incus-install/tasks/bootstrap.yaml b/roles/incus-install/tasks/bootstrap.yaml deleted file mode 100644 index c6e1dfa..0000000 --- a/roles/incus-install/tasks/bootstrap.yaml +++ /dev/null @@ -1,220 +0,0 @@ ---- -- name: Incus - Install packages and bootstrap - hosts: all - gather_facts: true - gather_subset: - - "default_ipv4" - - "default_ipv6" - - "distribution_release" - vars: - task_init: "{{ incus_init | default('{}') }}" - task_ip_address: "{{ incus_ip_address | default(ansible_default_ipv6['address'] | default(ansible_default_ipv4['address'])) }}" - task_name: "{{ incus_name | default('') }}" - task_roles: "{{ incus_roles | default(['ui', 'standalone']) }}" - - task_ovn_northbound: "{{ lookup('template', '../files/ovn/ovn-central.servers.tpl') | from_yaml | map('regex_replace', '^(.*)$', 'ssl:[\\1]:6641') | join(',') }}" - task_servers: "{{ lookup('template', 'files/incus.servers.tpl') | from_yaml | sort }}" - any_errors_fatal: true - become: true - tasks: - - name: Install the Incus package (deb) - ansible.builtin.apt: - name: - - incus - install_recommends: no - state: present - register: install_deb - when: 'ansible_distribution in ("Debian", "Ubuntu") and task_roles | length > 0' - - - name: Install the Incus package (rpm) - ansible.builtin.package: - name: - - incus - state: present - register: install_rpm - when: 'ansible_distribution == "CentOS" and task_roles | length > 0' - - - name: Install the Incus UI package (deb) - ansible.builtin.apt: - name: - - incus-ui-canonical - install_recommends: no - state: present - when: 'ansible_distribution in ("Debian", "Ubuntu") and "ui" in task_roles' - - # - name: Install btrfs tools - # ansible.builtin.package: - # name: - # - btrfs-progs - # state: present - # when: "task_roles | length > 0 and 'btrfs' in task_init['storage'] | dict2items | json_query('[].value.driver')" - # - # - name: Install ceph tools - # ansible.builtin.package: - # name: - # - ceph-common - # state: present - # when: "task_roles | length > 0 and 'ceph' in task_init['storage'] | dict2items | json_query('[].value.driver')" - # - # - name: Install LVM tools - # ansible.builtin.package: - # name: - # - lvm2 - # state: present - # when: "task_roles | length > 0 and 'lvm' in task_init['storage'] | dict2items | json_query('[].value.driver')" - # - # - name: Install ZFS dependencies - # ansible.builtin.package: - # name: - # - zfs-dkms - # state: present - # when: "task_roles | length > 0 and 'zfs' in task_init['storage'] | dict2items | json_query('[].value.driver') and ansible_distribution == 'Debian'" - # - # - name: Install ZFS tools - # ansible.builtin.package: - # name: - # - zfsutils-linux - # state: present - # when: "task_roles | length > 0 and 'zfs' in task_init['storage'] | dict2items | json_query('[].value.driver')" - - - name: Set uid allocation - ansible.builtin.shell: - cmd: "usermod root --add-subuids 10000000-1009999999" - when: '(install_deb.changed or install_rpm.changed) and ansible_distribution == "CentOS"' - - - name: Set gid allocation - ansible.builtin.shell: - cmd: "usermod root --add-subgids 10000000-1009999999" - when: '(install_deb.changed or install_rpm.changed) and ansible_distribution == "CentOS"' - - - name: Enable incus socket unit - ansible.builtin.systemd: - enabled: true - name: incus.socket - state: started - when: "install_deb.changed or install_rpm.changed" - - - name: Enable incus service unit - ansible.builtin.systemd: - enabled: true - name: incus.service - state: started - when: "install_deb.changed or install_rpm.changed" - - - name: Enable incus startup unit - ansible.builtin.systemd: - enabled: true - name: incus-startup.service - state: started - when: "install_deb.changed or install_rpm.changed" - - - name: Set client listen address - ansible.builtin.shell: - cmd: "incus --force-local config set core.https_address {{ task_ip_address }}" - when: '(install_deb.changed or install_rpm.changed) and ("standalone" in task_roles or ("cluster" in task_roles and task_servers[0] == inventory_hostname))' - - - name: Set cluster listen address - ansible.builtin.shell: - cmd: "incus --force-local config set cluster.https_address {{ task_ip_address }}" - when: '(install_deb.changed or install_rpm.changed) and "cluster" in task_roles and task_servers[0] == inventory_hostname' - - # - name: Set OVN NorthBound database - # shell: - # cmd: "incus --force-local config set network.ovn.northbound_connection={{ task_ovn_northbound }} network.ovn.client_cert=\"{{ lookup('file', '../data/ovn/'+ovn_name+'/'+inventory_hostname+'.crt') }}\" network.ovn.client_key=\"{{ lookup('file', '../data/ovn/'+ovn_name+'/'+inventory_hostname+'.key') }}\" network.ovn.ca_cert=\"{{ lookup('file', '../data/ovn/'+ovn_name+'/ca.crt') }}\"" - # notify: Restart Incus - # when: '(install_deb.changed or install_rpm.changed) and task_ovn_northbound and ("standalone" in task_roles or ("cluster" in task_roles and task_servers[0] == inventory_hostname))' - - - name: Add networks - ansible.builtin.shell: - cmd: "incus network create {{ item.key }} --type={{ item.value.type }}{% for k in item.value.local_config | default([]) %} {{ k }}={{ item.value.local_config[k] }}{% endfor %}{% for k in item.value.config | default([]) %} {{ k }}={{ item.value.config[k] }}{% endfor %}" - loop: "{{ task_init['network'] | dict2items }}" - when: '(install_deb.changed or install_rpm.changed) and ("standalone" in task_roles or ("cluster" in task_roles and task_servers[0] == inventory_hostname))' - - - name: Set network description - ansible.builtin.shell: - cmd: 'incus network set --property {{ item.key }} description="{{ item.value.description }}"' - loop: "{{ task_init['network'] | dict2items }}" - when: '(install_deb.changed or install_rpm.changed) and ("standalone" in task_roles or ("cluster" in task_roles and task_servers[0] == inventory_hostname)) and item.value.description | default(None)' - - - name: Add storage pools - ansible.builtin.shell: - cmd: "incus storage create {{ item.key }} {{ item.value.driver }}{% for k in item.value.local_config | default([]) %} {{ k }}={{ item.value.local_config[k] }}{% endfor %}{% for k in item.value.config | default([]) %} {{ k }}={{ item.value.config[k] }}{% endfor %}" - loop: "{{ task_init['storage'] | dict2items }}" - when: '(install_deb.changed or install_rpm.changed) and ("standalone" in task_roles or ("cluster" in task_roles and task_servers[0] == inventory_hostname))' - - - name: Set storage pool description - ansible.builtin.shell: - cmd: 'incus storage set --property {{ item.key }} description="{{ item.value.description }}"' - loop: "{{ task_init['storage'] | dict2items }}" - when: '(install_deb.changed or install_rpm.changed) and ("standalone" in task_roles or ("cluster" in task_roles and task_servers[0] == inventory_hostname)) and item.value.description | default(None)' - - - name: Add storage pool to default profile - ansible.builtin.shell: - cmd: "incus profile device add default root disk path=/ pool={{ item }}" - loop: "{{ task_init['storage'] | dict2items | json_query('[?value.default].key') }}" - when: '(install_deb.changed or install_rpm.changed) and ("standalone" in task_roles or ("cluster" in task_roles and task_servers[0] == inventory_hostname))' - - - name: Add network to default profile - ansible.builtin.shell: - cmd: "incus profile device add default eth0 nic network={{ item }} name=eth0" - loop: "{{ task_init['network'] | dict2items | json_query('[?value.default].key') }}" - when: '(install_deb.changed or install_rpm.changed) and ("standalone" in task_roles or ("cluster" in task_roles and task_servers[0] == inventory_hostname))' - - - name: Bootstrap the cluster - ansible.builtin.shell: - cmd: "incus --force-local cluster enable {{ inventory_hostname }}" - when: '(install_deb.changed or install_rpm.changed) and "cluster" in task_roles and task_servers[0] == inventory_hostname' - - - name: Create join tokens - delegate_to: "{{ task_servers[0] }}" - ansible.builtin.shell: - cmd: "incus --force-local --quiet cluster add {{ inventory_hostname }}" - register: cluster_add - when: '(install_deb.changed or install_rpm.changed) and "cluster" in task_roles and task_servers[0] != inventory_hostname' - - - name: Wait 5s to avoid token use before valid - ansible.builtin.wait_for: - timeout: 5 - delegate_to: localhost - when: "cluster_add.changed" - - - name: Join the cluster - throttle: 1 - ansible.builtin.shell: - cmd: "incus --force-local admin init --preseed" - stdin: |- - cluster: - enabled: true - cluster_address: "{{ task_ip_address }}" - cluster_token: "{{ cluster_add.stdout }}" - server_address: "{{ task_ip_address }}" - member_config: {% for pool in task_init.storage %}{% for key in task_init.storage[pool].local_config | default([]) %} - - - entity: storage-pool - name: {{ pool }} - key: {{ key }} - value: {{ task_init.storage[pool].local_config[key] }}{% endfor %}{% endfor %}{% for network in task_init.network %}{% for key in task_init.network[network].local_config | default([]) %} - - - entity: network - name: {{ network }} - key: {{ key }} - value: {{ task_init.network[network].local_config[key] }}{% endfor %}{% endfor %} - when: "cluster_add.changed" - - - name: Apply additional configuration - ansible.builtin.shell: - cmd: 'incus config set {{ item.key }}="{{ item.value }}"' - loop: "{{ task_init['config'] | default({}) | dict2items }}" - when: '(install_deb.changed or install_rpm.changed) and ("standalone" in task_roles or ("cluster" in task_roles and task_servers[0] == inventory_hostname))' - - - name: Load client certificates - ansible.builtin.shell: - cmd: 'incus config trust add-certificate --name "{{ item.key }}" --type={{ item.value.type | default(''client'') }} -' - stdin: "{{ item.value.certificate }}" - loop: "{{ task_init['clients'] | default({}) | dict2items }}" - when: '(install_deb.changed or install_rpm.changed) and ("standalone" in task_roles or ("cluster" in task_roles and task_servers[0] == inventory_hostname))' - handlers: - - name: Restart Incus - ansible.builtin.systemd: - name: incus.service - state: restarted diff --git a/roles/incus-install/tasks/install.yaml b/roles/incus-install/tasks/install.yaml new file mode 100644 index 0000000..2b5f4ab --- /dev/null +++ b/roles/incus-install/tasks/install.yaml @@ -0,0 +1,70 @@ +# required by gliech.incus role +- name: Ensure lxc conf directory exists + ansible.builtin.file: + state: directory + path: /etc/lxc + become: true + +- name: Install incus + ansible.builtin.import_role: + name: gliech.incus + vars: + incus_config: + config: + core.https_address: "[::]:8443" + networks: + - config: + ipv4.address: 10.172.89.1/24 + ipv4.firewall: "true" + ipv4.nat: "true" + ipv6.address: fd42:c9d2:6e9f:be57::1/64 + ipv6.nat: "true" + description: "" + name: incusbr0 + type: bridge + project: default + storage_pools: + - config: + source: /var/lib/incus/storage-pools/default + volatile.initial_source: /var/lib/incus/storage-pools/default + description: "" + name: default + driver: btrfs + - config: + size: 50GiB + source: /var/lib/incus/disks/docker_store.img + description: "" + name: docker_store + driver: btrfs + storage_volumes: [] + profiles: + - config: {} + description: Default Incus profile + devices: + eth0: + name: eth0 + network: incusbr0 + type: nic + root: + path: / + pool: default + type: disk + name: default + project: "" + projects: + - config: + features.images: "true" + features.networks: "true" + features.networks.zones: "true" + features.profiles: "true" + features.storage.buckets: "true" + features.storage.volumes: "true" + restricted: "false" + description: NAS + name: default + certificates: [] + cluster_groups: [] +# # TODO: Should presumably be split +# - name: "Install and bootstrap incus" +# ansible.builtin.include_tasks: bootstrap.yaml +# when: ansible_distribution == "Debian" and ansible_distribution_release == "bookworm" diff --git a/roles/incus-install/tasks/main.yaml b/roles/incus-install/tasks/main.yaml index c465a5f..6623f4f 100644 --- a/roles/incus-install/tasks/main.yaml +++ b/roles/incus-install/tasks/main.yaml @@ -1,7 +1,9 @@ --- -- name: "Add incus repository to system" +## for bookworm only +- name: "Add incus repository to bookworm system" ansible.builtin.include_tasks: add-repo.yaml + when: ansible_distribution == "Debian" and ansible_distribution_release == "bookworm" - # TODO: Should presumably be split -- name: "Install and bootstrap incus" - ansible.builtin.include_tasks: bootstrap.yaml +# TODO: there might be remaining issues on other OSes like centos, etc +- name: Install incus + ansible.builtin.include_tasks: install.yaml diff --git a/site.yaml b/site.yaml index ce1b5c6..1e43b4d 100644 --- a/site.yaml +++ b/site.yaml @@ -25,6 +25,11 @@ name: system tags: system + - name: Set up incus + ansible.builtin.import_role: + name: incus-install + tags: incus + - name: Set up nfs shares ansible.builtin.import_role: name: nfs