понедельник, 24 мая 2021 г.

Terraform провайдер libvirt в Debian Buster

Давно собирался попробовать управлять виртуалками в libvirt через Terraform. Для этого существует провайдер multain/libvirt. Для начала создам виртуальную машину с двумя дисками.

terraform {
  required_providers {
    libvirt = {
      source = "multani/libvirt"
      version = "0.6.3-1+4"
    }
  }
}

provider "libvirt" {
  uri = "qemu:///system"
}

variable "prefix" {
  description = "Resource name prefix"
  type        = string
  default     = "terraform-"
}

resource "libvirt_volume" "boot" {
  name = "${var.prefix}boot"
  size = 20*1024*1024*1024
}

resource "libvirt_volume" "data" {
  name = "${var.prefix}data"
  size = 20*1024*1024*1024
}

resource "libvirt_domain" "default" {
  name = "${var.prefix}default"
  vcpu = 1
  memory = 2048

  disk {
    file = "/var/lib/libvirt/images/debian-10.9.0-amd64-netinst.iso"
  }

  disk {
    volume_id = libvirt_volume.boot.id
  }

  disk {
    volume_id = libvirt_volume.data.id
  }

  boot_device {
    dev = [ "hd", "cdrom"]
  }

  network_interface {
    bridge = "dmz0"
  }
}

Инициализирую конфигурацию и пробую применить

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding multani/libvirt versions matching "0.6.3-1+4"...
- Installing multani/libvirt v0.6.3-1+4...
- Installed multani/libvirt v0.6.3-1+4 (self-signed, key ID D888B151BEF9257A)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.


$ terraform apply
╷
│ Error: Could not load plugin
│ 
│ 
│ Plugin reinitialization required. Please run "terraform init".
│ 
│ Plugins are external binaries that Terraform uses to access and manipulate
│ resources. The configuration provided requires plugins which can't be located,
│ don't satisfy the version constraints, or are otherwise incompatible.
│ 
│ Terraform automatically discovers provider requirements from your
│ configuration, including providers used in child modules. To see the
│ requirements and constraints, run "terraform providers".
│ 
│ failed to instantiate provider "registry.terraform.io/multani/libvirt" to obtain schema: Unrecognized remote plugin message: 
│ 
│ This usually means that the plugin is either invalid or simply
│ needs to be recompiled to support the latest protocol.

Terraform ругается на невозможность загрузки плагина и просит повторную инициализацию. Попробую запустить провайдер из консоли - в норме он должен ругаться что так делать нельзя

$ ./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4 
./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4: /usr/lib/x86_64-linux-gnu/libvirt.so.0: version `LIBVIRT_5.10.0' not found (required by ./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4)
./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4: /usr/lib/x86_64-linux-gnu/libvirt.so.0: version `LIBVIRT_5.8.0' not found (required by ./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4)
./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4: /usr/lib/x86_64-linux-gnu/libvirt.so.0: version `LIBVIRT_5.2.0' not found (required by ./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4)
./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4: /usr/lib/x86_64-linux-gnu/libvirt.so.0: version `LIBVIRT_5.5.0' not found (required by ./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4)
./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4: /usr/lib/x86_64-linux-gnu/libvirt.so.0: version `LIBVIRT_5.7.0' not found (required by ./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4)
./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4: /usr/lib/x86_64-linux-gnu/libvirt.so.0: version `LIBVIRT_5.6.0' not found (required by ./.terraform/providers/registry.terraform.io/multani/libvirt/0.6.3-1+4/linux_amd64/terraform-provider-libvirt_v0.6.3-1+4)

но вместо этого в консоль падает ошибка что в библиотеке libvirt.so.0 не найдем символы. Похоже провайдер собран с более свежей версией libvirt чем есть в Debian Buster. Самый простой способ решить проблему - скомпилировать провайдер из исходников. На Github есть инструкция как это сделать.

