renamed vars to use 'lxc' prefix instead of 'container'

This commit is contained in:
hiperman
2026-01-31 18:42:23 -05:00
parent 60fbe461be
commit 0a52e32f42
13 changed files with 174 additions and 176 deletions

View File

@@ -26,14 +26,26 @@ It also includes tasks which may be used individually:
### Required Variables ### Required Variables
| Variable | Description | Example | | Variable | Description | Example |
|----------|-------------|---------| |----------|-------------|---------|
| `os_template` | The OS template to create the LXC from. Mutually exclusive with `ct_id`| `local:vztmpl/debian-12_amd64.tar.zst` | | `container_template` | The OS template to create the LXC from. Mutually exclusive with `clone_from`| `local:vztmpl/debian-12_amd64.tar.zst` |
| `ct_id` | The vmid of the container or template container to clone the LXC from. Mutually exclusive with `os_template` | `201` | | `clone_from` | The vmid of the container or template container to clone the LXC from. Mutually exclusive with `container_template` | `201` |
### Required Proxmox API Authentication Variables ### Required Proxmox API Authentication Variables
**Note:** These should be defined in `group_vars/all.yml` as part of the `proxmox_api_connection` dictionary:
```yaml
# group_vars/all.yml
proxmox_api_connection:
api_host: "{{ proxmox_api_host }}"
api_port: "{{ proxmox_api_port }}"
api_user: "{{ proxmox_api_user }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
validate_certs: "{{ proxmox_api_validate_certs }}"
```
| Variable | Description | Example | | Variable | Description | Example |
|----------|-------------|---------| |----------|-------------|---------|
| `proxmox_api_user` | The username for Proxmox authentication, typically in format `username@realm` | `ansible@pve` | | `proxmox_api_user` | The username for Proxmox authentication, typically in format `username@realm` | `ansible@pve` |
@@ -49,47 +61,68 @@ It also includes tasks which may be used individually:
| Variable | Description | Default | | Variable | Description | Default |
|----------|-------------|---------| |----------|-------------|---------|
| `clone_type` | Only use with `ct_id`. Supports `full` and `linked` clones. | `full` | | `lxc_clone_type` | Only use with `lxc_clone_from`. Supports `full` and `linked` clones. | `full` |
| `container_storage` | Target storage for the container | `local-zfs` | | `lxc_storage` | Target storage for the container | `local-zfs` |
| `disk` | The target storage and storage size | `local-zfs:16` | | `lxc_disk` | The target storage and storage size | `local-zfs:16` |
| `container_password` | The password for the root account | `password123` | | `lxc_password` | The password for the root account | `password123` |
| `container_cores` | The number of CPU cores | `4` | | `lxc_cores` | The number of CPU cores | `4` |
| `container_memory` | Memory size in MB for container | `2048` | | `lxc_memory` | Memory size in MB for container | `2048` |
| `swap_memory` | Swap memory size in MB | `2048` | | `lxc_swap` | Swap memory size in MB | `2048` |
| `container_ipv4` | The IPv4 address | `dhcp` | | `lxc_ipv4` | The IPv4 address | `dhcp` |
| `container_ipv6` | The IPv6 address | `auto` | | `lxc_ipv6` | The IPv6 address | `auto` |
| `container_pubkey_file` | The SSH public key for authentication to root user | Creates a temp key in `/tmp` | | `lxc_pubkey_file` | The SSH public key for authentication to root user | Creates a temp key in `/tmp` |
| `container_features` | List of additional container features | `- nesting=1` | | `lxc_features` | List of additional container features | `- nesting=1` |
## Example Playbook ## Example Playbook
*Assuming Proxmox authentication variables are set*
#### Creating a new LXC ### Prerequisites
First, set up your Proxmox API connection in group vars:
```yaml ```yaml
- name: Create and start an LXC container # group_vars/all.yml
hosts: localhost proxmox_api_connection:
connection: local api_host: "10.0.1.1"
vars: api_port: 8006
- container_hostname: new-debian-container api_user: "automation@pve"
- os_template: "local:vztmpl/debian-12_amd64.tar.zst" api_token_id: "mytoken"
- container_ipv4: "10.0.0.99" api_token_secret: "{{ vault_proxmox_token }}"
roles: validate_certs: false
- role: proxmox-provision
proxmox_node: "pve01"
``` ```
#### Creating a new LXC by cloning an existing container with vmid 200 ### Creating a new LXC from template
```yaml ```yaml
- name: Create and start an LXC container - name: Create and start an LXC container
hosts: localhost hosts: localhost
connection: local connection: local
vars: vars:
- container_hostname: new-debian-container lxc_hostname: new-debian-container
- ct_id: 200 lxc_template: "local:vztmpl/debian-12_amd64.tar.zst"
- container_ipv4: "10.0.0.99" lxc_ipv4: "10.0.0.99"
roles: roles:
- role: proxmox-lxc-provision - role: proxmox-lxc-provision
``` ```
### Creating a new LXC by cloning an existing container with vmid 200
```yaml
- name: Create and start an LXC container
hosts: localhost
connection: local
vars:
lxc_hostname: new-debian-container
lxc_clone_from: 200
lxc_ipv4: "10.0.0.99"
roles:
- role: proxmox-lxc-provision
```
### Idempotent Behavior
The role now includes idempotency checking. If a container with the specified `container_vmid` already exists, the role will skip provisioning and exit gracefully.
#### Creating an LXC Container and Converting it to a Template #### Creating an LXC Container and Converting it to a Template
```yaml ```yaml

