--- - name: Validate sandbox declaration and API inputs ansible.builtin.assert: that: - sandbox_lxc.vmid | int > 100 - sandbox_lxc.hostname | length > 0 - sandbox_lxc.address is match('^10\.60\.0\.[0-9]{1,3}/24$') - sandbox_lxc.memory_mb | int >= 4096 - sandbox_pve_api_host | length > 0 - sandbox_pve_api_user | length > 0 - sandbox_pve_api_token_id | length > 0 - sandbox_pve_api_token_secret | length > 0 fail_msg: Invalid sandbox declaration or missing Proxmox API environment no_log: true - name: Check whether the LXC already exists ansible.builtin.stat: path: /etc/pve/lxc/{{ sandbox_lxc.vmid }}.conf register: sandbox_lxc_config - name: Read current sandbox LXC runtime state community.proxmox.proxmox_vm_info: api_host: "{{ sandbox_pve_api_host }}" api_user: "{{ sandbox_pve_api_user }}" api_token_id: "{{ sandbox_pve_api_token_id }}" api_token_secret: "{{ sandbox_pve_api_token_secret }}" validate_certs: "{{ sandbox_pve_validate_certs }}" ca_path: /etc/ssl/certs/ca-certificates.crt api_timeout: 120 vmid: "{{ sandbox_lxc.vmid }}" register: sandbox_lxc_info delegate_to: localhost no_log: true vars: ansible_python_interpreter: "{{ sandbox_pve_api_python_interpreter }}" - name: Read current sandbox LXC configuration ansible.builtin.uri: url: >- https://{{ sandbox_pve_api_host }}:8006/api2/json/nodes/{{ inventory_hostname }}/lxc/{{ sandbox_lxc.vmid }}/config headers: Authorization: >- PVEAPIToken={{ sandbox_pve_api_user }}!{{ sandbox_pve_api_token_id }}={{ sandbox_pve_api_token_secret }} ca_path: /etc/ssl/certs/ca-certificates.crt return_content: true status_code: [200, 404, 500] register: sandbox_lxc_current_config delegate_to: localhost no_log: true - name: Reconcile sandbox LXC through the PVE API community.proxmox.proxmox: api_host: "{{ sandbox_pve_api_host }}" api_user: "{{ sandbox_pve_api_user }}" api_token_id: "{{ sandbox_pve_api_token_id }}" api_token_secret: "{{ sandbox_pve_api_token_secret }}" validate_certs: "{{ sandbox_pve_validate_certs }}" ca_path: /etc/ssl/certs/ca-certificates.crt api_timeout: 120 node: "{{ inventory_hostname }}" vmid: "{{ sandbox_lxc.vmid }}" hostname: "{{ sandbox_lxc.hostname }}" ostemplate: "{{ sandbox_lxc_template }}" ostype: ubuntu cmode: shell disk_volume: storage: "{{ sandbox_rootfs_storage }}" size: "{{ sandbox_rootfs_gb if not sandbox_lxc_config.stat.exists else omit }}" cores: "{{ sandbox_lxc_cores }}" memory: "{{ sandbox_lxc.memory_mb }}" swap: "{{ sandbox_lxc_swap_mb }}" netif: net0: >- {{ 'name=eth0,bridge=' ~ sandbox_bridge ~ ',ip=' ~ sandbox_lxc.address ~ ',gw=' ~ sandbox_gateway ~ ',type=veth' ~ (',hwaddr=' ~ _sandbox_existing_mac if _sandbox_existing_mac | length > 0 else '') }} nameserver: "{{ sandbox_nameserver }}" searchdomain: "{{ sandbox_search_domain }}" unprivileged: false onboot: true startup: ["order=30", "up=30", "down=60"] tags: [ansible, sandbox, k3s, kata] pubkey: "{{ sandbox_lxc_pubkey }}" update: true state: present timeout: 120 register: sandbox_lxc_api when: not sandbox_lxc_config.stat.exists or _sandbox_api_drift delegate_to: localhost no_log: true vars: ansible_python_interpreter: "{{ sandbox_pve_api_python_interpreter }}" _sandbox_existing_mac: >- {{ sandbox_lxc_current_config.json.data.net0.split('hwaddr=')[1].split(',')[0] if 'hwaddr=' in (sandbox_lxc_current_config.json.data.net0 | default('')) else '' }} _sandbox_api_drift: >- {{ sandbox_lxc_current_config.status != 200 or sandbox_lxc_current_config.json.data.hostname | default('') != sandbox_lxc.hostname or sandbox_lxc_current_config.json.data.cores | default(0) | int != sandbox_lxc_cores | int or sandbox_lxc_current_config.json.data.memory | default(0) | int != sandbox_lxc.memory_mb | int or sandbox_lxc_current_config.json.data.swap | default(0) | int != sandbox_lxc_swap_mb | int or sandbox_lxc_current_config.json.data.nameserver | default('') != sandbox_nameserver or sandbox_lxc_current_config.json.data.searchdomain | default('') != sandbox_search_domain or sandbox_lxc_current_config.json.data.cmode | default('') != 'shell' or sandbox_lxc_current_config.json.data.onboot | default(0) | int != 1 or sandbox_lxc_current_config.json.data.tags | default('') != 'ansible;k3s;kata;sandbox' or ('bridge=' ~ sandbox_bridge) not in (sandbox_lxc_current_config.json.data.net0 | default('')) or ('ip=' ~ sandbox_lxc.address) not in (sandbox_lxc_current_config.json.data.net0 | default('')) or ('gw=' ~ sandbox_gateway) not in (sandbox_lxc_current_config.json.data.net0 | default('')) or (sandbox_rootfs_storage ~ ':') not in (sandbox_lxc_current_config.json.data.rootfs | default('')) }} - name: Grow existing sandbox rootfs through the PVE resize API ansible.builtin.uri: url: >- https://{{ sandbox_pve_api_host }}:8006/api2/json/nodes/{{ inventory_hostname }}/lxc/{{ sandbox_lxc.vmid }}/resize method: PUT headers: Authorization: >- PVEAPIToken={{ sandbox_pve_api_user }}!{{ sandbox_pve_api_token_id }}={{ sandbox_pve_api_token_secret }} body_format: form-urlencoded body: disk: rootfs size: "{{ sandbox_rootfs_gb }}G" ca_path: /etc/ssl/certs/ca-certificates.crt status_code: 200 when: - sandbox_lxc_config.stat.exists - _sandbox_current_rootfs_gb | int < sandbox_rootfs_gb | int delegate_to: localhost no_log: true vars: _sandbox_current_rootfs_gb: >- {{ sandbox_lxc_current_config.json.data.rootfs | default('') | regex_findall('size=([0-9]+)G') | first | default('0') }} # These properties are not exposed by community.proxmox. Every retained line # is required by the already validated nested Kata/kind runtime. - name: Reconcile Kata-specific native LXC properties ansible.builtin.lineinfile: path: /etc/pve/lxc/{{ sandbox_lxc.vmid }}.conf regexp: "^{{ item.key | regex_escape }}:" line: "{{ item.key }}: {{ item.value }}" loop: - { key: features, value: "nesting=1,keyctl=1,fuse=1,mknod=1,force_rw_sys=1" } - { key: dev0, value: "path=/dev/kvm,mode=0660" } - { key: dev1, value: "path=/dev/vhost-net,mode=0660" } - { key: dev2, value: "path=/dev/vhost-vsock,mode=0660" } - { key: dev3, value: "path=/dev/net/tun,mode=0666" } - { key: lxc.apparmor.profile, value: unconfined } - { key: lxc.cgroup2.devices.allow, value: a } - { key: lxc.cap.drop, value: "" } - { key: lxc.mount.auto, value: "proc:rw sys:rw" } - { key: lxc.mount.entry, value: "/lib/modules usr/lib/modules none bind,ro,create=dir 0 0" } loop_control: label: "{{ item.key }}" register: sandbox_lxc_native - name: Start sandbox LXC community.proxmox.proxmox: api_host: "{{ sandbox_pve_api_host }}" api_user: "{{ sandbox_pve_api_user }}" api_token_id: "{{ sandbox_pve_api_token_id }}" api_token_secret: "{{ sandbox_pve_api_token_secret }}" validate_certs: "{{ sandbox_pve_validate_certs }}" ca_path: /etc/ssl/certs/ca-certificates.crt api_timeout: 120 vmid: "{{ sandbox_lxc.vmid }}" state: started timeout: 120 when: >- not _sandbox_was_running or not (sandbox_lxc_api is changed or sandbox_lxc_native is changed) delegate_to: localhost no_log: true vars: ansible_python_interpreter: "{{ sandbox_pve_api_python_interpreter }}" _sandbox_was_running: >- {{ (sandbox_lxc_info.proxmox_vms | default([]) | first | default({})).status | default('absent') == 'running' }} - name: Restart existing sandbox LXC after configuration changes community.proxmox.proxmox: api_host: "{{ sandbox_pve_api_host }}" api_user: "{{ sandbox_pve_api_user }}" api_token_id: "{{ sandbox_pve_api_token_id }}" api_token_secret: "{{ sandbox_pve_api_token_secret }}" validate_certs: "{{ sandbox_pve_validate_certs }}" ca_path: /etc/ssl/certs/ca-certificates.crt api_timeout: 120 vmid: "{{ sandbox_lxc.vmid }}" state: restarted timeout: 120 when: - _sandbox_was_running - sandbox_lxc_api is changed or sandbox_lxc_native is changed delegate_to: localhost no_log: true vars: ansible_python_interpreter: "{{ sandbox_pve_api_python_interpreter }}" _sandbox_was_running: >- {{ (sandbox_lxc_info.proxmox_vms | default([]) | first | default({})).status | default('absent') == 'running' }}