Skip to content

Terraform Provider Integration

The PiVirt Terraform Provider (pilab-cloud/pivirt) allows infrastructure engineers to provision and manage virtual machines, storage pools, networks, and cloud clusters declaratively as code.

main.tf
terraform {
required_providers {
pivirt = {
source = "pilab-cloud/pivirt"
version = "~> 1.0"
}
}
}
provider "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"
}
Terminal window
git clone https://github.com/pilab-cloud/terraform-provider-pivirt
cd terraform-provider-pivirt
go build -o terraform-provider-pivirt
mkdir -p ~/.terraform.d/plugins/registry.terraform.io/pilab-cloud/pivirt/1.0.0/linux_amd64
mv terraform-provider-pivirt ~/.terraform.d/plugins/registry.terraform.io/pilab-cloud/pivirt/1.0.0/linux_amd64/
provider "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"
# Optional settings
namespace = "production"
timeout = "30m"
}
# Using environment variables
export PIVIRT_ENDPOINT="https://agent.pilab.hu:8443"
export PIVIRT_CA_FILE="~/.config/pvcli/ca.crt"
export PIVIRT_CERT_FILE="~/.config/pvcli/client.crt"
export PIVIRT_KEY_FILE="~/.config/pvcli/client.key"
# Or using token
export PIVIRT_TOKEN="your-jwt-token"
resource "pivirt_virtual_machine" "web" {
name = "web-01"
namespace = "production"
cpu {
cores = 2
model = "host-passthrough"
}
memory {
size = "4Gi"
}
disk {
name = "root"
size = "20Gi"
pool = "default"
bus = "virtio"
boot_order = 1
}
nic {
name = "eth0"
network = "virbr0"
model = "virtio"
}
os {
type = "linux"
boot_order = ["disk", "network"]
}
cloud_init {
user_data = file("${path.module}/cloud-init.yaml")
}
labels = {
app = "web"
env = "production"
}
}
resource "pivirt_storage_volume" "data" {
name = "data-01"
pool = "default"
size = "100Gi"
format = "qcow2"
labels = {
app = "database"
}
}
resource "pivirt_storage_snapshot" "backup" {
volume_id = pivirt_storage_volume.data.id
name = "backup-01"
}
resource "pivirt_network" "vxlan" {
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"
}
resource "pivirt_network_policy" "web_isolation" {
name = "web-isolation"
namespace = "production"
pod_selector {
match_labels = {
app = "web"
}
}
ingress {
from {
namespace_selector {
match_labels = {
name = "monitoring"
}
}
}
ports {
protocol = "TCP"
port = 80
}
}
}
data "pivirt_virtual_machines" "running" {
namespace = "production"
filter {
name = "status"
values = ["running"]
}
}
output "running_vms" {
value = data.pivirt_virtual_machines.running.vms
}
data "pivirt_virtual_machine" "web" {
name = "web-01"
namespace = "production"
}
output "web_vm_ip" {
value = data.pivirt_virtual_machine.web.ip_address
}
data "pivirt_storage_pools" "all" {}
output "storage_pools" {
value = data.pivirt_storage_pools.all.pools
}
main.tf
terraform {
required_providers {
pivirt = {
source = "pilab-cloud/pivirt"
version = "~> 1.0"
}
}
}
provider "pivirt" {
endpoint = var.pivirt_endpoint
ca_file = var.pivirt_ca_file
cert_file = var.pivirt_cert_file
key_file = var.pivirt_key_file
}
variable "pivirt_endpoint" {
type = string
default = "https://agent.pilab.hu:8443"
}
variable "pivirt_ca_file" {
type = string
default = "~/.config/pvcli/ca.crt"
}
variable "pivirt_cert_file" {
type = string
default = "~/.config/pvcli/client.crt"
}
variable "pivirt_key_file" {
type = string
default = "~/.config/pvcli/client.key"
}
# Network
resource "pivirt_network" "app_network" {
name = "app-network"
type = "bridge"
bridge {
name = "app-br"
interface = "eth1"
}
cidr = "10.10.0.0/24"
}
# Web servers
resource "pivirt_virtual_machine" "web" {
count = 3
name = "web-${count.index + 1}"
namespace = "production"
cpu {
cores = 2
}
memory {
size = "4Gi"
}
disk {
name = "root"
size = "20Gi"
pool = "default"
bus = "virtio"
}
nic {
name = "eth0"
network = pivirt_network.app_network.name
model = "virtio"
}
cloud_init {
user_data = templatefile("${path.module}/web-cloud-init.yaml", {
hostname = "web-${count.index + 1}"
})
}
labels = {
app = "web"
env = "production"
}
}
# Database server
resource "pivirt_virtual_machine" "db" {
name = "db-01"
namespace = "production"
cpu {
cores = 4
}
memory {
size = "8Gi"
}
disk {
name = "root"
size = "20Gi"
pool = "default"
bus = "virtio"
}
disk {
name = "data"
size = "100Gi"
pool = "fast-pool"
bus = "virtio"
}
nic {
name = "eth0"
network = pivirt_network.app_network.name
model = "virtio"
}
cloud_init {
user_data = file("${path.module}/db-cloud-init.yaml")
}
labels = {
app = "database"
env = "production"
}
}
# Network policy
resource "pivirt_network_policy" "web_to_db" {
name = "web-to-db"
namespace = "production"
pod_selector {
match_labels = {
app = "database"
}
}
ingress {
from {
pod_selector {
match_labels = {
app = "web"
}
}
}
ports {
protocol = "TCP"
port = 5432
}
}
}
# Outputs
output "web_ips" {
value = pivirt_virtual_machine.web[*].ip_address
}
output "db_ip" {
value = pivirt_virtual_machine.db.ip_address
}
web-cloud-init.yaml
#cloud-config
hostname: ${hostname}
fqdn: ${hostname}.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 ${hostname}</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
write_files:
- path: /etc/postgresql/16/main/postgresql.conf
content: |
listen_addresses = '*'
max_connections = 100
final_message: "Database server ready"
Terminal window
terraform init
Terminal window
terraform plan
Terminal window
terraform apply
Terminal window
terraform destroy
variable "vm_count" {
type = number
default = 3
}
variable "vm_size" {
type = object({
cpu = number
memory = string
disk = string
})
default = {
cpu = 2
memory = "4Gi"
disk = "20Gi"
}
}
module "web_servers" {
source = "./modules/web-server"
count = 3
namespace = "production"
network = pivirt_network.app_network.name
cloud_init = file("${path.module}/web-cloud-init.yaml")
}
terraform {
backend "s3" {
bucket = "terraform-state"
key = "pivirt/production/terraform.tfstate"
region = "eu-central-1"
}
}