View File

@@ -1,20 +1,20 @@
--- ---
container_template: "local:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst" lxc_template: "local:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst"
container_cores: 4 lxc_cores: 4
container_memory: 2048 lxc_memory: 2048
container_swap: 2048 lxc_swap: 2048
container_storage: local-zfs lxc_storage: local-zfs
container_size: 16 lxc_size: 16
container_disk: "{{ container_storage }}:{{ container_size }}" lxc_disk: "{{ lxc_storage }}:{{ lxc_size }}"
container_ipv4: dhcp lxc_ipv4: dhcp
container_ipv6: auto lxc_ipv6: auto
container_nameserver: 10.0.0.7 lxc_nameserver: 10.0.0.7
container_gateway: 10.0.0.1 lxc_gateway: 10.0.0.1
container_pubkey_file: "~/.ssh/id_ed25519.pub" lxc_pubkey_file: "~/.ssh/id_ed25519.pub"
container_unprivileged: true lxc_unprivileged: true
container_features: lxc_features:
- nesting=1 - nesting=1
container_nvidia_gpu_mount: false lxc_nvidia_gpu_mount: false
container_tags: ["ansible-managed"] lxc_tags: ["ansible-managed"]
clone_type: full lxc_clone_type: full
container_start: true lxc_start: true

View File

@@ -1,37 +1,24 @@
--- ---
- name: Create a full clone of the container - name: Create a full clone of the container
community.general.proxmox: community.general.proxmox:
api_user: "{{ proxmox_api_user }}" <<: "{{ proxmox_api_connection }}"
api_token_id: "{{ proxmox_api_token_id }}" vmid: "{{ lxc_vmid | default(0) }}"
api_token_secret: "{{ proxmox_api_token_secret }}" clone: "{{ lxc_clone_from }}"
api_host: "{{ proxmox_api_host }}" clone_type: "{{ lxc_clone_type }}"
node: "{{ proxmox_node }}" hostname: "{{ lxc_hostname }}"
storage: "{{ lxc_storage }}"
vmid: "{{ container_vmid | default(0) }}"
clone: "{{ clone_from }}"
clone_type: "{{ clone_type }}"
hostname: "{{ container_hostname }}"
storage: "{{ container_storage }}"
register: clone_result register: clone_result
- name: Debug container_mounts
ansible.builtin.debug:
msg:
- "container_mounts: {{ container_mounts }}"
- "Type: {{ container_mounts | type_debug }}"
- "Defined: {{ container_mounts is defined }}"
- "Length: {{ container_mounts | length }}"
- name: Add bind mounts via pct - name: Add bind mounts via pct
become: yes become: yes
ansible.builtin.shell: | ansible.builtin.shell: |
pct set {{ clone_result.vmid | default(container_vmid) }} {% for key, value in container_mounts.items() %}-{{ key }} {{ value }} {% endfor %} pct set {{ clone_result.vmid | default(lxc_vmid) }} {% for key, value in lxc_mounts.items() %}-{{ key }} {{ value }} {% endfor %}
delegate_to: "{{ proxmox_api_host }}" delegate_to: "{{ proxmox_api_host }}"
when: container_mounts is defined when: lxc_mounts is defined
- name: Resize rootfs after clone - name: Resize rootfs after clone
ansible.builtin.command: ansible.builtin.command:
cmd: "pct resize {{ clone_result.vmid }} rootfs {{ container_size }}G" cmd: "pct resize {{ clone_result.vmid }} rootfs {{ lxc_size }}G"
delegate_to: "{{ proxmox_api_host }}" delegate_to: "{{ proxmox_api_host }}"
become: yes become: yes
register: resize_result register: resize_result
@@ -39,4 +26,4 @@
failed_when: failed_when:
- resize_result.rc != 0 - resize_result.rc != 0
- "'already at specified size' not in resize_result.stderr" - "'already at specified size' not in resize_result.stderr"
when: container_size is defined when: lxc_size is defined

