Skip to content

Ansible Collection Integration

The PiVirt Ansible Collection (pilab.pivirt) provides automated playbooks and modules for orchestrating virtual machine lifecycles, storage pools, network bridges, and multi-node clusters.

Terminal window
# Install from Ansible Galaxy
ansible-galaxy collection install pilab.pivirt
# Install from source
git clone https://github.com/pilab-cloud/ansible-collection-pivirt
cd ansible-collection-pivirt
ansible-galaxy collection build
ansible-galaxy collection install pilab-pivirt-1.0.0.tar.gz
requirements.yml
collections:
- name: pilab.pivirt
version: ">=1.0.0"
Terminal window
ansible-galaxy install -r requirements.yml
inventory.yml
all:
children:
pivirt:
hosts:
agent.pilab.hu:
ansible_connection: local
pivirt_endpoint: "https://agent.pilab.hu:8443"
pivirt_ca_file: "~/.config/pvcli/ca.crt"
pivirt_cert_file: "~/.config/pvcli/client.crt"
pivirt_key_file: "~/.config/pvcli/client.key"
pivirt_namespace: "production"
# ansible.cfg
[defaults]
collections_paths = ~/.ansible/collections:/usr/share/ansible/collections
[pivirt]
endpoint = https://agent.pilab.hu:8443
ca_file = ~/.config/pvcli/ca.crt
cert_file = ~/.config/pvcli/client.crt
key_file = ~/.config/pvcli/client.key
namespace = production
- name: Create web server VM
pilab.pivirt.vm:
name: web-01
namespace: production
state: present
cpu:
cores: 2
model: host-passthrough
memory:
size: 4Gi
disks:
- name: root
size: 20Gi
pool: default
bus: virtio
boot_order: 1
nics:
- name: eth0
network: virbr0
model: virtio
cloud_init:
user_data: "{{ lookup('file', 'cloud-init.yaml') }}"
labels:
app: web
env: production
- name: Start VM
pilab.pivirt.vm:
name: web-01
namespace: production
state: running
- name: Stop VM
pilab.pivirt.vm:
name: web-01
namespace: production
state: stopped
- name: Restart VM
pilab.pivirt.vm:
name: web-01
namespace: production
state: restarted
- name: Delete VM
pilab.pivirt.vm:
name: web-01
namespace: production
state: absent
cascade: true # Also delete disks
- name: Get VM info
pilab.pivirt.vm_info:
name: web-01
namespace: production
register: vm_info
- name: Display VM IP
debug:
msg: "VM IP: {{ vm_info.vm.ip_address }}"
- name: Create storage volume
pilab.pivirt.storage_volume:
name: data-01
pool: default
size: 100Gi
format: qcow2
state: present
- name: Create volume snapshot
pilab.pivirt.storage_snapshot:
volume: data-01
name: backup-01
state: present
- name: Resize volume
pilab.pivirt.storage_volume:
name: data-01
size: 200Gi
- name: Create VXLAN network
pilab.pivirt.network:
name: vxlan-net
type: vxlan
vxlan:
vni: 1000
local_ip: 10.0.1.10
remote_ips:
- 10.0.1.11
- 10.0.1.12
cidr: 10.10.0.0/16
state: present
- name: Attach VM to network
pilab.pivirt.network_attach:
vm: web-01
network: vxlan-net
ip: 10.10.1.10
- name: Add worker node
pilab.pivirt.cluster_node:
cluster: production
name: worker-04
role: worker
ip: 10.0.1.24
state: present
- name: Drain node for maintenance
pilab.pivirt.cluster_node:
cluster: production
name: worker-01
drain: true
deploy-web-stack.yml
---
- name: Deploy web application stack
hosts: pivirt
gather_facts: false
vars:
namespace: production
web_count: 3
tasks:
- name: Create network
pilab.pivirt.network:
name: app-network
type: bridge
bridge:
name: app-br
interface: eth1
cidr: 10.10.0.0/24
state: present
- name: Create web servers
pilab.pivirt.vm:
name: "web-{{ item }}"
namespace: "{{ namespace }}"
state: running
cpu:
cores: 2
memory:
size: 4Gi
disks:
- name: root
size: 20Gi
pool: default
bus: virtio
nics:
- name: eth0
network: app-network
model: virtio
cloud_init:
user_data: "{{ lookup('template', 'web-cloud-init.yaml.j2') }}"
labels:
app: web
env: production
loop: "{{ range(1, web_count + 1) | list }}"
register: web_vms
- name: Create database server
pilab.pivirt.vm:
name: db-01
namespace: "{{ namespace }}"
state: running
cpu:
cores: 4
memory:
size: 8Gi
disks:
- name: root
size: 20Gi
pool: default
bus: virtio
- name: data
size: 100Gi
pool: fast-pool
bus: virtio
nics:
- name: eth0
network: app-network
model: virtio
cloud_init:
user_data: "{{ lookup('file', 'db-cloud-init.yaml') }}"
labels:
app: database
env: production
register: db_vm
- name: Create network policy
pilab.pivirt.network_policy:
name: web-to-db
namespace: "{{ namespace }}"
pod_selector:
match_labels:
app: database
ingress:
- from:
- pod_selector:
match_labels:
app: web
ports:
- protocol: TCP
port: 5432
state: present
- name: Display web server IPs
debug:
msg: "Web server {{ item.item }}: {{ item.vm.ip_address }}"
loop: "{{ web_vms.results }}"
- name: Display database IP
debug:
msg: "Database server: {{ db_vm.vm.ip_address }}"
# web-cloud-init.yaml.j2
#cloud-config
hostname: web-{{ item }}
fqdn: web-{{ item }}.pilab.hu
users:
- name: pivirt
groups: [sudo, docker]
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- {{ ssh_public_key }}
packages:
- nginx
- docker.io
runcmd:
- systemctl enable --now nginx
- systemctl enable --now docker
write_files:
- path: /var/www/html/index.html
content: |
<!DOCTYPE html>
<html>
<head><title>Welcome</title></head>
<body>
<h2>Welcome to web-{{ item }}</h2>
</body>
</html>
final_message: "Web server ready"
db-cloud-init.yaml
#cloud-config
hostname: db-01
fqdn: db-01.pilab.hu
users:
- name: pivirt
groups: [sudo, docker]
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- {{ ssh_public_key }}
packages:
- postgresql
- docker.io
runcmd:
- systemctl enable --now postgresql
- systemctl enable --now docker
final_message: "Database server ready"
backup-vms.yml
---
- name: Backup VMs
hosts: pivirt
gather_facts: false
vars:
namespace: production
retention_days: 7
tasks:
- name: Get all VMs
pilab.pivirt.vm_info:
namespace: "{{ namespace }}"
register: all_vms
- name: Create snapshots
pilab.pivirt.vm_snapshot:
vm: "{{ item.name }}"
name: "backup-{{ ansible_date_time.date }}"
state: present
loop: "{{ all_vms.vms }}"
when: item.status == 'running'
- name: Delete old snapshots
pilab.pivirt.vm_snapshot:
vm: "{{ item.0.name }}"
name: "{{ item.1.name }}"
state: absent
loop: "{{ all_vms.vms | product(old_snapshots) | list }}"
vars:
old_snapshots: "{{ item.0.snapshots | selectattr('created_at', 'lt', retention_date) | list }}"
retention_date: "{{ (ansible_date_time.epoch | int - (retention_days * 86400)) | to_datetime }}"
when: old_snapshots | length > 0
roles/web-server/tasks/main.yml
---
- name: Create web server VM
pilab.pivirt.vm:
name: "{{ vm_name }}"
namespace: "{{ namespace }}"
state: running
cpu:
cores: "{{ cpu_cores | default(2) }}"
memory:
size: "{{ memory_size | default('4Gi') }}"
disks:
- name: root
size: "{{ disk_size | default('20Gi') }}"
pool: "{{ storage_pool | default('default') }}"
bus: virtio
nics:
- name: eth0
network: "{{ network_name }}"
model: virtio
cloud_init:
user_data: "{{ lookup('template', 'cloud-init.yaml.j2') }}"
labels:
app: "{{ app_name }}"
env: "{{ environment }}"
register: vm_result
- name: Wait for VM to be ready
pause:
seconds: 30
when: vm_result.changed
- name: Get VM info
pilab.pivirt.vm_info:
name: "{{ vm_name }}"
namespace: "{{ namespace }}"
register: vm_info
group_vars/pivirt.yml
---
pivirt_endpoint: "https://agent.pilab.hu:8443"
pivirt_namespace: "production"
ssh_public_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
- name: Create web servers
pilab.pivirt.vm:
# ...
tags:
- web
- create
- name: Update VM configuration
pilab.pivirt.vm:
name: web-01
# ...
notify: Restart VM
handlers:
- name: Restart VM
pilab.pivirt.vm:
name: web-01
state: restarted