Для начала нужно установить git, make, golang-go (Go буду ставить из buster-backports) и libvirt-dev

$ sudo apt update
$ sudo apt install -y git make libvirt-dev 
$ sudo apt install -y -t buster-backports golang-go

Далее по инструкции

$ cd /tmp
$ git clone https://github.com/dmacvicar/terraform-provider-libvirt.git
$ cd terraform-provider-libvirt
$ make

После сборки проверяю что провайдер запускается в консоли

$ ./terraform-provider-libvirt 
This binary is a plugin. These are not meant to be executed directly.
Please execute the program that consumes these plugins, which will
load any plugins automatically

это ожидаемое поведение. Теперь нужно подключить этот провайдер в Terraform. Для этого воспользуюсь этой инструкцией.

$ cat > tfdev.rc <<_EOF_
provider_installation {
  dev_overrides {
    "multani/libvirt" = "/tmp/terraform-provider-libvirt"
  }

  direct {}
}
_EOF_

$ export TF_CLI_CONFIG_FILE=$(pwd)/tfdev.rc

Проверяю правильность конфигурации

$ terraform validate
╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - multani/libvirt in /tmp/terraform-provider-libvirt
│ 
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published releases.
╵
Success! The configuration is valid, but there were some validation warnings as shown above.

Теперь можно создать виртуальную машину

$ terraform apply
╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - multani/libvirt in /tmp/terraform-provider-libvirt
│ 
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published releases.
╵

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # libvirt_domain.default will be created
  + resource "libvirt_domain" "default" {
      + arch        = (known after apply)
      + disk        = [
          + {
              + block_device = null
              + file         = "/var/lib/libvirt/images/debian-10.9.0-amd64-netinst.iso"
              + scsi         = null
              + url          = null
              + volume_id    = null
              + wwn          = null
            },
          + {
              + block_device = null
              + file         = null
              + scsi         = null
              + url          = null
              + volume_id    = (known after apply)
              + wwn          = null
            },
          + {
              + block_device = null
              + file         = null
              + scsi         = null
              + url          = null
              + volume_id    = (known after apply)
              + wwn          = null
            },
        ]
      + emulator    = (known after apply)
      + fw_cfg_name = "opt/com.coreos/config"
      + id          = (known after apply)
      + machine     = (known after apply)
      + memory      = 2048
      + name        = "terraform-default"
      + qemu_agent  = false
      + running     = true
      + vcpu        = 1

      + boot_device {
          + dev = [
              + "hd",
              + "cdrom",
            ]
        }

      + network_interface {
          + addresses    = (known after apply)
          + bridge       = "dmz0"
          + hostname     = (known after apply)
          + mac          = (known after apply)
          + network_id   = (known after apply)
          + network_name = (known after apply)
        }
    }

  # libvirt_volume.boot will be created
  + resource "libvirt_volume" "boot" {
      + format = (known after apply)
      + id     = (known after apply)
      + name   = "terraform-boot"
      + pool   = "default"
      + size   = 21474836480
    }

  # libvirt_volume.data will be created
  + resource "libvirt_volume" "data" {
      + format = (known after apply)
      + id     = (known after apply)
      + name   = "terraform-data"
      + pool   = "default"
      + size   = 21474836480
    }

Plan: 3 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

libvirt_volume.data: Creating...
libvirt_volume.boot: Creating...
libvirt_volume.boot: Creation complete after 1s [id=/var/lib/libvirt/images/terraform-boot]
libvirt_volume.data: Creation complete after 1s [id=/var/lib/libvirt/images/terraform-data]
libvirt_domain.default: Creating...
libvirt_domain.default: Creation complete after 2s [id=58a3a5ae-6edd-46f2-b1cc-fad2fb6b79f4]

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

После тестирования всю конфигурацию можно удалить