View File

@@ -2,11 +2,7 @@
- ansible.builtin.include_tasks: stop.yaml - ansible.builtin.include_tasks: stop.yaml
- name: Convert container to template - name: Convert container to template
community.general.proxmox: community.general.proxmox:
api_user: "{{ proxmox_api_user }}" <<: "{{ proxmox_api_connection }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
api_host: "{{ proxmox_api_host }}"
node: server
state: template state: template
hostname: "{{ container_hostname }}" hostname: "{{ lxc_hostname }}"

View File

@@ -1,32 +1,25 @@
--- ---
- name: Create an LXC container - name: Create an LXC container
community.general.proxmox: community.general.proxmox:
api_host: "{{ proxmox_api_host }}" <<: "{{ proxmox_api_connection }}"
api_port: "{{ proxmox_api_port }}" vmid: "{{ lxc_vmid | default(omit) }}"
api_user: "{{ proxmox_api_user }}" hostname: "{{ lxc_hostname }}"
api_token_id: "{{ proxmox_api_token_id }}" password: "{{ lxc_password }}"
api_token_secret: "{{ proxmox_api_token_secret }}" ostemplate: "{{ lxc_template }}"
validate_certs: "{{ proxmox_api_validate_certs }}" cores: "{{ lxc_cores }}"
memory: "{{ lxc_memory }}"
node: "{{ proxmox_node }}" swap: "{{ lxc_swap }}"
vmid: "{{ container_vmid | default(omit) }}" disk: "{{ lxc_disk }}"
hostname: "{{ container_hostname }}" mounts: "{{ lxc_mounts | default(omit) }}"
password: "{{ container_password }}"
ostemplate: "{{ container_template }}"
cores: "{{ container_cores }}"
memory: "{{ container_memory }}"
swap: "{{ container_swap }}"
disk: "{{ container_disk }}"
mounts: "{{ container_mounts | default(omit) }}"
netif: > netif: >
{"net0": "name=eth0,gw={{ container_gateway }},ip={{ container_ipv4 }},ip6={{ container_ipv6 | default(omit) }},bridge=vmbr0"} {"net0": "name=eth0,gw={{ lxc_gateway }},ip={{ lxc_ipv4 }},ip6={{ lxc_ipv6 | default(omit) }},bridge=vmbr0"}
pubkey: "{{ lookup('file', container_pubkey_file) | default(omit) }}" pubkey: "{{ lookup('file', lxc_pubkey_file) | default(omit) }}"
onboot: "{{ container_onboot | default(false) }}" onboot: "{{ lxc_onboot | default(false) }}"
startup: "{{ container_startup | default(omit) }}" startup: "{{ lxc_startup | default(omit) }}"
unprivileged: "{{ container_unprivileged | default(true) }}" unprivileged: "{{ lxc_unprivileged | default(true) }}"
features: "{{ container_features | default(omit) }}" features: "{{ lxc_features | default(omit) }}"
timezone: "{{ container_timezone | default(omit) }}" timezone: "{{ lxc_timezone | default(omit) }}"
nameserver: "{{ container_nameserver | default(omit) }}" nameserver: "{{ lxc_nameserver | default(omit) }}"
state: present state: present
tags: "{{ container_tags | default(omit) }}" tags: "{{ lxc_tags | default(omit) }}"
register: container_result register: lxc_result

