Compare commits
9 Commits
b2379e597e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5fbc4e9928 | |||
| ce7ec1b25f | |||
| 441b9fa824 | |||
| 9d7f702f2a | |||
| 6e6bed6a40 | |||
| 3a2b4b8775 | |||
| 479996612e | |||
| 570eba84e7 | |||
| 62f4a3ea73 |
36
README.md
36
README.md
@@ -4,14 +4,14 @@ Ansible collection for infrastructure management, system configuration, and virt
|
|||||||
|
|
||||||
## Roles
|
## Roles
|
||||||
|
|
||||||
### proxmox-lxc-provision
|
### proxmox_lxc_provision
|
||||||
Manages Proxmox LXC containers with comprehensive lifecycle operations.
|
Manages Proxmox LXC containers with comprehensive lifecycle operations.
|
||||||
|
|
||||||
- Create, clone, start, stop, and delete containers
|
- Create, clone, start, stop, and delete containers
|
||||||
- Template conversion and configuration editing
|
- Template conversion and configuration editing
|
||||||
- Post-provisioning tasks and health checks
|
- Post-provisioning tasks and health checks
|
||||||
|
|
||||||
### system-setup
|
### system_setup
|
||||||
Performs initial system configuration for new servers.
|
Performs initial system configuration for new servers.
|
||||||
|
|
||||||
- Creates admin user with SSH key authentication
|
- Creates admin user with SSH key authentication
|
||||||
@@ -19,14 +19,14 @@ Performs initial system configuration for new servers.
|
|||||||
- Installs essential packages
|
- Installs essential packages
|
||||||
- Optional passwordless sudo configurations
|
- Optional passwordless sudo configurations
|
||||||
|
|
||||||
### system-maintenance
|
### system_maintenance
|
||||||
Updates packages and handles maintenance across multiple distributions.
|
Updates packages and handles maintenance across multiple distributions.
|
||||||
|
|
||||||
- Multi-distribution support (Debian/Ubuntu/Alpine)
|
- Multi-distribution support (Debian/Ubuntu/Alpine)
|
||||||
- Package updates and cleanup
|
- Package updates and cleanup
|
||||||
- Automatic reboot handling when required
|
- Automatic reboot handling when required
|
||||||
|
|
||||||
### nvidia-drivers
|
### nvidia_drivers
|
||||||
Installs NVIDIA drivers and CUDA runtime with proper idempotency and error handling.
|
Installs NVIDIA drivers and CUDA runtime with proper idempotency and error handling.
|
||||||
|
|
||||||
- Supports Debian/Ubuntu with automatic OS detection
|
- Supports Debian/Ubuntu with automatic OS detection
|
||||||
@@ -43,17 +43,34 @@ ansible-galaxy collection install patrickj.infrastructure
|
|||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
|
### Proxmox API Configuration
|
||||||
|
|
||||||
|
Set up your Proxmox API connection variables in group vars:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# group_vars/all.yml
|
||||||
|
proxmox_api_host: "10.0.1.1"
|
||||||
|
proxmox_api_port: 8006
|
||||||
|
proxmox_api_user: "automation@pve"
|
||||||
|
proxmox_api_token_id: "mytoken"
|
||||||
|
proxmox_api_token_secret: "{{ vault_proxmox_token }}"
|
||||||
|
proxmox_api_validate_certs: false
|
||||||
|
proxmox_node: "pve01"
|
||||||
|
```
|
||||||
|
|
||||||
### Basic Proxmox LXC Container Setup
|
### Basic Proxmox LXC Container Setup
|
||||||
|
|
||||||
```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_vmid: 100
|
||||||
- os_template: "local:vztmpl/debian-12_amd64.tar.zst"
|
lxc_hostname: new-debian-container
|
||||||
- container_ipv4: "10.0.0.99"
|
lxc_template: "local:vztmpl/debian-12_amd64.tar.zst"
|
||||||
|
lxc_ipv4: "10.0.0.99/24"
|
||||||
roles:
|
roles:
|
||||||
- role: proxmox-provision
|
- role: proxmox_lxc_provision
|
||||||
|
|
||||||
- name: Configure the LXC container
|
- name: Configure the LXC container
|
||||||
hosts: new-debian-container
|
hosts: new-debian-container
|
||||||
@@ -64,7 +81,7 @@ ansible-galaxy collection install patrickj.infrastructure
|
|||||||
vars:
|
vars:
|
||||||
password: "{{ admin_password }}"
|
password: "{{ admin_password }}"
|
||||||
ssh_pubkey_file: "~/.ssh/id_rsa.pub"
|
ssh_pubkey_file: "~/.ssh/id_rsa.pub"
|
||||||
|
|
||||||
- include_role:
|
- include_role:
|
||||||
name: patrickj.infrastructure.nvidia_drivers
|
name: patrickj.infrastructure.nvidia_drivers
|
||||||
vars:
|
vars:
|
||||||
@@ -77,6 +94,7 @@ ansible-galaxy collection install patrickj.infrastructure
|
|||||||
- Ansible >= 2.12
|
- Ansible >= 2.12
|
||||||
- Root/sudo privileges on target hosts
|
- Root/sudo privileges on target hosts
|
||||||
- community.general collection
|
- community.general collection
|
||||||
|
- community.proxmox collection
|
||||||
- ansible.posix collection
|
- ansible.posix collection
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ tags:
|
|||||||
- maintenance
|
- maintenance
|
||||||
dependencies:
|
dependencies:
|
||||||
"community.general": ">=1.0.0"
|
"community.general": ">=1.0.0"
|
||||||
|
"community.proxmox": ">=1.0.0"
|
||||||
"ansible.posix": ">=1.0.0"
|
"ansible.posix": ">=1.0.0"
|
||||||
repository: https://git.jaroszew.ski/ansible/ansible-collection-infrastructure
|
repository: https://git.jaroszew.ski/ansible/ansible-collection-infrastructure
|
||||||
documentation: https://git.jaroszew.ski/ansible/ansible-collection-infrastructure/README.md
|
documentation: https://git.jaroszew.ski/ansible/ansible-collection-infrastructure/README.md
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Installs NVIDIA drivers and CUDA runtime on Debian/Ubuntu systems with proper id
|
|||||||
```yaml
|
```yaml
|
||||||
- name: Install NVIDIA drivers with kernel modules
|
- name: Install NVIDIA drivers with kernel modules
|
||||||
include_role:
|
include_role:
|
||||||
name: nvidia-drivers
|
name: nvidia_drivers
|
||||||
vars:
|
vars:
|
||||||
nvidia_install_kernel_modules: true
|
nvidia_install_kernel_modules: true
|
||||||
nvidia_open_source_drivers: false
|
nvidia_open_source_drivers: false
|
||||||
@@ -37,7 +37,7 @@ Installs NVIDIA drivers and CUDA runtime on Debian/Ubuntu systems with proper id
|
|||||||
```yaml
|
```yaml
|
||||||
- name: Install NVIDIA userspace libraries
|
- name: Install NVIDIA userspace libraries
|
||||||
include_role:
|
include_role:
|
||||||
name: nvidia-drivers
|
name: nvidia_drivers
|
||||||
vars:
|
vars:
|
||||||
nvidia_install_kernel_modules: false
|
nvidia_install_kernel_modules: false
|
||||||
```
|
```
|
||||||
@@ -46,7 +46,7 @@ Installs NVIDIA drivers and CUDA runtime on Debian/Ubuntu systems with proper id
|
|||||||
```yaml
|
```yaml
|
||||||
- name: Install NVIDIA with extras
|
- name: Install NVIDIA with extras
|
||||||
include_role:
|
include_role:
|
||||||
name: nvidia-drivers
|
name: nvidia_drivers
|
||||||
vars:
|
vars:
|
||||||
nvidia_install_kernel_modules: true
|
nvidia_install_kernel_modules: true
|
||||||
nvidia_optional_packages:
|
nvidia_optional_packages:
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
# Ansible Role: proxmox-lxc-provision
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
This Ansible role manages the provision of LXC containers and templates on a Proxmox host. By default the role will create and start an LXC container. It allows creating a new container from a [container image](https://pve.proxmox.com/wiki/Linux_Container#pct_container_images) or cloning an existing container or template container.
|
|
||||||
|
|
||||||
It also includes tasks which may be used individually:
|
|
||||||
- `clone.yaml`: Creates a new LXC container by cloning another container or template
|
|
||||||
- `convert.yaml`: Converts an LXC container to a template
|
|
||||||
- `create.yaml`: Creates a new LXC container
|
|
||||||
- `delete.yaml`: Deletes an LXC container given its vmid or hostname
|
|
||||||
- `start.yaml`: Starts an LXC container
|
|
||||||
- `stop.yaml`: Stops an LXC container
|
|
||||||
- `update.yaml`: Updates an existing LXC container
|
|
||||||
- `wait.yaml`: Waits for SSH to be available on the container
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- Ansible 2.9 or higher
|
|
||||||
- Python 3.6 or higher
|
|
||||||
- requests
|
|
||||||
- proxmoxer
|
|
||||||
- passlib
|
|
||||||
|
|
||||||
## Role Variables
|
|
||||||
|
|
||||||
### Required Variables
|
|
||||||
|
|
||||||
| Variable | Description | Example |
|
|
||||||
|----------|-------------|---------|
|
|
||||||
| `container_template` | The OS template to create the LXC from. Mutually exclusive with `clone_from`| `local:vztmpl/debian-12_amd64.tar.zst` |
|
|
||||||
| `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
|
|
||||||
|
|
||||||
**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 |
|
|
||||||
|----------|-------------|---------|
|
|
||||||
| `proxmox_api_user` | The username for Proxmox authentication, typically in format `username@realm` | `ansible@pve` |
|
|
||||||
| `proxmox_api_token_id` | The API token ID used for authentication | `token` |
|
|
||||||
| `proxmox_api_token_secret` | The secret key associated with the API token | `xxx-yyy-zzz` (should be stored securely) |
|
|
||||||
| `proxmox_api_host` | The IP address or hostname of the Proxmox server | `192.168.1.10` |
|
|
||||||
| `proxmox_api_port` | The port on which the Proxmox API is listening | `8006` |
|
|
||||||
| `proxmox_node` | The name of the Proxmox node to target | `server1` |
|
|
||||||
| `proxmox_api_validate_certs` | Whether to validate SSL certificates (set to false for self-signed certs) | `false` |
|
|
||||||
|
|
||||||
|
|
||||||
### Optional Variables
|
|
||||||
|
|
||||||
| Variable | Description | Default |
|
|
||||||
|----------|-------------|---------|
|
|
||||||
| `lxc_clone_type` | Only use with `lxc_clone_from`. Supports `full` and `linked` clones. | `full` |
|
|
||||||
| `lxc_storage` | Target storage for the container | `local-zfs` |
|
|
||||||
| `lxc_disk` | The target storage and storage size | `local-zfs:16` |
|
|
||||||
| `lxc_password` | The password for the root account | `password123` |
|
|
||||||
| `lxc_cores` | The number of CPU cores | `4` |
|
|
||||||
| `lxc_memory` | Memory size in MB for container | `2048` |
|
|
||||||
| `lxc_swap` | Swap memory size in MB | `2048` |
|
|
||||||
| `lxc_ipv4` | The IPv4 address | `dhcp` |
|
|
||||||
| `lxc_ipv6` | The IPv6 address | `auto` |
|
|
||||||
| `lxc_pubkey_file` | The SSH public key for authentication to root user | Creates a temp key in `/tmp` |
|
|
||||||
| `lxc_features` | List of additional container features | `- nesting=1` |
|
|
||||||
|
|
||||||
|
|
||||||
## Example Playbook
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
First, set up your Proxmox API connection in group vars:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# group_vars/all.yml
|
|
||||||
proxmox_api_connection:
|
|
||||||
api_host: "10.0.1.1"
|
|
||||||
api_port: 8006
|
|
||||||
api_user: "automation@pve"
|
|
||||||
api_token_id: "mytoken"
|
|
||||||
api_token_secret: "{{ vault_proxmox_token }}"
|
|
||||||
validate_certs: false
|
|
||||||
|
|
||||||
proxmox_node: "pve01"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Creating a new LXC from template
|
|
||||||
```yaml
|
|
||||||
- name: Create and start an LXC container
|
|
||||||
hosts: localhost
|
|
||||||
connection: local
|
|
||||||
vars:
|
|
||||||
lxc_hostname: new-debian-container
|
|
||||||
lxc_template: "local:vztmpl/debian-12_amd64.tar.zst"
|
|
||||||
lxc_ipv4: "10.0.0.99"
|
|
||||||
roles:
|
|
||||||
- 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
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
- name: Create and start an LXC container
|
|
||||||
hosts: localhost
|
|
||||||
connection: local
|
|
||||||
vars:
|
|
||||||
- container_hostname: "{{ container_hostname }}"
|
|
||||||
- os_template: "local:vztmpl/debian-12_amd64.tar.zst"
|
|
||||||
- container_ipv4: "10.0.0.99"
|
|
||||||
roles:
|
|
||||||
- role: proxmox-lxc-provision
|
|
||||||
|
|
||||||
# Run configuration tasks on the container
|
|
||||||
# ...
|
|
||||||
|
|
||||||
- name: Convert the created container to a template
|
|
||||||
hosts: localhost
|
|
||||||
vars:
|
|
||||||
container_hostname: "{{ container_hostname }}"
|
|
||||||
tasks:
|
|
||||||
- include_role:
|
|
||||||
name: proxmox-lxc-provision
|
|
||||||
tasks_from: convert
|
|
||||||
```
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Query Proxmox for existing LXCs
|
|
||||||
community.proxmox.proxmox_lxc_info:
|
|
||||||
<<: "{{ proxmox_api_connection }}"
|
|
||||||
register: proxmox_lxcs
|
|
||||||
|
|
||||||
- name: Check if LXC with hostname already exists
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
lxc_exists: >-
|
|
||||||
{{
|
|
||||||
proxmox_lxcs.proxmox_lxcs
|
|
||||||
| selectattr('name', 'equalto', lxc_hostname)
|
|
||||||
| list
|
|
||||||
| length > 0
|
|
||||||
}}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
---
|
|
||||||
- ansible.builtin.include_tasks: stop.yaml
|
|
||||||
- name: Convert container to template
|
|
||||||
community.general.proxmox:
|
|
||||||
<<: "{{ proxmox_api_connection }}"
|
|
||||||
|
|
||||||
state: template
|
|
||||||
hostname: "{{ lxc_hostname }}"
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
---
|
|
||||||
- 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:
|
|
||||||
msg: "Neither lxc_clone_from or lxc_template are defined"
|
|
||||||
when: lxc_clone_from is undefined and lxc_template is undefined
|
|
||||||
|
|
||||||
- name: Clone container from another container or template, then update
|
|
||||||
when: lxc_clone_from is defined
|
|
||||||
block:
|
|
||||||
- name: Clone from template
|
|
||||||
ansible.builtin.include_tasks: clone.yaml
|
|
||||||
register: clone_result
|
|
||||||
|
|
||||||
- name: Update container
|
|
||||||
ansible.builtin.include_tasks: update.yaml
|
|
||||||
vars:
|
|
||||||
lxc_vmid: "{{ clone_result.vmid }}"
|
|
||||||
register: lxc_result
|
|
||||||
|
|
||||||
- name: Create the new container
|
|
||||||
ansible.builtin.include_tasks: create.yaml
|
|
||||||
when: lxc_template is defined and lxc_clone_from is undefined
|
|
||||||
|
|
||||||
- name: Start the created container and wait for ssh
|
|
||||||
vars:
|
|
||||||
lxc_vmid: "{{ lxc_result.vmid }}"
|
|
||||||
ansible.builtin.include_tasks: "{{ item }}"
|
|
||||||
loop:
|
|
||||||
- start.yaml
|
|
||||||
- wait.yaml
|
|
||||||
when: lxc_start
|
|
||||||
|
|
||||||
- name: Post clone updates
|
|
||||||
when: lxc_clone_from is defined
|
|
||||||
delegate_to: "{{ lxc_hostname }}"
|
|
||||||
block:
|
|
||||||
- name: Include post-clone tasks
|
|
||||||
ansible.builtin.include_tasks: post-clone.yaml
|
|
||||||
187
roles/proxmox_lxc_provision/README.md
Executable file
187
roles/proxmox_lxc_provision/README.md
Executable file
@@ -0,0 +1,187 @@
|
|||||||
|
# Ansible Role: proxmox_lxc_provision
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This Ansible role manages the provision of LXC containers and templates on a Proxmox host. By default the role will create and start an LXC container. It allows creating a new container from a [container image](https://pve.proxmox.com/wiki/Linux_Container#pct_container_images) or cloning an existing container or template container.
|
||||||
|
|
||||||
|
It also includes tasks which may be used individually:
|
||||||
|
- `clone.yml`: Creates a new LXC container by cloning another container or template
|
||||||
|
- `convert.yml`: Converts an LXC container to a template
|
||||||
|
- `create.yml`: Creates a new LXC container
|
||||||
|
- `delete.yml`: Deletes an LXC container given its vmid or hostname
|
||||||
|
- `start.yml`: Starts an LXC container
|
||||||
|
- `stop.yml`: Stops an LXC container
|
||||||
|
- `update.yml`: Updates an existing LXC container
|
||||||
|
- `wait.yml`: Waits for SSH to be available on the container
|
||||||
|
- `check-exists.yml`: Checks if an LXC exists by `lxc_vmid` or `lxc_hostname`
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Ansible 2.12 or higher
|
||||||
|
- Python 3.6 or higher
|
||||||
|
- requests
|
||||||
|
- proxmoxer
|
||||||
|
- passlib
|
||||||
|
|
||||||
|
## Role Variables
|
||||||
|
|
||||||
|
### Required Proxmox API Variables
|
||||||
|
|
||||||
|
| Variable | Description | Example |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `proxmox_api_host` | The IP address or hostname of the Proxmox server | `192.168.1.10` |
|
||||||
|
| `proxmox_api_user` | The username for Proxmox authentication, typically in format `username@realm` | `ansible@pve` |
|
||||||
|
| `proxmox_api_token_id` | The API token ID used for authentication | `token` |
|
||||||
|
| `proxmox_api_token_secret` | The secret key associated with the API token | `xxx-yyy-zzz` |
|
||||||
|
| `proxmox_node` | The name of the Proxmox node to target | `pve01` |
|
||||||
|
|
||||||
|
### Optional Proxmox API Variables
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `proxmox_api_port` | The port on which the Proxmox API is listening | `8006` |
|
||||||
|
| `proxmox_api_validate_certs` | Whether to validate SSL certificates | `false` |
|
||||||
|
| `proxmox_delegate_host` | Inventory hostname for delegated tasks (pct commands). Use this to inherit `ansible_become_password` from inventory. | `{{ proxmox_api_host }}` |
|
||||||
|
|
||||||
|
### Required Container Variables
|
||||||
|
|
||||||
|
| Variable | Description | Example |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `lxc_template` | The OS template to create the LXC from. Mutually exclusive with `lxc_clone_from` | `local:vztmpl/debian-12_amd64.tar.zst` |
|
||||||
|
| `lxc_clone_from` | The vmid of the container or template to clone. Mutually exclusive with `lxc_template` | `201` |
|
||||||
|
| `lxc_hostname` | The hostname for the container | `my-container` |
|
||||||
|
| `lxc_vmid` | The VM ID for the container | `100` |
|
||||||
|
|
||||||
|
### Optional Container Variables
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `lxc_clone_type` | Clone type when using `lxc_clone_from` | `full` |
|
||||||
|
| `lxc_storage` | Target storage for the container | `local-zfs` |
|
||||||
|
| `lxc_size` | Disk size in GB | `16` |
|
||||||
|
| `lxc_disk` | The target storage and storage size | `local-zfs:16` |
|
||||||
|
| `lxc_password` | The password for the root account | - |
|
||||||
|
| `lxc_cores` | The number of CPU cores | `4` |
|
||||||
|
| `lxc_memory` | Memory size in MB | `2048` |
|
||||||
|
| `lxc_swap` | Swap memory size in MB | `2048` |
|
||||||
|
| `lxc_ipv4` | The IPv4 address | `dhcp` |
|
||||||
|
| `lxc_ipv6` | The IPv6 address | `auto` |
|
||||||
|
| `lxc_gateway` | The default gateway | `10.0.0.1` |
|
||||||
|
| `lxc_nameserver` | DNS nameserver | `10.0.0.7` |
|
||||||
|
| `lxc_pubkey_file` | Path to SSH public key file | `~/.ssh/id_ed25519.pub` |
|
||||||
|
| `lxc_features` | List of container features | `["nesting=1"]` |
|
||||||
|
| `lxc_tags` | Tags for the container | `["ansible-managed"]` |
|
||||||
|
| `lxc_start` | Start container after creation | `true` |
|
||||||
|
|
||||||
|
|
||||||
|
## Example Playbook
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
Set up your Proxmox API connection variables in group vars:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# group_vars/all.yml
|
||||||
|
proxmox_api_host: "10.0.1.1"
|
||||||
|
proxmox_api_port: 8006
|
||||||
|
proxmox_api_user: "automation@pve"
|
||||||
|
proxmox_api_token_id: "mytoken"
|
||||||
|
proxmox_api_token_secret: "{{ vault_proxmox_token }}"
|
||||||
|
proxmox_api_validate_certs: false
|
||||||
|
proxmox_node: "pve01"
|
||||||
|
proxmox_delegate_host: "proxmox_server" # inventory hostname for become_password
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating a new LXC from template
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Create and start an LXC container
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
vars:
|
||||||
|
lxc_vmid: 100
|
||||||
|
lxc_hostname: new-debian-container
|
||||||
|
lxc_template: "local:vztmpl/debian-12_amd64.tar.zst"
|
||||||
|
lxc_ipv4: "10.0.0.99/24"
|
||||||
|
roles:
|
||||||
|
- role: proxmox_lxc_provision
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating a new LXC by cloning an existing container
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Clone an LXC container
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
vars:
|
||||||
|
lxc_vmid: 101
|
||||||
|
lxc_hostname: cloned-container
|
||||||
|
lxc_clone_from: 200
|
||||||
|
lxc_ipv4: "10.0.0.100/24"
|
||||||
|
roles:
|
||||||
|
- role: proxmox_lxc_provision
|
||||||
|
```
|
||||||
|
|
||||||
|
### Idempotent Behavior
|
||||||
|
|
||||||
|
The role includes idempotency checking. If a container with the specified `lxc_vmid` or `lxc_hostname` already exists, the role will skip provisioning and exit gracefully. Sets `lxc_exists` fact for use in subsequent tasks.
|
||||||
|
|
||||||
|
### Using Standalone Tasks
|
||||||
|
|
||||||
|
When using individual task files via `tasks_from`, you must set `module_defaults` at the play level since the tasks bypass the role's main entry point:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Convert container to a template
|
||||||
|
hosts: localhost
|
||||||
|
module_defaults:
|
||||||
|
community.proxmox.proxmox:
|
||||||
|
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 }}"
|
||||||
|
node: "{{ proxmox_node }}"
|
||||||
|
vars:
|
||||||
|
lxc_hostname: "{{ lxc_hostname }}"
|
||||||
|
tasks:
|
||||||
|
- include_role:
|
||||||
|
name: proxmox_lxc_provision
|
||||||
|
tasks_from: convert
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating an LXC Container and Converting it to a Template
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
- name: Create and start an LXC container
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
vars:
|
||||||
|
lxc_vmid: "{{ lxc_vmid }}"
|
||||||
|
lxc_hostname: "{{ lxc_hostname }}"
|
||||||
|
lxc_template: "local:vztmpl/debian-12_amd64.tar.zst"
|
||||||
|
lxc_ipv4: "10.0.0.99/24"
|
||||||
|
roles:
|
||||||
|
- role: proxmox_lxc_provision
|
||||||
|
|
||||||
|
# Run configuration tasks on the container...
|
||||||
|
|
||||||
|
- name: Convert the created container to a template
|
||||||
|
hosts: localhost
|
||||||
|
module_defaults:
|
||||||
|
community.proxmox.proxmox:
|
||||||
|
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 }}"
|
||||||
|
node: "{{ proxmox_node }}"
|
||||||
|
vars:
|
||||||
|
lxc_hostname: "{{ lxc_hostname }}"
|
||||||
|
tasks:
|
||||||
|
- include_role:
|
||||||
|
name: proxmox_lxc_provision
|
||||||
|
tasks_from: convert
|
||||||
|
```
|
||||||
@@ -1,4 +1,11 @@
|
|||||||
---
|
---
|
||||||
|
# Proxmox API connection defaults (optional)
|
||||||
|
proxmox_api_port: 8006
|
||||||
|
proxmox_api_validate_certs: false
|
||||||
|
# Host to delegate pct commands to (use inventory hostname for become_password to work)
|
||||||
|
proxmox_delegate_host: "{{ proxmox_api_host }}"
|
||||||
|
|
||||||
|
# LXC defaults
|
||||||
lxc_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"
|
||||||
lxc_cores: 4
|
lxc_cores: 4
|
||||||
lxc_memory: 2048
|
lxc_memory: 2048
|
||||||
14
roles/proxmox_lxc_provision/tasks/check-exists.yml
Executable file
14
roles/proxmox_lxc_provision/tasks/check-exists.yml
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
- name: Query Proxmox for existing LXCs
|
||||||
|
community.proxmox.proxmox_vm_info:
|
||||||
|
type: lxc
|
||||||
|
register: proxmox_lxcs
|
||||||
|
|
||||||
|
- name: Check if LXC already exists
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
lxc_exists: >-
|
||||||
|
{{
|
||||||
|
(lxc_vmid is defined and lxc_vmid | int in (proxmox_lxcs.proxmox_vms | map(attribute='vmid') | list))
|
||||||
|
or
|
||||||
|
(lxc_hostname is defined and (proxmox_lxcs.proxmox_vms | selectattr('name', 'equalto', lxc_hostname) | list | length > 0))
|
||||||
|
}}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Create a full clone of the container
|
- name: Create a full clone of the container
|
||||||
community.general.proxmox:
|
community.proxmox.proxmox:
|
||||||
<<: "{{ proxmox_api_connection }}"
|
|
||||||
vmid: "{{ lxc_vmid | default(0) }}"
|
vmid: "{{ lxc_vmid | default(0) }}"
|
||||||
clone: "{{ lxc_clone_from }}"
|
clone: "{{ lxc_clone_from }}"
|
||||||
clone_type: "{{ lxc_clone_type }}"
|
clone_type: "{{ lxc_clone_type }}"
|
||||||
@@ -13,17 +12,17 @@
|
|||||||
become: yes
|
become: yes
|
||||||
ansible.builtin.shell: |
|
ansible.builtin.shell: |
|
||||||
pct set {{ clone_result.vmid | default(lxc_vmid) }} {% for key, value in lxc_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_delegate_host }}"
|
||||||
when: lxc_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 {{ lxc_size }}G"
|
cmd: "pct resize {{ clone_result.vmid }} rootfs {{ lxc_size }}G"
|
||||||
delegate_to: "{{ proxmox_api_host }}"
|
delegate_to: "{{ proxmox_delegate_host }}"
|
||||||
become: yes
|
become: yes
|
||||||
register: resize_result
|
register: resize_result
|
||||||
changed_when: resize_result.rc == 0 and 'already at specified size' not in resize_result.stderr
|
changed_when: resize_result.rc == 0 and 'already at specified size' not in resize_result.stderr
|
||||||
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: lxc_size is defined
|
when: lxc_size is defined
|
||||||
7
roles/proxmox_lxc_provision/tasks/convert.yml
Executable file
7
roles/proxmox_lxc_provision/tasks/convert.yml
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
- ansible.builtin.include_tasks: stop.yml
|
||||||
|
|
||||||
|
- name: Convert container to template
|
||||||
|
community.proxmox.proxmox:
|
||||||
|
hostname: "{{ lxc_hostname }}"
|
||||||
|
state: template
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Create an LXC container
|
- name: Create an LXC container
|
||||||
community.general.proxmox:
|
community.proxmox.proxmox:
|
||||||
<<: "{{ proxmox_api_connection }}"
|
|
||||||
vmid: "{{ lxc_vmid | default(omit) }}"
|
vmid: "{{ lxc_vmid | default(omit) }}"
|
||||||
hostname: "{{ lxc_hostname }}"
|
hostname: "{{ lxc_hostname }}"
|
||||||
password: "{{ lxc_password }}"
|
password: "{{ lxc_password }}"
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
- ansible.builtin.include_tasks: stop.yaml
|
- ansible.builtin.include_tasks: stop.yml
|
||||||
|
|
||||||
- name: Delete a container
|
- name: Delete a container
|
||||||
community.general.proxmox:
|
community.proxmox.proxmox:
|
||||||
<<: "{{ proxmox_api_connection }}"
|
|
||||||
vmid: "{{ lxc_vmid | default(omit) }}"
|
vmid: "{{ lxc_vmid | default(omit) }}"
|
||||||
hostname: "{{ lxc_hostname | default(omit) }}"
|
hostname: "{{ lxc_hostname | default(omit) }}"
|
||||||
state: absent
|
state: absent
|
||||||
63
roles/proxmox_lxc_provision/tasks/main.yml
Executable file
63
roles/proxmox_lxc_provision/tasks/main.yml
Executable file
@@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
- name: Proxmox LXC provision
|
||||||
|
module_defaults:
|
||||||
|
community.proxmox.proxmox: &proxmox_defaults
|
||||||
|
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 }}"
|
||||||
|
node: "{{ proxmox_node }}"
|
||||||
|
community.proxmox.proxmox_vm_info: *proxmox_defaults
|
||||||
|
block:
|
||||||
|
- name: Check if container exists
|
||||||
|
ansible.builtin.include_tasks:
|
||||||
|
file: check-exists.yml
|
||||||
|
|
||||||
|
- name: Skip if container already exists
|
||||||
|
meta: end_host
|
||||||
|
when: lxc_exists | bool
|
||||||
|
|
||||||
|
- name: Container source must be defined (lxc_clone_from or lxc_template)
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: "Neither lxc_clone_from or lxc_template are defined"
|
||||||
|
when: lxc_clone_from is undefined and lxc_template is undefined
|
||||||
|
|
||||||
|
- name: Clone container from another container or template, then update
|
||||||
|
when: lxc_clone_from is defined
|
||||||
|
block:
|
||||||
|
- name: Clone from template
|
||||||
|
ansible.builtin.include_tasks:
|
||||||
|
file: clone.yml
|
||||||
|
register: clone_result
|
||||||
|
|
||||||
|
- name: Update container
|
||||||
|
ansible.builtin.include_tasks:
|
||||||
|
file: update.yml
|
||||||
|
vars:
|
||||||
|
lxc_vmid: "{{ clone_result.vmid }}"
|
||||||
|
register: lxc_result
|
||||||
|
|
||||||
|
- name: Create the new container
|
||||||
|
ansible.builtin.include_tasks:
|
||||||
|
file: create.yml
|
||||||
|
when: lxc_template is defined and lxc_clone_from is undefined
|
||||||
|
|
||||||
|
- name: Start the created container and wait for ssh
|
||||||
|
vars:
|
||||||
|
lxc_vmid: "{{ lxc_result.vmid }}"
|
||||||
|
ansible.builtin.include_tasks:
|
||||||
|
file: "{{ item }}"
|
||||||
|
loop:
|
||||||
|
- start.yml
|
||||||
|
- wait.yml
|
||||||
|
when: lxc_start
|
||||||
|
|
||||||
|
- name: Post clone updates
|
||||||
|
when: lxc_clone_from is defined
|
||||||
|
delegate_to: "{{ lxc_hostname }}"
|
||||||
|
block:
|
||||||
|
- name: Include post-clone tasks
|
||||||
|
ansible.builtin.include_tasks:
|
||||||
|
file: post-clone.yml
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
- name: Regenerate SSH host keys
|
- name: Regenerate SSH host keys
|
||||||
ansible.builtin.include_role:
|
ansible.builtin.include_role:
|
||||||
name: system-setup
|
name: system_setup
|
||||||
tasks_from: ssh
|
tasks_from: ssh
|
||||||
vars:
|
vars:
|
||||||
regenerate_ssh_keys: true
|
regenerate_ssh_keys: true
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Start the LXC container
|
- name: Start the LXC container
|
||||||
community.general.proxmox:
|
community.proxmox.proxmox:
|
||||||
<<: "{{ proxmox_api_connection }}"
|
|
||||||
vmid: "{{ lxc_result.vmid }}"
|
vmid: "{{ lxc_result.vmid }}"
|
||||||
state: started
|
state: started
|
||||||
register: start_result
|
register: start_result
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
---
|
---
|
||||||
- name: Stop container if it is running
|
- name: Stop container if it is running
|
||||||
community.general.proxmox:
|
community.proxmox.proxmox:
|
||||||
<<: "{{ proxmox_api_connection }}"
|
|
||||||
vmid: "{{ lxc_vmid | default(omit) }}"
|
vmid: "{{ lxc_vmid | default(omit) }}"
|
||||||
hostname: "{{ lxc_hostname | default(omit) }}"
|
hostname: "{{ lxc_hostname | default(omit) }}"
|
||||||
state: "stopped"
|
state: stopped
|
||||||
register: stop_result
|
register: stop_result
|
||||||
failed_when: |-
|
failed_when: |-
|
||||||
stop_result.failed and
|
stop_result.failed and
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
---
|
---
|
||||||
- name: Update an LXC container
|
- name: Update an LXC container
|
||||||
community.general.proxmox:
|
community.proxmox.proxmox:
|
||||||
<<: "{{ proxmox_api_connection }}"
|
|
||||||
vmid: "{{ lxc_vmid }}"
|
vmid: "{{ lxc_vmid }}"
|
||||||
hostname: "{{ lxc_hostname }}"
|
hostname: "{{ lxc_hostname }}"
|
||||||
password: "{{ lxc_password | default(omit) }}" # Updating password does not work
|
password: "{{ lxc_password | default(omit) }}"
|
||||||
cores: "{{ lxc_cores }}"
|
cores: "{{ lxc_cores }}"
|
||||||
memory: "{{ lxc_memory }}"
|
memory: "{{ lxc_memory }}"
|
||||||
swap: "{{ lxc_swap }}"
|
swap: "{{ lxc_swap }}"
|
||||||
@@ -20,7 +20,7 @@ Updates packages and handles system maintenance tasks across multiple distributi
|
|||||||
```yaml
|
```yaml
|
||||||
- name: Perform system maintenance
|
- name: Perform system maintenance
|
||||||
include_role:
|
include_role:
|
||||||
name: system-maintenance
|
name: system_maintenance
|
||||||
```
|
```
|
||||||
|
|
||||||
## What It Does
|
## What It Does
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
- name: Use appropriate tasks for given distribution
|
- name: Use appropriate tasks for given distribution
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
task_distro_file: "{{ ansible_os_family | lower }}.yaml"
|
task_distro_file: "{{ ansible_os_family | lower }}.yml"
|
||||||
|
|
||||||
- name: Verify that the distribution is supported
|
- name: Verify that the distribution is supported
|
||||||
become: false
|
become: false
|
||||||
@@ -9,7 +9,7 @@ Performs initial system configuration including user creation, SSH hardening, an
|
|||||||
- Installs essential packages
|
- Installs essential packages
|
||||||
- Optional passwordless sudo
|
- Optional passwordless sudo
|
||||||
- Optional SSH host key regeneration
|
- Optional SSH host key regeneration
|
||||||
- System package updates (via system-maintenance role)
|
- System package updates (via system_maintenance role)
|
||||||
|
|
||||||
## Variables
|
## Variables
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ ssh_pubkey_file: "/path/to/your/public/key.pub"
|
|||||||
```yaml
|
```yaml
|
||||||
- name: Initial system setup
|
- name: Initial system setup
|
||||||
include_role:
|
include_role:
|
||||||
name: system-setup
|
name: system_setup
|
||||||
vars:
|
vars:
|
||||||
password: "{{ admin_password }}"
|
password: "{{ admin_password }}"
|
||||||
ssh_pubkey_file: "~/.ssh/id_rsa.pub"
|
ssh_pubkey_file: "~/.ssh/id_rsa.pub"
|
||||||
@@ -48,7 +48,7 @@ ssh_pubkey_file: "/path/to/your/public/key.pub"
|
|||||||
```yaml
|
```yaml
|
||||||
- name: System setup with custom user
|
- name: System setup with custom user
|
||||||
include_role:
|
include_role:
|
||||||
name: system-setup
|
name: system_setup
|
||||||
vars:
|
vars:
|
||||||
username: myuser
|
username: myuser
|
||||||
password: "{{ user_password }}"
|
password: "{{ user_password }}"
|
||||||
@@ -65,7 +65,7 @@ ssh_pubkey_file: "/path/to/your/public/key.pub"
|
|||||||
|
|
||||||
## What It Does
|
## What It Does
|
||||||
|
|
||||||
1. **System Updates** - Calls system-maintenance role for package updates
|
1. **System Updates** - Calls system_maintenance role for package updates
|
||||||
2. **Package Installation** - Installs packages from `extra_packages` list
|
2. **Package Installation** - Installs packages from `extra_packages` list
|
||||||
3. **User Creation** - Creates user with password and sudo access
|
3. **User Creation** - Creates user with password and sudo access
|
||||||
4. **SSH Key Setup** - Configures authorized keys for the user
|
4. **SSH Key Setup** - Configures authorized keys for the user
|
||||||
@@ -76,7 +76,7 @@ ssh_pubkey_file: "/path/to/your/public/key.pub"
|
|||||||
|
|
||||||
- Root privileges
|
- Root privileges
|
||||||
- SSH public key file accessible to Ansible
|
- SSH public key file accessible to Ansible
|
||||||
- system-maintenance role (dependency)
|
- system_maintenance role (dependency)
|
||||||
|
|
||||||
## Security Notes
|
## Security Notes
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Upgrade and update packages
|
# Upgrade and update packages
|
||||||
- include_role:
|
- include_role:
|
||||||
name: system-maintenance
|
name: system_maintenance
|
||||||
|
|
||||||
# Install extra packages
|
# Install extra packages
|
||||||
- include_tasks: extra-packages.yaml
|
- include_tasks: extra-packages.yaml
|
||||||
Reference in New Issue
Block a user