$ terraform destroy
╷
│ Warning: Provider development overrides are in effect
│ 
│ The following provider development overrides are set in the CLI configuration:
│  - multani/libvirt in /tmp/terraform-provider-libvirt
│ 
│ The behavior may therefore not match any released version of the provider and applying changes may cause the state to become incompatible with published releases.
╵
libvirt_volume.data: Refreshing state... [id=/var/lib/libvirt/images/terraform-data]
libvirt_volume.boot: Refreshing state... [id=/var/lib/libvirt/images/terraform-boot]
libvirt_domain.default: Refreshing state... [id=58a3a5ae-6edd-46f2-b1cc-fad2fb6b79f4]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the last "terraform apply":

  # libvirt_domain.default has been changed
  ~ resource "libvirt_domain" "default" {
      + cmdline     = []
        id          = "58a3a5ae-6edd-46f2-b1cc-fad2fb6b79f4"
        name        = "terraform-default"
        # (10 unchanged attributes hidden)


        # (2 unchanged blocks hidden)
    }

Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the following plan may include actions to undo or respond to these changes.

─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # libvirt_domain.default will be destroyed
  - resource "libvirt_domain" "default" {
      - arch        = "x86_64" -> null
      - autostart   = false -> null
      - cmdline     = [] -> null
      - disk        = [
          - {
              - block_device = ""
              - file         = "/var/lib/libvirt/images/debian-10.9.0-amd64-netinst.iso"
              - scsi         = false
              - url          = ""
              - volume_id    = ""
              - wwn          = ""
            },
          - {
              - block_device = ""
              - file         = ""
              - scsi         = false
              - url          = ""
              - volume_id    = "/var/lib/libvirt/images/terraform-boot"
              - wwn          = ""
            },
          - {
              - block_device = ""
              - file         = ""
              - scsi         = false
              - url          = ""
              - volume_id    = "/var/lib/libvirt/images/terraform-data"
              - wwn          = ""
            },
        ] -> null
      - emulator    = "/usr/bin/qemu-system-x86_64" -> null
      - fw_cfg_name = "opt/com.coreos/config" -> null
      - id          = "58a3a5ae-6edd-46f2-b1cc-fad2fb6b79f4" -> null
      - machine     = "pc" -> null
      - memory      = 2048 -> null
      - name        = "terraform-default" -> null
      - qemu_agent  = false -> null
      - running     = true -> null
      - vcpu        = 1 -> null

      - boot_device {
          - dev = [
              - "hd",
              - "cdrom",
            ] -> null
        }

      - network_interface {
          - addresses      = [] -> null
          - bridge         = "dmz0" -> null
          - mac            = "52:54:00:8A:A2:99" -> null
          - wait_for_lease = false -> null
        }
    }

  # libvirt_volume.boot will be destroyed
  - resource "libvirt_volume" "boot" {
      - format = "qcow2" -> null
      - id     = "/var/lib/libvirt/images/terraform-boot" -> null
      - name   = "terraform-boot" -> null
      - pool   = "default" -> null
      - size   = 21474836480 -> null
    }

  # libvirt_volume.data will be destroyed
  - resource "libvirt_volume" "data" {
      - format = "qcow2" -> null
      - id     = "/var/lib/libvirt/images/terraform-data" -> null
      - name   = "terraform-data" -> null
      - pool   = "default" -> null
      - size   = 21474836480 -> null
    }

Plan: 0 to add, 0 to change, 3 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

libvirt_domain.default: Destroying... [id=58a3a5ae-6edd-46f2-b1cc-fad2fb6b79f4]
libvirt_domain.default: Destruction complete after 0s
libvirt_volume.data: Destroying... [id=/var/lib/libvirt/images/terraform-data]
libvirt_volume.boot: Destroying... [id=/var/lib/libvirt/images/terraform-boot]
libvirt_volume.data: Destruction complete after 0s
libvirt_volume.boot: Destruction complete after 0s

Destroy complete! Resources: 3 destroyed.

Полный список поддерживаемых провайдером libvirt ресурсов описан в документации.

Комментариев нет:

Отправить комментарий