View File

@@ -2,15 +2,9 @@
- ansible.builtin.include_tasks: stop.yaml - ansible.builtin.include_tasks: stop.yaml
- name: Delete a container - name: Delete a container
community.general.proxmox: community.general.proxmox:
api_host: "{{ proxmox_api_host }}" <<: "{{ proxmox_api_connection }}"
api_port: "{{ proxmox_api_port }}" vmid: "{{ lxc_vmid | default(omit) }}"
api_user: "{{ proxmox_api_user }}" hostname: "{{ lxc_hostname | default(omit) }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
validate_certs: "{{ proxmox_api_validate_certs }}"
vmid: "{{ container_vmid | default(omit) }}"
hostname: "{{ container_hostname | default(omit) }}"
state: absent state: absent
register: delete_result register: delete_result
failed_when: | failed_when: |

View File

@@ -2,21 +2,21 @@
- name: Remove all existing ID mappings - name: Remove all existing ID mappings
lineinfile: lineinfile:
path: "/etc/pve/lxc/{{ container_vmid }}.conf" path: "/etc/pve/lxc/{{ lxc_vmid }}.conf"
regexp: '^lxc\.idmap:' regexp: '^lxc\.idmap:'
state: absent state: absent
when: container_id_mappings is defined when: lxc_id_mappings is defined
- name: Add ID mappings - name: Add ID mappings
blockinfile: blockinfile:
path: "/etc/pve/lxc/{{ container_vmid }}.conf" path: "/etc/pve/lxc/{{ lxc_vmid }}.conf"
block: "{{ container_id_mappings }}" block: "{{ lxc_id_mappings }}"
insertafter: EOF insertafter: EOF
when: container_id_mappings is defined when: lxc_id_mappings is defined
- name: Remove existing GPU configuration - name: Remove existing GPU configuration
lineinfile: lineinfile:
path: "/etc/pve/lxc/{{ container_vmid }}.conf" path: "/etc/pve/lxc/{{ lxc_vmid }}.conf"
regexp: "{{ item }}" regexp: "{{ item }}"
state: absent state: absent
loop: loop:
@@ -26,11 +26,11 @@
- '^lxc\.mount\.entry: /dev/nvidiactl' - '^lxc\.mount\.entry: /dev/nvidiactl'
- '^lxc\.mount\.entry: /dev/nvidia-uvm ' - '^lxc\.mount\.entry: /dev/nvidia-uvm '
- '^lxc\.mount\.entry: /dev/nvidia-uvm-tools' - '^lxc\.mount\.entry: /dev/nvidia-uvm-tools'
when: container_nvidia_gpu_mount when: lxc_nvidia_gpu_mount
- name: Add GPU device for passthrough - name: Add GPU device for passthrough
blockinfile: blockinfile:
path: /etc/pve/lxc/{{ container_vmid }}.conf path: /etc/pve/lxc/{{ lxc_vmid }}.conf
block: | block: |
lxc.cgroup2.devices.allow: c {{ gpu_device_id }}:* rwm lxc.cgroup2.devices.allow: c {{ gpu_device_id }}:* rwm
lxc.cgroup2.devices.allow: c {{ uvm_device_id }}:* rwm lxc.cgroup2.devices.allow: c {{ uvm_device_id }}:* rwm
@@ -38,6 +38,6 @@
lxc.mount.entry: /dev/nvidiactl dev/nvidiactl none bind,optional,create=file lxc.mount.entry: /dev/nvidiactl dev/nvidiactl none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm dev/nvidia-uvm none bind,optional,create=file lxc.mount.entry: /dev/nvidia-uvm dev/nvidia-uvm none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm-tools dev/nvidia-uvm-tools none bind,optional,create=file lxc.mount.entry: /dev/nvidia-uvm-tools dev/nvidia-uvm-tools none bind,optional,create=file
when: container_nvidia_gpu_mount when: lxc_nvidia_gpu_mount

