Incus Terraform Provider

repository·main·Indexed 41 days ago

https://github.com/lxc/terraform-provider-incus

A Terraform provider for managing Incus resources, enabling the provisioning and management of containers and virtual machines via Terraform HCL. It includes data sources for certificates, clusters, images, and instances, as well as tools for generating provider data sources.

Tokens
30.4K
Snippets
89
Records
159
Agent score
50%

What's inside Incus Terraform Provider

  1. Manage Incus server configuration with incus_server

    main

    The incus_server resource manages the configuration settings of an Incus server or cluster.

    Important Lifecycle Behavior: Because an Incus server must exist before Terraform can connect to it, this resource behaves uniquely:

    • Creation: When you first add the resource, Terraform shows it as create in the plan, but it actually only updates the Terraform state to reflect that the existing server is now managed by Terraform.
    • Configuration Scope: The resource only manages configuration keys that are explicitly set in your Terraform configuration. Any existing keys on the server that are not mentioned in your HCL will be preserved and ignored by Terraform.
    • Destruction: When you delete the resource from your configuration, the Incus server itself is not deleted. Instead, only the specific configuration keys managed by Terraform are unset. All other server configuration keys remain untouched.
    resource "incus_server" "test" {
      config = {
        "logging.loki01.target.type"     = "loki"
        "logging.loki01.target.address"  = "https://loki01.int.example.net"
        "logging.loki01.target.username" = "foo"
        "logging.loki01.target.password" = "bar"
        "logging.loki01.types"           = "lifecycle,network-acl"
        "logging.loki01.lifecycle.types" = "instance"
      }
    }
  2. Understand computed project configuration keys

    main

    When defining the config map for an incus_project, note that certain keys are automatically managed by Incus. If you do not explicitly define these keys, they will be omitted from the Terraform state and treated as computed values:

    • features.images
    • features.profiles
    • features.storage.volumes
    • features.storage.buckets
  3. Understand computed config keys in incus_storage_pool

    main

    The config map in incus_storage_pool may contain keys automatically generated by Incus. If you do not explicitly define these keys, they will be treated as computed values in the Terraform state.

    Common computed keys by driver:

    • dir: source
    • zfs: size, source, zfs.pool_name
    • lvm: size, source, lvm.vg_name, lvm.thinpool_name
    • lvmcluster: size, lvm.vg_name
    • linstor: source, linstor.resource_group.name, linstor.resource_group.place_count, linstor.resource_group.storage_pool, linstor.volume.prefix, drbd.auto_add_quorum_tiebreaker, drbd.on_no_quorum
    • truenas: source, truenas.dataset
    • General: volatile.* keys.
  4. Manage network address sets with incus_network_address_set

    main

    The incus_network_address_set resource allows you to define a list of IPv4 or IPv6 addresses (with or without CIDR suffixes). These sets can be referenced in the source or destination fields of Incus ACLs to simplify rule management.

    resource "incus_network_address_set" "this" {
        name        = "Network Address Set"
        description = "Network Address Set description"
        addresses   = ["10.0.0.2", "10.0.0.3"]
    }
  5. Create a network in an Incus cluster

    main

    To create a network in a cluster, you must first define the network on each individual node in the cluster using the target argument. Once the node-level resources are defined, you create the actual cluster-wide network resource, ensuring it depends_on the node-specific resources.

    resource "incus_network" "my_network_node1" {
      name   = "my_network"
      target = "node1"
    }
    
    resource "incus_network" "my_network_node2" {
      name   = "my_network"
      target = "node2"
    }
    
    resource "incus_network" "my_network" {
      depends_on = [
        "incus_network.my_network_node1",
        "incus_network.my_network_node2",
      ]
    
      name = "my_network"
    
      config = {
        "ipv4.address" = "10.150.19.1/24"
        "ipv4.nat"     = "true"
        "ipv6.address" = "fd42:474b:622d:259d::1/64"
        "ipv6.nat"     = "true"
      }
    }
  6. Wait for instance readiness with wait_for

    main

    The wait_for block allows you to pause Terraform execution until the instance reaches a specific state. This is useful for ensuring services or networks are ready before proceeding.

    Supported type values:

    • agent: Waits for the Incus agent (required for VMs).
    • cloud-init: Waits for cloud-init to complete.
    • delay: Waits for a specified delay (e.g., 30s).
    • ipv4: Waits for an IPv4 address on a specific nic (e.g., eth0).
    • ipv6: Waits for an IPv6 address on a specific nic (e.g., eth0).
    • ready: Waits for the instance to be ready.

    Examples

    Wait for Incus agent (VMs):

    wait_for {
      type = "agent"
    }

    Wait for cloud-init:

    wait_for {
      type = "cloud-init"
    }

    Wait for IPv4/IPv6 on eth0:

    wait_for {
      type = "ipv4"
      nic  = "eth0"
    }
    
    wait_for {
      type = "ipv6"
      nic  = "eth0"
    }
  7. How templates work in generate-datasources

    main

    The tool uses Go templates to define both the target file paths and the content of the generated files. There are two types of templates:

    1. Regular templates: Executed once for every entity (resource) defined in the configuration. These have access to the entityArgs for the current entity.
    2. Global templates: Executed exactly once for the entire generation process. These receive a map containing all entities, where the key is the entity name and the value is its corresponding entityArgs.
  8. Use the incus_cluster data source

    main

    The incus_cluster data source provides information about an Incus cluster. It can be used to discover cluster members and determine if the current Incus setup is running in a clustered configuration. If the setup is not clustered, the members attribute will be null.

    data "incus_cluster" "this" {
      # No arguments are required.
    }
  9. Import an incus_network_forward resource

    main

    To import an existing Incus network forward into your Terraform state, use the following ID syntax:

    [<remote>:][<project>/]<network-name>/<listen-address>

    • <remote> (Optional): Remote name.
    • <project> (Optional): Project name.
    • <network-name> (Required): Network name.
    • <listen-address> (Required): IP Listen Address.
    # Using terraform import command
    terraform import incus_network_forward.forward1 proj/my-network/10.150.19.10
    
    # Using an import block (Terraform v1.5.0+)
    resource "incus_network_forward" "forward1" {
      network_name   = "my-network"
      listen_address = "10.150.19.10"
      project        = "proj"
    }
    
    import {
      to = incus_network_forward.forward1
      id = "proj/my-network/10.150.19.10"
    }
  10. Import an incus_network_acl

    main

    To import an existing Incus network ACL into Terraform, use the following ID syntax: [<remote>:][<project>/]<name>

    • <remote>: Optional remote name.
    • <project>: Optional project name.
    • <name>: Required network name.

    Using terraform import

    terraform import incus_network_acl.acl1 proj/acl1

    Using the import block (Terraform v1.5.0+)

    resource "incus_network_acl" "acl1" {
      name    = "acl1"
      project = "proj"
    }
    
    import {
      to = incus_network_acl.acl1
      id = "proj/acl1"
    }
  11. Create an Incus network load balancer

    main

    The incus_network_lb resource forwards ports from external IPs to internal ones within an Incus network, distributing traffic among multiple backends.

    Important Compatibility Note: The load balancer resource is exclusively compatible with OVN (Open Virtual Network). You must ensure your uplink network is of type ovn.

    resource "incus_network" "network" {
      name = "ovn"
      type = "ovn"
    
      config = {
        # ...
      }
    }
    
    resource "incus_network_lb" "load_balancer" {
      network        = incus_network.network.name
      description    = "My Load Balancer"
      listen_address = "10.10.10.200"
    
      config = {
        "key" = "value"
      }
    
      backend {
        name           = "instance-1"
        description    = "Load Balancer Backend"
        target_address = "10.0.0.10"
        target_port    = "80"
      }
    
      backend {
        name           = "instance-2"
        description    = "Load Balancer Backend"
        target_address = "10.0.0.11"
        target_port    = "80"
      }
    
      port {
        description = "Port 8080/tcp"
        protocol    = "tcp"
        listen_port = "8080"
        target_backend = [
          "instance-1",
          "instance-2",
        ]
      }
    }