Files
calvin.house 859c0b0ae3 Pulumi libvirt project commit
Initial commit for pulumi kvm project
2026-07-10 02:54:21 +00:00

218 lines
5.2 KiB
Python

import pulumi
import pulumi_libvirt as libvirt
import yaml
# Function to convert GB to bytes for disk size stated in stack config
def gb_to_bytes(gb: int) -> int:
return int(gb) * 1024 * 1024 * 1024
config = pulumi.Config("kvm")
ssh_user = config.get("ssh_user") or "root"
target_host = config.require("target_host")
guest_name = config.require("guest_name")
bridge_interface = config.require("bridge_interface")
secret_hash = config.require_secret("password_hash")
# Load cloud-config
with open(config.require("user_data_path"), "r") as f:
user_data = pulumi.Output.format(f.read(), password_hash=secret_hash)
# Set KVM host
host_provider = libvirt.Provider(
"ssh-provider",
uri=f"qemu+sshcmd://{ssh_user}@{target_host}/system"
)
meta_data_yaml = yaml.dump({"instance-id": f"i-{guest_name}", "local-hostname": guest_name})
# Initialize DNS nameservers and search domain
dns_servers = config.require_object("dns_servers")
dns_search = config.get_object("dns_search") or []
# Initialize network config
network_config_payload = {
"version": 1,
"config": []
}
# Append "physical" interface
physical_interface = {
"type": "physical",
"name": "eth0",
"subnets": [
{
"type": "static",
"address": config.require("static_ip"),
"gateway": config.require("gateway")
}
]
}
network_config_payload["config"].append(physical_interface)
# Append nameservers
if dns_servers:
nameserver_block = {
"type": "nameserver",
"interface": "eth0",
"address": dns_servers
}
network_config_payload["config"].append(nameserver_block)
# Append search domain
if dns_search:
network_config_payload["config"][0]["subnets"][0]["dns_search"] = list(str(dns_search))
network_config_yaml = yaml.dump(network_config_payload)
base_volume = libvirt.Volume(
"base-vol",
name=f"{guest_name}-base",
pool=pool_target,
capacity=gb_to_bytes(10),
target={
"format": {"type": "qcow2"}
},
create={
"content": {
"url": base_image_path
}
},
opts=pulumi.ResourceOptions(provider=host_provider)
)
guest_volume = libvirt.Volume(
"guest-disk",
name=f"{guest_name}",
pool=pool_target,
capacity=gb_to_bytes(config.require_int("disk_gb")),
target={
"format": {"type": "qcow2"}
},
backing_store={
"path": base_volume.id,
"format": {
"type": "qcow2"
}
},
opts=pulumi.ResourceOptions(provider=host_provider)
)
cloud_init_disk = libvirt.CloudinitDisk(
"cloudinit-iso",
meta_data=meta_data_yaml,
user_data=user_data,
network_config=network_config_yaml,
opts=pulumi.ResourceOptions(provider=host_provider)
)
# Create the cloud-init volume with metadata
cloud_init_volume = libvirt.Volume(
"cloudinit-vol",
pool=pool_target,
target={
"format": {"type": "raw"}
},
create={
"content": {
"url": cloud_init_disk.path
}
},
opts=pulumi.ResourceOptions(provider=host_provider)
)
guest = libvirt.Domain(
"kvm-guest",
name=guest_name,
type="kvm",
autostart=True,
cpu={
"mode": "host-passthrough"
},
memory=config.require_int("memory_mb"),
memory_unit="MiB",
vcpu=config.require_int("vcpu"),
os={
"type": "hvm",
"type_arch": "x86_64",
"type_machine": "q35",
"firmware": "efi",
"boot_devices": []
},
features={
"acpi": True
},
devices={
"disks": [
{
"source": {
"volume": {
"pool": guest_volume.pool,
"volume": guest_volume.name
}
},
"target": {
"dev": "vda",
"bus": "virtio"
},
"driver": {
"type": "qcow2"
},
"boot": {
"order": 1
}
},
{
"device": "cdrom",
"source": {
"volume": {
"pool": cloud_init_volume.pool,
"volume": cloud_init_volume.name
}
},
"target": {
"dev": "sda",
"bus": "sata"
},
"driver": {
"type": "raw"
}
}
],
"interfaces": [
{
"type": "bridge",
"model": {
"type": "virtio"
},
"source": {
"bridge": {
"bridge": bridge_interface
}
},
"wait_for_ip": {
"timeout": 300,
"source": "lease"
}
}
],
"graphics": [
{
"type": "vnc",
"vnc": {
"autoport": True,
"listen": "127.0.0.1"
}
}
]
},
opts=pulumi.ResourceOptions(provider=host_provider)
)
pulumi.export("deployed_node", guest.name)