View File

@@ -1,11 +1,23 @@
--- ---
- name: Container source must be defined (clone_from or container_template) - name: Check if container exists
community.general.proxmox:
<<: "{{ proxmox_api_connection }}"
vmid: "{{ lxc_vmid }}"
state: current
register: existing_container
ignore_errors: true
- name: Skip if container already exists
meta: end_host
when: existing_container is succeeded
- name: Container source must be defined (lxc_clone_from or lxc_template)
ansible.builtin.fail: ansible.builtin.fail:
msg: "Neither clone_from or container_template are defined" msg: "Neither lxc_clone_from or lxc_template are defined"
when: clone_from is undefined and container_template is undefined when: lxc_clone_from is undefined and lxc_template is undefined
- name: Clone container from another container or template, then update - name: Clone container from another container or template, then update
when: clone_from is defined when: lxc_clone_from is defined
block: block:
- name: Clone from template - name: Clone from template
ansible.builtin.include_tasks: clone.yaml ansible.builtin.include_tasks: clone.yaml
@@ -14,25 +26,25 @@
- name: Update container - name: Update container
ansible.builtin.include_tasks: update.yaml ansible.builtin.include_tasks: update.yaml
vars: vars:
container_vmid: "{{ clone_result.vmid }}" lxc_vmid: "{{ clone_result.vmid }}"
register: container_result register: lxc_result
- name: Create the new container - name: Create the new container
ansible.builtin.include_tasks: create.yaml ansible.builtin.include_tasks: create.yaml
when: container_template is defined and clone_from is undefined when: lxc_template is defined and lxc_clone_from is undefined
- name: Start the created container and wait for ssh - name: Start the created container and wait for ssh
vars: vars:
container_vmid: "{{ container_result.vmid }}" lxc_vmid: "{{ lxc_result.vmid }}"
ansible.builtin.include_tasks: "{{ item }}" ansible.builtin.include_tasks: "{{ item }}"
loop: loop:
- start.yaml - start.yaml
- wait.yaml - wait.yaml
when: container_start when: lxc_start
- name: Post clone updates - name: Post clone updates
when: clone_from is defined when: lxc_clone_from is defined
delegate_to: "{{ container_hostname }}" delegate_to: "{{ lxc_hostname }}"
block: block:
- name: Include post-clone tasks - name: Include post-clone tasks
ansible.builtin.include_tasks: post-clone.yaml ansible.builtin.include_tasks: post-clone.yaml

View File

@@ -2,9 +2,9 @@
- name: Change root password - name: Change root password
ansible.builtin.user: ansible.builtin.user:
name: root name: root
password: "{{ container_password | password_hash('sha512') }}" password: "{{ lxc_password | password_hash('sha512') }}"
update_password: always update_password: always
when: container_password is defined when: lxc_password is defined
- name: Change admin password - name: Change admin password
ansible.builtin.user: ansible.builtin.user:
@@ -22,6 +22,6 @@
- name: Remove previous entry from known hosts - name: Remove previous entry from known hosts
ansible.builtin.known_hosts: ansible.builtin.known_hosts:
name: "{{ hostvars[container_hostname]['ansible_host'] }}" name: "{{ hostvars[lxc_hostname]['ansible_host'] }}"
state: absent state: absent
delegate_to: localhost delegate_to: localhost

View File

@@ -1,14 +1,8 @@
--- ---
- name: Start the LXC container - name: Start the LXC container
community.general.proxmox: community.general.proxmox:
api_host: "{{ proxmox_api_host }}" <<: "{{ proxmox_api_connection }}"
api_port: "{{ proxmox_api_port }}" vmid: "{{ lxc_result.vmid }}"
api_user: "{{ proxmox_api_user }}"
api_token_id: "{{ proxmox_api_token_id }}"
api_token_secret: "{{ proxmox_api_token_secret }}"
validate_certs: "{{ proxmox_api_validate_certs }}"
vmid: "{{ container_result.vmid }}"
state: started state: started
register: start_result register: start_result
retries: 3 retries: 3

View File

@@ -1,13 +1,9 @@
--- ---
- name: Stop container if it is running - name: Stop container if it is running
community.general.proxmox: community.general.proxmox:
api_user: "{{ proxmox_api_user }}" <<: "{{ proxmox_api_connection }}"
api_token_id: "{{ proxmox_api_token_id }}" vmid: "{{ lxc_vmid | default(omit) }}"
api_token_secret: "{{ proxmox_api_token_secret }}" hostname: "{{ lxc_hostname | default(omit) }}"
api_host: "{{ proxmox_api_host }}"
vmid: "{{ container_vmid | default(omit) }}"
hostname: "{{ container_hostname | default(omit) }}"
state: "stopped" state: "stopped"
register: stop_result register: stop_result
failed_when: |- failed_when: |-

View File

@@ -1,29 +1,22 @@
--- ---
- name: Update an LXC container - name: Update an LXC container
community.general.proxmox: community.general.proxmox:
api_host: "{{ proxmox_api_host }}" <<: "{{ proxmox_api_connection }}"
api_port: "{{ proxmox_api_port }}" vmid: "{{ lxc_vmid }}"
api_user: "{{ proxmox_api_user }}" hostname: "{{ lxc_hostname }}"
api_token_id: "{{ proxmox_api_token_id }}" password: "{{ lxc_password | default(omit) }}" # Updating password does not work
api_token_secret: "{{ proxmox_api_token_secret }}" cores: "{{ lxc_cores }}"
validate_certs: "{{ proxmox_api_validate_certs }}" memory: "{{ lxc_memory }}"
node: "{{ proxmox_node }}" swap: "{{ lxc_swap }}"
disk: "{{ lxc_disk }}"
vmid: "{{ container_vmid }}" netif: '{"net0": "name=eth0,gw={{ lxc_gateway }},ip={{ lxc_ipv4 }},ip6={{ lxc_ipv6 | default(omit) }},bridge=vmbr0"}'
hostname: "{{ container_hostname }}" pubkey: "{{ lookup('file', lxc_pubkey_file) | default(omit) }}"
password: "{{ container_password | default(omit) }}" # Updating password does not work onboot: "{{ lxc_onboot | default(false) }}"
cores: "{{ container_cores }}" startup: "{{ lxc_startup | default(omit) }}"
memory: "{{ container_memory }}" features: "{{ lxc_features | default(omit) }}"
swap: "{{ container_swap }}" timezone: "{{ lxc_timezone | default(omit) }}"
disk: "{{ container_disk }}" nameserver: "{{ lxc_nameserver | default(omit) }}"
netif: '{"net0": "name=eth0,gw={{ container_gateway }},ip={{ container_ipv4 }},ip6={{ container_ipv6 | default(omit) }},bridge=vmbr0"}'
pubkey: "{{ lookup('file', container_pubkey_file) | default(omit) }}"
onboot: "{{ container_onboot | default(false) }}"
startup: "{{ container_startup | default(omit) }}"
features: "{{ container_features | default(omit) }}"
timezone: "{{ container_timezone | default(omit) }}"
nameserver: "{{ container_nameserver | default(omit) }}"
state: present state: present
tags: "{{ container_tags | default(omit) }}" tags: "{{ lxc_tags | default(omit) }}"
update: true update: true
register: container_result register: lxc_result

View File

@@ -7,12 +7,12 @@
- name: Debug - Check if container is in inventory - name: Debug - Check if container is in inventory
ansible.builtin.debug: ansible.builtin.debug:
msg: "Container {{ container_hostname }} found with IP: {{ hostvars[container_hostname]['ansible_host'] | default('NOT FOUND') }}" msg: "Container {{ lxc_hostname }} found with IP: {{ hostvars[lxc_hostname]['ansible_host'] | default('NOT FOUND') }}"
- name: Wait for SSH to become available - name: Wait for SSH to become available
ansible.builtin.wait_for: ansible.builtin.wait_for:
host: "{{ hostvars[container_hostname]['ansible_host'] }}" host: "{{ hostvars[lxc_hostname]['ansible_host'] }}"
port: 22 port: 22
delay: 3 delay: 3
state: started state: started